From eb737c7a9810e73c3b6b53c1ad9e9b81fcbf3920 Mon Sep 17 00:00:00 2001 From: Andrew Rumble Date: Fri, 22 Aug 2025 15:44:15 +0100 Subject: [PATCH] Register email changes with analytics when appropriate GitOrigin-RevId: 3261df7f1fd4a2c032967731bcc2a61ffb89f094 --- .../web/app/src/Features/User/UserUpdater.js | 57 ++++++++++++++++++- 1 file changed, 55 insertions(+), 2 deletions(-) diff --git a/services/web/app/src/Features/User/UserUpdater.js b/services/web/app/src/Features/User/UserUpdater.js index f21ee9a1ed..adf67dfa3f 100644 --- a/services/web/app/src/Features/User/UserUpdater.js +++ b/services/web/app/src/Features/User/UserUpdater.js @@ -13,6 +13,7 @@ const Errors = require('../Errors/Errors') const NewsletterManager = require('../Newsletter/NewsletterManager') const UserAuditLogHandler = require('./UserAuditLogHandler') const AnalyticsManager = require('../Analytics/AnalyticsManager') +const EmailChangeHelper = require('../Analytics/EmailChangeHelper') const SubscriptionLocator = require('../Subscription/SubscriptionLocator') const NotificationsBuilder = require('../Notifications/NotificationsBuilder') const _ = require('lodash') @@ -111,17 +112,36 @@ async function addEmailAddress(userId, newEmail, affiliationOptions, auditLog) { throw OError.tag(error, 'problem adding affiliation while adding email') } + const createdAt = new Date() + let res try { const reversedHostname = newEmail.split('@')[1].split('').reverse().join('') const update = { $push: { - emails: { email: newEmail, createdAt: new Date(), reversedHostname }, + emails: { email: newEmail, createdAt, reversedHostname }, }, } - await updateUser({ _id: userId, 'emails.email': { $ne: newEmail } }, update) + res = await updateUser( + { _id: userId, 'emails.email': { $ne: newEmail } }, + update + ) } catch (error) { throw OError.tag(error, 'problem updating users emails') } + + if (res.matchedCount !== 1) { + return + } + + EmailChangeHelper.registerEmailCreation(userId, newEmail, { + createdAt: new Date(), + emailCreatedAt: createdAt, + }).catch(error => { + logger.warn( + { error, userId, newEmail }, + 'Error registering email creation with analytics' + ) + }) } async function clearSAMLData(userId, auditLog, sendEmail) { @@ -221,6 +241,17 @@ async function setDefaultEmailAddress( 'primary-email-address-updated' ) + EmailChangeHelper.registerEmailUpdate(userId, email, { + isPrimary: true, + action: 'updated', + createdAt: new Date(), + }).catch(err => { + logger.warn( + { err, userId, email }, + 'Error registering email change with analytics' + ) + }) + if (sendSecurityAlert) { // no need to wait, errors are logged and not passed back _sendSecurityAlertPrimaryEmailChanged( @@ -362,6 +393,18 @@ async function confirmEmail(userId, email, affiliationOptions) { throw new Errors.NotFoundError('user id and email do no match') } await FeaturesUpdater.promises.refreshFeatures(userId, 'confirm-email') + + EmailChangeHelper.registerEmailUpdate(userId, email, { + emailConfirmedAt: confirmedAt, + action: 'updated', + isPrimary: false, + }).catch(error => + logger.warn( + { error, userId, email }, + 'Error registering email confirmation with analytics' + ) + ) + try { await maybeCreateRedundantSubscriptionNotification(userId, email) } catch (error) { @@ -456,6 +499,16 @@ async function removeEmailAddress( throw new Error('Cannot remove email') } + EmailChangeHelper.registerEmailDeletion(userId, email, { + isPrimary: false, + emailDeletedAt: new Date(), + }).catch(error => + logger.warn( + { error, userId, email }, + 'Error registering email deletion with analytics' + ) + ) + await FeaturesUpdater.promises.refreshFeatures(userId, 'remove-email') }