2024-11-08 03:34:14 -05:00
|
|
|
// @ts-check
|
2024-10-18 07:04:57 -04:00
|
|
|
import '../app/src/models/User.js'
|
2024-11-08 03:34:14 -05:00
|
|
|
import { batchedUpdateWithResultHandling } from '@overleaf/mongo-utils/batchedUpdate.js'
|
2024-10-18 07:04:57 -04:00
|
|
|
import { promiseMapWithLimit } from '@overleaf/promise-utils'
|
|
|
|
import { getQueue } from '../app/src/infrastructure/Queues.js'
|
|
|
|
import SubscriptionLocator from '../app/src/Features/Subscription/SubscriptionLocator.js'
|
|
|
|
import PlansLocator from '../app/src/Features/Subscription/PlansLocator.js'
|
|
|
|
import FeaturesHelper from '../app/src/Features/Subscription/FeaturesHelper.js'
|
2024-11-08 03:34:14 -05:00
|
|
|
import { db } from '../app/src/infrastructure/mongodb.js'
|
2022-03-07 08:00:49 -05:00
|
|
|
|
2024-11-08 03:34:14 -05:00
|
|
|
const WRITE_CONCURRENCY = parseInt(process.env.WRITE_CONCURRENCY || '10', 10)
|
2022-03-07 08:00:49 -05:00
|
|
|
|
|
|
|
const mixpanelSinkQueue = getQueue('analytics-mixpanel-sink')
|
|
|
|
|
|
|
|
async function processUser(user) {
|
|
|
|
const analyticsId = user.analyticsId || user._id
|
|
|
|
|
|
|
|
await _sendPropertyToQueue(analyticsId, 'user-id', user._id)
|
|
|
|
await _sendPropertyToQueue(analyticsId, 'analytics-id', analyticsId)
|
|
|
|
await _sendPropertyToQueue(analyticsId, 'created-at', user.signUpDate)
|
2022-05-12 05:33:54 -04:00
|
|
|
if (user.alphaProgram !== undefined) {
|
|
|
|
await _sendPropertyToQueue(analyticsId, 'alpha-program', user.alphaProgram)
|
|
|
|
}
|
|
|
|
if (user.betaProgram !== undefined) {
|
|
|
|
await _sendPropertyToQueue(analyticsId, 'beta-program', user.betaProgram)
|
|
|
|
}
|
2022-03-07 08:00:49 -05:00
|
|
|
|
|
|
|
const groupSubscriptionPlanCode = await _getGroupSubscriptionPlanCode(
|
|
|
|
user._id
|
|
|
|
)
|
|
|
|
if (groupSubscriptionPlanCode) {
|
|
|
|
await _sendPropertyToQueue(
|
|
|
|
analyticsId,
|
|
|
|
'group-subscription-plan-code',
|
|
|
|
groupSubscriptionPlanCode
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
const matchedFeatureSet = FeaturesHelper.getMatchedFeatureSet(user.features)
|
|
|
|
if (matchedFeatureSet !== 'personal') {
|
|
|
|
await _sendPropertyToQueue(analyticsId, 'feature-set', matchedFeatureSet)
|
|
|
|
}
|
|
|
|
|
|
|
|
if (user.splitTests) {
|
|
|
|
for (const splitTestName of Object.keys(user.splitTests)) {
|
|
|
|
const assignments = user.splitTests[splitTestName]
|
|
|
|
if (Array.isArray(assignments)) {
|
|
|
|
for (const assignment of assignments) {
|
|
|
|
await _sendPropertyToQueue(
|
|
|
|
analyticsId,
|
|
|
|
`split-test-${splitTestName}-${assignment.versionNumber}`,
|
|
|
|
`${assignment.variantName}`
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
async function _getGroupSubscriptionPlanCode(userId) {
|
|
|
|
const subscriptions =
|
|
|
|
await SubscriptionLocator.promises.getMemberSubscriptions(userId)
|
|
|
|
let bestPlanCode = null
|
|
|
|
let bestFeatures = {}
|
|
|
|
for (const subscription of subscriptions) {
|
|
|
|
const plan = PlansLocator.findLocalPlanInSettings(subscription.planCode)
|
|
|
|
if (
|
|
|
|
plan &&
|
|
|
|
FeaturesHelper.isFeatureSetBetter(plan.features, bestFeatures)
|
|
|
|
) {
|
|
|
|
bestPlanCode = plan.planCode
|
|
|
|
bestFeatures = plan.features
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return bestPlanCode
|
|
|
|
}
|
|
|
|
|
|
|
|
async function _sendPropertyToQueue(
|
|
|
|
analyticsId,
|
|
|
|
propertyName,
|
|
|
|
propertyValue,
|
|
|
|
createdAt = new Date()
|
|
|
|
) {
|
2022-05-12 05:33:54 -04:00
|
|
|
if (propertyValue == null) {
|
|
|
|
return
|
|
|
|
}
|
2022-03-07 08:00:49 -05:00
|
|
|
await mixpanelSinkQueue.add('user-property', {
|
|
|
|
analyticsId,
|
|
|
|
propertyName,
|
|
|
|
propertyValue,
|
|
|
|
createdAt,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
async function processBatch(_, users) {
|
|
|
|
await promiseMapWithLimit(WRITE_CONCURRENCY, users, async user => {
|
|
|
|
await processUser(user)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
batchedUpdateWithResultHandling(
|
2024-11-08 03:34:14 -05:00
|
|
|
db.users,
|
2022-03-07 08:00:49 -05:00
|
|
|
{
|
|
|
|
$nor: [
|
|
|
|
{ thirdPartyIdentifiers: { $exists: false } },
|
|
|
|
{ thirdPartyIdentifiers: { $size: 0 } },
|
|
|
|
],
|
|
|
|
},
|
|
|
|
processBatch,
|
|
|
|
{
|
|
|
|
_id: true,
|
|
|
|
analyticsId: true,
|
|
|
|
signUpDate: true,
|
|
|
|
splitTests: true,
|
|
|
|
alphaProgram: true,
|
|
|
|
betaProgram: true,
|
|
|
|
}
|
|
|
|
)
|