lowercase_institution_user_ids.mjs 3.0 KB

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