From 7957c2eae781ee7211d415dfb9ddb5633a11d8d4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timoth=C3=A9e=20Alby?= Date: Wed, 19 May 2021 10:29:39 +0200 Subject: [PATCH] Merge pull request #4050 from overleaf/ta-set-user-property Send 'created-at' User Property GitOrigin-RevId: 2a6c8356f0a64ffbc55eac485bb80c38b326f683 --- .../Features/Analytics/AnalyticsManager.js | 26 +++++++++++++++++++ .../web/app/src/Features/User/UserCreator.js | 1 + services/web/app/src/infrastructure/Queues.js | 7 +++++ .../src/Analytics/AnalyticsManagerTests.js | 7 +++++ .../test/unit/src/User/UserCreatorTests.js | 8 +++++- 5 files changed, 48 insertions(+), 1 deletion(-) diff --git a/services/web/app/src/Features/Analytics/AnalyticsManager.js b/services/web/app/src/Features/Analytics/AnalyticsManager.js index 66c796ba51..c55bb6a769 100644 --- a/services/web/app/src/Features/Analytics/AnalyticsManager.js +++ b/services/web/app/src/Features/Analytics/AnalyticsManager.js @@ -4,6 +4,7 @@ const Queues = require('../../infrastructure/Queues') const analyticsEventsQueue = Queues.getAnalyticsEventsQueue() const analyticsEditingSessionsQueue = Queues.getAnalyticsEditingSessionsQueue() +const analyticsUserPropertiesQueue = Queues.getAnalyticsUserPropertiesQueue() function identifyUser(userId, oldUserId) { if (isAnalyticsDisabled() || isSmokeTestUser(userId)) { @@ -59,6 +60,30 @@ function updateEditingSession(userId, projectId, countryCode) { }) } +function setUserProperty(userId, propertyName, propertyValue) { + if (isAnalyticsDisabled() || isSmokeTestUser(userId)) { + return + } + Metrics.analyticsQueue.inc({ + status: 'adding', + event_type: 'user-property', + }) + analyticsUserPropertiesQueue + .add({ userId, propertyName, propertyValue }) + .then(() => { + Metrics.analyticsQueue.inc({ + status: 'added', + event_type: 'user-property', + }) + }) + .catch(() => { + Metrics.analyticsQueue.inc({ + status: 'error', + event_type: 'user-property', + }) + }) +} + function isSmokeTestUser(userId) { const smokeTestUserId = Settings.smokeTest && Settings.smokeTest.userId return smokeTestUserId != null && userId.toString() === smokeTestUserId @@ -72,4 +97,5 @@ module.exports = { identifyUser, recordEvent, updateEditingSession, + setUserProperty, } diff --git a/services/web/app/src/Features/User/UserCreator.js b/services/web/app/src/Features/User/UserCreator.js index 66b9594552..9af477085d 100644 --- a/services/web/app/src/Features/User/UserCreator.js +++ b/services/web/app/src/Features/User/UserCreator.js @@ -81,6 +81,7 @@ async function createNewUser(attributes, options = {}) { } Analytics.recordEvent(user._id, 'user-registered') + Analytics.setUserProperty(user._id, 'created-at', new Date()) try { await UserOnboardingEmailQueueManager.scheduleOnboardingEmail(user) } catch (error) { diff --git a/services/web/app/src/infrastructure/Queues.js b/services/web/app/src/infrastructure/Queues.js index 5fe50e5b19..2bd7e5e667 100644 --- a/services/web/app/src/infrastructure/Queues.js +++ b/services/web/app/src/infrastructure/Queues.js @@ -21,6 +21,12 @@ function getAnalyticsEditingSessionsQueue() { } } +function getAnalyticsUserPropertiesQueue() { + if (Settings.analytics.enabled) { + return getOrCreateQueue('analytics-user-properties') + } +} + function getOnboardingEmailsQueue() { return getOrCreateQueue('emails-onboarding') } @@ -46,5 +52,6 @@ function getOrCreateQueue(queueName, defaultJobOptions) { module.exports = { getAnalyticsEventsQueue, getAnalyticsEditingSessionsQueue, + getAnalyticsUserPropertiesQueue, getOnboardingEmailsQueue, } diff --git a/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js b/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js index 3827d9a995..847713832b 100644 --- a/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js +++ b/services/web/test/unit/src/Analytics/AnalyticsManagerTests.js @@ -25,6 +25,10 @@ describe('AnalyticsManager', function () { add: sinon.stub().resolves(), process: sinon.stub().resolves(), } + this.analyticsUserPropertiesQueue = { + add: sinon.stub().resolves(), + process: sinon.stub().resolves(), + } const self = this this.Queues = { getAnalyticsEventsQueue: () => { @@ -36,6 +40,9 @@ describe('AnalyticsManager', function () { getOnboardingEmailsQueue: () => { return self.onboardingEmailsQueue }, + getAnalyticsUserPropertiesQueue: () => { + return self.analyticsUserPropertiesQueue + }, } this.backgroundRequest = sinon.stub().yields() this.request = sinon.stub().yields() diff --git a/services/web/test/unit/src/User/UserCreatorTests.js b/services/web/test/unit/src/User/UserCreatorTests.js index b902a62125..4ef1c7c175 100644 --- a/services/web/test/unit/src/User/UserCreatorTests.js +++ b/services/web/test/unit/src/User/UserCreatorTests.js @@ -43,6 +43,7 @@ describe('UserCreator', function () { }), '../Analytics/AnalyticsManager': (this.Analytics = { recordEvent: sinon.stub(), + setUserProperty: sinon.stub(), }), './UserOnboardingEmailManager': (this.UserOnboardingEmailManager = { scheduleOnboardingEmail: sinon.stub(), @@ -261,7 +262,7 @@ describe('UserCreator', function () { assert.equal(user.emails[0].samlProviderId, '1') }) - it('should fire an analytics event on registration', async function () { + it('should fire an analytics event and user property on registration', async function () { const user = await this.UserCreator.promises.createNewUser({ email: this.email, }) @@ -271,6 +272,11 @@ describe('UserCreator', function () { user._id, 'user-registered' ) + sinon.assert.calledWith( + this.Analytics.setUserProperty, + user._id, + 'created-at' + ) }) it('should schedule an onboarding email on registration', async function () {