Merge pull request #4639 from overleaf/ab-web-mono-analytics-id

Analytics ID support

GitOrigin-RevId: 820a6c0f4d19f046f6c791ce4dc64dbc80748924
This commit is contained in:
Alexandre Bourdin
2021-09-09 16:45:41 +02:00
committed by Copybot
parent 3af8fc63de
commit 44a8883b6d
36 changed files with 557 additions and 249 deletions
@@ -12,7 +12,7 @@ describe('AnalyticsController', function () {
this.AnalyticsManager = {
updateEditingSession: sinon.stub(),
recordEvent: sinon.stub(),
recordEventForSession: sinon.stub(),
}
this.Features = {
@@ -42,6 +42,7 @@ describe('AnalyticsController', function () {
params: {
projectId: 'a project id',
},
session: {},
}
this.GeoIpLookup.getDetails = sinon
.stub()
@@ -78,35 +79,18 @@ describe('AnalyticsController', function () {
delete this.expectedData._csrf
})
it('should use the user_id', function (done) {
this.SessionManager.getLoggedInUserId.returns('1234')
it('should use the session', function (done) {
this.controller.recordEvent(this.req, this.res)
this.AnalyticsManager.recordEvent
.calledWith('1234', this.req.params.event, this.expectedData)
.should.equal(true)
done()
})
it('should use the session id', function (done) {
this.controller.recordEvent(this.req, this.res)
this.AnalyticsManager.recordEvent
.calledWith(
this.req.sessionID,
this.req.params.event,
this.expectedData
)
this.AnalyticsManager.recordEventForSession
.calledWith(this.req.session, this.req.params.event, this.expectedData)
.should.equal(true)
done()
})
it('should remove the CSRF token before sending to the manager', function (done) {
this.controller.recordEvent(this.req, this.res)
this.AnalyticsManager.recordEvent
.calledWith(
this.req.sessionID,
this.req.params.event,
this.expectedData
)
this.AnalyticsManager.recordEventForSession
.calledWith(this.req.session, this.req.params.event, this.expectedData)
.should.equal(true)
done()
})
@@ -10,6 +10,7 @@ const MODULE_PATH = path.join(
describe('AnalyticsManager', function () {
beforeEach(function () {
this.fakeUserId = '123abc'
this.analyticsId = '123456'
this.Settings = {
analytics: { enabled: true },
}
@@ -50,6 +51,9 @@ describe('AnalyticsManager', function () {
requires: {
'@overleaf/settings': this.Settings,
'../../infrastructure/Queues': this.Queues,
'./UserAnalyticsIdCache': (this.UserAnalyticsIdCache = {
get: sinon.stub().resolves(this.analyticsId),
}),
},
})
})
@@ -70,21 +74,26 @@ describe('AnalyticsManager', function () {
describe('queues the appropriate message for', function () {
it('identifyUser', function () {
const oldUserId = '456def'
this.AnalyticsManager.identifyUser(this.fakeUserId, oldUserId)
const analyticsId = '456def'
this.AnalyticsManager.identifyUser(this.fakeUserId, analyticsId)
sinon.assert.calledWithMatch(this.analyticsEventsQueue.add, 'identify', {
userId: this.fakeUserId,
oldUserId,
analyticsId,
})
})
it('recordEvent', function () {
it('recordEventForUser', async function () {
const event = 'fake-event'
this.AnalyticsManager.recordEvent(this.fakeUserId, event, null)
sinon.assert.calledWithMatch(this.analyticsEventsQueue.add, 'event', {
await this.AnalyticsManager.recordEventForUser(
this.fakeUserId,
event,
null
)
sinon.assert.calledWithMatch(this.analyticsEventsQueue.add, 'event', {
analyticsId: this.analyticsId,
event,
userId: this.fakeUserId,
segmentation: null,
isLoggedIn: true,
})
})
@@ -28,6 +28,7 @@ describe('AuthenticationController', function () {
this.res = new MockResponse()
this.callback = sinon.stub()
this.next = sinon.stub()
this.req.session.analyticsId = 'abc-123'
this.AuthenticationController = SandboxedModule.require(modulePath, {
requires: {
@@ -53,8 +54,9 @@ describe('AuthenticationController', function () {
setupLoginData: sinon.stub(),
}),
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
recordEvent: sinon.stub(),
recordEventForUser: sinon.stub(),
identifyUser: sinon.stub(),
getIdsFromSession: sinon.stub().returns({ userId: this.user._id }),
}),
'../../infrastructure/SessionStoreManager': (this.SessionStoreManager = {}),
'@overleaf/settings': (this.Settings = {
@@ -1236,9 +1238,11 @@ describe('AuthenticationController', function () {
})
it('should call identifyUser', function () {
this.AnalyticsManager.identifyUser
.calledWith(this.user._id, this.req.sessionID)
.should.equal(true)
sinon.assert.calledWith(
this.AnalyticsManager.identifyUser,
this.user._id,
this.req.session.analyticsId
)
})
it('should setup the user data in the background', function () {
@@ -1271,9 +1275,11 @@ describe('AuthenticationController', function () {
})
it('should track the login event', function () {
this.AnalyticsManager.recordEvent
.calledWith(this.user._id, 'user-logged-in')
.should.equal(true)
sinon.assert.calledWith(
this.AnalyticsManager.recordEventForUser,
this.user._id,
'user-logged-in'
)
})
})
})
@@ -24,7 +24,7 @@ const { ObjectId } = require('mongodb')
describe('CollaboratorsInviteController', function () {
beforeEach(function () {
this.user = { _id: 'id' }
this.AnalyticsManger = { recordEvent: sinon.stub() }
this.AnalyticsManger = { recordEventForUser: sinon.stub() }
this.sendingUser = null
this.AuthenticationController = {
getSessionUser: req => {
@@ -173,7 +173,7 @@ describe('ProjectController', function () {
.BrandVariationsHandler,
'../ThirdPartyDataStore/TpdsProjectFlusher': this.TpdsProjectFlusher,
'../../models/Project': {},
'../Analytics/AnalyticsManager': { recordEvent: () => {} },
'../Analytics/AnalyticsManager': { recordEventForUser: () => {} },
'../../infrastructure/Modules': {
hooks: { fire: sinon.stub().yields(null, []) },
},
@@ -40,7 +40,7 @@ describe('FeaturesUpdater', function () {
'../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}),
'../User/UserGetter': (this.UserGetter = {}),
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
setUserProperty: sinon.stub(),
setUserPropertyForUser: sinon.stub(),
}),
'../../infrastructure/Modules': (this.Modules = {
hooks: { fire: sinon.stub() },
@@ -182,7 +182,7 @@ describe('FeaturesUpdater', function () {
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.user_id,
'feature-set',
'personal'
@@ -201,7 +201,7 @@ describe('FeaturesUpdater', function () {
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.user_id,
'feature-set',
'mixed'
@@ -27,8 +27,8 @@ describe('RecurlyEventHandler', function () {
this.RecurlyEventHandler = SandboxedModule.require(modulePath, {
requires: {
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
recordEvent: sinon.stub(),
setUserProperty: sinon.stub(),
recordEventForUser: sinon.stub(),
setUserPropertyForUser: sinon.stub(),
}),
},
})
@@ -40,7 +40,7 @@ describe('RecurlyEventHandler', function () {
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-started',
{
@@ -50,19 +50,19 @@ describe('RecurlyEventHandler', function () {
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-is-trial',
true
@@ -83,7 +83,7 @@ describe('RecurlyEventHandler', function () {
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-started',
{
@@ -93,13 +93,13 @@ describe('RecurlyEventHandler', function () {
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-is-trial',
false
@@ -114,7 +114,7 @@ describe('RecurlyEventHandler', function () {
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-updated',
{
@@ -123,19 +123,19 @@ describe('RecurlyEventHandler', function () {
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-state',
'active'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-is-trial',
true
@@ -149,7 +149,7 @@ describe('RecurlyEventHandler', function () {
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-cancelled',
{
@@ -159,13 +159,13 @@ describe('RecurlyEventHandler', function () {
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-state',
'cancelled'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-is-trial',
true
@@ -179,7 +179,7 @@ describe('RecurlyEventHandler', function () {
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-expired',
{
@@ -189,19 +189,19 @@ describe('RecurlyEventHandler', function () {
}
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-plan-code',
this.planCode
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-state',
'expired'
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.userId,
'subscription-is-trial',
true
@@ -214,7 +214,7 @@ describe('RecurlyEventHandler', function () {
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-renewed',
{
@@ -231,7 +231,7 @@ describe('RecurlyEventHandler', function () {
this.eventData
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-reactivated',
{
@@ -255,7 +255,7 @@ describe('RecurlyEventHandler', function () {
}
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-invoice-collected'
)
@@ -274,7 +274,7 @@ describe('RecurlyEventHandler', function () {
},
}
)
sinon.assert.notCalled(this.AnalyticsManager.recordEvent)
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUser)
})
it('with closed_invoice_notification', function () {
@@ -291,7 +291,7 @@ describe('RecurlyEventHandler', function () {
}
)
sinon.assert.calledWith(
this.AnalyticsManager.recordEvent,
this.AnalyticsManager.recordEventForUser,
this.userId,
'subscription-invoice-collected'
)
@@ -310,6 +310,6 @@ describe('RecurlyEventHandler', function () {
},
}
)
sinon.assert.notCalled(this.AnalyticsManager.recordEvent)
sinon.assert.notCalled(this.AnalyticsManager.recordEventForUser)
})
})
@@ -141,8 +141,9 @@ describe('SubscriptionController', function () {
}),
'./Errors': SubscriptionErrors,
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
recordEvent: sinon.stub(),
setUserProperty: sinon.stub(),
recordEventForUser: sinon.stub(),
recordEventForSession: sinon.stub(),
setUserPropertyForUser: sinon.stub(),
}),
'../SplitTests/SplitTestHandler': (this.SplitTestHandler = {
getTestSegmentation: () => {},
@@ -108,7 +108,7 @@ describe('SubscriptionHandler', function () {
this.EmailHandler = { sendEmail: sinon.stub() }
this.AnalyticsManager = { recordEvent: sinon.stub() }
this.AnalyticsManager = { recordEventForUser: sinon.stub() }
this.PlansLocator = {
findLocalPlanInSettings: sinon.stub().returns({ planCode: 'plan' }),
@@ -105,7 +105,7 @@ describe('SubscriptionUpdater', function () {
findOneAndUpdate: sinon.stub().yields(),
}
this.AnalyticsManager = {
setUserProperty: sinon.stub(),
setUserPropertyForUser: sinon.stub(),
}
this.SubscriptionUpdater = SandboxedModule.require(modulePath, {
requires: {
@@ -527,7 +527,7 @@ describe('SubscriptionUpdater', function () {
this.otherUserId,
() => {
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.otherUserId,
'group-subscription-plan-code',
'group_subscription'
@@ -547,7 +547,7 @@ describe('SubscriptionUpdater', function () {
this.otherUserId
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.otherUserId,
'group-subscription-plan-code',
'group_subscription'
@@ -564,7 +564,7 @@ describe('SubscriptionUpdater', function () {
this.otherUserId
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.otherUserId,
'group-subscription-plan-code',
'better_group_subscription'
@@ -581,7 +581,7 @@ describe('SubscriptionUpdater', function () {
this.otherUserId
)
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.otherUserId,
'group-subscription-plan-code',
'better_group_subscription'
@@ -622,7 +622,7 @@ describe('SubscriptionUpdater', function () {
this.otherUserId,
() => {
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.otherUserId,
'group-subscription-plan-code',
null
@@ -635,7 +635,7 @@ describe('SubscriptionUpdater', function () {
it('should set the group plan code user property when removing user from all groups', function (done) {
this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
sinon.assert.calledWith(
this.AnalyticsManager.setUserProperty,
this.AnalyticsManager.setUserPropertyForUser,
this.otherUserId,
'group-subscription-plan-code',
null
@@ -12,7 +12,6 @@
* Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
*/
const SandboxedModule = require('sandboxed-module')
const assert = require('assert')
const path = require('path')
const sinon = require('sinon')
const modulePath = path.join(
@@ -43,7 +42,7 @@ describe('TokenAccessHandler', function () {
}),
crypto: (this.Crypto = require('crypto')),
'../Analytics/AnalyticsManager': (this.Analytics = {
recordEvent: sinon.stub(),
recordEventForUser: sinon.stub(),
}),
},
}))
@@ -138,7 +137,7 @@ describe('TokenAccessHandler', function () {
this.Project.updateOne.lastCall.args[1].$addToSet
).to.have.keys('tokenAccessReadOnly_refs')
sinon.assert.calledWith(
this.Analytics.recordEvent,
this.Analytics.recordEventForUser,
this.userId,
'project-joined',
{ mode: 'read-only' }
@@ -199,7 +198,7 @@ describe('TokenAccessHandler', function () {
this.Project.updateOne.lastCall.args[1].$addToSet
).to.have.keys('tokenAccessReadAndWrite_refs')
sinon.assert.calledWith(
this.Analytics.recordEvent,
this.Analytics.recordEventForUser,
this.userId,
'project-joined',
{ mode: 'read-write' }
@@ -24,6 +24,7 @@ describe('UserController', function () {
_id: this.user_id,
email: 'old@something.com',
},
analyticsId: this.user_id,
},
sessionID: '123',
body: {},
@@ -544,9 +545,10 @@ describe('UserController', function () {
})
it('should register the user and send them an email', function () {
this.UserRegistrationHandler.registerNewUserAndSendActivationEmail
.calledWith(this.email)
.should.equal(true)
sinon.assert.calledWith(
this.UserRegistrationHandler.registerNewUserAndSendActivationEmail,
this.email
)
})
it('should return the user and activation url', function () {
@@ -42,8 +42,8 @@ describe('UserCreator', function () {
},
}),
'../Analytics/AnalyticsManager': (this.Analytics = {
recordEvent: sinon.stub(),
setUserProperty: sinon.stub(),
recordEventForUser: sinon.stub(),
setUserPropertyForUser: sinon.stub(),
}),
'./UserOnboardingEmailManager': (this.UserOnboardingEmailManager = {
scheduleOnboardingEmail: sinon.stub(),
@@ -271,12 +271,12 @@ describe('UserCreator', function () {
})
assert.equal(user.email, this.email)
sinon.assert.calledWith(
this.Analytics.recordEvent,
this.Analytics.recordEventForUser,
user._id,
'user-registered'
)
sinon.assert.calledWith(
this.Analytics.setUserProperty,
this.Analytics.setUserPropertyForUser,
user._id,
'created-at'
)
@@ -36,7 +36,7 @@ describe('UserPostRegistrationAnalyticsManager', function () {
},
}
this.AnalyticsManager = {
setUserProperty: sinon.stub().resolves(),
setUserPropertyForUser: sinon.stub().resolves(),
}
this.UserPostRegistrationAnalyticsManager = SandboxedModule.require(
MODULE_PATH,
@@ -72,7 +72,8 @@ describe('UserPostRegistrationAnalyticsManager', function () {
)
expect(this.InstitutionsAPI.promises.getUserAffiliations).not.to.have.been
.called
expect(this.AnalyticsManager.setUserProperty).not.to.have.been.called
expect(this.AnalyticsManager.setUserPropertyForUser).not.to.have.been
.called
})
it('sets user property if user has commons account affiliationd', async function () {
@@ -92,7 +93,9 @@ describe('UserPostRegistrationAnalyticsManager', function () {
await this.UserPostRegistrationAnalyticsManager.postRegistrationAnalytics(
this.fakeUserId
)
expect(this.AnalyticsManager.setUserProperty).to.have.been.calledWith(
expect(
this.AnalyticsManager.setUserPropertyForUser
).to.have.been.calledWith(
this.fakeUserId,
'registered-from-commons-account',
true
@@ -110,7 +113,8 @@ describe('UserPostRegistrationAnalyticsManager', function () {
await this.UserPostRegistrationAnalyticsManager.postRegistrationAnalytics(
this.fakeUserId
)
expect(this.AnalyticsManager.setUserProperty).not.to.have.been.called
expect(this.AnalyticsManager.setUserPropertyForUser).not.to.have.been
.called
})
})
})
@@ -24,7 +24,11 @@ const EmailHelper = require('../../../../app/src/Features/Helpers/EmailHelper')
describe('UserRegistrationHandler', function () {
beforeEach(function () {
this.user = { _id: (this.user_id = '31j2lk21kjl') }
this.analyticsId = '123456'
this.user = {
_id: (this.user_id = '31j2lk21kjl'),
analyticsId: this.analyticsId,
}
this.User = { updateOne: sinon.stub().callsArgWith(2) }
this.UserGetter = { getUserByAnyEmail: sinon.stub() }
this.UserCreator = {
@@ -49,7 +53,9 @@ describe('UserRegistrationHandler', function () {
'../Email/EmailHandler': this.EmailHandler,
'../Security/OneTimeTokenHandler': this.OneTimeTokenHandler,
'../Analytics/AnalyticsManager': (this.AnalyticsManager = {
recordEvent: sinon.stub(),
recordEventForUser: sinon.stub(),
setUserPropertyForUser: sinon.stub(),
identifyUser: sinon.stub(),
}),
'@overleaf/settings': (this.settings = {
siteUrl: 'http://sl.example.com',
@@ -58,10 +64,11 @@ describe('UserRegistrationHandler', function () {
},
})
return (this.passingRequest = {
this.passingRequest = {
email: 'something@email.com',
password: '123',
})
analyticsId: this.analyticsId,
}
})
describe('validate Register Request', function () {
@@ -167,16 +174,15 @@ describe('UserRegistrationHandler', function () {
})
it('should create a new user', function (done) {
return this.handler.registerNewUser(this.passingRequest, err => {
this.UserCreator.createNewUser
.calledWith({
email: this.passingRequest.email,
holdingAccount: false,
first_name: this.passingRequest.first_name,
last_name: this.passingRequest.last_name,
})
.should.equal(true)
return done()
this.handler.registerNewUser(this.passingRequest, err => {
sinon.assert.calledWith(this.UserCreator.createNewUser, {
email: this.passingRequest.email,
holdingAccount: false,
first_name: this.passingRequest.first_name,
last_name: this.passingRequest.last_name,
analyticsId: this.user.analyticsId,
})
done()
})
})
@@ -227,15 +233,6 @@ describe('UserRegistrationHandler', function () {
return done()
})
})
it('should track the registration event', function (done) {
return this.handler.registerNewUser(this.passingRequest, err => {
this.AnalyticsManager.recordEvent
.calledWith(this.user._id, 'user-registered')
.should.equal(true)
return done()
})
})
})
it('should call the ReferalAllocator', function (done) {
@@ -270,12 +267,10 @@ describe('UserRegistrationHandler', function () {
})
it('should ask the UserRegistrationHandler to register user', function () {
return this.handler.registerNewUser
.calledWith({
email: this.email,
password: this.password,
})
.should.equal(true)
sinon.assert.calledWith(this.handler.registerNewUser, {
email: this.email,
password: this.password,
})
})
it('should generate a new password reset token', function () {