el refactor part 1

This commit is contained in:
janderedev 2022-04-04 17:01:18 +02:00
parent a38f18ffc6
commit 084b357e20
No known key found for this signature in database
GPG key ID: 5D5E18ACB990F57A
28 changed files with 154 additions and 103 deletions

View file

@ -2,7 +2,7 @@ import { ulid } from "ulid";
import { client } from "../../index"; import { client } from "../../index";
import Infraction from "../../struct/antispam/Infraction"; import Infraction from "../../struct/antispam/Infraction";
import InfractionType from "../../struct/antispam/InfractionType"; import InfractionType from "../../struct/antispam/InfractionType";
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import TempBan from "../../struct/TempBan"; import TempBan from "../../struct/TempBan";
import { fetchUsername, logModAction } from "../modules/mod_logs"; import { fetchUsername, logModAction } from "../modules/mod_logs";
@ -10,6 +10,7 @@ import { storeTempBan } from "../modules/tempbans";
import { isModerator, NO_MANAGER_MSG, parseUserOrId, storeInfraction } from "../util"; import { isModerator, NO_MANAGER_MSG, parseUserOrId, storeInfraction } from "../util";
import Day from 'dayjs'; import Day from 'dayjs';
import RelativeTime from 'dayjs/plugin/relativeTime'; import RelativeTime from 'dayjs/plugin/relativeTime';
import CommandCategory from "../../struct/commands/CommandCategory";
Day.extend(RelativeTime); Day.extend(RelativeTime);
@ -19,7 +20,7 @@ export default {
description: 'Ban a member from the server', description: 'Ban a member from the server',
syntax: '/ban @username [10m|1h|...?] [reason?]', syntax: '/ban @username [10m|1h|...?] [reason?]',
removeEmptyArgs: true, removeEmptyArgs: true,
category: 'moderation', category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!await isModerator(message)) if (!await isModerator(message))
return message.reply(NO_MANAGER_MSG); return message.reply(NO_MANAGER_MSG);
@ -123,4 +124,4 @@ export default {
]); ]);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,9 +1,10 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { hasPerm, parseUser } from "../util"; import { hasPerm, parseUser } from "../util";
import ServerConfig from "../../struct/ServerConfig"; import ServerConfig from "../../struct/ServerConfig";
import { client } from "../.."; import { client } from "../..";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "@janderedev/revolt.js/dist/maps/Users";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
const SYNTAX = '/admin add @user; /admin remove @user; /admin list'; const SYNTAX = '/admin add @user; /admin remove @user; /admin list';
@ -12,7 +13,7 @@ export default {
aliases: [ 'admins', 'manager', 'managers' ], aliases: [ 'admins', 'manager', 'managers' ],
description: 'Allow users to control the bot\'s configuration', description: 'Allow users to control the bot\'s configuration',
syntax: SYNTAX, syntax: SYNTAX,
category: 'configuration', category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!hasPerm(message.member!, 'ManageServer')) if (!hasPerm(message.member!, 'ManageServer'))
return message.reply('You need **ManageServer** permission to use this command.'); return message.reply('You need **ManageServer** permission to use this command.');
@ -63,4 +64,4 @@ export default {
message.reply(`Available subcommands: ${SYNTAX}`); message.reply(`Available subcommands: ${SYNTAX}`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,4 +1,4 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import { client } from "../.."; import { client } from "../..";
import { commands, DEFAULT_PREFIX, ownerIDs } from "../modules/command_handler"; import { commands, DEFAULT_PREFIX, ownerIDs } from "../modules/command_handler";
@ -8,6 +8,7 @@ import path from 'path';
import { wordlist } from "../modules/user_scan"; import { wordlist } from "../modules/user_scan";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { adminBotLog } from "../logging"; import { adminBotLog } from "../logging";
import CommandCategory from "../../struct/commands/CommandCategory";
// id: expireDate // id: expireDate
const sudoOverrides: { [key: string]: number|null } = {} const sudoOverrides: { [key: string]: number|null } = {}
@ -37,7 +38,7 @@ export default {
description: 'Bot administration', description: 'Bot administration',
removeEmptyArgs: true, removeEmptyArgs: true,
restrict: 'BOTOWNER', restrict: 'BOTOWNER',
category: 'owner', category: CommandCategory.Owner,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!args.length) return message.reply('No subcommand specified. Available subcommands: ' + SUBCOMMANDS.join(', ')); if (!args.length) return message.reply('No subcommand specified. Available subcommands: ' + SUBCOMMANDS.join(', '));
@ -130,6 +131,6 @@ export default {
} }
} catch(e) { console.error(e) } } catch(e) { console.error(e) }
} }
} as Command; } as SimpleCommand;
export { isSudo, updateSudoTimeout } export { isSudo, updateSudoTimeout }

