Files
talk/bin/cli-users
T
Wyatt Johnson d4889eb52c more role fixes
2017-11-27 16:44:40 -07:00

387 lines
8.7 KiB
JavaScript
Executable File

#!/usr/bin/env node
/**
* Module dependencies.
*/
const program = require('./commander');
const inquirer = require('inquirer');
const UsersService = require('../services/users');
const UserModel = require('../models/user');
const USER_ROLES = require('../models/enum/user_roles');
const mongoose = require('../services/mongoose');
const util = require('./util');
const Table = require('cli-table');
const validateRequired = (msg = 'Field is required', len = 1) => (input) => {
if (input && input.length >= len) {
return true;
}
return msg;
};
// Regeister the shutdown criteria.
util.onshutdown([
() => mongoose.disconnect()
]);
function getUserCreateAnswers(options) {
if (options.flag_mode) {
let user = {
email: options.email,
password: options.password,
confirmPassword: options.password,
username: options.name,
role: 'COMMENTER'
};
if (options.role && USER_ROLES.indexOf(options.role) > -1) {
user.roles = options.role;
}
return Promise.resolve(user);
}
return inquirer.prompt([
{
name: 'email',
message: 'Email',
format: 'email',
validate: validateRequired('Email is required')
},
{
name: 'password',
message: 'Password',
type: 'password',
filter: (password) => {
return UsersService
.isValidPassword(password)
.catch((err) => {
throw err.message;
});
}
},
{
name: 'confirmPassword',
message: 'Confirm Password',
type: 'password',
filter: (confirmPassword) => {
return UsersService
.isValidPassword(confirmPassword)
.catch((err) => {
throw err.message;
});
}
},
{
name: 'username',
message: 'Username',
filter: (username) => {
return UsersService
.isValidUsername(username)
.catch((err) => {
throw err.message;
});
}
},
{
name: 'role',
message: 'User Role',
type: 'list',
choices: USER_ROLES
}
]);
}
/**
* Prompts for input and registers a user based on those.
*/
async function createUser(options) {
try {
const answers = await getUserCreateAnswers(options);
if (answers.password !== answers.confirmPassword) {
throw new Error('Passwords do not match');
}
const user = await UsersService.createLocalUser(answers.email.trim(), answers.password.trim(), answers.username.trim());
await UsersService.setRole(user.id, answers.role);
await UsersService.sendEmailConfirmation(user, answers.email.trim());
console.log(`Created User ${user.id}.`);
util.shutdown();
} catch (err) {
console.error(err);
util.shutdown();
}
}
/**
* Deletes a user.
*/
function deleteUser(userID) {
UserModel
.findOneAndRemove({
id: userID
})
.then(() => {
console.log('Deleted user');
util.shutdown();
})
.catch((err) => {
console.error(err);
util.shutdown();
});
}
/**
* Changes the password for a user.
*/
function passwd(userID) {
inquirer.prompt([
{
name: 'password',
message: 'Password',
type: 'password',
validate: validateRequired('Password is required')
},
{
name: 'confirmPassword',
message: 'Confirm Password',
type: 'password',
validate: validateRequired('Confirm Password is required')
}
])
.then((answers) => {
if (answers.password !== answers.confirmPassword) {
throw new Error('Password mismatch');
}
return UsersService.changePassword(userID, answers.password);
})
.then(() => {
console.log('Password changed.');
util.shutdown();
})
.catch((err) => {
console.error(err);
util.shutdown(1);
});
}
/**
* Updates the user from the options array.
*/
function updateUser(userID, options) {
const updates = [];
if (options.email && typeof options.email === 'string' && options.email.length > 0) {
let q = UserModel.update({
'id': userID,
'profiles.provider': 'local'
}, {
$set: {
'profiles.$.id': options.email
}
});
updates.push(q);
}
if (options.name && typeof options.name === 'string' && options.name.length > 0) {
let q = UserModel.update({
'id': userID
}, {
$set: {
username: options.name
}
});
updates.push(q);
}
Promise
.all(updates.map((q) => q.exec()))
.then(() => {
console.log(`User ${userID} updated.`);
util.shutdown();
})
.catch((err) => {
console.error(err);
util.shutdown(1);
});
}
/**
* Lists all the users registered in the database.
*/
function listUsers() {
UsersService
.all()
.then((users) => {
let table = new Table({
head: [
'ID',
'Username',
'Profiles',
'Roles',
'Status',
'State'
]
});
users.forEach((user) => {
const profile = user.profiles.find(({provider}) => provider === 'local');
let state;
if (profile && profile.metadata && profile.metadata.confirmed_at) {
state = 'Verified';
} else {
state = 'Unverified';
}
table.push([
user.id,
user.username,
user.profiles.map((p) => p.provider).join(', '),
user.role,
user.status,
state
]);
});
console.log(table.toString());
util.shutdown();
})
.catch((err) => {
console.error(err);
util.shutdown(1);
});
}
/**
* Merges two users using the specified ID's.
* @param {String} dstUserID id of the user to which is the target of the merge
* @param {String} srcUserID id of the user to which is the source of the merge
*/
function mergeUsers(dstUserID, srcUserID) {
UsersService
.mergeUsers(dstUserID, srcUserID)
.then(() => {
console.log(`User ${srcUserID} was merged into user ${dstUserID}.`);
util.shutdown();
})
.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 setRole(userID, role, options) {
try {
if (options.interactive || !role) {
const answers = await inquirer.prompt([
{
name: 'role',
message: 'User Role',
type: 'list',
choices: USER_ROLES
}
]);
role = answers.role;
}
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
*/
async function verify(userID, email) {
try {
await UsersService.confirmEmail(userID, email);
console.log(`User ${userID} had their email ${email} verified.`);
util.shutdown();
} catch (err) {
console.error(err);
util.shutdown(1);
}
}
//==============================================================================
// Setting up the program command line arguments.
//==============================================================================
program
.command('create')
.option('--email [email]', 'Email to use')
.option('--password [password]', 'Password to use')
.option('--name [name]', 'Name to use')
.option('--role [role]', 'Role to add')
.option('-f, --flag_mode', 'Source from flags instead of prompting')
.description('create a new user')
.action(createUser);
program
.command('delete <userID>')
.description('delete a user')
.action(deleteUser);
program
.command('passwd <userID>')
.description('change a password for a user')
.action(passwd);
program
.command('update <userID>')
.option('--email [email]', 'Email to use')
.option('--name [name]', 'Name to use')
.description('update a user')
.action(updateUser);
program
.command('list')
.description('list all the users in the database')
.action(listUsers);
program
.command('merge <dstUserID> <srcUserID>')
.description('merge srcUser into the dstUser')
.action(mergeUsers);
program
.command('setrole <userID> [role]')
.option('-i, --interactive', 'Enable interactive mode')
.description('sets the role on a user')
.action(setRole);
program
.command('verify <userID> <email>')
.description('verifies the given user\'s email address')
.action(verify);
program.parse(process.argv);
// If there is no command listed, output help.
if (!process.argv.slice(2).length) {
program.outputHelp();
util.shutdown();
}