// dtp-base-cli.js // Copyright (C) 2024 DTP Technologies, LLC // All Rights Reserved 'use strict'; import 'dotenv/config'; import { dirname } from 'path'; import fs from 'fs'; import { fileURLToPath } from 'url'; const __dirname = dirname(fileURLToPath(import.meta.url)); // jshint ignore:line import mongoose from 'mongoose'; import randomstring from 'randomstring'; import { SiteRuntime } from './lib/site-runtime.js'; class SiteTerminalApp extends SiteRuntime { static get name ( ) { return 'SiteTerminalApp'; } static get slug ( ) { return 'cliApp'; } constructor ( ) { super(SiteTerminalApp, __dirname); } async start ( ) { await super.start(); this.processors = { 'help': { handler: this.cmdHelp.bind(this), help: 'help [command name]', }, 'create-account': { handler: this.cmdCreateAccount.bind(this), help: 'create-account email username [password]', }, 'grant': { handler: this.cmdGrant.bind(this), help: 'grant [admin|moderator] username', }, 'reset-indexes': { handler: this.cmdResetIndexes.bind(this), help: 'reset-indexes [modelname, modelname, ...]', }, 'revoke': { handler: this.cmdRevoke.bind(this), help: 'revoke [admin|moderator] username', }, }; } async shutdown ( ) { await super.shutdown(); return 0; // exitCode } async run (args) { this.log.debug('running', { args }); const command = args.shift(); const processor = this.processors[command]; if (!processor) { this.log.error('Unknown command', { command }); return; } return processor.handler(args); } async cmdHelp (args) { const commandName = args.shift(); if (commandName) { const command = this.processors[commandName]; if (!command) { this.log.error('invalid/unknown command', { commandName }); return; } console.log(`\n\nCommand: ${commandName}\n${command.help}\n`); } console.log( `\nDTP Chat Command Line Interface Help\nVersion: ${this.config.pkg.version}\n` ); for (const commandName in this.processors) { const command = this.processors[commandName]; console.log(`Command: ${commandName}\n${command.help}\n`); } } async cmdCreateAccount (args) { const { user: userService } = this.services; const email = args.shift(); const username = args.shift(); const password = args.shift() || randomstring.generate(8); this.log.info('creating user account', { email, username }); await userService.create({ email, username, password }); } async cmdGrant (args) { const User = mongoose.model('User'); const privilege = args.shift(); const username = args.shift(); const user = await User.findOne({ username_lc: username.toLowerCase().trim() }).select('_id'); if (!user) { throw new Error('User not found'); } switch (privilege) { case 'admin': this.log.info('granting admin privileges'); await User.updateOne({ _id: user._id }, { $set: { 'flags.isAdmin': true } }); break; case 'moderator': this.log.info('granting moderator privileges'); await User.updateOne({ _id: user._id }, { $set: { 'flags.isAdmin': true } }); break; } } async cmdResetIndexes (args) { try { this.log.info('resetting MongoDB indexes...', { args }); await this.resetIndexes(args); } catch (error) { this.log.error('failed to reset database indexes', { error }); } } async cmdRevoke (args) { const User = mongoose.model('User'); const username_lc = args.shift(); const user = await User.findOne({ username_lc }).select('_id'); if (!user) { throw new Error('User not found'); } const privilege = args.shift(); switch (privilege) { case 'admin': this.log.info('revoking admin privileges'); await User.updateOne({ _id: user._id }, { $set: { 'flags.isAdmin': false } }); break; case 'moderator': this.log.info('revoking moderator privileges'); await User.updateOne({ _id: user._id }, { $set: { 'flags.isAdmin': false } }); break; } } } (async ( ) => { let app; try { app = new SiteTerminalApp(); await app.start(); await app.run(process.argv.slice(2)); } catch (error) { console.error('failed to start terminal interface', error); } finally { await app.shutdown(); process.nextTick(( ) => { process.exit(0); }); } })();