Forráskód Böngészése

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

Revert "Analytics ID support"

GitOrigin-RevId: cc5da762ba1bafcbcea65ed0dd86342896b6d1eb
Alexandre Bourdin 5 éve
szülő
commit
5b8de28250
36 módosított fájl, 248 hozzáadás és 556 törlés
  1. 3 5
      services/web/app/src/Features/Analytics/AnalyticsController.js
  2. 33 142
      services/web/app/src/Features/Analytics/AnalyticsManager.js
  3. 4 4
      services/web/app/src/Features/Analytics/AnalyticsRegistrationSourceHelper.js
  4. 0 26
      services/web/app/src/Features/Analytics/UserAnalyticsIdCache.js
  5. 4 11
      services/web/app/src/Features/Authentication/AuthenticationController.js
  6. 4 8
      services/web/app/src/Features/Collaborators/CollaboratorsInviteController.js
  7. 1 1
      services/web/app/src/Features/Project/ProjectController.js
  8. 5 5
      services/web/app/src/Features/Project/ProjectCreationHandler.js
  9. 1 1
      services/web/app/src/Features/SplitTests/SplitTestHandler.js
  10. 29 124
      services/web/app/src/Features/SplitTests/SplitTestV2Handler.js
  11. 1 1
      services/web/app/src/Features/Subscription/FeaturesUpdater.js
  12. 32 80
      services/web/app/src/Features/Subscription/RecurlyEventHandler.js
  13. 1 1
      services/web/app/src/Features/Subscription/SubscriptionController.js
  14. 1 1
      services/web/app/src/Features/Subscription/SubscriptionUpdater.js
  15. 2 6
      services/web/app/src/Features/TokenAccess/TokenAccessHandler.js
  16. 2 10
      services/web/app/src/Features/User/UserCreator.js
  17. 1 1
      services/web/app/src/Features/User/UserPostRegistrationAnalyticsManager.js
  18. 2 1
      services/web/app/src/Features/User/UserRegistrationHandler.js
  19. 0 5
      services/web/app/src/infrastructure/Server.js
  20. 0 1
      services/web/app/src/models/User.js
  21. 1 1
      services/web/modules/server-ce-scripts/scripts/create-user.js
  22. 23 7
      services/web/test/unit/src/Analytics/AnalyticsControllerTests.js
  23. 6 15
      services/web/test/unit/src/Analytics/AnalyticsManagerTests.js
  24. 7 13
      services/web/test/unit/src/Authentication/AuthenticationControllerTests.js
  25. 1 1
      services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js
  26. 1 1
      services/web/test/unit/src/Project/ProjectControllerTests.js
  27. 3 3
      services/web/test/unit/src/Subscription/FeaturesUpdaterTests.js
  28. 26 26
      services/web/test/unit/src/Subscription/RecurlyEventHandlerTests.js
  29. 2 3
      services/web/test/unit/src/Subscription/SubscriptionControllerTests.js
  30. 1 1
      services/web/test/unit/src/Subscription/SubscriptionHandlerTests.js
  31. 7 7
      services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js
  32. 4 3
      services/web/test/unit/src/TokenAccess/TokenAccessHandlerTests.js
  33. 3 5
      services/web/test/unit/src/User/UserControllerTests.js
  34. 4 4
      services/web/test/unit/src/User/UserCreatorTests.js
  35. 4 8
      services/web/test/unit/src/User/UserPostRegistrationAnalyticsManagerTests.js
  36. 29 24
      services/web/test/unit/src/User/UserRegistrationHandlerTests.js

+ 3 - 5
services/web/app/src/Features/Analytics/AnalyticsController.js

@@ -30,12 +30,10 @@ module.exports = {
     if (!Features.hasFeature('analytics')) {
     if (!Features.hasFeature('analytics')) {
       return res.sendStatus(202)
       return res.sendStatus(202)
     }
     }
+    const userId =
+      SessionManager.getLoggedInUserId(req.session) || req.sessionID
     delete req.body._csrf
     delete req.body._csrf
-    AnalyticsManager.recordEventForSession(
-      req.session,
-      req.params.event,
-      req.body
-    )
+    AnalyticsManager.recordEvent(userId, req.params.event, req.body)
     res.sendStatus(202)
     res.sendStatus(202)
   },
   },
 }
 }

+ 33 - 142
services/web/app/src/Features/Analytics/AnalyticsManager.js

@@ -1,32 +1,21 @@
-const SessionManager = require('../Authentication/SessionManager')
-const UserAnalyticsIdCache = require('./UserAnalyticsIdCache')
 const Settings = require('@overleaf/settings')
 const Settings = require('@overleaf/settings')
 const Metrics = require('../../infrastructure/Metrics')
 const Metrics = require('../../infrastructure/Metrics')
 const Queues = require('../../infrastructure/Queues')
 const Queues = require('../../infrastructure/Queues')
-const uuid = require('uuid')
-const _ = require('lodash')
-const { expressify } = require('../../util/promises')
 
 
 const analyticsEventsQueue = Queues.getAnalyticsEventsQueue()
 const analyticsEventsQueue = Queues.getAnalyticsEventsQueue()
 const analyticsEditingSessionsQueue = Queues.getAnalyticsEditingSessionsQueue()
 const analyticsEditingSessionsQueue = Queues.getAnalyticsEditingSessionsQueue()
 const analyticsUserPropertiesQueue = Queues.getAnalyticsUserPropertiesQueue()
 const analyticsUserPropertiesQueue = Queues.getAnalyticsUserPropertiesQueue()
 
 
-const ONE_MINUTE_MS = 60 * 1000
-
-function identifyUser(userId, analyticsId, isNewUser) {
-  if (!userId || !analyticsId) {
+function identifyUser(userId, oldUserId) {
+  if (!userId || !oldUserId) {
     return
     return
   }
   }
-  if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
+  if (isAnalyticsDisabled() || isSmokeTestUser(userId)) {
     return
     return
   }
   }
   Metrics.analyticsQueue.inc({ status: 'adding', event_type: 'identify' })
   Metrics.analyticsQueue.inc({ status: 'adding', event_type: 'identify' })
   analyticsEventsQueue
   analyticsEventsQueue
-    .add(
-      'identify',
-      { userId, analyticsId, isNewUser },
-      { delay: ONE_MINUTE_MS }
-    )
+    .add('identify', { userId, oldUserId })
     .then(() => {
     .then(() => {
       Metrics.analyticsQueue.inc({ status: 'added', event_type: 'identify' })
       Metrics.analyticsQueue.inc({ status: 'added', event_type: 'identify' })
     })
     })
@@ -35,81 +24,29 @@ function identifyUser(userId, analyticsId, isNewUser) {
     })
     })
 }
 }
 
 
-async function recordEventForUser(userId, event, segmentation) {
+function recordEvent(userId, event, segmentation) {
   if (!userId) {
   if (!userId) {
     return
     return
   }
   }
-  if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
-    return
-  }
-  const analyticsId = await UserAnalyticsIdCache.get(userId)
-  if (analyticsId) {
-    _recordEvent({ analyticsId, userId, event, segmentation, isLoggedIn: true })
-  }
-}
-
-function recordEventForSession(session, event, segmentation) {
-  const { analyticsId, userId } = getIdsFromSession(session)
-  if (!analyticsId) {
-    return
-  }
-  if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
+  if (isAnalyticsDisabled() || isSmokeTestUser(userId)) {
     return
     return
   }
   }
-  _recordEvent({
-    analyticsId,
-    userId,
-    event,
-    segmentation,
-    isLoggedIn: !!userId,
-  })
-}
-
-async function setUserPropertyForUser(userId, propertyName, propertyValue) {
-  if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
-    return
-  }
-
-  _checkPropertyValue(propertyValue)
-
-  const analyticsId = await UserAnalyticsIdCache.get(userId)
-  if (analyticsId) {
-    _setUserProperty({ analyticsId, propertyName, propertyValue })
-  }
-}
-
-async function setUserPropertyForAnalyticsId(
-  analyticsId,
-  propertyName,
-  propertyValue
-) {
-  if (_isAnalyticsDisabled()) {
-    return
-  }
-
-  _checkPropertyValue(propertyValue)
-
-  _setUserProperty({ analyticsId, propertyName, propertyValue })
-}
-
-async function setUserPropertyForSession(session, propertyName, propertyValue) {
-  const { analyticsId, userId } = getIdsFromSession(session)
-  if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
-    return
-  }
-
-  _checkPropertyValue(propertyValue)
-
-  if (analyticsId) {
-    _setUserProperty({ analyticsId, propertyName, propertyValue })
-  }
+  Metrics.analyticsQueue.inc({ status: 'adding', event_type: 'event' })
+  analyticsEventsQueue
+    .add('event', { userId, event, segmentation })
+    .then(() => {
+      Metrics.analyticsQueue.inc({ status: 'added', event_type: 'event' })
+    })
+    .catch(() => {
+      Metrics.analyticsQueue.inc({ status: 'error', event_type: 'event' })
+    })
 }
 }
 
 
 function updateEditingSession(userId, projectId, countryCode) {
 function updateEditingSession(userId, projectId, countryCode) {
   if (!userId) {
   if (!userId) {
     return
     return
   }
   }
-  if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
+  if (isAnalyticsDisabled() || isSmokeTestUser(userId)) {
     return
     return
   }
   }
   Metrics.analyticsQueue.inc({
   Metrics.analyticsQueue.inc({
@@ -132,36 +69,26 @@ function updateEditingSession(userId, projectId, countryCode) {
     })
     })
 }
 }
 
 
