overleaf/services/web/app/coffee/Features/Subscription/FeaturesUpdater.coffee
Simon Detheridge 48995d2d44 Don't add old v1 features for new accounts
Introduces the notion of v1 'grandfathered features', specifically Gihub and Mendeley integration. This allows us to create new v1 accounts for new users without them automatically getting the new features.

Requires a settings change in `settings.web.sl.coffee` to disable these features by default for v1 accounts.

bug: overleaf/sharelatex#1014
2018-10-12 17:45:57 +01:00

101 lines
3.9 KiB
CoffeeScript

async = require("async")
PlansLocator = require("./PlansLocator")
_ = require("underscore")
SubscriptionLocator = require("./SubscriptionLocator")
UserFeaturesUpdater = require("./UserFeaturesUpdater")
Settings = require("settings-sharelatex")
logger = require("logger-sharelatex")
ReferalFeatures = require("../Referal/ReferalFeatures")
V1SubscriptionManager = require("./V1SubscriptionManager")
InstitutionsFeatures = require '../Institutions/InstitutionsFeatures'
oneMonthInSeconds = 60 * 60 * 24 * 30
module.exports = FeaturesUpdater =
refreshFeatures: (user_id, notifyV1 = true, callback = () ->)->
if typeof notifyV1 == 'function'
callback = notifyV1
notifyV1 = true
if notifyV1
V1SubscriptionManager.notifyV1OfFeaturesChange user_id, (error) ->
if error?
logger.err {err: error, user_id}, "error notifying v1 about updated features"
jobs =
individualFeatures: (cb) -> FeaturesUpdater._getIndividualFeatures user_id, cb
groupFeatureSets: (cb) -> FeaturesUpdater._getGroupFeatureSets user_id, cb
institutionFeatures:(cb) -> InstitutionsFeatures.getInstitutionsFeatures user_id, cb
v1Features: (cb) -> FeaturesUpdater._getV1Features user_id, cb
bonusFeatures: (cb) -> ReferalFeatures.getBonusFeatures user_id, cb
async.series jobs, (err, results)->
if err?
logger.err err:err, user_id:user_id,
"error getting subscription or group for refreshFeatures"
return callback(err)
{individualFeatures, groupFeatureSets, institutionFeatures, v1Features, bonusFeatures} = results
logger.log {user_id, individualFeatures, groupFeatureSets, institutionFeatures, v1Features, bonusFeatures}, 'merging user features'
featureSets = groupFeatureSets.concat [individualFeatures, institutionFeatures, v1Features, bonusFeatures]
features = _.reduce(featureSets, FeaturesUpdater._mergeFeatures, Settings.defaultFeatures)
logger.log {user_id, features}, 'updating user features'
UserFeaturesUpdater.updateFeatures user_id, features, callback
_getIndividualFeatures: (user_id, callback = (error, features = {}) ->) ->
SubscriptionLocator.getUsersSubscription user_id, (err, sub)->
callback err, FeaturesUpdater._subscriptionToFeatures(sub)
_getGroupFeatureSets: (user_id, callback = (error, featureSets = []) ->) ->
SubscriptionLocator.getGroupSubscriptionsMemberOf user_id, (err, subs) ->
callback err, (subs or []).map FeaturesUpdater._subscriptionToFeatures
_getV1Features: (user_id, callback = (error, features = {}) ->) ->
V1SubscriptionManager.getPlanCodeFromV1 user_id, (err, planCode, v1Id) ->
if err?
return callback(err)
callback(err, FeaturesUpdater._mergeFeatures(
V1SubscriptionManager.getGrandfatheredFeaturesForV1User(v1Id) or {},
FeaturesUpdater._planCodeToFeatures(planCode)
))
_mergeFeatures: (featuresA, featuresB) ->
features = Object.assign({}, featuresA)
for key, value of featuresB
# Special merging logic for non-boolean features
if key == 'compileGroup'
if features['compileGroup'] == 'priority' or featuresB['compileGroup'] == 'priority'
features['compileGroup'] = 'priority'
else
features['compileGroup'] = 'standard'
else if key == 'collaborators'
if features['collaborators'] == -1 or featuresB['collaborators'] == -1
features['collaborators'] = -1
else
features['collaborators'] = Math.max(
features['collaborators'] or 0,
featuresB['collaborators'] or 0
)
else if key == 'compileTimeout'
features['compileTimeout'] = Math.max(
features['compileTimeout'] or 0,
featuresB['compileTimeout'] or 0
)
else
# Boolean keys, true is better
features[key] = features[key] or featuresB[key]
return features
_subscriptionToFeatures: (subscription) ->
FeaturesUpdater._planCodeToFeatures(subscription?.planCode)
_planCodeToFeatures: (planCode) ->
if !planCode?
return {}
plan = PlansLocator.findLocalPlanInSettings planCode
if !plan?
return {}
else
return plan.features