Merge pull request #2414 from overleaf/ta-features-overrides

Persistent Features Override

GitOrigin-RevId: 9bb389458a4fde3cc36dbc5b8c3f7185b7e4e9bf
This commit is contained in:
Eric Mc Sween 2019-12-02 08:51:57 -05:00 committed by sharelatex
parent 86352c58be
commit a493ec94b2
4 changed files with 117 additions and 3 deletions

View file

@ -50,6 +50,9 @@ const FeaturesUpdater = {
},
samlFeatures(cb) {
return FeaturesUpdater._getSamlFeatures(user_id, cb)
},
featuresOverrides(cb) {
return FeaturesUpdater._getFeaturesOverrides(user_id, cb)
}
}
return async.series(jobs, function(err, results) {
@ -67,7 +70,8 @@ const FeaturesUpdater = {
institutionFeatures,
v1Features,
bonusFeatures,
samlFeatures
samlFeatures,
featuresOverrides
} = results
logger.log(
{
@ -77,7 +81,8 @@ const FeaturesUpdater = {
institutionFeatures,
v1Features,
bonusFeatures,
samlFeatures
samlFeatures,
featuresOverrides
},
'merging user features'
)
@ -86,7 +91,8 @@ const FeaturesUpdater = {
institutionFeatures,
v1Features,
bonusFeatures,
samlFeatures
samlFeatures,
featuresOverrides
])
const features = _.reduce(
featureSets,
@ -143,6 +149,36 @@ const FeaturesUpdater = {
})
},
_getFeaturesOverrides(user_id, callback) {
UserGetter.getUser(user_id, { featuresOverrides: 1 }, (error, user) => {
if (error) {
return callback(error)
}
if (
!user ||
!user.featuresOverrides ||
user.featuresOverrides.length === 0
) {
return callback(null, {})
}
let activeFeaturesOverrides = []
for (let featuresOverride of user.featuresOverrides) {
if (
!featuresOverride.expiresAt ||
featuresOverride.expiresAt > new Date()
) {
activeFeaturesOverrides.push(featuresOverride.features)
}
}
const features = _.reduce(
activeFeaturesOverrides,
FeaturesUpdater._mergeFeatures,
{}
)
return callback(null, features)
})
},
_getV1Features(user_id, callback) {
if (callback == null) {
callback = function(error, features) {}

View file

@ -91,6 +91,32 @@ const UserSchema = new Schema({
default: Settings.defaultFeatures.referencesSearch
}
},
featuresOverrides: [
{
createdAt: {
type: Date,
default() {
return new Date()
}
},
expiresAt: { type: Date },
note: { type: String },
features: {
collaborators: { type: Number },
versioning: { type: Boolean },
dropbox: { type: Boolean },
github: { type: Boolean },
gitBridge: { type: Boolean },
compileTimeout: { type: Number },
compileGroup: { type: String },
templates: { type: Boolean },
trackChanges: { type: Boolean },
mendeley: { type: Boolean },
zotero: { type: Boolean },
referencesSearch: { type: Boolean }
}
}
],
// when auto-merged from SL and must-reconfirm is set, we may end up using
// `sharelatexHashedPassword` to recover accounts...
sharelatexHashedPassword: String,

View file

@ -338,4 +338,51 @@ describe('FeatureUpdater.refreshFeatures', function() {
)
}) // returns a promise
})
describe('when the user has features overrides', function() {
beforeEach(function() {
const futureDate = new Date()
futureDate.setDate(futureDate.getDate() + 1)
return User.update(
{
_id: this.user._id
},
{
featuresOverrides: [
{
features: {
github: true
}
},
{
features: {
dropbox: true
},
expiresAt: new Date(1990, 12, 25)
},
{
features: {
trackChanges: true
},
expiresAt: futureDate
}
]
}
)
}) // returns a promise
it('should set their features to the overridden set', function(done) {
return syncUserAndGetFeatures(this.user, (error, features) => {
if (error != null) {
throw error
}
let expectedFeatures = Object.assign(settings.defaultFeatures, {
github: true,
trackChanges: true
})
expect(features).to.deep.equal(expectedFeatures)
return done()
})
})
})
})

View file

@ -142,6 +142,11 @@ class User {
UserModel.update({ _id: this.id }, update, callback)
}
setFeaturesOverride(featuresOverride, callback) {
const update = { $push: { featuresOverrides: featuresOverride } }
UserModel.update({ _id: this.id }, update, callback)
}
setOverleafId(overleafId, callback) {
UserModel.update({ _id: this.id }, { 'overleaf.id': overleafId }, callback)
}