Files
talk/bin/cli-users
T
Gerardo Gálvez 8163b52301 Flag users as "Always premoderate" (#2145)
* Flag users as "Always premoderate"

Status can be set using the action dropdown in the People tab and in User Details.
Users flagged as "Always premoderate" will have their comments sent to the premod queue.
Users can be filtered with the Always Premoderate status.
Include Always Premoderate status changes in User History.
Add spanish translations.

* Reorder CSS as per cvle's suggestion

* Address second comment
2019-02-13 20:08:22 +01:00

348 lines
7.9 KiB
JavaScript
Executable File

#!/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,
},
{ 'Always premod comments': user.alwaysPremod }
);
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 <userID>')
.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 <userID>')
.description('sets the role on a user')
.action(setUserRole);
program
.command('verify <userID> <email>')
.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();
}