Przeglądaj źródła

Merge pull request #6984 from overleaf/ab-backfill-mixpanel-props

Add script to backfill Mixpanel properties for SSO users

GitOrigin-RevId: da7aef545dd4c66d3916febcc287043cbf455f65
Alexandre Bourdin 4 lat temu
rodzic
commit
5355c7382c

+ 111 - 0
services/web/scripts/backfill_mixpanel_user_properties.js

@@ -0,0 +1,111 @@
+const WRITE_CONCURRENCY = parseInt(process.env.WRITE_CONCURRENCY, 10) || 10
+
+require('../app/src/models/User')
+
+const { batchedUpdateWithResultHandling } = require('./helpers/batchedUpdate')
+const { promiseMapWithLimit } = require('../app/src/util/promises')
+const { getQueue } = require('../app/src/infrastructure/Queues')
+
+const SubscriptionLocator = require('../app/src/Features/Subscription/SubscriptionLocator')
+const PlansLocator = require('../app/src/Features/Subscription/PlansLocator')
+const FeaturesHelper = require('../app/src/Features/Subscription/FeaturesHelper')
+
+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)
+  await _sendPropertyToQueue(analyticsId, 'alpha-program', user.alphaProgram)
+  await _sendPropertyToQueue(analyticsId, 'beta-program', user.betaProgram)
+
+  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()
+) {
+  await mixpanelSinkQueue.add('user-property', {
+    analyticsId,
+    propertyName,
+    propertyValue,
+    createdAt,
+  })
+}
+
+async function processBatch(_, users) {
+  await promiseMapWithLimit(WRITE_CONCURRENCY, users, async user => {
+    await processUser(user)
+  })
+}
+
+batchedUpdateWithResultHandling(
+  'users',
+  {
+    $nor: [
+      { thirdPartyIdentifiers: { $exists: false } },
+      { thirdPartyIdentifiers: { $size: 0 } },
+    ],
+  },
+  processBatch,
+  {
+    _id: true,
+    analyticsId: true,
+    signUpDate: true,
+    splitTests: true,
+    alphaProgram: true,
+    betaProgram: true,
+  }
+)