3 var fflip
= require('fflip');
4 var mongoUtils
= require('gitter-web-persistence-utils/lib/mongo-utils');
5 var persistence
= require('gitter-web-persistence');
8 * List of criteria functions to be used by feature toggles
11 /* Allow a certain percentage of users */
12 percentageOfUsers: function(userDetails
, percent
) {
13 var user
= userDetails
.user
;
14 if (!user
) return false;
15 var timestamp
= Math
.round(mongoUtils
.getTimestampFromObjectId(user
._id
) / 1000) || 0;
16 return timestamp
% 100 < percent
|| undefined;
19 /* Allow a hash of usernames */
20 allowUsernames: function(userDetails
, usernameHash
) {
21 var user
= userDetails
.user
;
22 if (!user
) return false;
23 if (!usernameHash
) return undefined;
24 return !!usernameHash
[user
.username
] || undefined;
27 disableBrowser: function(userDetails
, browsers
) {
28 if (!browsers
) return undefined;
30 var agent
= userDetails
.req
.getParsedUserAgent();
32 var disabledVersion
= browsers
[agent
.family
];
33 if (!disabledVersion
) return undefined;
35 if (disabledVersion
=== 'all') return false;
36 if (agent
.major
<= disabledVersion
) return false;
40 bucket: function(userDetails
, bucket
) {
41 var user
= userDetails
.user
;
42 if (!user
) return false;
43 var userId
= user
._id
;
45 // This is copied from gitter-env.
46 var lastChar
= userId
.toString().slice(-1);
47 var userBucket
= parseInt(lastChar
+ '', 16) % 2 ? 'A' : 'B';
49 return userBucket
=== bucket
|| undefined;
52 createdAfter: function(userDetails
, timestamp
) {
53 var user
= userDetails
.user
;
54 if (!user
) return false;
55 var userTimestamp
= mongoUtils
.getTimestampFromObjectId(user
._id
);
56 return userTimestamp
> timestamp
|| undefined;
59 bucketCreatedAfter: function(userDetails
, opts
) {
61 (Criteria
.bucket(userDetails
, opts
.bucket
) &&
62 Criteria
.createdAfter(userDetails
, opts
.createdAfter
)) ||
67 /* Enabled criteria */
68 enabled: function(/*user*/) {
73 function getFeatures(callback
) {
74 persistence
.FeatureToggle
.find({})
77 .then(function(togglesList
) {
78 if (!togglesList
|| togglesList
.length
=== 0) {
82 var featureToggles
= togglesList
.reduce(function(memo
, toggle
) {
83 memo
[toggle
.name
] = { criteria
: toggle
.criteria
};
87 // NOTE: this callback doesn't have an err.
88 callback(featureToggles
);
94 features
: getFeatures
,
95 reload
: 60, // Reload features every 60 seconds
96 maxCookieAge
: 31 * 86400 * 1000,
101 fflip
.express_middleware
,
102 function(req
, res
, next
) {
103 // Only logged in users get features
104 if (!req
.user
) return next();
106 req
.fflip
.setForUser({ user
: req
.user
, req
: req
});