update_institution_user_saml_ids.mjs 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. import { db } from '../app/src/infrastructure/mongodb.mjs'
  2. import minimist from 'minimist'
  3. import UserGetter from '../app/src/Features/User/UserGetter.mjs'
  4. import { scriptRunner } from './lib/ScriptRunner.mjs'
  5. function usage() {
  6. console.log(
  7. 'Usage: node update_institution_user_saml_ids.mjs -i <institution-id> -s <search> [-r <replace>]'
  8. )
  9. console.log(
  10. 'Performs string replacement on external user IDs for all users in an institution. A search-and-replace or/and an append operation must be specified.'
  11. )
  12. console.log('Options:')
  13. console.log(
  14. ' --institution-id, -i Institution ID to update'
  15. )
  16. console.log(' --search, -s String to search for')
  17. console.log(
  18. ' --search-regexp Regular expression to search for (ignored if --search is provided)'
  19. )
  20. console.log(
  21. ' --replace, -r String to replace with (optional, defaults to empty string)'
  22. )
  23. console.log(
  24. ' --append, -a String to append at the end'
  25. )
  26. console.log(
  27. ' --dry-run, -d Shows changes but does not perform updates'
  28. )
  29. console.log(
  30. ' --help, -h Show this help message'
  31. )
  32. process.exit(0)
  33. }
  34. const {
  35. 'dry-run': dryRun,
  36. 'institution-id': providerId,
  37. search,
  38. 'search-regexp': searchRegexp,
  39. replace,
  40. append,
  41. help,
  42. } = minimist(process.argv.slice(2), {
  43. string: ['institution-id', 'search', 'search-regexp', 'replace'],
  44. boolean: ['dry-run', 'help'],
  45. alias: {
  46. 'institution-id': 'i',
  47. search: 's',
  48. replace: 'r',
  49. append: 'a',
  50. 'dry-run': 'd',
  51. help: 'h',
  52. },
  53. default: {
  54. 'dry-run': true,
  55. replace: '',
  56. },
  57. })
  58. async function main() {
  59. const hasSearchOrAppend =
  60. Boolean(search) || Boolean(searchRegexp) || Boolean(append)
  61. if (help || !providerId || !hasSearchOrAppend) {
  62. usage()
  63. }
  64. const users = await UserGetter.promises.getSsoUsersAtInstitution(providerId, {
  65. _id: 1,
  66. samlIdentifiers: 1,
  67. })
  68. console.log('SSO Users found for institution: ' + users.length)
  69. let usersToUpdate = 0
  70. let usersUpdated = 0
  71. for (const user of users) {
  72. const matchingIdentifier = user.samlIdentifiers.find(
  73. u => u.providerId === providerId
  74. )
  75. if (!matchingIdentifier) {
  76. continue
  77. }
  78. let updatedId
  79. if (search) {
  80. updatedId = matchingIdentifier.externalUserId.replaceAll(search, replace)
  81. } else if (searchRegexp) {
  82. const regexp = new RegExp(searchRegexp, 'g')
  83. updatedId = matchingIdentifier.externalUserId.replaceAll(regexp, replace)
  84. }
  85. if (append) {
  86. updatedId = matchingIdentifier.externalUserId + append
  87. }
  88. usersToUpdate = usersToUpdate + 1
  89. console.log(`${user._id},${matchingIdentifier.externalUserId},${updatedId}`)
  90. if (dryRun) {
  91. continue
  92. }
  93. try {
  94. await db.users.updateOne(
  95. { _id: user._id, 'samlIdentifiers.providerId': providerId },
  96. { $set: { 'samlIdentifiers.$.externalUserId': updatedId } }
  97. )
  98. usersUpdated = usersUpdated + 1
  99. } catch (error) {
  100. console.error(error)
  101. }
  102. }
  103. if (dryRun) {
  104. console.log(`DRY RUN: ${usersToUpdate} users will be updated`)
  105. } else {
  106. console.log(`UPDATED: ${usersUpdated}/${usersToUpdate} users successfully`)
  107. }
  108. }
  109. try {
  110. await scriptRunner(main)
  111. process.exit(0)
  112. } catch (error) {
  113. console.error(error)
  114. process.exit(1)
  115. }