|
|
@@ -0,0 +1,120 @@
|
|
|
+import { db } from '../app/src/infrastructure/mongodb.js'
|
|
|
+import minimist from 'minimist'
|
|
|
+import UserGetter from '../app/src/Features/User/UserGetter.js'
|
|
|
+import fs from 'fs'
|
|
|
+
|
|
|
+function usage() {
|
|
|
+ console.log(
|
|
|
+ 'Usage: node lowercase_institution_user_ids.mjs -i <institution-id>'
|
|
|
+ )
|
|
|
+ console.log(
|
|
|
+ 'Converts external user IDs to lowercase for all users in an institute'
|
|
|
+ )
|
|
|
+ console.log('Options:')
|
|
|
+ console.log(
|
|
|
+ ' --institution-id, -i Institution ID to update'
|
|
|
+ )
|
|
|
+ console.log(
|
|
|
+ ' --dry-run, -d Finds users with non-lowercase id but does not do any updates'
|
|
|
+ )
|
|
|
+ console.log(
|
|
|
+ ' --file, -f A file that contains external user ids to be updated'
|
|
|
+ )
|
|
|
+
|
|
|
+ console.log(
|
|
|
+ ' If not provided, the script will update all the users within the institution that have upper case external user id'
|
|
|
+ )
|
|
|
+ console.log(
|
|
|
+ ' -h, --help Show this help message'
|
|
|
+ )
|
|
|
+ process.exit(0)
|
|
|
+}
|
|
|
+
|
|
|
+const {
|
|
|
+ 'dry-run': dryRun,
|
|
|
+ 'institution-id': providerId,
|
|
|
+ help,
|
|
|
+ file,
|
|
|
+} = minimist(process.argv.slice(2), {
|
|
|
+ string: ['institution-id', 'file'],
|
|
|
+ boolean: ['dry-run', 'help'],
|
|
|
+ alias: {
|
|
|
+ 'institution-id': 'i',
|
|
|
+ 'dry-run': 'd',
|
|
|
+ help: 'h',
|
|
|
+ file: 'f',
|
|
|
+ },
|
|
|
+ default: {
|
|
|
+ 'dry-run': true,
|
|
|
+ },
|
|
|
+})
|
|
|
+
|
|
|
+async function main() {
|
|
|
+ if (help || !providerId) {
|
|
|
+ usage()
|
|
|
+ }
|
|
|
+
|
|
|
+ let externalUserIdsToUpdate = null
|
|
|
+ if (file) {
|
|
|
+ const lines = fs.readFileSync(file, 'utf8').split('\n')
|
|
|
+ externalUserIdsToUpdate = new Set(lines)
|
|
|
+ }
|
|
|
+
|
|
|
+ const users = await UserGetter.promises.getSsoUsersAtInstitution(providerId, {
|
|
|
+ _id: 1,
|
|
|
+ samlIdentifiers: 1,
|
|
|
+ })
|
|
|
+
|
|
|
+ let userToUpdate = 0
|
|
|
+ let userUpdated = 0
|
|
|
+
|
|
|
+ for (const user of users) {
|
|
|
+ const matchingIdentifier = user.samlIdentifiers.find(
|
|
|
+ u => u.providerId === providerId
|
|
|
+ )
|
|
|
+ const lowercaseId = matchingIdentifier.externalUserId.toLowerCase()
|
|
|
+
|
|
|
+ // skip if external user id is already in lower case
|
|
|
+ if (lowercaseId === matchingIdentifier.externalUserId) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ // skip if an id file is provided but current external user id is not in the file
|
|
|
+ if (externalUserIdsToUpdate && !externalUserIdsToUpdate.has(lowercaseId)) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ userToUpdate = userToUpdate + 1
|
|
|
+ console.log(
|
|
|
+ `${user._id},${matchingIdentifier.externalUserId},${lowercaseId}`
|
|
|
+ )
|
|
|
+
|
|
|
+ if (dryRun) {
|
|
|
+ continue
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ await db.users.updateOne(
|
|
|
+ { _id: user._id, 'samlIdentifiers.providerId': providerId },
|
|
|
+ { $set: { 'samlIdentifiers.$.externalUserId': lowercaseId } }
|
|
|
+ )
|
|
|
+ userUpdated = userUpdated + 1
|
|
|
+ } catch (error) {
|
|
|
+ console.error(error)
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (dryRun) {
|
|
|
+ console.log(`DRY RUN: ${userToUpdate} users will be updated`)
|
|
|
+ } else {
|
|
|
+ console.log(`UPDATED: ${userUpdated}/${userToUpdate} users successfully`)
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+try {
|
|
|
+ await main()
|
|
|
+ process.exit(0)
|
|
|
+} catch (error) {
|
|
|
+ console.error(error)
|
|
|
+ process.exit(1)
|
|
|
+}
|