DTP Base provides a scalable and secure Node.js application development harness ready for production service.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

212 lines
5.5 KiB

// dtp-time-tracker-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.help.bind(this),
help: 'help [command name]',
},
'create-account': {
handler: this.createAccount.bind(this),
help: 'create-account email username [password]',
},
'grant': {
handler: this.grant.bind(this),
help: 'grant [admin|moderator] username',
},
'revoke': {
handler: this.revoke.bind(this),
help: 'revoke [admin|moderator] username',
},
'probe': {
handler: this.probeMediaFile.bind(this),
help: 'probe filename',
},
'transcode-mov': {
handler: this.transcodeMov.bind(this),
help: 'transcode-mov filename',
},
'transcode-gif': {
handler: this.transcodeGif.bind(this),
help: 'transcode-gif filename',
},
};
}
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 help (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 createAccount (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 grant (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 revoke (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 probeMediaFile (args) {
const { media: mediaService } = this.services;
const filename = args.shift();
const probe = await mediaService.ffprobe(filename);
this.log.info('FFPROBE result', { probe });
}
async transcodeMov (args) {
const { video: videoService } = this.services;
const filename = args.shift();
const stat = await fs.promises.stat(filename);
const file = {
path: filename,
size: stat.size,
type: 'video/quicktime',
};
await videoService.transcodeMov(file);
this.log.info('transcode output ready', { filename: file.path });
}
async transcodeGif (args) {
const { video: videoService } = this.services;
const filename = args.shift();
const stat = await fs.promises.stat(filename);
const file = {
path: filename,
size: stat.size,
type: 'image/gif',
};
await videoService.transcodeGif(file);
this.log.info('transcode output ready', { filename: file.path });
}
}
(async ( ) => {
let app;
try {
app = new SiteTerminalApp();
await app.start();
await app.run(process.argv.slice(2));
} catch (error) {
console.error('failed to start Time Tracker terminal application', error);
} finally {
await app.shutdown();
process.nextTick(( ) => {
process.exit(0);
});
}
})();