|
@@ -82,7 +82,7 @@ async function recordEventForUser(userId, event, segmentation) {
|
|
|
userId,
|
|
userId,
|
|
|
event,
|
|
event,
|
|
|
segmentation,
|
|
segmentation,
|
|
|
- isLabsUser: Boolean(labsProgram),
|
|
|
|
|
|
|
+ isLabsUser: labsProgram,
|
|
|
isLoggedIn: true,
|
|
isLoggedIn: true,
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
@@ -97,6 +97,31 @@ function recordEventForUserInBackground(userId, event, segmentation) {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+async function recordEventForMongoUser(user, event, segmentation) {
|
|
|
|
|
+ const { userId, analyticsId, labsProgram } = _getIdsFromMongoUser(user)
|
|
|
|
|
+ if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ _recordEvent({
|
|
|
|
|
+ analyticsId,
|
|
|
|
|
+ userId,
|
|
|
|
|
+ event,
|
|
|
|
|
+ segmentation,
|
|
|
|
|
+ isLabsUser: labsProgram,
|
|
|
|
|
+ isLoggedIn: true,
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+function recordEventForMongoUserInBackground(user, event, segmentation) {
|
|
|
|
|
+ const { userId } = _getIdsFromMongoUser(user) // throw before going into the background.
|
|
|
|
|
+ recordEventForMongoUser(user, event, segmentation).catch(err => {
|
|
|
|
|
+ logger.warn(
|
|
|
|
|
+ { err, userId, event, segmentation },
|
|
|
|
|
+ 'failed to record event for user'
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function recordEventForSession(session, event, segmentation) {
|
|
function recordEventForSession(session, event, segmentation) {
|
|
|
const { analyticsId, userId } = getIdsFromSession(session)
|
|
const { analyticsId, userId } = getIdsFromSession(session)
|
|
|
if (!analyticsId) {
|
|
if (!analyticsId) {
|
|
@@ -142,7 +167,7 @@ async function setUserPropertyForUser(userId, propertyName, propertyValue) {
|
|
|
if (analyticsId) {
|
|
if (analyticsId) {
|
|
|
await _setUserProperty({
|
|
await _setUserProperty({
|
|
|
analyticsId,
|
|
analyticsId,
|
|
|
- isLabsUser: Boolean(labsProgram),
|
|
|
|
|
|
|
+ isLabsUser: labsProgram,
|
|
|
propertyName,
|
|
propertyName,
|
|
|
propertyValue,
|
|
propertyValue,
|
|
|
})
|
|
})
|
|
@@ -158,6 +183,41 @@ function setUserPropertyForUserInBackground(userId, property, value) {
|
|
|
})
|
|
})
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @param {{_id: ObjectId, analyticsId: string, labsProgram: boolean}} user
|
|
|
|
|
+ * @param {string} propertyName
|
|
|
|
|
+ * @param {any} propertyValue
|
|
|
|
|
+ * @return {Promise<void>}
|
|
|
|
|
+ */
|
|
|
|
|
+async function setUserPropertyForMongoUser(user, propertyName, propertyValue) {
|
|
|
|
|
+ const { userId, analyticsId, labsProgram } = _getIdsFromMongoUser(user)
|
|
|
|
|
+ if (_isAnalyticsDisabled() || _isSmokeTestUser(userId)) {
|
|
|
|
|
+ return
|
|
|
|
|
+ }
|
|
|
|
|
+ _checkPropertyValue(propertyValue)
|
|
|
|
|
+ await _setUserProperty({
|
|
|
|
|
+ analyticsId,
|
|
|
|
|
+ isLabsUser: labsProgram,
|
|
|
|
|
+ propertyName,
|
|
|
|
|
+ propertyValue,
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+/**
|
|
|
|
|
+ * @param {{_id: ObjectId, analyticsId: string, labsProgram: boolean}} user
|
|
|
|
|
+ * @param {string} property
|
|
|
|
|
+ * @param {any} value
|
|
|
|
|
+ */
|
|
|
|
|
+function setUserPropertyForMongoUserInBackground(user, property, value) {
|
|
|
|
|
+ const { userId } = _getIdsFromMongoUser(user) // throw before going into the background.
|
|
|
|
|
+ setUserPropertyForMongoUser(user, property, value).catch(err => {
|
|
|
|
|
+ logger.warn(
|
|
|
|
|
+ { err, userId, property, value },
|
|
|
|
|
+ 'failed to set user property for user'
|
|
|
|
|
+ )
|
|
|
|
|
+ })
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
async function setUserPropertyForAnalyticsId(
|
|
async function setUserPropertyForAnalyticsId(
|
|
|
analyticsId,
|
|
analyticsId,
|
|
|
propertyName,
|
|
propertyName,
|
|
@@ -192,8 +252,8 @@ async function setUserPropertyForSession(session, propertyName, propertyValue) {
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
function setUserPropertyForSessionInBackground(session, property, value) {
|
|
function setUserPropertyForSessionInBackground(session, property, value) {
|
|
|
|
|
+ const { analyticsId, userId } = getIdsFromSession(session) // throw before going into the background.
|
|
|
setUserPropertyForSession(session, property, value).catch(err => {
|
|
setUserPropertyForSession(session, property, value).catch(err => {
|
|
|
- const { analyticsId, userId } = getIdsFromSession(session)
|
|
|
|
|
logger.warn(
|
|
logger.warn(
|
|
|
{ err, analyticsId, userId, property, value },
|
|
{ err, analyticsId, userId, property, value },
|
|
|
'failed to set user property for session'
|
|
'failed to set user property for session'
|
|
@@ -452,6 +512,26 @@ function _isAnalyticsDisabled() {
|
|
|
return !(Settings.analytics && Settings.analytics.enabled)
|
|
return !(Settings.analytics && Settings.analytics.enabled)
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+/**
|
|
|
|
|
+ * @param {{_id: ObjectId, analyticsId: string, labsProgram: boolean}} user
|
|
|
|
|
+ * @return {{userId: string, analyticsId: string, labsProgram: boolean}}
|
|
|
|
|
+ */
|
|
|
|
|
+function _getIdsFromMongoUser(user) {
|
|
|
|
|
+ const userId = user?._id?.toString()
|
|
|
|
|
+ if (!userId) {
|
|
|
|
|
+ throw new Error('bug: include db.users._id in projection')
|
|
|
|
|
+ }
|
|
|
|
|
+ const analyticsId = user?.analyticsId
|
|
|
|
|
+ if (!analyticsId) {
|
|
|
|
|
+ throw new Error('bug: include db.users.analyticsId in projection')
|
|
|
|
|
+ }
|
|
|
|
|
+ const labsProgram = user?.labsProgram
|
|
|
|
|
+ if (typeof labsProgram !== 'boolean') {
|
|
|
|
|
+ throw new Error('bug: include db.users.labsProgram in projection')
|
|
|
|
|
+ }
|
|
|
|
|
+ return { userId, analyticsId, labsProgram }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
function _checkPropertyValue(propertyValue) {
|
|
function _checkPropertyValue(propertyValue) {
|
|
|
if (propertyValue === undefined) {
|
|
if (propertyValue === undefined) {
|
|
|
throw new Error(
|
|
throw new Error(
|
|
@@ -498,13 +578,15 @@ async function analyticsIdMiddleware(req, res, next) {
|
|
|
if (sessionUser) {
|
|
if (sessionUser) {
|
|
|
// For old sessions, session.analyticsId is the anon id immediately after login. Do not use it!
|
|
// For old sessions, session.analyticsId is the anon id immediately after login. Do not use it!
|
|
|
session.analyticsId = sessionUser.analyticsId
|
|
session.analyticsId = sessionUser.analyticsId
|
|
|
- if (!session.analyticsId) {
|
|
|
|
|
- session.analyticsId = sessionUser.analyticsId =
|
|
|
|
|
- await UserAnalyticsDataCache.getAnalyticsId(
|
|
|
|
|
|
|
+ if (!session.analyticsId || typeof sessionUser.labsProgram !== 'boolean') {
|
|
|
|
|
+ const { analyticsId, labsProgram } =
|
|
|
|
|
+ await UserAnalyticsDataCache.getAnalyticsData(
|
|
|
sessionUser._id,
|
|
sessionUser._id,
|
|
|
// Do not drill down further, this middleware is on all endpoints.
|
|
// Do not drill down further, this middleware is on all endpoints.
|
|
|
'analyticsIdMiddleware'
|
|
'analyticsIdMiddleware'
|
|
|
)
|
|
)
|
|
|
|
|
+ session.analyticsId = sessionUser.analyticsId = analyticsId
|
|
|
|
|
+ sessionUser.labsProgram = labsProgram
|
|
|
}
|
|
}
|
|
|
} else if (!session.analyticsId) {
|
|
} else if (!session.analyticsId) {
|
|
|
// generate an `analyticsId` if needed
|
|
// generate an `analyticsId` if needed
|
|
@@ -521,9 +603,13 @@ export default {
|
|
|
recordEventForSession,
|
|
recordEventForSession,
|
|
|
recordEventForUser,
|
|
recordEventForUser,
|
|
|
recordEventForUserInBackground,
|
|
recordEventForUserInBackground,
|
|
|
|
|
+ recordEventForMongoUser,
|
|
|
|
|
+ recordEventForMongoUserInBackground,
|
|
|
emitPackageUsage,
|
|
emitPackageUsage,
|
|
|
setUserPropertyForUser,
|
|
setUserPropertyForUser,
|
|
|
setUserPropertyForUserInBackground,
|
|
setUserPropertyForUserInBackground,
|
|
|
|
|
+ setUserPropertyForMongoUser,
|
|
|
|
|
+ setUserPropertyForMongoUserInBackground,
|
|
|
setUserPropertyForSession,
|
|
setUserPropertyForSession,
|
|
|
setUserPropertyForSessionInBackground,
|
|
setUserPropertyForSessionInBackground,
|
|
|
setUserPropertyForAnalyticsId,
|
|
setUserPropertyForAnalyticsId,
|