|
|
@@ -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: {
|