lowercase_institution_user_ids.mjs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. import { db } from '../app/src/infrastructure/mongodb.js'
  2. import minimist from 'minimist'
  3. import UserGetter from '../app/src/Features/User/UserGetter.js'
  4. import fs from 'node:fs'
  5. import { scriptRunner } from './lib/ScriptRunner.mjs'
  6. function usage() {
  7. console.log(
  8. 'Usage: node lowercase_institution_user_ids.mjs -i <institution-id>'
  9. )
  10. console.log(
  11. 'Converts external user IDs to lowercase for all users in an institute'
  12. )
  13. console.log('Options:')
  14. console.log(
  15. ' --institution-id, -i Institution ID to update'
  16. )
  17. console.log(
  18. ' --dry-run, -d Finds users with non-lowercase id but does not do any updates'
  19. )
  20. console.log(
  21. ' --file, -f A file that contains external user ids to be updated'
  22. )
  23. console.log(
  24. ' If not provided, the script will update all the users within the institution that have upper case external user id'
  25. )
  26. console.log(
  27. ' -h, --help Show this help message'
  28. )
  29. process.exit(0)
  30. }
  31. const {
  32. 'dry-run': dryRun,
  33. 'institution-id': providerId,
  34. help,
  35. file,
  36. } = minimist(process.argv.slice(2), {
  37. string: ['institution-id', 'file'],
  38. boolean: ['dry-run', 'help'],
  39. alias: {
  40. 'institution-id': 'i',
  41. 'dry-run': 'd',
  42. help: 'h',
  43. file: 'f',
  44. },
  45. default: {
  46. 'dry-run': true,
  47. },
  48. })
  49. async function main() {
  50. if (help || !providerId) {
  51. usage()
  52. }
  53. let externalUserIdsToUpdate = null
  54. if (file) {
  55. const lines = fs.readFileSync(file, 'utf8').split('\n')
  56. externalUserIdsToUpdate = new Set(lines)
  57. }
  58. const users = await UserGetter.promises.getSsoUsersAtInstitution(providerId, {
  59. _id: 1,
  60. samlIdentifiers: 1,
  61. })
  62. let userToUpdate = 0
  63. let userUpdated = 0
  64. for (const user of users) {
  65. const matchingIdentifier = user.samlIdentifiers.find(
  66. u => u.providerId === providerId
  67. )
  68. const lowercaseId = matchingIdentifier.externalUserId.toLowerCase()
  69. // skip if external user id is already in lower case
  70. if (lowercaseId === matchingIdentifier.externalUserId) {
  71. continue
  72. }
  73. // skip if an id file is provided but current external user id is not in the file
  74. if (externalUserIdsToUpdate && !externalUserIdsToUpdate.has(lowercaseId)) {
  75. continue
  76. }
  77. userToUpdate = userToUpdate + 1
  78. console.log(
  79. `${user._id},${matchingIdentifier.externalUserId},${lowercaseId}`
  80. )
  81. if (dryRun) {
  82. continue
  83. }
  84. try {
  85. await db.users.updateOne(
  86. { _id: user._id, 'samlIdentifiers.providerId': providerId },
  87. { $set: { 'samlIdentifiers.$.externalUserId': lowercaseId } }
  88. )
  89. userUpdated = userUpdated + 1
  90. } catch (error) {
  91. console.error(error)
  92. }
  93. }
  94. if (dryRun) {
  95. console.log(`DRY RUN: ${userToUpdate} users will be updated`)
  96. } else {
  97. console.log(`UPDATED: ${userUpdated}/${userToUpdate} users successfully`)
  98. }
  99. }
  100. try {
  101. await scriptRunner(main)
  102. process.exit(0)
  103. } catch (error) {
  104. console.error(error)
  105. process.exit(1)
  106. }