-function _recordEvent(
-  { analyticsId, userId, event, segmentation, isLoggedIn },
-  { delay } = {}
-) {
-  Metrics.analyticsQueue.inc({ status: 'adding', event_type: 'event' })
-  analyticsEventsQueue
-    .add(
-      'event',
-      { analyticsId, userId, event, segmentation, isLoggedIn },
-      { delay }
+function setUserProperty(userId, propertyName, propertyValue) {
+  if (!userId) {
+    return
+  }
+  if (isAnalyticsDisabled() || isSmokeTestUser(userId)) {
+    return
+  }
+
+  if (propertyValue === undefined) {
+    throw new Error(
+      'propertyValue cannot be undefined, use null to unset a property'
     )
     )
-    .then(() => {
-      Metrics.analyticsQueue.inc({ status: 'added', event_type: 'event' })
-    })
-    .catch(() => {
-      Metrics.analyticsQueue.inc({ status: 'error', event_type: 'event' })
-    })
-}
+  }
 
 
-function _setUserProperty({ analyticsId, propertyName, propertyValue }) {
   Metrics.analyticsQueue.inc({
   Metrics.analyticsQueue.inc({
     status: 'adding',
     status: 'adding',
     event_type: 'user-property',
     event_type: 'user-property',
   })
   })
   analyticsUserPropertiesQueue
   analyticsUserPropertiesQueue
-    .add({
-      analyticsId,
-      propertyName,
-      propertyValue,
-    })
+    .add({ userId, propertyName, propertyValue })
     .then(() => {
     .then(() => {
       Metrics.analyticsQueue.inc({
       Metrics.analyticsQueue.inc({
         status: 'added',
         status: 'added',
@@ -176,54 +103,18 @@ function _setUserProperty({ analyticsId, propertyName, propertyValue }) {
     })
     })
 }
 }
 
 
-function _isSmokeTestUser(userId) {
+function isSmokeTestUser(userId) {
   const smokeTestUserId = Settings.smokeTest && Settings.smokeTest.userId
   const smokeTestUserId = Settings.smokeTest && Settings.smokeTest.userId
   return smokeTestUserId != null && userId.toString() === smokeTestUserId
   return smokeTestUserId != null && userId.toString() === smokeTestUserId
 }
 }
 
 
-function _isAnalyticsDisabled() {
+function isAnalyticsDisabled() {
   return !(Settings.analytics && Settings.analytics.enabled)
   return !(Settings.analytics && Settings.analytics.enabled)
 }
 }
 
 
-function _checkPropertyValue(propertyValue) {
-  if (propertyValue === undefined) {
-    throw new Error(
-      'propertyValue cannot be undefined, use null to unset a property'
-    )
-  }
-}
-
-function getIdsFromSession(session) {
-  const analyticsId = _.get(session, ['analyticsId'])
-  const userId = SessionManager.getLoggedInUserId(session)
-  return { analyticsId, userId }
-}
-
-async function analyticsIdMiddleware(req, res, next) {
-  const session = req.session
-  const sessionUser = SessionManager.getSessionUser(session)
-  if (session.analyticsId) {
-    if (sessionUser && session.analyticsId !== sessionUser.analyticsId) {
-      session.analyticsId = sessionUser.analyticsId
-    }
-  } else {
-    if (sessionUser) {
-      session.analyticsId = sessionUser.analyticsId
-    } else {
-      session.analyticsId = uuid.v4()
-    }
-  }
-  next()
-}
-
 module.exports = {
 module.exports = {
   identifyUser,
   identifyUser,
-  recordEventForSession,
-  recordEventForUser,
-  setUserPropertyForUser,
-  setUserPropertyForSession,
-  setUserPropertyForAnalyticsId,
+  recordEvent,
   updateEditingSession,
   updateEditingSession,
-  getIdsFromSession,
-  analyticsIdMiddleware: expressify(analyticsIdMiddleware),
+  setUserProperty,
 }
 }

+ 4 - 4
services/web/app/src/Features/Analytics/AnalyticsRegistrationSourceHelper.js

@@ -79,7 +79,7 @@ function addUserProperties(userId, session) {
   }
   }
 
 
   if (session.referal_id) {
   if (session.referal_id) {
-    AnalyticsManager.setUserPropertyForUser(
+    AnalyticsManager.setUserProperty(
       userId,
       userId,
       `registered-from-bonus-scheme`,
       `registered-from-bonus-scheme`,
       true
       true
@@ -87,7 +87,7 @@ function addUserProperties(userId, session) {
   }
   }
 
 
   if (session.required_login_for) {
   if (session.required_login_for) {
-    AnalyticsManager.setUserPropertyForUser(
+    AnalyticsManager.setUserProperty(
       userId,
       userId,
       `registered-from-${session.required_login_for}`,
       `registered-from-${session.required_login_for}`,
       true
       true
@@ -96,7 +96,7 @@ function addUserProperties(userId, session) {
 
 
   if (session.inbound) {
   if (session.inbound) {
     if (session.inbound.referrer) {
     if (session.inbound.referrer) {
-      AnalyticsManager.setUserPropertyForUser(
+      AnalyticsManager.setUserProperty(
         userId,
         userId,
         `registered-from-referrer-${session.inbound.referrer.medium}`,
         `registered-from-referrer-${session.inbound.referrer.medium}`,
         session.inbound.referrer.detail || 'other'
         session.inbound.referrer.detail || 'other'
@@ -106,7 +106,7 @@ function addUserProperties(userId, session) {
     if (session.inbound.utm) {
     if (session.inbound.utm) {
       for (const utmKey of UTM_KEYS) {
       for (const utmKey of UTM_KEYS) {
         if (session.inbound.utm[utmKey]) {
         if (session.inbound.utm[utmKey]) {
-          AnalyticsManager.setUserPropertyForUser(
+          AnalyticsManager.setUserProperty(
             userId,
             userId,
             `registered-from-${utmKey.replace('_', '-')}`,
             `registered-from-${utmKey.replace('_', '-')}`,
             session.inbound.utm[utmKey]
             session.inbound.utm[utmKey]

+ 0 - 26
services/web/app/src/Features/Analytics/UserAnalyticsIdCache.js

@@ -1,26 +0,0 @@
-const UserGetter = require('../User/UserGetter')
-const { CacheLoader } = require('cache-flow')
-
-class UserAnalyticsIdCache extends CacheLoader {
-  constructor() {
-    super('user-analytics-id', {
-      expirationTime: 60,
-      maxSize: 10000,
-    })
-  }
-
-  async load(userId) {
-    const user = await UserGetter.promises.getUser(userId, { analyticsId: 1 })
-    if (user) {
-      return user.analyticsId || user._id
-    }
-  }
-
-  keyToString(userId) {
-    if (userId) {
-      return userId.toString()
-    }
-  }
-}
-
-module.exports = new UserAnalyticsIdCache()

+ 4 - 11
services/web/app/src/Features/Authentication/AuthenticationController.js

@@ -48,7 +48,6 @@ const AuthenticationController = {
       ip_address: user._login_req_ip,
       ip_address: user._login_req_ip,
       must_reconfirm: user.must_reconfirm,
       must_reconfirm: user.must_reconfirm,
       v1_id: user.overleaf != null ? user.overleaf.id : undefined,
       v1_id: user.overleaf != null ? user.overleaf.id : undefined,
-      analyticsId: user.analyticsId || user._id,
     }
     }
     callback(null, lightUser)
     callback(null, lightUser)
   },
   },
@@ -83,9 +82,6 @@ const AuthenticationController = {
       return res.redirect('/login')
       return res.redirect('/login')
     } // OAuth2 'state' mismatch
     } // OAuth2 'state' mismatch
 
 
-    const anonymousAnalyticsId = req.session.analyticsId
-    const isNewUser = req.session.justRegistered || false
-
     const Modules = require('../../infrastructure/Modules')
     const Modules = require('../../infrastructure/Modules')
     Modules.hooks.fire(
     Modules.hooks.fire(
       'preFinishLogin',
       'preFinishLogin',
@@ -110,7 +106,7 @@ const AuthenticationController = {
 
 
         const redir =
         const redir =
           AuthenticationController._getRedirectFromSession(req) || '/project'
           AuthenticationController._getRedirectFromSession(req) || '/project'
-        _loginAsyncHandlers(req, user, anonymousAnalyticsId, isNewUser)
+        _loginAsyncHandlers(req, user)
         const userId = user._id
         const userId = user._id
         UserAuditLogHandler.addEntry(userId, 'login', userId, req.ip, err => {
         UserAuditLogHandler.addEntry(userId, 'login', userId, req.ip, err => {
           if (err) {
           if (err) {
@@ -490,8 +486,7 @@ function _afterLoginSessionSetup(req, user, callback) {
     })
     })
   })
   })
 }
 }
-
-function _loginAsyncHandlers(req, user, anonymousAnalyticsId, isNewUser) {
+function _loginAsyncHandlers(req, user) {
   UserHandler.setupLoginData(user, err => {
   UserHandler.setupLoginData(user, err => {
     if (err != null) {
     if (err != null) {
       logger.warn({ err }, 'error setting up login data')
       logger.warn({ err }, 'error setting up login data')
@@ -500,14 +495,12 @@ function _loginAsyncHandlers(req, user, anonymousAnalyticsId, isNewUser) {
   LoginRateLimiter.recordSuccessfulLogin(user.email)
   LoginRateLimiter.recordSuccessfulLogin(user.email)
   AuthenticationController._recordSuccessfulLogin(user._id)
   AuthenticationController._recordSuccessfulLogin(user._id)
   AuthenticationController.ipMatchCheck(req, user)
   AuthenticationController.ipMatchCheck(req, user)
-  Analytics.recordEventForUser(user._id, 'user-logged-in')
-  Analytics.identifyUser(user._id, anonymousAnalyticsId, isNewUser)
-
+  Analytics.recordEvent(user._id, 'user-logged-in')
+  Analytics.identifyUser(user._id, req.sessionID)
   logger.log(
   logger.log(
     { email: user.email, user_id: user._id.toString() },
     { email: user.email, user_id: user._id.toString() },
     'successful log in'
     'successful log in'
   )
   )
-
   req.session.justLoggedIn = true
   req.session.justLoggedIn = true
   // capture the request ip for use when creating the session
   // capture the request ip for use when creating the session
   return (user._login_req_ip = req.ip)
   return (user._login_req_ip = req.ip)

+ 4 - 8
services/web/app/src/Features/Collaborators/CollaboratorsInviteController.js

@@ -377,14 +377,10 @@ module.exports = CollaboratorsInviteController = {
           'project:membership:changed',
           'project:membership:changed',
           { invites: true, members: true }
           { invites: true, members: true }
         )
         )
-        AnalyticsManager.recordEventForUser(
-          currentUser._id,
-          'project-invite-accept',
-          {
-            projectId,
-            userId: currentUser._id,
-          }
-        )
+        AnalyticsManager.recordEvent(currentUser._id, 'project-invite-accept', {
+          projectId,
+          userId: currentUser._id,
+        })
         if (req.xhr) {
         if (req.xhr) {
           return res.sendStatus(204) //  Done async via project page notification
           return res.sendStatus(204) //  Done async via project page notification
         } else {
         } else {

+ 1 - 1
services/web/app/src/Features/Project/ProjectController.js

@@ -780,7 +780,7 @@ const ProjectController = {
             metrics.inc(metricName)
             metrics.inc(metricName)
 
 
             if (userId) {
             if (userId) {
-              AnalyticsManager.recordEventForUser(userId, 'project-opened', {
+              AnalyticsManager.recordEvent(userId, 'project-opened', {
                 projectId: project._id,
                 projectId: project._id,
               })
               })
             }
             }

+ 5 - 5
services/web/app/src/Features/Project/ProjectCreationHandler.js

@@ -35,12 +35,12 @@ async function createBlankProject(ownerId, projectName, attributes = {}) {
   const isImport = attributes && attributes.overleaf
   const isImport = attributes && attributes.overleaf
   const project = await _createBlankProject(ownerId, projectName, attributes)
   const project = await _createBlankProject(ownerId, projectName, attributes)
   if (isImport) {
   if (isImport) {
-    AnalyticsManager.recordEventForUser(ownerId, 'project-imported', {
+    AnalyticsManager.recordEvent(ownerId, 'project-imported', {
       projectId: project._id,
       projectId: project._id,
       attributes,
       attributes,
     })
     })
   } else {
   } else {
-    AnalyticsManager.recordEventForUser(ownerId, 'project-created', {
+    AnalyticsManager.recordEvent(ownerId, 'project-created', {
       projectId: project._id,
       projectId: project._id,
       attributes,
       attributes,
     })
     })
@@ -50,7 +50,7 @@ async function createBlankProject(ownerId, projectName, attributes = {}) {
 
 
 async function createProjectFromSnippet(ownerId, projectName, docLines) {
 async function createProjectFromSnippet(ownerId, projectName, docLines) {
   const project = await _createBlankProject(ownerId, projectName)
   const project = await _createBlankProject(ownerId, projectName)
-  AnalyticsManager.recordEventForUser(ownerId, 'project-created', {
+  AnalyticsManager.recordEvent(ownerId, 'project-created', {
     projectId: project._id,
     projectId: project._id,
   })
   })
   await _createRootDoc(project, ownerId, docLines)
   await _createRootDoc(project, ownerId, docLines)
@@ -63,7 +63,7 @@ async function createBasicProject(ownerId, projectName) {
   const docLines = await _buildTemplate('mainbasic.tex', ownerId, projectName)
   const docLines = await _buildTemplate('mainbasic.tex', ownerId, projectName)
   await _createRootDoc(project, ownerId, docLines)
   await _createRootDoc(project, ownerId, docLines)
 
 
-  AnalyticsManager.recordEventForUser(ownerId, 'project-created', {
+  AnalyticsManager.recordEvent(ownerId, 'project-created', {
     projectId: project._id,
     projectId: project._id,
   })
   })
 
 
@@ -75,7 +75,7 @@ async function createExampleProject(ownerId, projectName) {
 
 
   await _addExampleProjectFiles(ownerId, projectName, project)
   await _addExampleProjectFiles(ownerId, projectName, project)
 
 
-  AnalyticsManager.recordEventForUser(ownerId, 'project-created', {
+  AnalyticsManager.recordEvent(ownerId, 'project-created', {
     projectId: project._id,
     projectId: project._id,
   })
   })
 
 

+ 1 - 1
services/web/app/src/Features/SplitTests/SplitTestHandler.js

@@ -96,7 +96,7 @@ async function assignUserToVariant(userId, splitTest) {
       [`splitTests.${splitTest.id}`]: selectedVariant,
       [`splitTests.${splitTest.id}`]: selectedVariant,
     },
     },
   })
   })
-  AnalyticsManager.setUserPropertyForUser(
+  AnalyticsManager.setUserProperty(
     userId,
     userId,
     `split-test-${splitTest.id}`,
     `split-test-${splitTest.id}`,
     selectedVariant
     selectedVariant

+ 29 - 124
services/web/app/src/Features/SplitTests/SplitTestV2Handler.js

@@ -1,7 +1,6 @@
 const UserGetter = require('../User/UserGetter')
 const UserGetter = require('../User/UserGetter')
 const UserUpdater = require('../User/UserUpdater')
 const UserUpdater = require('../User/UserUpdater')
 const AnalyticsManager = require('../Analytics/AnalyticsManager')
 const AnalyticsManager = require('../Analytics/AnalyticsManager')
-const UserAnalyticsIdCache = require('../Analytics/UserAnalyticsIdCache')
 const crypto = require('crypto')
 const crypto = require('crypto')
 const _ = require('lodash')
 const _ = require('lodash')
 const { callbackify } = require('util')
 const { callbackify } = require('util')
@@ -25,7 +24,7 @@ const BETA_PHASE = 'beta'
  *   // execute the default behaviour (control group)
  *   // execute the default behaviour (control group)
  * }
  * }
  * // then record an event
  * // then record an event
- * AnalyticsManager.recordEventForUser(userId, 'example-project-created', {
+ * AnalyticsManager.recordEvent(userId, 'example-project-created', {
  *   projectId: project._id,
  *   projectId: project._id,
  *   ...assignment.analytics.segmentation
  *   ...assignment.analytics.segmentation
  * })
  * })
@@ -36,50 +35,8 @@ const BETA_PHASE = 'beta'
  * @returns {Promise<{variant: string, analytics: {segmentation: {splitTest: string, variant: string, phase: string, versionNumber: number}|{}}}>}
  * @returns {Promise<{variant: string, analytics: {segmentation: {splitTest: string, variant: string, phase: string, versionNumber: number}|{}}}>}
  */
  */
 async function getAssignment(userId, splitTestName, options) {
 async function getAssignment(userId, splitTestName, options) {
-  if (!userId) {
-    return { variant: 'default', analytics: { segmentation: {} } }
-  }
-  const analyticsId = await UserAnalyticsIdCache.get(userId)
-  return _getAssignment(analyticsId, userId, undefined, splitTestName, options)
-}
-
-/**
- * Get the assignment of a user to a split test by their session.
- *
- * @example
- * // Assign user and record an event
- *
- * const assignment = await SplitTestV2Handler.getAssignment(req.session, 'example-project')
- * if (assignment.variant === 'awesome-new-version') {
- *   // execute my awesome change
- * }
- * else {
- *   // execute the default behaviour (control group)
- * }
- * // then record an event
- * AnalyticsManager.recordEventForSession(req.session, 'example-project-created', {
- *   projectId: project._id,
- *   ...assignment.analytics.segmentation
- * })
- *
- * @param session the request session
- * @param splitTestName the unique name of the split test
- * @param options {Object<sync: boolean>} - for test purposes only, to force the synchronous update of the user's profile
- * @returns {Promise<{variant: string, analytics: {segmentation: {splitTest: string, variant: string, phase: string, versionNumber: number}|{}}}>}
- */
-async function getAssignmentForSession(session, splitTestName, options) {
-  const { userId, analyticsId } = AnalyticsManager.getIdsFromSession(session)
-  return _getAssignment(analyticsId, userId, session, splitTestName, options)
-}
-
-async function _getAssignment(
-  analyticsId,
-  userId,
-  session,
-  splitTestName,
-  options
-) {
   const splitTest = await splitTestCache.get(splitTestName)
   const splitTest = await splitTestCache.get(splitTestName)
+
   if (splitTest) {
   if (splitTest) {
     const currentVersion = splitTest.getCurrentVersion()
     const currentVersion = splitTest.getCurrentVersion()
     if (currentVersion.active) {
     if (currentVersion.active) {
@@ -88,12 +45,10 @@ async function _getAssignment(
         selectedVariantName,
         selectedVariantName,
         phase,
         phase,
         versionNumber,
         versionNumber,
-      } = await _getAssignmentMetadata(analyticsId, userId, splitTest)
+      } = await _getAssignmentMetadata(userId, splitTest)
       if (activeForUser) {
       if (activeForUser) {
         const assignmentConfig = {
         const assignmentConfig = {
           userId,
           userId,
-          analyticsId,
-          session,
           splitTestName,
           splitTestName,
           variantName: selectedVariantName,
           variantName: selectedVariantName,
           phase,
           phase,
@@ -134,44 +89,21 @@ async function assignInLocalsContext(res, userId, splitTestName, options) {
   res.locals.splitTestVariants[splitTestName] = assignment.variant
   res.locals.splitTestVariants[splitTestName] = assignment.variant
 }
 }
 
 
-async function assignInLocalsContextForSession(
-  res,
-  session,
-  splitTestName,
-  options
-) {
-  const assignment = await getAssignmentForSession(
-    session,
-    splitTestName,
-    options
-  )
-  if (!res.locals.splitTestVariants) {
-    res.locals.splitTestVariants = {}
-  }
-  res.locals.splitTestVariants[splitTestName] = assignment.variant
-}
-
-async function _getAssignmentMetadata(analyticsId, userId, splitTest) {
+async function _getAssignmentMetadata(userId, splitTest) {
   const currentVersion = splitTest.getCurrentVersion()
   const currentVersion = splitTest.getCurrentVersion()
   const phase = currentVersion.phase
   const phase = currentVersion.phase
   if ([ALPHA_PHASE, BETA_PHASE].includes(phase)) {
   if ([ALPHA_PHASE, BETA_PHASE].includes(phase)) {
-    if (userId) {
-      const user = await _getUser(userId)
-      if (
-        (phase === ALPHA_PHASE && !(user && user.alphaProgram)) ||
-        (phase === BETA_PHASE && !(user && user.betaProgram))
-      ) {
-        return {
-          activeForUser: false,
-        }
-      }
-    } else {
+    const user = await _getUser(userId)
+    if (
+      (phase === ALPHA_PHASE && !(user && user.alphaProgram)) ||
+      (phase === BETA_PHASE && !(user && user.betaProgram))
+    ) {
       return {
       return {
         activeForUser: false,
         activeForUser: false,
       }
       }
     }
     }
   }
   }
-  const percentile = _getPercentile(analyticsId, splitTest.name, phase)
+  const percentile = _getPercentile(userId, splitTest.name, phase)
   const selectedVariantName = _getVariantFromPercentile(
   const selectedVariantName = _getVariantFromPercentile(
     currentVersion.variants,
     currentVersion.variants,
     percentile
     percentile
@@ -184,10 +116,10 @@ async function _getAssignmentMetadata(analyticsId, userId, splitTest) {
   }
   }
 }
 }
 
 
-function _getPercentile(analyticsId, splitTestName, splitTestPhase) {
+function _getPercentile(userId, splitTestName, splitTestPhase) {
   const hash = crypto
   const hash = crypto
     .createHash('md5')
     .createHash('md5')
-    .update(analyticsId + splitTestName + splitTestPhase)
+    .update(userId + splitTestName + splitTestPhase)
     .digest('hex')
     .digest('hex')
   const hashPrefix = hash.substr(0, 8)
   const hashPrefix = hash.substr(0, 8)
   return Math.floor(
   return Math.floor(
@@ -207,52 +139,29 @@ function _getVariantFromPercentile(variants, percentile) {
 
 
 async function _updateVariantAssignment({
 async function _updateVariantAssignment({
   userId,
   userId,
-  analyticsId,
-  session,
   splitTestName,
   splitTestName,
   phase,
   phase,
   versionNumber,
   versionNumber,
   variantName,
   variantName,
 }) {
 }) {
-  const persistedAssignment = {
-    variantName,
-    versionNumber,
-    phase,
-    assignedAt: new Date(),
-  }
-  if (userId) {
-    const user = await _getUser(userId)
-    if (user) {
-      const assignedSplitTests = user.splitTests || []
-      const assignmentLog = assignedSplitTests[splitTestName] || []
-      const existingAssignment = _.find(assignmentLog, { versionNumber })
-      if (!existingAssignment) {
-        await UserUpdater.promises.updateUser(userId, {
-          $addToSet: {
-            [`splitTests.${splitTestName}`]: persistedAssignment,
-          },
-        })
-        AnalyticsManager.setUserPropertyForAnalyticsId(
-          analyticsId,
-          `split-test-${splitTestName}-${versionNumber}`,
-          variantName
-        )
-      }
-    }
-  } else if (session) {
-    if (!session.splitTests) {
-      session.splitTests = {}
-    }
-    if (!session.splitTests[splitTestName]) {
-      session.splitTests[splitTestName] = []
-    }
-    const existingAssignment = _.find(session.splitTests[splitTestName], {
-      versionNumber,
-    })
+  const user = await _getUser(userId)
+  if (user) {
+    const assignedSplitTests = user.splitTests || []
+    const assignmentLog = assignedSplitTests[splitTestName] || []
+    const existingAssignment = _.find(assignmentLog, { versionNumber })
     if (!existingAssignment) {
     if (!existingAssignment) {
-      session.splitTests[splitTestName].push(persistedAssignment)
-      AnalyticsManager.setUserPropertyForAnalyticsId(
-        analyticsId,
+      await UserUpdater.promises.updateUser(userId, {
+        $addToSet: {
+          [`splitTests.${splitTestName}`]: {
+            variantName,
+            versionNumber,
+            phase,
+            assignedAt: new Date(),
+          },
+        },
+      })
+      AnalyticsManager.setUserProperty(
+        userId,
         `split-test-${splitTestName}-${versionNumber}`,
         `split-test-${splitTestName}-${versionNumber}`,
         variantName
         variantName
       )
       )
@@ -270,13 +179,9 @@ async function _getUser(id) {
 
 
 module.exports = {
 module.exports = {
   getAssignment: callbackify(getAssignment),
   getAssignment: callbackify(getAssignment),
-  getAssignmentForSession: callbackify(getAssignmentForSession),
   assignInLocalsContext: callbackify(assignInLocalsContext),
   assignInLocalsContext: callbackify(assignInLocalsContext),
-  assignInLocalsContextForSession: callbackify(assignInLocalsContextForSession),
   promises: {
   promises: {
     getAssignment,
     getAssignment,
-    getAssignmentForSession,
     assignInLocalsContext,
     assignInLocalsContext,
-    assignInLocalsContextForSession,
   },
   },
 }
 }

+ 1 - 1
services/web/app/src/Features/Subscription/FeaturesUpdater.js

@@ -28,7 +28,7 @@ const FeaturesUpdater = {
         const matchedFeatureSet = FeaturesUpdater._getMatchedFeatureSet(
         const matchedFeatureSet = FeaturesUpdater._getMatchedFeatureSet(
           features
           features
         )
         )
-        AnalyticsManager.setUserPropertyForUser(
+        AnalyticsManager.setUserProperty(
           userId,
           userId,
           'feature-set',
           'feature-set',
           matchedFeatureSet
           matchedFeatureSet

+ 32 - 80
services/web/app/src/Features/Subscription/RecurlyEventHandler.js

@@ -39,133 +39,85 @@ function sendRecurlyAnalyticsEvent(event, eventData) {
   }
   }
 }
 }
 
 
-async function _sendSubscriptionStartedEvent(eventData) {
+function _sendSubscriptionStartedEvent(eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
-  AnalyticsManager.recordEventForUser(userId, 'subscription-started', {
+  AnalyticsManager.recordEvent(userId, 'subscription-started', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
   })
   })
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-plan-code',
-    planCode
-  )
-  AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-is-trial',
-    isTrial
-  )
+  AnalyticsManager.setUserProperty(userId, 'subscription-plan-code', planCode)
+  AnalyticsManager.setUserProperty(userId, 'subscription-state', state)
+  AnalyticsManager.setUserProperty(userId, 'subscription-is-trial', isTrial)
 }
 }
 
 
-async function _sendSubscriptionUpdatedEvent(eventData) {
+function _sendSubscriptionUpdatedEvent(eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
-  AnalyticsManager.recordEventForUser(userId, 'subscription-updated', {
+  AnalyticsManager.recordEvent(userId, 'subscription-updated', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
   })
   })
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-plan-code',
-    planCode
-  )
-  AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-is-trial',
-    isTrial
-  )
+  AnalyticsManager.setUserProperty(userId, 'subscription-plan-code', planCode)
+  AnalyticsManager.setUserProperty(userId, 'subscription-state', state)
+  AnalyticsManager.setUserProperty(userId, 'subscription-is-trial', isTrial)
 }
 }
 
 
-async function _sendSubscriptionCancelledEvent(eventData) {
+function _sendSubscriptionCancelledEvent(eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
-  AnalyticsManager.recordEventForUser(userId, 'subscription-cancelled', {
+  AnalyticsManager.recordEvent(userId, 'subscription-cancelled', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
   })
   })
-  AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-is-trial',
-    isTrial
-  )
+  AnalyticsManager.setUserProperty(userId, 'subscription-state', state)
+  AnalyticsManager.setUserProperty(userId, 'subscription-is-trial', isTrial)
 }
 }
 
 
-async function _sendSubscriptionExpiredEvent(eventData) {
+function _sendSubscriptionExpiredEvent(eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
-  AnalyticsManager.recordEventForUser(userId, 'subscription-expired', {
+  AnalyticsManager.recordEvent(userId, 'subscription-expired', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
   })
   })
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-plan-code',
-    planCode
-  )
-  AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-is-trial',
-    isTrial
-  )
+  AnalyticsManager.setUserProperty(userId, 'subscription-plan-code', planCode)
+  AnalyticsManager.setUserProperty(userId, 'subscription-state', state)
+  AnalyticsManager.setUserProperty(userId, 'subscription-is-trial', isTrial)
 }
 }
 
 
-async function _sendSubscriptionRenewedEvent(eventData) {
+function _sendSubscriptionRenewedEvent(eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
-  AnalyticsManager.recordEventForUser(userId, 'subscription-renewed', {
+  AnalyticsManager.recordEvent(userId, 'subscription-renewed', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
     is_trial: isTrial,
     is_trial: isTrial,
   })
   })
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-plan-code',
-    planCode
-  )
-  AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-is-trial',
-    isTrial
-  )
+  AnalyticsManager.setUserProperty(userId, 'subscription-plan-code', planCode)
+  AnalyticsManager.setUserProperty(userId, 'subscription-state', state)
+  AnalyticsManager.setUserProperty(userId, 'subscription-is-trial', isTrial)
 }
 }
 
 
-async function _sendSubscriptionReactivatedEvent(eventData) {
+function _sendSubscriptionReactivatedEvent(eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
   const { planCode, quantity, state, isTrial } = _getSubscriptionData(eventData)
-  AnalyticsManager.recordEventForUser(userId, 'subscription-reactivated', {
+  AnalyticsManager.recordEvent(userId, 'subscription-reactivated', {
     plan_code: planCode,
     plan_code: planCode,
     quantity,
     quantity,
   })
   })
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-plan-code',
-    planCode
-  )
-  AnalyticsManager.setUserPropertyForUser(userId, 'subscription-state', state)
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-is-trial',
-    isTrial
-  )
+  AnalyticsManager.setUserProperty(userId, 'subscription-plan-code', planCode)
+  AnalyticsManager.setUserProperty(userId, 'subscription-state', state)
+  AnalyticsManager.setUserProperty(userId, 'subscription-is-trial', isTrial)
 }
 }
 
 
-async function _sendInvoicePaidEvent(eventData) {
+function _sendInvoicePaidEvent(eventData) {
   const userId = _getUserId(eventData)
   const userId = _getUserId(eventData)
-  AnalyticsManager.recordEventForUser(userId, 'subscription-invoice-collected')
-  AnalyticsManager.setUserPropertyForUser(
-    userId,
-    'subscription-is-trial',
-    false
-  )
+  AnalyticsManager.recordEvent(userId, 'subscription-invoice-collected')
+  AnalyticsManager.setUserProperty(userId, 'subscription-is-trial', false)
 }
 }
 
 
 function _getUserId(eventData) {
 function _getUserId(eventData) {

+ 1 - 1
services/web/app/src/Features/Subscription/SubscriptionController.js

@@ -116,7 +116,7 @@ async function userSubscriptionPage(req, res) {
     personalSubscription ? personalSubscription.plan : undefined
     personalSubscription ? personalSubscription.plan : undefined
   )
   )
 
 
-  AnalyticsManager.recordEventForSession(req.session, 'subscription-page-view')
+  AnalyticsManager.recordEvent(user._id, 'subscription-page-view')
 
 
   const data = {
   const data = {
     title: 'your_subscription',
     title: 'your_subscription',

+ 1 - 1
services/web/app/src/Features/Subscription/SubscriptionUpdater.js

@@ -360,7 +360,7 @@ async function _sendUserGroupPlanCodeUserProperty(userId) {
         bestFeatures = plan.features
         bestFeatures = plan.features
       }
       }
     }
     }
-    AnalyticsManager.setUserPropertyForUser(
+    AnalyticsManager.setUserProperty(
       userId,
       userId,
       'group-subscription-plan-code',
       'group-subscription-plan-code',
       bestPlanCode
       bestPlanCode

+ 2 - 6
services/web/app/src/Features/TokenAccess/TokenAccessHandler.js

@@ -164,9 +164,7 @@ const TokenAccessHandler = {
   addReadOnlyUserToProject(userId, projectId, callback) {
   addReadOnlyUserToProject(userId, projectId, callback) {
     userId = ObjectId(userId.toString())
     userId = ObjectId(userId.toString())
     projectId = ObjectId(projectId.toString())
     projectId = ObjectId(projectId.toString())
-    Analytics.recordEventForUser(userId, 'project-joined', {
-      mode: 'read-only',
-    })
+    Analytics.recordEvent(userId, 'project-joined', { mode: 'read-only' })
     Project.updateOne(
     Project.updateOne(
       {
       {
         _id: projectId,
         _id: projectId,
@@ -181,9 +179,7 @@ const TokenAccessHandler = {
   addReadAndWriteUserToProject(userId, projectId, callback) {
   addReadAndWriteUserToProject(userId, projectId, callback) {
     userId = ObjectId(userId.toString())
     userId = ObjectId(userId.toString())
     projectId = ObjectId(projectId.toString())
     projectId = ObjectId(projectId.toString())
-    Analytics.recordEventForUser(userId, 'project-joined', {
-      mode: 'read-write',
-    })
+    Analytics.recordEvent(userId, 'project-joined', { mode: 'read-write' })
     Project.updateOne(
     Project.updateOne(
       {
       {
         _id: projectId,
         _id: projectId,

+ 2 - 10
services/web/app/src/Features/User/UserCreator.js

@@ -84,16 +84,8 @@ async function createNewUser(attributes, options = {}) {
     }
     }
   }
   }
 
 
-  await Analytics.recordEventForUser(user._id, 'user-registered')
-  await Analytics.setUserPropertyForUser(user._id, 'created-at', new Date())
-  await Analytics.setUserPropertyForUser(user._id, 'user-id', user._id)
-  if (attributes.analyticsId) {
-    await Analytics.setUserPropertyForUser(
-      user._id,
-      'analytics-id',
-      attributes.analyticsId
-    )
-  }
+  Analytics.recordEvent(user._id, 'user-registered')
+  Analytics.setUserProperty(user._id, 'created-at', new Date())
 
 
   if (Features.hasFeature('saas')) {
   if (Features.hasFeature('saas')) {
     try {
     try {

+ 1 - 1
services/web/app/src/Features/User/UserPostRegistrationAnalyticsManager.js

@@ -32,7 +32,7 @@ async function checkAffiliations(userId) {
   )
   )
 
 
   if (hasCommonsAccountAffiliation) {
   if (hasCommonsAccountAffiliation) {
-    await AnalyticsManager.setUserPropertyForUser(
+    await AnalyticsManager.setUserProperty(
       userId,
       userId,
       'registered-from-commons-account',
       'registered-from-commons-account',
       true
       true

+ 2 - 1
services/web/app/src/Features/User/UserRegistrationHandler.js

@@ -8,6 +8,7 @@ const logger = require('logger-sharelatex')
 const crypto = require('crypto')
 const crypto = require('crypto')
 const EmailHandler = require('../Email/EmailHandler')
 const EmailHandler = require('../Email/EmailHandler')
 const OneTimeTokenHandler = require('../Security/OneTimeTokenHandler')
 const OneTimeTokenHandler = require('../Security/OneTimeTokenHandler')
+const Analytics = require('../Analytics/AnalyticsManager')
 const settings = require('@overleaf/settings')
 const settings = require('@overleaf/settings')
 const EmailHelper = require('../Helpers/EmailHelper')
 const EmailHelper = require('../Helpers/EmailHelper')
 
 
@@ -30,7 +31,6 @@ const UserRegistrationHandler = {
           email: userDetails.email,
           email: userDetails.email,
           first_name: userDetails.first_name,
           first_name: userDetails.first_name,
           last_name: userDetails.last_name,
           last_name: userDetails.last_name,
-          analyticsId: userDetails.analyticsId,
         },
         },
         {},
         {},
         callback
         callback
@@ -87,6 +87,7 @@ const UserRegistrationHandler = {
             }, // this can be slow, just fire it off
             }, // this can be slow, just fire it off
           ],
           ],
           error => {
           error => {
+            Analytics.recordEvent(user._id, 'user-registered')
             callback(error, user)
             callback(error, user)
           }
           }
         )
         )

+ 0 - 5
services/web/app/src/infrastructure/Server.js

@@ -15,7 +15,6 @@ const sessionsRedisClient = UserSessionsRedis.client()
 
 
 const SessionAutostartMiddleware = require('./SessionAutostartMiddleware')
 const SessionAutostartMiddleware = require('./SessionAutostartMiddleware')
 const SessionStoreManager = require('./SessionStoreManager')
 const SessionStoreManager = require('./SessionStoreManager')
-const AnalyticsManager = require('../Features/Analytics/AnalyticsManager')
 const session = require('express-session')
 const session = require('express-session')
 const RedisStore = require('connect-redis')(session)
 const RedisStore = require('connect-redis')(session)
 const bodyParser = require('./BodyParserWrapper')
 const bodyParser = require('./BodyParserWrapper')
@@ -33,7 +32,6 @@ const ProxyManager = require('./ProxyManager')
 const translations = require('./Translations')
 const translations = require('./Translations')
 const Modules = require('./Modules')
 const Modules = require('./Modules')
 const Views = require('./Views')
 const Views = require('./Views')
-const Features = require('./Features')
 
 
 const ErrorController = require('../Features/Errors/ErrorController')
 const ErrorController = require('../Features/Errors/ErrorController')
 const HttpErrorHandler = require('../Features/Errors/HttpErrorHandler')
 const HttpErrorHandler = require('../Features/Errors/HttpErrorHandler')
@@ -127,9 +125,6 @@ webRouter.use(
     rolling: true,
     rolling: true,
   })
   })
 )
 )
-if (Features.hasFeature('saas')) {
-  webRouter.use(AnalyticsManager.analyticsIdMiddleware)
-}
 
 
 // patch the session store to generate a validation token for every new session
 // patch the session store to generate a validation token for every new session
 SessionStoreManager.enableValidationToken(sessionStore)
 SessionStoreManager.enableValidationToken(sessionStore)

+ 0 - 1
services/web/app/src/models/User.js

@@ -166,7 +166,6 @@ const UserSchema = new Schema({
   onboardingEmailSentAt: { type: Date },
   onboardingEmailSentAt: { type: Date },
   auditLog: [AuditLogEntrySchema],
   auditLog: [AuditLogEntrySchema],
   splitTests: Schema.Types.Mixed,
   splitTests: Schema.Types.Mixed,
-  analyticsId: { type: String },
 })
 })
 
 
 exports.User = mongoose.model('User', UserSchema)
 exports.User = mongoose.model('User', UserSchema)

+ 1 - 1
services/web/modules/server-ce-scripts/scripts/create-user.js

@@ -18,7 +18,7 @@ async function main() {
 
 
   await new Promise((resolve, reject) => {
   await new Promise((resolve, reject) => {
     UserRegistrationHandler.registerNewUserAndSendActivationEmail(
     UserRegistrationHandler.registerNewUserAndSendActivationEmail(
-      email,
+        email,
       (error, user, setNewPasswordUrl) => {
       (error, user, setNewPasswordUrl) => {
         if (error) {
         if (error) {
           return reject(error)
           return reject(error)

+ 23 - 7
services/web/test/unit/src/Analytics/AnalyticsControllerTests.js

@@ -12,7 +12,7 @@ describe('AnalyticsController', function () {
 
 
     this.AnalyticsManager = {
     this.AnalyticsManager = {
       updateEditingSession: sinon.stub(),
       updateEditingSession: sinon.stub(),
-      recordEventForSession: sinon.stub(),
+      recordEvent: sinon.stub(),
     }
     }
 
 
     this.Features = {
     this.Features = {
@@ -42,7 +42,6 @@ describe('AnalyticsController', function () {
         params: {
         params: {
           projectId: 'a project id',
           projectId: 'a project id',
         },
         },
-        session: {},
       }
       }
       this.GeoIpLookup.getDetails = sinon
       this.GeoIpLookup.getDetails = sinon
         .stub()
         .stub()
@@ -79,18 +78,35 @@ describe('AnalyticsController', function () {
       delete this.expectedData._csrf
       delete this.expectedData._csrf
     })
     })
 
 
-    it('should use the session', function (done) {
+    it('should use the user_id', function (done) {
+      this.SessionManager.getLoggedInUserId.returns('1234')
+      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.controller.recordEvent(this.req, this.res)
-      this.AnalyticsManager.recordEventForSession
-        .calledWith(this.req.session, this.req.params.event, this.expectedData)
+      this.AnalyticsManager.recordEvent
+        .calledWith(
+          this.req.sessionID,
+          this.req.params.event,
+          this.expectedData
+        )
         .should.equal(true)
         .should.equal(true)
       done()
       done()
     })
     })
 
 
     it('should remove the CSRF token before sending to the manager', function (done) {
     it('should remove the CSRF token before sending to the manager', function (done) {
       this.controller.recordEvent(this.req, this.res)
       this.controller.recordEvent(this.req, this.res)
-      this.AnalyticsManager.recordEventForSession
-        .calledWith(this.req.session, this.req.params.event, this.expectedData)
+      this.AnalyticsManager.recordEvent
+        .calledWith(
+          this.req.sessionID,
+          this.req.params.event,
+          this.expectedData
+        )
         .should.equal(true)
         .should.equal(true)
       done()
       done()
     })
     })

+ 6 - 15
services/web/test/unit/src/Analytics/AnalyticsManagerTests.js

@@ -10,7 +10,6 @@ const MODULE_PATH = path.join(
 describe('AnalyticsManager', function () {
 describe('AnalyticsManager', function () {
   beforeEach(function () {
   beforeEach(function () {
     this.fakeUserId = '123abc'
     this.fakeUserId = '123abc'
-    this.analyticsId = '123456'
     this.Settings = {
     this.Settings = {
       analytics: { enabled: true },
       analytics: { enabled: true },
     }
     }
@@ -51,9 +50,6 @@ describe('AnalyticsManager', function () {
       requires: {
       requires: {
         '@overleaf/settings': this.Settings,
         '@overleaf/settings': this.Settings,
         '../../infrastructure/Queues': this.Queues,
         '../../infrastructure/Queues': this.Queues,
-        './UserAnalyticsIdCache': (this.UserAnalyticsIdCache = {
-          get: sinon.stub().resolves(this.analyticsId),
-        }),
       },
       },
     })
     })
   })
   })
@@ -74,26 +70,21 @@ describe('AnalyticsManager', function () {
 
 
   describe('queues the appropriate message for', function () {
   describe('queues the appropriate message for', function () {
     it('identifyUser', function () {
     it('identifyUser', function () {
-      const analyticsId = '456def'
-      this.AnalyticsManager.identifyUser(this.fakeUserId, analyticsId)
+      const oldUserId = '456def'
+      this.AnalyticsManager.identifyUser(this.fakeUserId, oldUserId)
       sinon.assert.calledWithMatch(this.analyticsEventsQueue.add, 'identify', {
       sinon.assert.calledWithMatch(this.analyticsEventsQueue.add, 'identify', {
         userId: this.fakeUserId,
         userId: this.fakeUserId,
-        analyticsId,
+        oldUserId,
       })
       })
     })
     })
 
 
-    it('recordEventForUser', async function () {
+    it('recordEvent', function () {
       const event = 'fake-event'
       const event = 'fake-event'
-      await this.AnalyticsManager.recordEventForUser(
-        this.fakeUserId,
-        event,
-        null
-      )
+      this.AnalyticsManager.recordEvent(this.fakeUserId, event, null)
       sinon.assert.calledWithMatch(this.analyticsEventsQueue.add, 'event', {
       sinon.assert.calledWithMatch(this.analyticsEventsQueue.add, 'event', {
-        analyticsId: this.analyticsId,
         event,
         event,
+        userId: this.fakeUserId,
         segmentation: null,
         segmentation: null,
-        isLoggedIn: true,
       })
       })
     })
     })
 
 

+ 7 - 13
services/web/test/unit/src/Authentication/AuthenticationControllerTests.js

@@ -28,7 +28,6 @@ describe('AuthenticationController', function () {
     this.res = new MockResponse()
     this.res = new MockResponse()
     this.callback = sinon.stub()
     this.callback = sinon.stub()
     this.next = sinon.stub()
     this.next = sinon.stub()
-    this.req.session.analyticsId = 'abc-123'
 
 
     this.AuthenticationController = SandboxedModule.require(modulePath, {
     this.AuthenticationController = SandboxedModule.require(modulePath, {
       requires: {
       requires: {
@@ -54,9 +53,8 @@ describe('AuthenticationController', function () {
           setupLoginData: sinon.stub(),
           setupLoginData: sinon.stub(),
         }),
         }),
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
-          recordEventForUser: sinon.stub(),
+          recordEvent: sinon.stub(),
           identifyUser: sinon.stub(),
           identifyUser: sinon.stub(),
-          getIdsFromSession: sinon.stub().returns({ userId: this.user._id }),
         }),
         }),
         '../../infrastructure/SessionStoreManager': (this.SessionStoreManager = {}),
         '../../infrastructure/SessionStoreManager': (this.SessionStoreManager = {}),
         '@overleaf/settings': (this.Settings = {
         '@overleaf/settings': (this.Settings = {
@@ -1238,11 +1236,9 @@ describe('AuthenticationController', function () {
       })
       })
 
 
       it('should call identifyUser', function () {
       it('should call identifyUser', function () {
-        sinon.assert.calledWith(
-          this.AnalyticsManager.identifyUser,
-          this.user._id,
-          this.req.session.analyticsId
-        )
+        this.AnalyticsManager.identifyUser
+          .calledWith(this.user._id, this.req.sessionID)
+          .should.equal(true)
       })
       })
 
 
       it('should setup the user data in the background', function () {
       it('should setup the user data in the background', function () {
@@ -1275,11 +1271,9 @@ describe('AuthenticationController', function () {
       })
       })
 
 
       it('should track the login event', function () {
       it('should track the login event', function () {
-        sinon.assert.calledWith(
-          this.AnalyticsManager.recordEventForUser,
-          this.user._id,
-          'user-logged-in'
-        )
+        this.AnalyticsManager.recordEvent
+          .calledWith(this.user._id, 'user-logged-in')
+          .should.equal(true)
       })
       })
     })
     })
   })
   })

+ 1 - 1
services/web/test/unit/src/Collaborators/CollaboratorsInviteControllerTests.js

@@ -24,7 +24,7 @@ const { ObjectId } = require('mongodb')
 describe('CollaboratorsInviteController', function () {
 describe('CollaboratorsInviteController', function () {
   beforeEach(function () {
   beforeEach(function () {
     this.user = { _id: 'id' }
     this.user = { _id: 'id' }
-    this.AnalyticsManger = { recordEventForUser: sinon.stub() }
+    this.AnalyticsManger = { recordEvent: sinon.stub() }
     this.sendingUser = null
     this.sendingUser = null
     this.AuthenticationController = {
     this.AuthenticationController = {
       getSessionUser: req => {
       getSessionUser: req => {

+ 1 - 1
services/web/test/unit/src/Project/ProjectControllerTests.js

@@ -173,7 +173,7 @@ describe('ProjectController', function () {
           .BrandVariationsHandler,
           .BrandVariationsHandler,
         '../ThirdPartyDataStore/TpdsProjectFlusher': this.TpdsProjectFlusher,
         '../ThirdPartyDataStore/TpdsProjectFlusher': this.TpdsProjectFlusher,
         '../../models/Project': {},
         '../../models/Project': {},
-        '../Analytics/AnalyticsManager': { recordEventForUser: () => {} },
+        '../Analytics/AnalyticsManager': { recordEvent: () => {} },
         '../../infrastructure/Modules': {
         '../../infrastructure/Modules': {
           hooks: { fire: sinon.stub().yields(null, []) },
           hooks: { fire: sinon.stub().yields(null, []) },
         },
         },

+ 3 - 3
services/web/test/unit/src/Subscription/FeaturesUpdaterTests.js

@@ -40,7 +40,7 @@ describe('FeaturesUpdater', function () {
         '../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}),
         '../Institutions/InstitutionsFeatures': (this.InstitutionsFeatures = {}),
         '../User/UserGetter': (this.UserGetter = {}),
         '../User/UserGetter': (this.UserGetter = {}),
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
-          setUserPropertyForUser: sinon.stub(),
+          setUserProperty: sinon.stub(),
         }),
         }),
         '../../infrastructure/Modules': (this.Modules = {
         '../../infrastructure/Modules': (this.Modules = {
           hooks: { fire: sinon.stub() },
           hooks: { fire: sinon.stub() },
@@ -182,7 +182,7 @@ describe('FeaturesUpdater', function () {
         )
         )
 
 
         sinon.assert.calledWith(
         sinon.assert.calledWith(
-          this.AnalyticsManager.setUserPropertyForUser,
+          this.AnalyticsManager.setUserProperty,
           this.user_id,
           this.user_id,
           'feature-set',
           'feature-set',
           'personal'
           'personal'
@@ -201,7 +201,7 @@ describe('FeaturesUpdater', function () {
         )
         )
 
 
         sinon.assert.calledWith(
         sinon.assert.calledWith(
-          this.AnalyticsManager.setUserPropertyForUser,
+          this.AnalyticsManager.setUserProperty,
           this.user_id,
           this.user_id,
           'feature-set',
           'feature-set',
           'mixed'
           'mixed'

+ 26 - 26
services/web/test/unit/src/Subscription/RecurlyEventHandlerTests.js

@@ -27,8 +27,8 @@ describe('RecurlyEventHandler', function () {
     this.RecurlyEventHandler = SandboxedModule.require(modulePath, {
     this.RecurlyEventHandler = SandboxedModule.require(modulePath, {
       requires: {
       requires: {
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
-          recordEventForUser: sinon.stub(),
-          setUserPropertyForUser: sinon.stub(),
+          recordEvent: sinon.stub(),
+          setUserProperty: sinon.stub(),
         }),
         }),
       },
       },
     })
     })
@@ -40,7 +40,7 @@ describe('RecurlyEventHandler', function () {
       this.eventData
       this.eventData
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-started',
       'subscription-started',
       {
       {
@@ -50,19 +50,19 @@ describe('RecurlyEventHandler', function () {
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-plan-code',
       'subscription-plan-code',
       this.planCode
       this.planCode
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-state',
       'subscription-state',
       'active'
       'active'
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-is-trial',
       'subscription-is-trial',
       true
       true
@@ -83,7 +83,7 @@ describe('RecurlyEventHandler', function () {
       this.eventData
       this.eventData
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-started',
       'subscription-started',
       {
       {
@@ -93,13 +93,13 @@ describe('RecurlyEventHandler', function () {
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-state',
       'subscription-state',
       'active'
       'active'
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-is-trial',
       'subscription-is-trial',
       false
       false
@@ -114,7 +114,7 @@ describe('RecurlyEventHandler', function () {
       this.eventData
       this.eventData
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-updated',
       'subscription-updated',
       {
       {
@@ -123,19 +123,19 @@ describe('RecurlyEventHandler', function () {
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-plan-code',
       'subscription-plan-code',
       this.planCode
       this.planCode
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-state',
       'subscription-state',
       'active'
       'active'
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-is-trial',
       'subscription-is-trial',
       true
       true
@@ -149,7 +149,7 @@ describe('RecurlyEventHandler', function () {
       this.eventData
       this.eventData
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-cancelled',
       'subscription-cancelled',
       {
       {
@@ -159,13 +159,13 @@ describe('RecurlyEventHandler', function () {
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-state',
       'subscription-state',
       'cancelled'
       'cancelled'
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-is-trial',
       'subscription-is-trial',
       true
       true
@@ -179,7 +179,7 @@ describe('RecurlyEventHandler', function () {
       this.eventData
       this.eventData
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-expired',
       'subscription-expired',
       {
       {
@@ -189,19 +189,19 @@ describe('RecurlyEventHandler', function () {
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-plan-code',
       'subscription-plan-code',
       this.planCode
       this.planCode
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-state',
       'subscription-state',
       'expired'
       'expired'
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.setUserPropertyForUser,
+      this.AnalyticsManager.setUserProperty,
       this.userId,
       this.userId,
       'subscription-is-trial',
       'subscription-is-trial',
       true
       true
@@ -214,7 +214,7 @@ describe('RecurlyEventHandler', function () {
       this.eventData
       this.eventData
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-renewed',
       'subscription-renewed',
       {
       {
@@ -231,7 +231,7 @@ describe('RecurlyEventHandler', function () {
       this.eventData
       this.eventData
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-reactivated',
       'subscription-reactivated',
       {
       {
@@ -255,7 +255,7 @@ describe('RecurlyEventHandler', function () {
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-invoice-collected'
       'subscription-invoice-collected'
     )
     )
@@ -274,7 +274,7 @@ describe('RecurlyEventHandler', function () {
         },
         },
       }
       }
     )
     )
-    sinon.assert.notCalled(this.AnalyticsManager.recordEventForUser)
+    sinon.assert.notCalled(this.AnalyticsManager.recordEvent)
   })
   })
 
 
   it('with closed_invoice_notification', function () {
   it('with closed_invoice_notification', function () {
@@ -291,7 +291,7 @@ describe('RecurlyEventHandler', function () {
       }
       }
     )
     )
     sinon.assert.calledWith(
     sinon.assert.calledWith(
-      this.AnalyticsManager.recordEventForUser,
+      this.AnalyticsManager.recordEvent,
       this.userId,
       this.userId,
       'subscription-invoice-collected'
       'subscription-invoice-collected'
     )
     )
@@ -310,6 +310,6 @@ describe('RecurlyEventHandler', function () {
         },
         },
       }
       }
     )
     )
-    sinon.assert.notCalled(this.AnalyticsManager.recordEventForUser)
+    sinon.assert.notCalled(this.AnalyticsManager.recordEvent)
   })
   })
 })
 })

+ 2 - 3
services/web/test/unit/src/Subscription/SubscriptionControllerTests.js

@@ -141,9 +141,8 @@ describe('SubscriptionController', function () {
         }),
         }),
         './Errors': SubscriptionErrors,
         './Errors': SubscriptionErrors,
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
-          recordEventForUser: sinon.stub(),
-          recordEventForSession: sinon.stub(),
-          setUserPropertyForUser: sinon.stub(),
+          recordEvent: sinon.stub(),
+          setUserProperty: sinon.stub(),
         }),
         }),
         '../SplitTests/SplitTestHandler': (this.SplitTestHandler = {
         '../SplitTests/SplitTestHandler': (this.SplitTestHandler = {
           getTestSegmentation: () => {},
           getTestSegmentation: () => {},

+ 1 - 1
services/web/test/unit/src/Subscription/SubscriptionHandlerTests.js

@@ -108,7 +108,7 @@ describe('SubscriptionHandler', function () {
 
 
     this.EmailHandler = { sendEmail: sinon.stub() }
     this.EmailHandler = { sendEmail: sinon.stub() }
 
 
-    this.AnalyticsManager = { recordEventForUser: sinon.stub() }
+    this.AnalyticsManager = { recordEvent: sinon.stub() }
 
 
     this.PlansLocator = {
     this.PlansLocator = {
       findLocalPlanInSettings: sinon.stub().returns({ planCode: 'plan' }),
       findLocalPlanInSettings: sinon.stub().returns({ planCode: 'plan' }),

+ 7 - 7
services/web/test/unit/src/Subscription/SubscriptionUpdaterTests.js

@@ -105,7 +105,7 @@ describe('SubscriptionUpdater', function () {
       findOneAndUpdate: sinon.stub().yields(),
       findOneAndUpdate: sinon.stub().yields(),
     }
     }
     this.AnalyticsManager = {
     this.AnalyticsManager = {
-      setUserPropertyForUser: sinon.stub(),
+      setUserProperty: sinon.stub(),
     }
     }
     this.SubscriptionUpdater = SandboxedModule.require(modulePath, {
     this.SubscriptionUpdater = SandboxedModule.require(modulePath, {
       requires: {
       requires: {
@@ -527,7 +527,7 @@ describe('SubscriptionUpdater', function () {
         this.otherUserId,
         this.otherUserId,
         () => {
         () => {
           sinon.assert.calledWith(
           sinon.assert.calledWith(
-            this.AnalyticsManager.setUserPropertyForUser,
+            this.AnalyticsManager.setUserProperty,
             this.otherUserId,
             this.otherUserId,
             'group-subscription-plan-code',
             'group-subscription-plan-code',
             'group_subscription'
             'group_subscription'
@@ -547,7 +547,7 @@ describe('SubscriptionUpdater', function () {
         this.otherUserId
         this.otherUserId
       )
       )
       sinon.assert.calledWith(
       sinon.assert.calledWith(
-        this.AnalyticsManager.setUserPropertyForUser,
+        this.AnalyticsManager.setUserProperty,
         this.otherUserId,
         this.otherUserId,
         'group-subscription-plan-code',
         'group-subscription-plan-code',
         'group_subscription'
         'group_subscription'
@@ -564,7 +564,7 @@ describe('SubscriptionUpdater', function () {
         this.otherUserId
         this.otherUserId
       )
       )
       sinon.assert.calledWith(
       sinon.assert.calledWith(
-        this.AnalyticsManager.setUserPropertyForUser,
+        this.AnalyticsManager.setUserProperty,
         this.otherUserId,
         this.otherUserId,
         'group-subscription-plan-code',
         'group-subscription-plan-code',
         'better_group_subscription'
         'better_group_subscription'
@@ -581,7 +581,7 @@ describe('SubscriptionUpdater', function () {
         this.otherUserId
         this.otherUserId
       )
       )
       sinon.assert.calledWith(
       sinon.assert.calledWith(
-        this.AnalyticsManager.setUserPropertyForUser,
+        this.AnalyticsManager.setUserProperty,
         this.otherUserId,
         this.otherUserId,
         'group-subscription-plan-code',
         'group-subscription-plan-code',
         'better_group_subscription'
         'better_group_subscription'
@@ -622,7 +622,7 @@ describe('SubscriptionUpdater', function () {
         this.otherUserId,
         this.otherUserId,
         () => {
         () => {
           sinon.assert.calledWith(
           sinon.assert.calledWith(
-            this.AnalyticsManager.setUserPropertyForUser,
+            this.AnalyticsManager.setUserProperty,
             this.otherUserId,
             this.otherUserId,
             'group-subscription-plan-code',
             'group-subscription-plan-code',
             null
             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) {
     it('should set the group plan code user property when removing user from all groups', function (done) {
       this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
       this.SubscriptionUpdater.removeUserFromAllGroups(this.otherUserId, () => {
         sinon.assert.calledWith(
         sinon.assert.calledWith(
-          this.AnalyticsManager.setUserPropertyForUser,
+          this.AnalyticsManager.setUserProperty,
           this.otherUserId,
           this.otherUserId,
           'group-subscription-plan-code',
           'group-subscription-plan-code',
           null
           null

+ 4 - 3
services/web/test/unit/src/TokenAccess/TokenAccessHandlerTests.js

@@ -12,6 +12,7 @@
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  * Full docs: https://github.com/decaffeinate/decaffeinate/blob/master/docs/suggestions.md
  */
  */
 const SandboxedModule = require('sandboxed-module')
 const SandboxedModule = require('sandboxed-module')
+const assert = require('assert')
 const path = require('path')
 const path = require('path')
 const sinon = require('sinon')
 const sinon = require('sinon')
 const modulePath = path.join(
 const modulePath = path.join(
@@ -42,7 +43,7 @@ describe('TokenAccessHandler', function () {
         }),
         }),
         crypto: (this.Crypto = require('crypto')),
         crypto: (this.Crypto = require('crypto')),
         '../Analytics/AnalyticsManager': (this.Analytics = {
         '../Analytics/AnalyticsManager': (this.Analytics = {
-          recordEventForUser: sinon.stub(),
+          recordEvent: sinon.stub(),
         }),
         }),
       },
       },
     }))
     }))
@@ -137,7 +138,7 @@ describe('TokenAccessHandler', function () {
             this.Project.updateOne.lastCall.args[1].$addToSet
             this.Project.updateOne.lastCall.args[1].$addToSet
           ).to.have.keys('tokenAccessReadOnly_refs')
           ).to.have.keys('tokenAccessReadOnly_refs')
           sinon.assert.calledWith(
           sinon.assert.calledWith(
-            this.Analytics.recordEventForUser,
+            this.Analytics.recordEvent,
             this.userId,
             this.userId,
             'project-joined',
             'project-joined',
             { mode: 'read-only' }
             { mode: 'read-only' }
@@ -198,7 +199,7 @@ describe('TokenAccessHandler', function () {
             this.Project.updateOne.lastCall.args[1].$addToSet
             this.Project.updateOne.lastCall.args[1].$addToSet
           ).to.have.keys('tokenAccessReadAndWrite_refs')
           ).to.have.keys('tokenAccessReadAndWrite_refs')
           sinon.assert.calledWith(
           sinon.assert.calledWith(
-            this.Analytics.recordEventForUser,
+            this.Analytics.recordEvent,
             this.userId,
             this.userId,
             'project-joined',
             'project-joined',
             { mode: 'read-write' }
             { mode: 'read-write' }

+ 3 - 5
services/web/test/unit/src/User/UserControllerTests.js

@@ -24,7 +24,6 @@ describe('UserController', function () {
           _id: this.user_id,
           _id: this.user_id,
           email: 'old@something.com',
           email: 'old@something.com',
         },
         },
-        analyticsId: this.user_id,
       },
       },
       sessionID: '123',
       sessionID: '123',
       body: {},
       body: {},
@@ -545,10 +544,9 @@ describe('UserController', function () {
     })
     })
 
 
     it('should register the user and send them an email', function () {
     it('should register the user and send them an email', function () {
-      sinon.assert.calledWith(
-        this.UserRegistrationHandler.registerNewUserAndSendActivationEmail,
-        this.email
-      )
+      this.UserRegistrationHandler.registerNewUserAndSendActivationEmail
+        .calledWith(this.email)
+        .should.equal(true)
     })
     })
 
 
     it('should return the user and activation url', function () {
     it('should return the user and activation url', function () {

+ 4 - 4
services/web/test/unit/src/User/UserCreatorTests.js

@@ -42,8 +42,8 @@ describe('UserCreator', function () {
           },
           },
         }),
         }),
         '../Analytics/AnalyticsManager': (this.Analytics = {
         '../Analytics/AnalyticsManager': (this.Analytics = {
-          recordEventForUser: sinon.stub(),
-          setUserPropertyForUser: sinon.stub(),
+          recordEvent: sinon.stub(),
+          setUserProperty: sinon.stub(),
         }),
         }),
         './UserOnboardingEmailManager': (this.UserOnboardingEmailManager = {
         './UserOnboardingEmailManager': (this.UserOnboardingEmailManager = {
           scheduleOnboardingEmail: sinon.stub(),
           scheduleOnboardingEmail: sinon.stub(),
@@ -271,12 +271,12 @@ describe('UserCreator', function () {
         })
         })
         assert.equal(user.email, this.email)
         assert.equal(user.email, this.email)
         sinon.assert.calledWith(
         sinon.assert.calledWith(
-          this.Analytics.recordEventForUser,
+          this.Analytics.recordEvent,
           user._id,
           user._id,
           'user-registered'
           'user-registered'
         )
         )
         sinon.assert.calledWith(
         sinon.assert.calledWith(
-          this.Analytics.setUserPropertyForUser,
+          this.Analytics.setUserProperty,
           user._id,
           user._id,
           'created-at'
           'created-at'
         )
         )

+ 4 - 8
services/web/test/unit/src/User/UserPostRegistrationAnalyticsManagerTests.js

@@ -36,7 +36,7 @@ describe('UserPostRegistrationAnalyticsManager', function () {
       },
       },
     }
     }
     this.AnalyticsManager = {
     this.AnalyticsManager = {
-      setUserPropertyForUser: sinon.stub().resolves(),
+      setUserProperty: sinon.stub().resolves(),
     }
     }
     this.UserPostRegistrationAnalyticsManager = SandboxedModule.require(
     this.UserPostRegistrationAnalyticsManager = SandboxedModule.require(
       MODULE_PATH,
       MODULE_PATH,
@@ -72,8 +72,7 @@ describe('UserPostRegistrationAnalyticsManager', function () {
       )
       )
       expect(this.InstitutionsAPI.promises.getUserAffiliations).not.to.have.been
       expect(this.InstitutionsAPI.promises.getUserAffiliations).not.to.have.been
         .called
         .called
-      expect(this.AnalyticsManager.setUserPropertyForUser).not.to.have.been
-        .called
+      expect(this.AnalyticsManager.setUserProperty).not.to.have.been.called
     })
     })
 
 
     it('sets user property if user has commons account affiliationd', async function () {
     it('sets user property if user has commons account affiliationd', async function () {
@@ -93,9 +92,7 @@ describe('UserPostRegistrationAnalyticsManager', function () {
       await this.UserPostRegistrationAnalyticsManager.postRegistrationAnalytics(
       await this.UserPostRegistrationAnalyticsManager.postRegistrationAnalytics(
         this.fakeUserId
         this.fakeUserId
       )
       )
-      expect(
-        this.AnalyticsManager.setUserPropertyForUser
-      ).to.have.been.calledWith(
+      expect(this.AnalyticsManager.setUserProperty).to.have.been.calledWith(
         this.fakeUserId,
         this.fakeUserId,
         'registered-from-commons-account',
         'registered-from-commons-account',
         true
         true
@@ -113,8 +110,7 @@ describe('UserPostRegistrationAnalyticsManager', function () {
       await this.UserPostRegistrationAnalyticsManager.postRegistrationAnalytics(
       await this.UserPostRegistrationAnalyticsManager.postRegistrationAnalytics(
         this.fakeUserId
         this.fakeUserId
       )
       )
-      expect(this.AnalyticsManager.setUserPropertyForUser).not.to.have.been
-        .called
+      expect(this.AnalyticsManager.setUserProperty).not.to.have.been.called
     })
     })
   })
   })
 })
 })

+ 29 - 24
services/web/test/unit/src/User/UserRegistrationHandlerTests.js

@@ -24,11 +24,7 @@ const EmailHelper = require('../../../../app/src/Features/Helpers/EmailHelper')
 
 
 describe('UserRegistrationHandler', function () {
 describe('UserRegistrationHandler', function () {
   beforeEach(function () {
   beforeEach(function () {
-    this.analyticsId = '123456'
-    this.user = {
-      _id: (this.user_id = '31j2lk21kjl'),
-      analyticsId: this.analyticsId,
-    }
+    this.user = { _id: (this.user_id = '31j2lk21kjl') }
     this.User = { updateOne: sinon.stub().callsArgWith(2) }
     this.User = { updateOne: sinon.stub().callsArgWith(2) }
     this.UserGetter = { getUserByAnyEmail: sinon.stub() }
     this.UserGetter = { getUserByAnyEmail: sinon.stub() }
     this.UserCreator = {
     this.UserCreator = {
@@ -53,9 +49,7 @@ describe('UserRegistrationHandler', function () {
         '../Email/EmailHandler': this.EmailHandler,
         '../Email/EmailHandler': this.EmailHandler,
         '../Security/OneTimeTokenHandler': this.OneTimeTokenHandler,
         '../Security/OneTimeTokenHandler': this.OneTimeTokenHandler,
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
         '../Analytics/AnalyticsManager': (this.AnalyticsManager = {
-          recordEventForUser: sinon.stub(),
-          setUserPropertyForUser: sinon.stub(),
-          identifyUser: sinon.stub(),
+          recordEvent: sinon.stub(),
         }),
         }),
         '@overleaf/settings': (this.settings = {
         '@overleaf/settings': (this.settings = {
           siteUrl: 'http://sl.example.com',
           siteUrl: 'http://sl.example.com',
@@ -64,11 +58,10 @@ describe('UserRegistrationHandler', function () {
       },
       },
     })
     })
 
 
-    this.passingRequest = {
+    return (this.passingRequest = {
       email: 'something@email.com',
       email: 'something@email.com',
       password: '123',
       password: '123',
-      analyticsId: this.analyticsId,
-    }
+    })
   })
   })
 
 
   describe('validate Register Request', function () {
   describe('validate Register Request', function () {
@@ -174,15 +167,16 @@ describe('UserRegistrationHandler', function () {
       })
       })
 
 
       it('should create a new user', function (done) {
       it('should create a new user', function (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()
+        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()
         })
         })
       })
       })
 
 
@@ -233,6 +227,15 @@ describe('UserRegistrationHandler', function () {
           return done()
           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) {
     it('should call the ReferalAllocator', function (done) {
@@ -267,10 +270,12 @@ describe('UserRegistrationHandler', function () {
       })
       })
 
 
       it('should ask the UserRegistrationHandler to register user', function () {
       it('should ask the UserRegistrationHandler to register user', function () {
-        sinon.assert.calledWith(this.handler.registerNewUser, {
-          email: this.email,
-          password: this.password,
-        })
+        return this.handler.registerNewUser
+          .calledWith({
+            email: this.email,
+            password: this.password,
+          })
+          .should.equal(true)
       })
       })
 
 
       it('should generate a new password reset token', function () {
       it('should generate a new password reset token', function () {