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
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);
|
|
});
|
|
}
|
|
|
|
})();
|