Merge pull request #4200 from overleaf/ab-feature-set-user-property

Resolve and send feature set user property to analytics

GitOrigin-RevId: 08ddd0fe9202b02f7d37547dab1d078bf441a8cf
This commit is contained in:
Alexandre Bourdin 2021-06-16 16:22:15 +02:00 committed by Copybot
parent 255761b31b
commit 9f1784b4c4
2 changed files with 86 additions and 9 deletions

View file

@ -10,6 +10,7 @@ const ReferalFeatures = require('../Referal/ReferalFeatures')
const V1SubscriptionManager = require('./V1SubscriptionManager') const V1SubscriptionManager = require('./V1SubscriptionManager')
const InstitutionsFeatures = require('../Institutions/InstitutionsFeatures') const InstitutionsFeatures = require('../Institutions/InstitutionsFeatures')
const UserGetter = require('../User/UserGetter') const UserGetter = require('../User/UserGetter')
const AnalyticsManager = require('../Analytics/AnalyticsManager')
const FeaturesUpdater = { const FeaturesUpdater = {
refreshFeatures(userId, reason, callback = () => {}) { refreshFeatures(userId, reason, callback = () => {}) {
@ -23,6 +24,16 @@ const FeaturesUpdater = {
return callback(error) return callback(error)
} }
logger.log({ userId, features }, 'updating user features') logger.log({ userId, features }, 'updating user features')
const matchedFeatureSet = FeaturesUpdater._getMatchedFeatureSet(
features
)
AnalyticsManager.setUserProperty(
userId,
'feature-set',
matchedFeatureSet
)
UserFeaturesUpdater.updateFeatures( UserFeaturesUpdater.updateFeatures(
userId, userId,
features, features,
@ -301,6 +312,15 @@ const FeaturesUpdater = {
} }
) )
}, },
_getMatchedFeatureSet(features) {
for (const [name, featureSet] of Object.entries(Settings.features)) {
if (_.isEqual(features, featureSet)) {
return name
}
}
return 'mixed'
},
} }
const refreshFeaturesPromise = (userId, reason) => const refreshFeaturesPromise = (userId, reason) =>

View file

@ -13,11 +13,35 @@ describe('FeaturesUpdater', function () {
'./UserFeaturesUpdater': (this.UserFeaturesUpdater = {}), './UserFeaturesUpdater': (this.UserFeaturesUpdater = {}),
'./SubscriptionLocator': (this.SubscriptionLocator = {}), './SubscriptionLocator': (this.SubscriptionLocator = {}),
'./PlansLocator': (this.PlansLocator = {}), './PlansLocator': (this.PlansLocator = {}),
'settings-sharelatex': (this.Settings = {}), 'settings-sharelatex': (this.Settings = {
features: {
personal: {
collaborators: 1,
dropbox: false,
compileTimeout: 60,
compileGroup: 'standard',
},
collaborator: {
collaborators: 10,
dropbox: true,
compileTimeout: 240,
compileGroup: 'priority',
},
professional: {
collaborators: -1,
dropbox: true,
compileTimeout: 240,
compileGroup: 'priority',
},
},
}),
'../Referal/ReferalFeatures': (this.ReferalFeatures = {}), '../Referal/ReferalFeatures': (this.ReferalFeatures = {}),
'./V1SubscriptionManager': (this.V1SubscriptionManager = {}), './V1SubscriptionManager': (this.V1SubscriptionManager = {}),
'../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}), '../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}),
'../User/UserGetter': (this.UserGetter = {}), '../User/UserGetter': (this.UserGetter = {}),
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
setUserProperty: sinon.stub(),
}),
'../../infrastructure/Modules': (this.Modules = { '../../infrastructure/Modules': (this.Modules = {
hooks: { fire: sinon.stub() }, hooks: { fire: sinon.stub() },
}), }),
@ -55,7 +79,6 @@ describe('FeaturesUpdater', function () {
this.UserGetter.getUser = sinon.stub().yields(null, this.user) this.UserGetter.getUser = sinon.stub().yields(null, this.user)
this.callback = sinon.stub() this.callback = sinon.stub()
}) })
it('should return features and featuresChanged', function () { it('should return features and featuresChanged', function () {
this.FeaturesUpdater.refreshFeatures( this.FeaturesUpdater.refreshFeatures(
this.user_id, this.user_id,
@ -67,7 +90,6 @@ describe('FeaturesUpdater', function () {
} }
) )
}) })
describe('normally', function () { describe('normally', function () {
beforeEach(function () { beforeEach(function () {
this.FeaturesUpdater.refreshFeatures( this.FeaturesUpdater.refreshFeatures(
@ -76,37 +98,31 @@ describe('FeaturesUpdater', function () {
this.callback this.callback
) )
}) })
it('should get the individual features', function () { it('should get the individual features', function () {
this.FeaturesUpdater._getIndividualFeatures this.FeaturesUpdater._getIndividualFeatures
.calledWith(this.user_id) .calledWith(this.user_id)
.should.equal(true) .should.equal(true)
}) })
it('should get the group features', function () { it('should get the group features', function () {
this.FeaturesUpdater._getGroupFeatureSets this.FeaturesUpdater._getGroupFeatureSets
.calledWith(this.user_id) .calledWith(this.user_id)
.should.equal(true) .should.equal(true)
}) })
it('should get the institution features', function () { it('should get the institution features', function () {
this.InstitutionsFeatures.getInstitutionsFeatures this.InstitutionsFeatures.getInstitutionsFeatures
.calledWith(this.user_id) .calledWith(this.user_id)
.should.equal(true) .should.equal(true)
}) })
it('should get the v1 features', function () { it('should get the v1 features', function () {
this.FeaturesUpdater._getV1Features this.FeaturesUpdater._getV1Features
.calledWith(this.user_id) .calledWith(this.user_id)
.should.equal(true) .should.equal(true)
}) })
it('should get the bonus features', function () { it('should get the bonus features', function () {
this.ReferalFeatures.getBonusFeatures this.ReferalFeatures.getBonusFeatures
.calledWith(this.user_id) .calledWith(this.user_id)
.should.equal(true) .should.equal(true)
}) })
it('should merge from the default features', function () { it('should merge from the default features', function () {
this.FeaturesUpdater._mergeFeatures this.FeaturesUpdater._mergeFeatures
.calledWith(this.Settings.defaultFeatures) .calledWith(this.Settings.defaultFeatures)
@ -152,6 +168,47 @@ describe('FeaturesUpdater', function () {
.should.equal(true) .should.equal(true)
}) })
}) })
describe('analytics user properties', function () {
it('should send the corresponding feature set user property', function () {
this.FeaturesUpdater._mergeFeatures = sinon
.stub()
.returns(this.Settings.features.personal)
this.FeaturesUpdater.refreshFeatures(
this.user_id,
'test',
this.callback
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.user_id,
'feature-set',
'personal'
)
})
it('should send mixed feature set user property', function () {
this.FeaturesUpdater._mergeFeatures = sinon
.stub()
.returns({ dropbox: true, feature: 'some' })
this.FeaturesUpdater.refreshFeatures(
this.user_id,
'test',
this.callback
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.user_id,
'feature-set',
'mixed'
)
})
})
describe('when losing dropbox feature', function () { describe('when losing dropbox feature', function () {
beforeEach(function () { beforeEach(function () {
this.user = { this.user = {