View file

@ -1,6 +1,7 @@
import { FindOneResult } from "monk"; import { FindOneResult } from "monk";
import { client } from "../.."; import { client } from "../..";
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import ServerConfig from "../../struct/ServerConfig"; import ServerConfig from "../../struct/ServerConfig";
import { scanServer } from "../modules/user_scan"; import { scanServer } from "../modules/user_scan";
@ -12,7 +13,7 @@ export default {
name: 'botctl', name: 'botctl',
aliases: null, aliases: null,
description: 'Perform administrative actions', description: 'Perform administrative actions',
category: 'configuration', category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!isBotManager(message)) return message.reply(NO_MANAGER_MSG); if (!isBotManager(message)) return message.reply(NO_MANAGER_MSG);
@ -55,4 +56,4 @@ export default {
message.reply(`Unknown option`); message.reply(`Unknown option`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,11 +1,12 @@
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
export default { export default {
name: 'debug', name: 'debug',
aliases: null, aliases: null,
description: 'Gives info helpful for development and debugging', description: 'Gives info helpful for development and debugging',
category: 'misc', category: CommandCategory.Misc,
run: (message: MessageCommandContext, args: string[]) => { run: (message: MessageCommandContext, args: string[]) => {
message.reply(`Server ID: ${message.channel?.server_id || 'None'}\n` message.reply(`Server ID: ${message.channel?.server_id || 'None'}\n`
+ `Server context: ${message.serverContext._id} ` + `Server context: ${message.serverContext._id} `
@ -13,4 +14,4 @@ export default {
+ `Channel ID: ${message.channel_id}\n` + `Channel ID: ${message.channel_id}\n`
+ `User ID: ${message.author_id}`); + `User ID: ${message.author_id}`);
} }
} as Command; } as SimpleCommand;

View file

@ -1,8 +1,9 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { inspect } from 'util'; import { inspect } from 'util';
import { client } from "../.."; import { client } from "../..";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
export default { export default {
name: 'eval', name: 'eval',
@ -10,7 +11,7 @@ export default {
description: 'Evaluate JS code', description: 'Evaluate JS code',
restrict: 'BOTOWNER', restrict: 'BOTOWNER',
removeEmptyArgs: false, removeEmptyArgs: false,
category: 'owner', category: CommandCategory.Owner,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let cmd = args.join(' '); let cmd = args.join(' ');
@ -38,7 +39,7 @@ export default {
m?.edit({ content: `## Execution failed\n\`\`\`js\n${render(e)}\n\`\`\`` }); m?.edit({ content: `## Execution failed\n\`\`\`js\n${render(e)}\n\`\`\`` });
} }
} }
} as Command; } as SimpleCommand;
function removeSecrets(input: string): string { function removeSecrets(input: string): string {
if (process.env['DB_PASS']) input = input.replace(new RegExp(process.env['DB_PASS']!, 'gi'), '[Secret redacted]'); if (process.env['DB_PASS']) input = input.replace(new RegExp(process.env['DB_PASS']!, 'gi'), '[Secret redacted]');

View file

@ -1,30 +1,34 @@
import Command from "../../struct/Command"; import Command from "../../struct/commands/SimpleCommand";
import { commands, DEFAULT_PREFIX, ownerIDs } from "../modules/command_handler"; import { commands, DEFAULT_PREFIX, ownerIDs } from "../modules/command_handler";
import CommandCategory from "../../struct/CommandCategory";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
const categories: { [key: string]: CommandCategory } = { const categories: { [key in CommandCategory]: {
'moderation': { friendlyName: string,
description: string,
aliases: string[],
} } = {
[CommandCategory.Moderation]: {
friendlyName: 'Moderation', friendlyName: 'Moderation',
description: 'Moderation-focused commands', description: 'Moderation-focused commands',
aliases: [ 'mod', 'mods' ], aliases: [ 'mod', 'mods' ],
}, },
'configuration': { [CommandCategory.Config]: {
friendlyName: 'Configuration', friendlyName: 'Configuration',
description: 'Configure AutoMod', description: 'Configure AutoMod',
aliases: [ 'conf', 'config' ], aliases: [ 'conf', 'config' ],
}, },
'misc': { [CommandCategory.Misc]: {
friendlyName: 'Misc', friendlyName: 'Misc',
description: 'Random stuff :yed:', description: 'Random stuff :yed:',
aliases: [ 'miscellaneous', 'weirdwordicantspell' ], aliases: [ 'miscellaneous', 'weirdwordicantspell' ],
}, },
'owner': { [CommandCategory.Owner]: {
friendlyName: 'Owner', friendlyName: 'Owner',
description: 'Owner-only commands for managing AutoMod', description: 'Owner-only commands for managing AutoMod',
aliases: [], aliases: [],
}, },
'uncategorized': { [CommandCategory.None]: {
friendlyName: 'Uncategorized', friendlyName: 'Uncategorized',
description: 'Uncategorized commands', description: 'Uncategorized commands',
aliases: [], aliases: [],
@ -36,7 +40,7 @@ export default {
aliases: null, aliases: null,
description: 'Help command.', description: 'Help command.',
removeEmptyArgs: true, removeEmptyArgs: true,
category: 'misc', category: CommandCategory.Misc,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
const isBotOwner = ownerIDs.includes(message.author_id); const isBotOwner = ownerIDs.includes(message.author_id);
const prefix = DEFAULT_PREFIX; // TODO: fetch prefix from server config const prefix = DEFAULT_PREFIX; // TODO: fetch prefix from server config
@ -50,15 +54,15 @@ export default {
let total = 0; let total = 0;
for (const categoryName in categories) { for (const categoryName in CommandCategory) {
let cmdCount = commands.filter( let cmdCount = commands.filter(
cmd => ((cmd.category || 'uncategorized') == categoryName) && cmd => (cmd.category == categoryName) &&
(cmd.restrict == 'BOTOWNER' ? isBotOwner : true) // Ensure owner commands are only shown to bot owner (cmd.restrict == 'BOTOWNER' ? isBotOwner : true) // Ensure owner commands are only shown to bot owner
).length; ).length;
if (cmdCount > 0) { if (cmdCount > 0) {
total++; total++;
const category = categories[categoryName]; const category = (categories as any)[categoryName];
msg += `**${category.friendlyName}**\n` + msg += `**${category.friendlyName}**\n` +
` \u200b \u200b ↳ ${(category.description)} \u200b $\\big |$ \u200b **${cmdCount}** command${cmdCount == 1 ? '' : 's'}\n`; ` \u200b \u200b ↳ ${(category.description)} \u200b $\\big |$ \u200b **${cmdCount}** command${cmdCount == 1 ? '' : 's'}\n`;
} }

View file

@ -3,7 +3,8 @@ import { ulid } from "ulid";
import { client } from "../.."; import { client } from "../..";
import Infraction from "../../struct/antispam/Infraction"; import Infraction from "../../struct/antispam/Infraction";
import InfractionType from "../../struct/antispam/InfractionType"; import InfractionType from "../../struct/antispam/InfractionType";
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import { logModAction } from "../modules/mod_logs"; import { logModAction } from "../modules/mod_logs";
import { isModerator, NO_MANAGER_MSG, parseUser, storeInfraction } from "../util"; import { isModerator, NO_MANAGER_MSG, parseUser, storeInfraction } from "../util";
@ -14,7 +15,7 @@ export default {
description: 'Eject a member from the server', description: 'Eject a member from the server',
syntax: '/kick @username [reason?]', syntax: '/kick @username [reason?]',
removeEmptyArgs: true, removeEmptyArgs: true,
category: 'moderation', category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!await isModerator(message)) if (!await isModerator(message))
return message.reply(NO_MANAGER_MSG); return message.reply(NO_MANAGER_MSG);
@ -67,4 +68,4 @@ export default {
logModAction('kick', message.serverContext, message.member!, targetUser._id, reason, infraction._id), logModAction('kick', message.serverContext, message.member!, targetUser._id, reason, infraction._id),
]); ]);
} }
} as Command; } as SimpleCommand;

View file

@ -1,6 +1,7 @@
import { FindOneResult } from "monk"; import { FindOneResult } from "monk";
import { client } from "../.."; import { client } from "../..";
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import PendingLogin from "../../struct/PendingLogin"; import PendingLogin from "../../struct/PendingLogin";
import logger from "../logger"; import logger from "../logger";
@ -10,7 +11,7 @@ export default {
name: 'login', name: 'login',
aliases: null, aliases: null,
description: 'Log into the web dashboard', description: 'Log into the web dashboard',
category: 'misc', category: CommandCategory.Misc,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
try { try {
const code = args.shift(); const code = args.shift();
@ -59,4 +60,4 @@ export default {
message.reply(`An error occurred: ${e}`); message.reply(`An error occurred: ${e}`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,6 +1,7 @@
import { FindOneResult, FindResult } from "monk"; import { FindOneResult, FindResult } from "monk";
import { client } from "../.."; import { client } from "../..";
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import PendingLogin from "../../struct/PendingLogin"; import PendingLogin from "../../struct/PendingLogin";
import { DEFAULT_PREFIX } from "../modules/command_handler"; import { DEFAULT_PREFIX } from "../modules/command_handler";
@ -9,7 +10,7 @@ export default {
name: 'logout', name: 'logout',
aliases: null, aliases: null,
description: 'Log out of sessions created with /login', description: 'Log out of sessions created with /login',
category: 'misc', category: CommandCategory.Misc,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
try { try {
const code = args.shift(); const code = args.shift();
@ -56,4 +57,4 @@ export default {
message.reply(`An error occurred: ${e}`); message.reply(`An error occurred: ${e}`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,10 +1,11 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { isBotManager, NO_MANAGER_MSG, parseUser } from "../util"; import { isBotManager, NO_MANAGER_MSG, parseUser } from "../util";
import ServerConfig from "../../struct/ServerConfig"; import ServerConfig from "../../struct/ServerConfig";
import { client } from "../.."; import { client } from "../..";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "@janderedev/revolt.js/dist/maps/Users";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
const SYNTAX = '/mod add @user; /mod remove @user; /mod list'; const SYNTAX = '/mod add @user; /mod remove @user; /mod list';
@ -15,7 +16,7 @@ export default {
aliases: [ 'moderators', 'mod', 'mods' ], aliases: [ 'moderators', 'mod', 'mods' ],
description: 'Allow users to moderate other users', description: 'Allow users to moderate other users',
syntax: SYNTAX, syntax: SYNTAX,
category: 'configuration', category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG); if (!await isBotManager(message)) return message.reply(NO_MANAGER_MSG);
@ -65,4 +66,4 @@ export default {
message.reply(`Available subcommands: ${SYNTAX}`); message.reply(`Available subcommands: ${SYNTAX}`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,13 +1,14 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { client } from "../.."; import { client } from "../..";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
export default { export default {
name: 'ping', name: 'ping',
aliases: null, aliases: null,
description: 'ping pong', description: 'ping pong',
category: 'misc', category: CommandCategory.Misc,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let now = Date.now(); let now = Date.now();
message.reply(`Measuring...`) message.reply(`Measuring...`)
@ -18,4 +19,4 @@ export default {
+ `Msg: \`${Math.round(Date.now() - now) / 2}ms\`` }); + `Msg: \`${Math.round(Date.now() - now) / 2}ms\`` });
}); });
} }
} as Command; } as SimpleCommand;

View file

@ -1,10 +1,11 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { client } from "../.."; import { client } from "../..";
import ServerConfig from "../../struct/ServerConfig"; import ServerConfig from "../../struct/ServerConfig";
import { DEFAULT_PREFIX } from "../modules/command_handler"; import { DEFAULT_PREFIX } from "../modules/command_handler";
import { hasPerm, isBotManager, NO_MANAGER_MSG } from "../util"; import { hasPerm, isBotManager, NO_MANAGER_MSG } from "../util";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
const SYNTAX = '/prefix set [new prefix]; /prefix get; prefix clear'; const SYNTAX = '/prefix set [new prefix]; /prefix get; prefix clear';
const MENTION_TEXT = 'You can also @mention me instead of using the prefix.'; const MENTION_TEXT = 'You can also @mention me instead of using the prefix.';
@ -14,7 +15,7 @@ export default {
aliases: null, aliases: null,
description: 'Configure AutoMod\'s prefix', description: 'Configure AutoMod\'s prefix',
syntax: SYNTAX, syntax: SYNTAX,
category: 'configuration', category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let config: ServerConfig = (await client.db.get('servers').findOne({ id: message.channel?.server_id })) ?? {}; let config: ServerConfig = (await client.db.get('servers').findOne({ id: message.channel?.server_id })) ?? {};
@ -56,7 +57,7 @@ export default {
} }
} }
} as Command; } as SimpleCommand;
function validatePrefix(prefix: string): string|true { function validatePrefix(prefix: string): string|true {
// Check length // Check length

View file

@ -1,8 +1,9 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { decodeTime } from 'ulid'; import { decodeTime } from 'ulid';
import { isModerator, parseUser } from "../util"; import { isModerator, parseUser } from "../util";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
const SYNTAX = '/purge [SELECTOR] [@user?[, @user?[, ...]]]; where SELECTOR: [number] || [messageID]-[messageID]'; const SYNTAX = '/purge [SELECTOR] [@user?[, @user?[, ...]]]; where SELECTOR: [number] || [messageID]-[messageID]';
const MAX_PURGE_AMOUNT = 100; const MAX_PURGE_AMOUNT = 100;
@ -12,7 +13,7 @@ export default {
aliases: [ 'clear' ], aliases: [ 'clear' ],
description: 'Mass delete messages', description: 'Mass delete messages',
syntax: SYNTAX, syntax: SYNTAX,
category: 'moderation', category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
try { try {
if (!message.member || !await isModerator(message)) return message.reply('🔒 Access denied'); if (!message.member || !await isModerator(message)) return message.reply('🔒 Access denied');
@ -89,4 +90,4 @@ export default {
message.channel?.sendMessage(`An error has occurred: ${e}`); message.channel?.sendMessage(`An error has occurred: ${e}`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,13 +1,14 @@
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
export default { export default {
name: 'settings', name: 'settings',
aliases: [ 'setting' ], aliases: [ 'setting' ],
description: 'Manage AutoMod\'s configuration', description: 'Manage AutoMod\'s configuration',
category: 'configuration', category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
await message.reply(`Bot configuration can be managed from ` await message.reply(`Bot configuration can be managed from `
+ `[here](<${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}/dashboard>).`); + `[here](<${process.env.WEB_UI_URL || 'https://automod.janderedev.xyz'}/dashboard>).`);
} }
} as Command; } as SimpleCommand;

View file

@ -1,7 +1,8 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { exec } from 'child_process'; import { exec } from 'child_process';
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
export default { export default {
name: 'shell', name: 'shell',
@ -9,7 +10,7 @@ export default {
description: 'Run code in a shell', description: 'Run code in a shell',
restrict: 'BOTOWNER', restrict: 'BOTOWNER',
removeEmptyArgs: false, removeEmptyArgs: false,
category: 'owner', category: CommandCategory.Owner,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let cmd = args.join(' '); let cmd = args.join(' ');
@ -44,4 +45,4 @@ export default {
message.channel?.sendMessage(`${e}`); message.channel?.sendMessage(`${e}`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,12 +1,13 @@
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
export default { export default {
name: 'test', name: 'test',
aliases: [ 'testalias' ], aliases: [ 'testalias' ],
description: 'Test command', description: 'Test command',
category: 'misc', category: CommandCategory.Misc,
run: (message: MessageCommandContext, args: string[]) => { run: (message: MessageCommandContext, args: string[]) => {
message.reply('Beep boop.'); message.reply('Beep boop.');
} }
} as Command; } as SimpleCommand;

View file

@ -1,6 +1,7 @@
import { FindResult } from "monk"; import { FindResult } from "monk";
import { client } from "../.."; import { client } from "../..";
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import TempBan from "../../struct/TempBan"; import TempBan from "../../struct/TempBan";
import { removeTempBan } from "../modules/tempbans"; import { removeTempBan } from "../modules/tempbans";
@ -11,7 +12,7 @@ export default {
aliases: [ 'pardon' ], aliases: [ 'pardon' ],
description: 'Unbans a user', description: 'Unbans a user',
syntax: '/unban [@user or ID]', syntax: '/unban [@user or ID]',
category: 'moderation', category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG); if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG);
@ -74,4 +75,4 @@ export default {
await msg.edit({ content: `@${bannedUser.username} has been unbanned.` }); await msg.edit({ content: `@${bannedUser.username} has been unbanned.` });
} catch(e) { console.error(e) } } catch(e) { console.error(e) }
} }
} as Command; } as SimpleCommand;

View file

@ -1,7 +1,8 @@
import { FindResult } from "monk"; import { FindResult } from "monk";
import { ulid } from "ulid"; import { ulid } from "ulid";
import { client } from "../.."; import { client } from "../..";
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import ServerConfig from "../../struct/ServerConfig"; import ServerConfig from "../../struct/ServerConfig";
import { logModAction } from "../modules/mod_logs"; import { logModAction } from "../modules/mod_logs";
@ -21,7 +22,7 @@ export default {
name: 'votekick', name: 'votekick',
aliases: [ 'voteban' ], aliases: [ 'voteban' ],
description: 'Allow trusted users to vote kick users', description: 'Allow trusted users to vote kick users',
category: 'moderation', category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
try { try {
const serverConfig: ServerConfig = await client.db.get('servers').findOne({ id: message.serverContext._id }); const serverConfig: ServerConfig = await client.db.get('servers').findOne({ id: message.serverContext._id });
@ -113,4 +114,4 @@ export default {
message.reply('Oops, something happened: ' + e); message.reply('Oops, something happened: ' + e);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,17 +1,18 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { isModerator, NO_MANAGER_MSG, parseUserOrId, storeInfraction } from "../util"; import { isModerator, NO_MANAGER_MSG, parseUserOrId, storeInfraction } from "../util";
import Infraction from "../../struct/antispam/Infraction"; import Infraction from "../../struct/antispam/Infraction";
import { ulid } from "ulid"; import { ulid } from "ulid";
import InfractionType from "../../struct/antispam/InfractionType"; import InfractionType from "../../struct/antispam/InfractionType";
import { fetchUsername, logModAction } from "../modules/mod_logs"; import { fetchUsername, logModAction } from "../modules/mod_logs";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
export default { export default {
name: 'warn', name: 'warn',
aliases: null, aliases: null,
removeEmptyArgs: false, removeEmptyArgs: false,
description: 'add an infraction to an user\'s record', description: 'add an infraction to an user\'s record',
category: 'moderation', category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG); if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG);
let user = await parseUserOrId(args.shift() ?? ''); let user = await parseUserOrId(args.shift() ?? '');
@ -46,4 +47,4 @@ export default {
logModAction('warn', message.serverContext, message.member!, user._id, reason, infraction._id, `This is warn number ${userWarnCount} for this user.`), logModAction('warn', message.serverContext, message.member!, user._id, reason, infraction._id, `This is warn number ${userWarnCount} for this user.`),
]); ]);
} }
} as Command; } as SimpleCommand;

View file

@ -1,4 +1,4 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import { client } from "../.."; import { client } from "../..";
import Infraction from "../../struct/antispam/Infraction"; import Infraction from "../../struct/antispam/Infraction";
import InfractionType from "../../struct/antispam/InfractionType"; import InfractionType from "../../struct/antispam/InfractionType";
@ -8,6 +8,7 @@ import RelativeTime from 'dayjs/plugin/relativeTime';
import Xlsx from 'xlsx'; import Xlsx from 'xlsx';
import { fetchUsername } from "../modules/mod_logs"; import { fetchUsername } from "../modules/mod_logs";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import CommandCategory from "../../struct/commands/CommandCategory";
Day.extend(RelativeTime); Day.extend(RelativeTime);
@ -16,7 +17,7 @@ export default {
aliases: [ 'warnings', 'infractions', 'infraction' ], aliases: [ 'warnings', 'infractions', 'infraction' ],
description: 'Show all user infractions', description: 'Show all user infractions',
syntax: '/warns; /warns @username ["export-csv"]; /warns rm [ID]', syntax: '/warns; /warns @username ["export-csv"]; /warns rm [ID]',
category: 'moderation', category: CommandCategory.Moderation,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG); if (!await isModerator(message)) return message.reply(NO_MANAGER_MSG);
@ -122,7 +123,7 @@ export default {
} }
} }
} }
} as Command; } as SimpleCommand;
function getInfEmoji(inf: Infraction) { function getInfEmoji(inf: Infraction) {
switch(inf.actionType) { switch(inf.actionType) {

View file

@ -1,7 +1,8 @@
import { Message } from "@janderedev/revolt.js/dist/maps/Messages"; import { Message } from "@janderedev/revolt.js/dist/maps/Messages";
import { User } from "@janderedev/revolt.js/dist/maps/Users"; import { User } from "@janderedev/revolt.js/dist/maps/Users";
import { client } from "../.."; import { client } from "../..";
import Command from "../../struct/Command"; import CommandCategory from "../../struct/commands/CommandCategory";
import SimpleCommand from "../../struct/commands/SimpleCommand";
import MessageCommandContext from "../../struct/MessageCommandContext"; import MessageCommandContext from "../../struct/MessageCommandContext";
import ServerConfig from "../../struct/ServerConfig"; import ServerConfig from "../../struct/ServerConfig";
import { isBotManager, NO_MANAGER_MSG, parseUser } from "../util"; import { isBotManager, NO_MANAGER_MSG, parseUser } from "../util";
@ -13,7 +14,7 @@ export default {
aliases: [], aliases: [],
description: 'Allow users or roles to bypass moderation rules', description: 'Allow users or roles to bypass moderation rules',
syntax: SYNTAX, syntax: SYNTAX,
category: 'configuration', category: CommandCategory.Config,
run: async (message: MessageCommandContext, args: string[]) => { run: async (message: MessageCommandContext, args: string[]) => {
let config: ServerConfig = await client.db.get('servers').findOne({ id: message.serverContext._id }) || {} let config: ServerConfig = await client.db.get('servers').findOne({ id: message.serverContext._id }) || {}
if (!config.whitelist) config.whitelist = { users: [], roles: [], managers: true } if (!config.whitelist) config.whitelist = { users: [], roles: [], managers: true }
@ -113,4 +114,4 @@ export default {
message.reply(`Command syntax: ${SYNTAX}`); message.reply(`Command syntax: ${SYNTAX}`);
} }
} }
} as Command; } as SimpleCommand;

View file

@ -1,4 +1,4 @@
import Command from "../../struct/Command"; import SimpleCommand from "../../struct/commands/SimpleCommand";
import logger from "../logger"; import logger from "../logger";
import { client } from "../../index"; import { client } from "../../index";
import fs from 'fs'; import fs from 'fs';
@ -22,13 +22,13 @@ const DEFAULT_PREFIX = process.env['PREFIX']
?? process.env['COMMAND_PREFIX'] ?? process.env['COMMAND_PREFIX']
?? '/'; ?? '/';
let commands: Command[]; let commands: SimpleCommand[];
(async () => { (async () => {
commands = (await Promise.all( commands = (await Promise.all(
fs.readdirSync(path.join(dirname, '..', 'commands')) fs.readdirSync(path.join(dirname, '..', 'commands'))
.filter(file => file.endsWith('.js')) .filter(file => file.endsWith('.js'))
.map(async file => await import(path.join(dirname, '..', 'commands', file)) as Command) .map(async file => await import(path.join(dirname, '..', 'commands', file)) as SimpleCommand)
)).map(c => (c as any).default) )).map(c => (c as any).default)
client.on('message/update', async msg => { client.on('message/update', async msg => {

View file

@ -115,6 +115,12 @@ async function getPermissionLevel(user: User|Member, server: Server): Promise<0|
return 0; return 0;
} }
function getPermissionBasedOnRole(member: Member): 0|1|2|3 {
if (hasPerm(member, 'ManageServer')) return 3;
if (hasPerm(member, 'KickMembers')) return 1;
return 0;
}
function hasPerm(member: Member, perm: keyof typeof ServerPermission): boolean { function hasPerm(member: Member, perm: keyof typeof ServerPermission): boolean {
let p = ServerPermission[perm]; let p = ServerPermission[perm];
if (member.server?.owner == member.user?._id) return true; if (member.server?.owner == member.user?._id) return true;
@ -308,6 +314,7 @@ export {
isModerator, isModerator,
isBotManager, isBotManager,
getPermissionLevel, getPermissionLevel,
getPermissionBasedOnRole,
parseUser, parseUser,
parseUserOrId, parseUserOrId,
storeInfraction, storeInfraction,

View file

@ -1,18 +0,0 @@
import { ChannelPermission, ServerPermission } from "@janderedev/revolt.js";
class Command {
name: string;
aliases: string[] | null;
description: string | null;
syntax?: string | null;
restrict?: 'BOTOWNER' | null;
removeEmptyArgs?: boolean | null;
run: Function;
category?: string;
requiredPermissions?: {
server?: keyof typeof ServerPermission,
channel?: keyof typeof ChannelPermission,
}
}
export default Command;

View file

@ -1,7 +0,0 @@
class CommandCategory {
friendlyName: string;
description: string;
aliases: string[];
}
export default CommandCategory;

View file

@ -0,0 +1,9 @@
enum CommandCategory {
Moderation = 'Moderation',
Config = 'Config',
Owner = 'Owner',
Misc = 'Misc',
None = 'None',
}
export default CommandCategory;

View file

@ -0,0 +1,35 @@
import CommandCategory from "./CommandCategory";
import MessageCommandContext from "../MessageCommandContext";
/**
* A basic command, consisting of basic attributes
* and a single run() function.
*/
class SimpleCommand {
// Primary name of the command.
name: string;
// An array of alternative command names.
aliases: string[] | null;
// The description is shown in /help.
description: string | null;
// The syntax is shown in /help.
syntax?: string | null;
// Restrict the command to bot owners.
restrict?: 'BOTOWNER' | null;
// Unless explicitly set to false, the command handler will
// remove empty args (e.g. double spaces).
removeEmptyArgs?: boolean | null;
// This is executed whenever the command is ran.
run: (message: MessageCommandContext, args: string[]) => Promise<any>;
// The category the command belongs to, used for /help.
category: CommandCategory;
}
export default SimpleCommand;