add_notification_ieee_collabratec_users.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. const path = require('path')
  2. const fs = require('fs')
  3. const NotificationsBuilder = require('../app/src/Features/Notifications/NotificationsBuilder')
  4. const { waitForDb } = require('../app/src/infrastructure/mongodb')
  5. const { Subscription } = require('../app/src/models/Subscription')
  6. const minimist = require('minimist')
  7. const { db } = require('../app/src/infrastructure/mongodb')
  8. const { promiseMapWithLimit } = require('@overleaf/promise-utils')
  9. /**
  10. * This script is used to notify some users in the IEEEPublications group that
  11. * they will lose access to Overleaf.
  12. *
  13. * Parameters:
  14. * --filename: the filename of the JSON file containing emails of users that
  15. * should **not** be notified.
  16. * --commit: if present, the script will commit the changes to the database.
  17. *
  18. * Usage:
  19. * - dry run:
  20. * node add_notification_ieee_collabratec_users.js --filename=emails.json
  21. * - commit:
  22. * node add_notification_ieee_collabratec_users.js --filename=emails.json --commit
  23. */
  24. let COMMIT = false
  25. let EMAILS_FILENAME
  26. /**
  27. * The IEEE have provided us with a list of active users that should not be removed
  28. * (and therefore not notified). This method retrives those users.
  29. */
  30. function getActiveUserEmails(filename) {
  31. const data = fs.readFileSync(path.join(__dirname, filename), 'utf8')
  32. const emailsArray = JSON.parse(data)
  33. const emailsSet = new Set(emailsArray)
  34. console.log(
  35. `Read ${emailsSet.size} (${emailsArray.length} in array) emails from ${filename}`
  36. )
  37. return emailsSet
  38. }
  39. async function getIEEEUsers() {
  40. return await db.subscriptions
  41. .aggregate([
  42. { $match: { teamName: 'IEEEPublications' } },
  43. { $unwind: '$member_ids' },
  44. {
  45. $lookup: {
  46. from: 'users',
  47. localField: 'member_ids',
  48. foreignField: '_id',
  49. as: 'member_details',
  50. },
  51. },
  52. {
  53. $project: {
  54. _id: 1,
  55. teamName: 1,
  56. 'member_details._id': 1,
  57. 'member_details.email': 1,
  58. 'member_details.emails.email': 1,
  59. },
  60. },
  61. ])
  62. .toArray()
  63. }
  64. async function main() {
  65. const start = performance.now()
  66. if (!EMAILS_FILENAME) {
  67. throw new Error('No email filename provided')
  68. }
  69. await waitForDb()
  70. const subscription = await Subscription.findOne({
  71. teamName: 'IEEEPublications',
  72. })
  73. if (!subscription) {
  74. console.error(`No IEEEPublications group subscription found so quitting`)
  75. return
  76. }
  77. // First we remove all existing Collabratec retirement notifications
  78. if (COMMIT) {
  79. await db.notifications.deleteMany({
  80. key: 'notification-ieee-collabratec-retirement',
  81. })
  82. }
  83. let totalUsers = 0
  84. let totalUsersNotified = 0
  85. const usersArray = await getIEEEUsers()
  86. const activeUsers = getActiveUserEmails(EMAILS_FILENAME)
  87. const activeUsersFound = new Set()
  88. // Then go through each collabratec user to see if we need to notify them
  89. await promiseMapWithLimit(10, usersArray, async member => {
  90. if (totalUsers % 5000 === 0)
  91. console.log(
  92. `notified: ${totalUsersNotified} - progress: ${totalUsers} / ${usersArray.length}`
  93. )
  94. totalUsers = totalUsers + 1
  95. const userDetails = member.member_details[0]
  96. for (const email of userDetails.emails) {
  97. if (activeUsers.has(email.email)) {
  98. activeUsersFound.add(email.email)
  99. return
  100. }
  101. }
  102. if (COMMIT) {
  103. await NotificationsBuilder.promises
  104. .ieeeCollabratecRetirement(userDetails._id.toString())
  105. .create()
  106. }
  107. totalUsersNotified += 1
  108. })
  109. console.log(`Found ${totalUsers} users in IEEEPublications group`)
  110. console.log(
  111. `Found ${totalUsersNotified} users in IEEEPublications group to notify`
  112. )
  113. console.log(`Found ${activeUsersFound.size} active users`)
  114. const activeUsersNotFound = Array.from(activeUsers).filter(
  115. user => !activeUsersFound.has(user)
  116. )
  117. console.log(`${activeUsersNotFound.length} IEEE active users not found:`)
  118. console.log(activeUsersNotFound)
  119. const end = performance.now()
  120. console.log(`Took ${end - start} ms`)
  121. }
  122. const setup = () => {
  123. const argv = minimist(process.argv.slice(2))
  124. COMMIT = argv.commit !== undefined
  125. EMAILS_FILENAME = argv.filename
  126. if (!COMMIT) {
  127. console.warn('Doing dry run. Add --commit to commit changes')
  128. }
  129. }
  130. setup()
  131. main()
  132. .then(() => {
  133. process.exit(0)
  134. })
  135. .catch(err => {
  136. console.error(err)
  137. process.exit(1)
  138. })