#!/usr/bin/env node /** * Module dependencies. */ const util = require('./util'); const program = require('commander'); const inquirer = require('inquirer'); const mongoose = require('../services/mongoose'); const SettingModel = require('../models/setting'); const MODERATION_OPTIONS = require('../models/enum/moderation_options'); const SettingsService = require('../services/settings'); const SetupService = require('../services/setup'); const UsersService = require('../services/users'); const MigrationService = require('../services/migration'); const { ErrSettingsInit, ErrSettingsNotInit } = require('../errors'); const Context = require('../graph/context'); // Register the shutdown criteria. util.onshutdown([() => mongoose.disconnect()]); //============================================================================== // Setting up the program command line arguments. //============================================================================== program .description('runs the setup wizard to setup the application') .option('--defaults', 'apply defaults for config instead of prompting') .parse(process.argv); //============================================================================== // Setup the application //============================================================================== const performSetup = async () => { // Get the current settings, we are expecing an error here. try { // Try to get the settings. await SettingsService.retrieve(); // We should NOT have gotten a settings object, this means that the // application is already setup. Error out here. throw new ErrSettingsInit(); } catch (err) { // If the error is `not init`, then we're good, otherwise, it's something // else. if (!err instanceof ErrSettingsNotInit) { throw err; return; } } if (program.defaults) { await SettingsService.init(); // Get the migrations to run. let migrations = await MigrationService.listPending(); // Perform all migrations. await MigrationService.run(migrations); console.log('Settings created.'); console.log('\nTalk is now installed!'); return; } // Create the base settings model. let settings = new SettingModel(); console.log( "\nWe'll ask you some questions in order to setup your installation of Talk.\n" ); let answers = await inquirer.prompt([ { type: 'input', name: 'organizationName', message: 'Organization Name', default: settings.organizationName, validate: input => { if (input && input.length > 0) { return true; } return 'Organization Name is required.'; }, }, { type: 'list', choices: MODERATION_OPTIONS, name: 'moderation', default: settings.moderation, message: 'Select a moderation mode', }, { type: 'confirm', name: 'requireEmailConfirmation', default: settings.requireEmailConfirmation, message: 'Should emails always be confirmed', }, ]); // Update the settings that were changed. Object.keys(answers).forEach(key => { if (answers[key] !== undefined) { settings[key] = answers[key]; } }); answers = await inquirer.prompt([ { type: 'confirm', name: 'inputWhitelistedDomains', default: true, message: 'Would you like to specify a whitelisted domain', }, { type: 'input', name: 'whitelistedDomain', message: 'Whitelisted Domain', when: ({ inputWhitelistedDomains }) => inputWhitelistedDomains, validate: input => { if (input && input.length > 0) { return true; } return 'Whitelisted Domain cannot be empty.'; }, }, ]); if (answers.inputWhitelistedDomains) { settings.domains.whitelist = [answers.whitelistedDomain]; } console.log("\nWe'll ask you some questions about your first admin user.\n"); let { username, email } = await inquirer.prompt([ { type: 'input', name: 'username', message: 'Username', filter: username => { return UsersService.isValidUsername(username, false).catch(err => { throw err.message; }); }, }, { name: 'email', message: 'Email', format: 'email', validate: value => { if (value && value.length >= 3) { return true; } return 'Email is required'; }, }, ]); let password = ''; while (!password) { answers = await inquirer.prompt([ { name: 'password', message: 'Password', type: 'password', filter: password => { try { UsersService.isValidPassword(password); } catch (err) { throw err.message; } return password; }, }, { name: 'confirmPassword', message: 'Confirm Password', type: 'password', }, ]); if (answers.password !== answers.confirmPassword) { console.error('Passwords do not match'); } else { password = answers.password; } } const ctx = Context.forSystem(); let { user: newUser } = await SetupService.setup(ctx, { settings: settings.toObject(), user: { email, username, password, }, }); console.log('Settings created.'); console.log(`User ${newUser.id} created.`); console.log('\nTalk is now installed!'); console.log( '\nWe recommend adding TALK_INSTALL_LOCK=TRUE to your environment to turn off the dynamic setup.' ); }; // Start the setup process. performSetup() .then(() => { util.shutdown(); }) .catch(e => { console.error(e); util.shutdown(1); });