From 9855050218af2139acd1267aad5785cc1db1f37f Mon Sep 17 00:00:00 2001 From: weaponsforge Date: Thu, 20 Jul 2023 03:49:51 +0800 Subject: [PATCH] feat: Create an npm script for updating the Firebase Auth user data, #125 --- server/README.md | 30 ++++++++ server/package.json | 1 + server/src/scripts/user/update.js | 114 ++++++++++++++++++++++++++++++ 3 files changed, 145 insertions(+) create mode 100644 server/src/scripts/user/update.js diff --git a/server/README.md b/server/README.md index 5f22b8d..ef9de52 100644 --- a/server/README.md +++ b/server/README.md @@ -167,6 +167,36 @@ Requires `email`, `password` and `displayname` for CLI input parameters. See bel `npm run user:create --email=randomemail@gmail.com --password=anypasasword --displayname="Game Tester" --emailverified=true` +### `npm run user:update` + +Updates an existing Firebase Auth user.
+Requires one of `email` or `uid` and 1 or more optional flags for CLI input parameter. See below for example usage.
+ +#### Usage:
+`npm run user:update --email=randomemail@gmail.com --password=mysecretpassword`
+`npm run user:update --email=randomemail@gmail.com --displayname=Hello World --account_level=0 --disabled=false`
+`npm run user:update --email=randomemail@gmail.com --emailverified=false` + +### Flags + +- `--email` + - Firebase Auth user email +- `--uid` + - Firebase Auth user ID +- `--password` + - Password +- `--displayname` + - Firebase Auth user display name +- `--disabled` + - Disables a Firebase Auth user account + - Setting to `--disabled=false` enables the accouunt +- `--emailverified` + - Sets a Firebase Auth user account's `"emailVerified"` status to true + - Setting to `--emailverified=false` sets the account's `"emailVerified"` status to false +- `--account_level` + - Sets a Firebase Auth user account's `account_level` custom claims + + ### `npm run user:delete` Deletes an existing Firebase Auth user.
diff --git a/server/package.json b/server/package.json index 9a1b556..d6e03bb 100644 --- a/server/package.json +++ b/server/package.json @@ -7,6 +7,7 @@ "lint": "eslint src --ignore-path .gitignore", "lint:fix": "eslint --ignore-path .gitignore --fix src", "user:create": "node src/scripts/user/create", + "user:update": "node src/scripts/user/update", "user:delete": "node src/scripts/user/delete", "cards:webscrape": "node src/scripts/cards/webscraper/main" }, diff --git a/server/src/scripts/user/update.js b/server/src/scripts/user/update.js new file mode 100644 index 0000000..07d636e --- /dev/null +++ b/server/src/scripts/user/update.js @@ -0,0 +1,114 @@ +const { updateuser, getuser } = require('../../classes/user') +const getargs = require('../../utils/getargs') + +const ARGS_FALSE_VAL = '' +const ARGS_TRUE_VAL = 'true' +const ACCOUNT_LEVEL_SUPERADMIN = 0 +const ACCOUNT_LEVEL_ADMIN = 1 +const ACCOUNT_LEVEL_USER = 2 + +/** + * Checks if a value is valid Boolean value from the "args" data + * @param {String} argValue - "emailverified", "disabled" Value(s) from the "arg" data + * @returns {Bool} + */ +const isArgsBoolean = (argValue) => { + return [ARGS_FALSE_VAL, ARGS_TRUE_VAL].includes(argValue) +} + +/** + * Checks if a value is valid account_level Number value from the "args" data + * @param {Number} argValue - "account_level" Value from the "arg" data + * @returns {Bool} + */ +const isValidAccountLevel = (argValue) => { + return [ + ACCOUNT_LEVEL_SUPERADMIN.toString(), + ACCOUNT_LEVEL_ADMIN.toString(), + ACCOUNT_LEVEL_USER.toString() + ].includes(argValue) +} + +/** + * Updates a Firebase Auth user data + */ +const updateUser = async () => { + try { + const optionalKeys = ['email', 'uid', 'password', 'emailverified', 'displayname', 'account_level', 'disabled'] + let userData + + // Get the nodejs args + const args = getargs({ + params: optionalKeys, + optional: optionalKeys + }) + + if (args.email === undefined && args.uid === undefined) { + throw new Error('One of "email" or "uid" must be defined.') + } + + // Check for 1 or more optional parameters + const allParams = Object.keys(args).filter(key => !['email', 'uid'].includes(key)) + + if (allParams.length === 0) { + throw new Error('Missing at least 1 optional parameter.') + } + + // Get the user data if "args.uid" is undefined + if (args.uid === undefined) { + console.log('Fetching user data...') + + userData = await getuser({ + email: args.email + }) + } + + const params = { + uid: args?.uid ?? userData.uid + } + + // Validate and set the optional "args" parameters + optionalKeys.forEach(key => { + if (args[key] !== undefined) { + switch (key) { + case 'account_level': + if (!isValidAccountLevel(args[key])) { + throw new Error(`Invalid Number value in the "${key}" key`) + } + + params[key] = parseInt(args[key]) + break + case 'emailverified': + case 'disabled': + if (!isArgsBoolean(args[key])) { + throw new Error(`Invalid Boolean value in the "${key}" key`) + } + + params[key] = (args[key] === 'true') + break + case 'displayname': + if (isArgsBoolean(args[key])) { + throw new Error('Display name format not supported.') + } + + params[key] = args[key] + break + default: + params[key] = args[key] + break + } + } + }) + + // At least 1 of the optional args params should be present + console.log(`Updating user UID ${params.uid}...`) + const user = await updateuser(params) + + console.log('User updated!') + console.log(user) + } catch (err) { + console.log(`[ERROR]: ${err.message}`) + } +} + +updateUser()