From 83f934f387596357a5f0ff48be86e108918f1231 Mon Sep 17 00:00:00 2001 From: Jimmy Domagala-Tang <Jimmy.Domagala-Tang@overleaf.com> Date: Wed, 5 Jul 2023 08:32:40 -0400 Subject: [PATCH] Merge pull request #13620 from overleaf/jdt-survey-rollout-slider Jdt survey rollout slider GitOrigin-RevId: 958000c86fc79447484405b2382871bd118fb9fa --- .../app/src/Features/Survey/SurveyHandler.js | 31 ++++++++++++++++++- services/web/app/src/models/Survey.js | 4 +++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/services/web/app/src/Features/Survey/SurveyHandler.js b/services/web/app/src/Features/Survey/SurveyHandler.js index 81b3f519c0..705f6efd4d 100644 --- a/services/web/app/src/Features/Survey/SurveyHandler.js +++ b/services/web/app/src/Features/Survey/SurveyHandler.js @@ -1,3 +1,4 @@ +const crypto = require('crypto') const SurveyCache = require('./SurveyCache') const SubscriptionLocator = require('../Subscription/SubscriptionLocator') const { callbackify } = require('../../util/promises') @@ -7,6 +8,8 @@ const { callbackify } = require('../../util/promises') */ /** + * determines if there is a survey to show, given current surveys and rollout percentages + * uses userId in computation, to ensure that rollout groups always contain same users * @param {string} userId * @returns {Promise<Survey | undefined>} */ @@ -20,11 +23,37 @@ async function getSurvey(userId) { return } } - const { name, preText, linkText, url } = survey?.toObject() || {} + + const { name, preText, linkText, url, options } = survey?.toObject() || {} + // default to full rollout for backwards compatibility + const rolloutPercentage = options?.rolloutPercentage || 100 + if (!_userInRolloutPercentile(userId, name, rolloutPercentage)) { + return + } + return { name, preText, linkText, url } } } +function _userRolloutPercentile(userId, surveyName) { + const hash = crypto + .createHash('md5') + .update(userId + surveyName) + .digest('hex') + const hashPrefix = hash.substring(0, 8) + return Math.floor( + ((parseInt(hashPrefix, 16) % 0xffffffff) / 0xffffffff) * 100 + ) +} + +function _userInRolloutPercentile(userId, surveyName, rolloutPercentage) { + if (rolloutPercentage === 100) { + return true + } + const userPercentile = _userRolloutPercentile(userId, surveyName) + return userPercentile < rolloutPercentage +} + module.exports = { getSurvey: callbackify(getSurvey), promises: { diff --git a/services/web/app/src/models/Survey.js b/services/web/app/src/models/Survey.js index 2898d94107..5d56a20b54 100644 --- a/services/web/app/src/models/Survey.js +++ b/services/web/app/src/models/Survey.js @@ -36,6 +36,10 @@ const SurveySchema = new Schema( type: Boolean, default: false, }, + rolloutPercentage: { + type: Number, + default: 100, + }, }, }, {