#!/usr/bin/env node /** * Module dependencies. */ const util = require('./util'); const program = require('commander'); const inquirer = require('inquirer'); const { stripIndent } = require('common-tags'); const Table = require('cli-table2'); // Make things colorful! require('colors'); // Register the autocomplete plugin. inquirer.registerPrompt( 'autocomplete', require('inquirer-autocomplete-prompt') ); const Context = require('../graph/context'); const UsersService = require('../services/users'); const UserModel = require('../models/user'); const USER_ROLES = require('../models/enum/user_roles'); const mongoose = require('../services/mongoose'); // Register the shutdown criteria. util.onshutdown([() => mongoose.disconnect()]); /** * Deletes a user and cleans up their associated verifications. */ async function deleteUser(userID) { try { // Find the user we're removing. const user = await UserModel.findOne({ id: userID }); if (!user) { throw new Error(`user with id ${userID} not found`); } printUserAsTable(user); console.warn(stripIndent` This will delete the above user. This might take a long time if there is a lot of data, please confirm that you want to continue. `); const { confirm } = await inquirer.prompt({ type: 'confirm', name: 'confirm', message: 'Continue', default: false, }); if (!confirm) { return util.shutdown(); } const ctx = Context.forSystem(); const { data, errors } = await ctx.graphql( ` mutation DeleteUser($user_id: ID!) { delUser(id: $user_id) { errors { translation_key } } } `, { user_id: user.id } ); if (errors) { throw errors; } if (data.errors) { throw data.errors; } console.log('User was deleted.'); util.shutdown(); } catch (err) { console.error(err); util.shutdown(1); } } function printUserAsTable(user) { let table = new Table({}); table.push( { ID: user.id.gray }, { Username: user.username }, { Emails: user.emails }, { Tags: user.tags ? user.tags.map(({ tag: { name } }) => name) : '' }, { Role: user.role }, { Verified: user.hasVerifiedEmail }, { Username: user.status.username.status }, { Banned: user.banned }, { Suspension: user.suspended ? `Until ${user.status.suspension.until}` : false, } ); console.log(table.toString()); } /** * Searches for users based on their username and email address. */ async function searchUsers() { const ctx = Context.forSystem(); const searchQuery = ` query SearchUsers($value: String) { users(query: {value: $value}) { nodes { id username role profiles { id provider } } } } `; try { const answers = await inquirer.prompt({ type: 'autocomplete', name: 'userID', message: 'Search for a user', source: async (answers, value) => { if (value === null) { value = ''; } const { data, errors } = await ctx.graphql(searchQuery, { value, }); if (errors && errors.length > 0) { throw errors[0]; } if (data.users === null) { return []; } return data.users.nodes.map(user => { const emails = user.profiles .filter(({ provider }) => provider === 'local') .map(({ id }) => id) .join(', '); return { name: `${user.username} (${emails}) ${user.id.gray} - ${ user.role.gray }`, value: user.id, }; }); }, }); const { userID } = answers; const user = await UserModel.findOne({ id: userID }); printUserAsTable(user); util.shutdown(0); } catch (err) { console.error(err); util.shutdown(1); } } /** * Adds a role to a user * @param {String} userUD id of the user to add the role to * @param {String} role the role to add */ async function setUserRole(userID) { try { const { role } = await inquirer.prompt([ { name: 'role', message: 'User Role', type: 'list', choices: USER_ROLES, }, ]); await UsersService.setRole(userID, role); console.log(`Set User ${userID} to the ${role} role.`); util.shutdown(); } catch (err) { console.error(err); util.shutdown(1); } } /** * Verifies an email address for a user. * * @param userID the user's id * @param email the user's email address to be verified, otherwise verifies the * first email if there is one, if there are multiple, you get a * prompt. */ async function verifyUserEmail(userID, email) { try { // Get the user. const user = await UserModel.findOne({ id: userID }); if (!user) { throw new Error(`user with ID ${userID} cannot be found`); } // Get all the user's email addresses. const emails = user.emails; if (emails.length === 0) { throw new Error('user did not have any email addresses'); } if (!email && emails.length === 1) { // The email wasn't passed, and there is only one option. email = emails[0]; } else if (!emails.includes(email)) { // The email passed doesn't belong to this user. throw new Error(`user does not have the email ${email}`); } else if (emails.length > 1) { // The email wasn't passed, and there is more than one choice. const answers = await inquirer.prompt([ { name: 'email', message: 'Select Email to Verify', type: 'list', choices: emails, }, ]); email = answers.email; } // Verify the email. await UsersService.confirmEmail(userID, email); console.log(`User ${userID} had their email ${email} verified.`); util.shutdown(); } catch (err) { console.error(err); util.shutdown(1); } } /** * createUser will prompt the user for the user information when creating a * local user. */ async function createUser() { try { const answers = await inquirer.prompt([ { name: 'email', message: 'Email', }, { name: 'username', message: 'Username', }, { name: 'password', message: 'Password', type: 'password', }, { name: 'role', message: 'Role', type: 'list', choices: USER_ROLES, }, ]); const { email, username, password, role } = answers; const ctx = Context.forSystem(); // Create the user. const user = await UsersService.createLocalUser( ctx, email, password, username ); // Set the role. await UsersService.setRole(user.id, role); console.log(`Created User[${user.id}]`); util.shutdown(0); } catch (err) { console.error(err); util.shutdown(1); } } //============================================================================== // Setting up the program command line arguments. //============================================================================== program .command('create') .description('creates a local user') .action(createUser); program .command('delete ') .description('delete a user') .action(deleteUser); program .command('list') .description('searches for a user based on their stored username and email') .action(searchUsers); program .command('set-role ') .description('sets the role on a user') .action(setUserRole); program .command('verify ') .description("verifies the given user's email address") .action(verifyUserEmail); program.parse(process.argv); // If there is no command listed, output help. if (!process.argv.slice(2).length) { program.outputHelp(); util.shutdown(); }