From a01b8b8fd2e704b6afc8d1f6dd47ffbbfc2b2d9e Mon Sep 17 00:00:00 2001 From: "Ean Milligan (Bastion)" Date: Sat, 28 May 2022 02:07:00 -0400 Subject: [PATCH] Added Audit system, Guild auditing put on hold --- db/initialize.ts | 16 +++++++++ db/populateDefaults.ts | 2 +- deps.ts | 2 +- mod.ts | 5 +++ src/commandUtils.ts | 1 + src/commands/_index.ts | 2 ++ src/commands/audit.ts | 54 ++++++++++++++++++++++++++++ src/commands/auditCmd/_index.ts | 9 +++++ src/commands/auditCmd/auditDB.ts | 48 +++++++++++++++++++++++++ src/commands/auditCmd/auditGuilds.ts | 21 +++++++++++ src/commands/auditCmd/auditHelp.ts | 35 ++++++++++++++++++ src/commands/stats.ts | 10 ++---- src/commonEmbeds.ts | 8 +++++ 13 files changed, 204 insertions(+), 9 deletions(-) create mode 100644 src/commands/audit.ts create mode 100644 src/commands/auditCmd/_index.ts create mode 100644 src/commands/auditCmd/auditDB.ts create mode 100644 src/commands/auditCmd/auditGuilds.ts create mode 100644 src/commands/auditCmd/auditHelp.ts create mode 100644 src/commonEmbeds.ts diff --git a/db/initialize.ts b/db/initialize.ts index 6569c81..321233a 100644 --- a/db/initialize.ts +++ b/db/initialize.ts @@ -10,6 +10,7 @@ await dbClient.execute(`USE ${config.db.name}`); console.log('DB created'); console.log('Attempt to drop all tables'); +await dbClient.execute(`DROP VIEW IF EXISTS db_size;`); await dbClient.execute(`DROP TABLE IF EXISTS allowed_channels;`); await dbClient.execute(`DROP TABLE IF EXISTS all_keys;`); await dbClient.execute(`DROP TABLE IF EXISTS allowed_guilds;`); @@ -110,5 +111,20 @@ await dbClient.execute(` `); console.log('Table created'); +// Database sizes view +console.log('Attempting to create view db_size'); +await dbClient.execute(` + CREATE VIEW db_size AS + SELECT + table_name AS "table", + ROUND(((data_length + index_length) / 1024 / 1024), 3) AS "size", + table_rows AS "rows" + FROM information_schema.TABLES + WHERE + table_schema = "${config.db.name}" + AND table_name <> "db_size"; +`); +console.log('View Created'); + await dbClient.close(); console.log('Done!'); diff --git a/db/populateDefaults.ts b/db/populateDefaults.ts index 37043e5..5c17030 100644 --- a/db/populateDefaults.ts +++ b/db/populateDefaults.ts @@ -10,7 +10,7 @@ await dbClient.execute('INSERT INTO all_keys(userid,apiKey) values(?,?)', [confi console.log('Inesrtion done'); console.log('Attempting to insert default commands into command_cnt'); -const commands = ['ping', 'rip', 'rollhelp', 'help', 'info', 'version', 'report', 'stats', 'roll', 'emojis', 'api', 'privacy', 'mention']; +const commands = ['ping', 'rip', 'rollhelp', 'help', 'info', 'version', 'report', 'stats', 'roll', 'emojis', 'api', 'privacy', 'mention', 'audit']; for (const command of commands) { await dbClient.execute('INSERT INTO command_cnt(command) values(?)', [command]).catch((e) => { console.log(`Failed to insert ${command} into database`, e); diff --git a/deps.ts b/deps.ts index 49a1d7f..9ac0a09 100644 --- a/deps.ts +++ b/deps.ts @@ -8,7 +8,7 @@ export { } from "https://deno.land/x/discordeno@12.0.1/mod.ts"; export type { - DiscordenoMessage, DiscordenoGuild, CreateMessage + DiscordenoMessage, DiscordenoGuild, CreateMessage, EmbedField } from "https://deno.land/x/discordeno@12.0.1/mod.ts"; export { Client } from "https://deno.land/x/mysql@v2.10.2/mod.ts"; diff --git a/mod.ts b/mod.ts index 14bfd5e..e78a2f1 100644 --- a/mod.ts +++ b/mod.ts @@ -190,6 +190,11 @@ startBot({ // API sub commands commands.api(message, args); break; + case 'audit': + // [[audit arg + // Audit sub commands + commands.audit(message, args); + break; default: // Non-standard commands if (command?.startsWith('xdy')) { diff --git a/src/commandUtils.ts b/src/commandUtils.ts index 8a3c27b..ac87957 100644 --- a/src/commandUtils.ts +++ b/src/commandUtils.ts @@ -27,6 +27,7 @@ export const generateStats = (guildCount: number, channelCount: number, memberCo embeds: [{ color: infoColor2, title: 'The Artificer\'s Statistics:', + timestamp: new Date().toISOString(), fields: [ { name: 'Guilds:', diff --git a/src/commands/_index.ts b/src/commands/_index.ts index eb10cd9..ad6a367 100644 --- a/src/commands/_index.ts +++ b/src/commands/_index.ts @@ -11,6 +11,7 @@ import { api } from './apiCmd.ts'; import { emoji } from './emoji.ts'; import { roll } from './roll.ts'; import { handleMentions } from './handleMentions.ts'; +import { audit } from './audit.ts'; export default { ping, @@ -26,4 +27,5 @@ export default { emoji, roll, handleMentions, + audit, }; diff --git a/src/commands/audit.ts b/src/commands/audit.ts new file mode 100644 index 0000000..1e295cd --- /dev/null +++ b/src/commands/audit.ts @@ -0,0 +1,54 @@ +import config from '../../config.ts'; +import { dbClient } from '../db.ts'; +import { + // Discordeno deps + DiscordenoMessage, + // Log4Deno deps + log, + LT, +} from '../../deps.ts'; +import auditCommands from './auditCmd/_index.ts'; +import { failColor } from '../commandUtils.ts'; + +export const audit = async (message: DiscordenoMessage, args: string[]) => { + // Light telemetry to see how many times a command is being run + dbClient.execute(`CALL INC_CNT("audit");`).catch((e) => { + log(LT.ERROR, `Failed to call stored procedure INC_CNT: ${JSON.stringify(e)}`); + }); + + // Local apiArg in lowercase + const auditArg = (args[0] || 'help').toLowerCase(); + + // Makes sure the user is authenticated to run the API command + if (message.authorId === config.api.admin) { + switch (auditArg) { + case 'help': + case 'h': + // [[audit help or [[audit h + // Shows API help details + auditCommands.auditHelp(message); + break; + case 'db': + // [[audit db + // Shows current DB table sizes + auditCommands.auditDB(message); + break; + case 'guilds': + // [[audit guilds + // Shows breakdown of guilds and detials on them + auditCommands.auditGuilds(message); + break; + default: + break; + } + } else { + message.send({ + embeds: [{ + color: failColor, + title: `Audit commands are powerful and can only be used by ${config.name}'s owner.`, + }], + }).catch((e) => { + log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); + }); + } +}; diff --git a/src/commands/auditCmd/_index.ts b/src/commands/auditCmd/_index.ts new file mode 100644 index 0000000..8142da6 --- /dev/null +++ b/src/commands/auditCmd/_index.ts @@ -0,0 +1,9 @@ +import { auditHelp } from './auditHelp.ts'; +import { auditDB } from './auditDB.ts'; +import { auditGuilds } from './auditGuilds.ts'; + +export default { + auditHelp, + auditDB, + auditGuilds, +}; diff --git a/src/commands/auditCmd/auditDB.ts b/src/commands/auditCmd/auditDB.ts new file mode 100644 index 0000000..8f49ccc --- /dev/null +++ b/src/commands/auditCmd/auditDB.ts @@ -0,0 +1,48 @@ +import { dbClient } from '../../db.ts'; +import { + // Discordeno deps + DiscordenoMessage, + EmbedField, + // Log4Deno deps + log, + LT, +} from '../../../deps.ts'; +import { infoColor2 } from '../../commandUtils.ts'; +import { compilingStats } from '../../commonEmbeds.ts'; + +export const auditDB = async (message: DiscordenoMessage) => { + try { + const m = await message.send(compilingStats); + + // Get DB statistics + const auditQuery = await dbClient.query(`SELECT * FROM db_size;`).catch((e) => { + log(LT.ERROR, `Failed to query DB: ${JSON.stringify(e)}`); + }); + + // Turn all tables into embed fields, currently only properly will handle 25 tables, but we'll fix that when artificer gets 26 tables + const embedFields: Array = []; + auditQuery.forEach((row: any) => { + embedFields.push({ + name: `${row.table}`, + value: `**Size:** ${row.size} MB +**Rows:** ${row.rows}`, + inline: true, + }); + }); + + // Send the results + m.edit({ + embeds: [{ + color: infoColor2, + title: 'Database Audit', + description: 'Lists all tables with their current size and row count.', + timestamp: new Date().toISOString(), + fields: embedFields, + }], + }).catch((e) => { + log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); + }); + } catch (e) { + log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); + } +}; diff --git a/src/commands/auditCmd/auditGuilds.ts b/src/commands/auditCmd/auditGuilds.ts new file mode 100644 index 0000000..c80b9fe --- /dev/null +++ b/src/commands/auditCmd/auditGuilds.ts @@ -0,0 +1,21 @@ +import { + // Discordeno deps + DiscordenoMessage, + // Log4Deno deps + log, + LT, +} from '../../../deps.ts'; +import { infoColor2 } from '../../commandUtils.ts'; + +export const auditGuilds = (message: DiscordenoMessage) => { + message.send({ + embeds: [{ + color: infoColor2, + title: 'Guilds Audit', + description: 'WIP', + timestamp: new Date().toISOString(), + }], + }).catch((e) => { + log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); + }); +}; diff --git a/src/commands/auditCmd/auditHelp.ts b/src/commands/auditCmd/auditHelp.ts new file mode 100644 index 0000000..5f1640a --- /dev/null +++ b/src/commands/auditCmd/auditHelp.ts @@ -0,0 +1,35 @@ +import config from '../../../config.ts'; +import { + // Discordeno deps + DiscordenoMessage, + // Log4Deno deps + log, + LT, +} from '../../../deps.ts'; +import { infoColor1 } from '../../commandUtils.ts'; + +export const auditHelp = (message: DiscordenoMessage) => { + message.send({ + embeds: [{ + color: infoColor1, + title: 'Audit Help', + fields: [ + { + name: `\`${config.prefix}audit help\``, + value: 'This command', + inline: true + }, { + name: `\`${config.prefix}audit db\``, + value: 'Shows current DB table sizes', + inline: true + }, { + name: `\`${config.prefix}audit guilds\``, + value: 'Shows breakdown of guilds and detials on them', + inline: true + }, + ] + }], + }).catch((e) => { + log(LT.ERROR, `Failed to send message: ${JSON.stringify(message)} | ${JSON.stringify(e)}`); + }); +}; diff --git a/src/commands/stats.ts b/src/commands/stats.ts index 6fb6136..3034b15 100644 --- a/src/commands/stats.ts +++ b/src/commands/stats.ts @@ -8,7 +8,8 @@ import { log, LT, } from '../../deps.ts'; -import { generateStats, warnColor } from '../commandUtils.ts'; +import { generateStats } from '../commandUtils.ts'; +import { compilingStats } from '../commonEmbeds.ts'; export const stats = async (message: DiscordenoMessage) => { // Light telemetry to see how many times a command is being run @@ -17,12 +18,7 @@ export const stats = async (message: DiscordenoMessage) => { }); try { - const m = await message.send({ - embeds: [{ - color: warnColor, - title: 'Compiling latest statistics . . .', - }], - }); + const m = await message.send(compilingStats); // Calculate how many times commands have been run const rollQuery = await dbClient.query(`SELECT count FROM command_cnt WHERE command = "roll";`).catch((e) => { diff --git a/src/commonEmbeds.ts b/src/commonEmbeds.ts new file mode 100644 index 0000000..2dcd9a4 --- /dev/null +++ b/src/commonEmbeds.ts @@ -0,0 +1,8 @@ +import { warnColor } from './commandUtils.ts'; + +export const compilingStats = { + embeds: [{ + color: warnColor, + title: 'Compiling latest statistics . . .', + }], +};