Просмотр исходного кода

Convert export_institution_chat script to ES module

GitOrigin-RevId: 8570922654049edb514f8091421e5be2f04988cd
Andrew Rumble 2 лет назад
Родитель
Сommit
d2e6608f01
1 измененных файлов с 146 добавлено и 0 удалено
  1. 146 0
      services/web/scripts/export_institution_chat.mjs

+ 146 - 0
services/web/scripts/export_institution_chat.mjs

@@ -0,0 +1,146 @@
+import {
+  db,
+  READ_PREFERENCE_SECONDARY,
+  waitForDb,
+  ObjectId,
+} from '../app/src/infrastructure/mongodb.js'
+import minimist from 'minimist'
+import InstitutionHubsController from '../modules/metrics/app/src/InstitutionHubsController.js'
+
+function usage() {
+  console.log(
+    `Usage: node export_institution_chat.js --institution <id> --from <date> --to <date> [--pretty] [--help]
+
+    --institution=ID
+      The V1 institution ID
+
+    --from=DATE
+      The start of the report period. Specified as an ISO 8601 date string
+      (e.g. 2024-08-01T00:00:00.000Z)
+
+    --to=DATE
+      The end of the report period. Specified as an ISO 8601 date string
+      (e.g. 2024-09-01T00:00:00.000Z)
+
+    --help
+      Prints this help page\n`
+  )
+}
+
+function parseArgs() {
+  const argv = minimist(process.argv.slice(2), {
+    string: ['institution', 'from', 'to'],
+    bool: ['help'],
+    default: {
+      help: false,
+    },
+  })
+  if (argv.help) {
+    usage()
+    process.exit(0)
+  }
+
+  if (!argv.institution || !argv.from || !argv.to) {
+    usage()
+    process.exit(1)
+  }
+
+  const institutionId = parseInt(argv.institution, 10)
+  const from = new Date(argv.from).getTime()
+  const to = new Date(argv.to).getTime()
+
+  if (to < from) {
+    console.error('The end date must be after the start date.')
+    process.exit(1)
+  }
+
+  return { institutionId, from, to }
+}
+
+async function fetchInstitutionAndAffiliations(institutionId) {
+  const { json: affiliations } =
+    await InstitutionHubsController.promises.v1InstitutionsApi(
+      institutionId,
+      'csv_affiliations'
+    )
+  return affiliations.filter(({ license }) => license === 'pro_plus')
+}
+
+function getUserMappings(affiliations) {
+  const entries = affiliations.map(({ user_id: userId, email }) => [
+    userId,
+    email,
+  ])
+  return new Map(entries)
+}
+
+async function main() {
+  const args = parseArgs()
+  await waitForDb()
+  const affiliations = await fetchInstitutionAndAffiliations(args.institutionId)
+  const userMappings = getUserMappings(affiliations)
+
+  const projectRecords = []
+
+  for (const [userId, email] of userMappings.entries()) {
+    projectRecords.push(...(await processUser(userId, email, args)))
+  }
+  console.log(JSON.stringify(projectRecords, null, 2))
+}
+
+async function processUser(userId, email, args) {
+  const projectsOwnedByUser = db.projects.find(
+    { owner_ref: new ObjectId(userId) },
+    { projection: { name: 1 }, readPreference: READ_PREFERENCE_SECONDARY }
+  )
+  const projectRecords = []
+  for await (const project of projectsOwnedByUser) {
+    const hasMessages = await processProject(project, args)
+    if (hasMessages) {
+      projectRecords.push({
+        projectId: project._id,
+        owner: email,
+      })
+    }
+  }
+  return projectRecords
+}
+
+async function processProject(project, args) {
+  const { _id: projectId } = project
+  const globalRoom = await db.rooms.findOne(
+    {
+      project_id: new ObjectId(projectId),
+      thread_id: { $exists: false },
+    },
+    { readPreference: READ_PREFERENCE_SECONDARY }
+  )
+  if (!globalRoom) {
+    return null
+  }
+  const messages = await db.messages
+    .find(
+      {
+        room_id: globalRoom._id,
+        timestamp: { $gte: args.from, $lte: args.to },
+      },
+      {
+        projection: {
+          user_id: 1,
+          timestamp: 1,
+        },
+        readPreference: READ_PREFERENCE_SECONDARY,
+      }
+    )
+    .sort({ timestamp: 1 })
+    .toArray()
+  return messages.length > 0
+}
+
+try {
+  await main()
+  process.exit(0)
+} catch (err) {
+  console.error(err)
+  process.exit(1)
+}