EventEmitter, reformatting, system message disable option

This commit is contained in:
mmacierzanka committed 2021-07-05 20:42:23 +02:00
1 parent 7d9cdb508b
commit 2ceb32e186
4 files changed
+395 -277

No files matched your search

+92 -65
View File
@@ -1,38 +1,40 @@
//IMPORTS //IMPORTS
import { Client, ClientOptions, Message } from 'discord.js'; import { Client, ClientOptions, Message } from "discord.js";
import { Command, CommandManager, CommandMessageStructure, PermissionsError } from './Command.js'; import {
import { HelpMessage, HelpMessageParams } from './Help.js'; Command,
import * as http from 'http'; CommandManager,
import { SystemMessageManager } from './SystemMessage.js'; CommandMessageStructure,
PermissionsError,
} from "./Command.js";
import { HelpMessage, HelpMessageParams } from "./Help.js";
import * as http from "http";
import { SystemMessageManager } from "./SystemMessage.js";
import { EventEmitter } from "events";
//TYPE DEFINITIONS //TYPE DEFINITIONS
interface ConfigurationOptions { interface ConfigurationOptions {
token?: string, token?: string;
helpCommand: boolean helpCommand: boolean;
} }
interface ConstructorOptions { interface ConstructorOptions {
name: string, name: string;
prefix: string, prefix: string;
argumentSeparator?: string argumentSeparator?: string;
helpCommand?: boolean, helpCommand?: boolean;
clientOptions?: ClientOptions, clientOptions?: ClientOptions;
token?: string, token?: string;
} }
//MAIN CLASS //MAIN CLASS
class Bot { class Bot extends EventEmitter {
name: string; name: string;
client: Client; client: Client;
commands: CommandManager; commands: CommandManager;
config: ConfigurationOptions; config: ConfigurationOptions;
messages: { messages: {
help: HelpMessageParams, help: HelpMessageParams;
system: SystemMessageManager system: SystemMessageManager;
} };
on: {
message: (m: Message) => any,
command: (m: Message, cmdInfo?: CommandMessageStructure) => any
}
/** /**
* Bot instance initializer * Bot instance initializer
@@ -46,27 +48,28 @@ class Bot {
* @param {string} [options.token] - bot token from Discord Developer Portal * @param {string} [options.token] - bot token from Discord Developer Portal
*/ */
constructor(options: ConstructorOptions) { constructor(options: ConstructorOptions) {
super();
this.name = options.name; this.name = options.name;
this.client = new Client(options.clientOptions); this.client = new Client(options.clientOptions);
this.commands = new CommandManager(options.prefix, options.argumentSeparator); this.commands = new CommandManager(
options.prefix,
options.argumentSeparator
);
this.config = { this.config = {
token: options.token, token: options.token,
helpCommand: options.helpCommand != undefined ? options.helpCommand : true helpCommand:
} options.helpCommand != undefined ? options.helpCommand : true,
};
this.messages = { this.messages = {
help: { help: {
title: 'Help', title: "Help",
description: 'List of all available commands', description: "List of all available commands",
color: '#ff5500', color: "#ff5500",
usage: '[command name (optional)]', usage: "[command name (optional)]",
bottomText: 'List of all available commands' bottomText: "List of all available commands",
}, },
system: new SystemMessageManager(this.name) system: new SystemMessageManager(this.name),
} };
this.on = {
message: (m: Message) => {},
command: (m: Message, cmdInfo?: CommandMessageStructure) => {}
}
} }
/** /**
@@ -75,56 +78,80 @@ class Bot {
* @param {string} [token] - app token from Discord Developer Portal * @param {string} [token] - app token from Discord Developer Portal
* @returns *Promise<boolean>* * @returns *Promise<boolean>*
*/ */
async start(port?: number, token?: string) : Promise<boolean> { async start(port?: number, token?: string): Promise<boolean> {
try { try {
console.log(`Bot name: ${this.name}`); console.log(`Bot name: ${this.name}`);
console.log(`Prefix: ${this.commands.prefix} \n`); console.log(`Prefix: ${this.commands.prefix} \n`);
const loginToken: string = token || this.config.token || ''; const loginToken: string = token || this.config.token || "";
if(loginToken === '') { if (loginToken === "") {
throw new ReferenceError('No token specified. Please pass your Discord application token as an argument to the "start" method or in the constructor'); throw new ReferenceError(
'No token specified. Please pass your Discord application token as an argument to the "start" method or in the constructor'
);
} }
if(port) { if (port) {
console.log(`Creating http server on port ${port}...`); console.log(`Creating http server on port ${port}...`);
http.createServer().listen(port); http.createServer().listen(port);
} }
console.log('Starting modules...'); console.log("Starting modules...");
if(this.config.helpCommand) { if (this.config.helpCommand) {
const helpMsg: Command = new HelpMessage(this.commands, this.messages.help, this.name); const helpMsg: Command = new HelpMessage(
this.commands,
this.messages.help,
this.name
);
this.commands.add(helpMsg); this.commands.add(helpMsg);
} }
console.log('Connecting to Discord...'); console.log("Connecting to Discord...");
if(await this.client.login(loginToken)) { if (await this.client.login(loginToken)) {
console.log('BOT IS READY!\n'); this.client.on("ready", () => {
this.client.on('message', async m => { this.emit("ready");
this.on.message(m); });
const cmdMsg: CommandMessageStructure | null = this.commands.fetch(m); this.client.on("message", async (m) => {
if(cmdMsg?.command) { const cmdMsg: CommandMessageStructure | null =
this.on.command(m, cmdMsg); this.commands.fetch(m);
if (cmdMsg?.command) {
this.emit("command", [m, cmdMsg]);
try { try {
await cmdMsg.command.start(m, cmdMsg.arguments); await cmdMsg.command.start(m, cmdMsg.arguments);
} } catch (e) {
catch (e) { if (e instanceof PermissionsError) {
if(e instanceof PermissionsError) { this.messages.system.send(
this.messages.system.send('PERMISSION', { user: m.member || undefined, command: cmdMsg.command }, m.channel); "PERMISSION",
} {
else { user: m.member || undefined,
this.messages.system.send('ERROR', { command: cmdMsg.command, user: m.member || undefined, error: e }, m.channel); command: cmdMsg.command,
},
m.channel
);
} else {
this.messages.system.send(
"ERROR",
{
command: cmdMsg.command,
user: m.member || undefined,
error: e,
},
m.channel
);
console.error(e); console.error(e);
} }
return; return;
} }
} } else if (cmdMsg) {
else if(cmdMsg) { this.messages.system.send(
this.messages.system.send('NOT_FOUND', { phrase: m.content, user: m.member || undefined }, m.channel); "NOT_FOUND",
{ phrase: m.content, user: m.member || undefined },
m.channel
);
} else {
this.emit("message", [m]);
} }
}); });
} } else {
else {
return false; return false;
} }
return true; return true;
} } catch (e) {
catch (e) {
console.error(`ERROR! ${e.toString()}`); console.error(`ERROR! ${e.toString()}`);
return false; return false;
} }
+134 -107
View File
@@ -1,29 +1,38 @@
//IMPORTS //IMPORTS
import { Permissions, PermissionResolvable, Message, GuildMember, MessageEmbed } from 'discord.js'; import {
Permissions,
PermissionResolvable,
Message,
GuildMember,
MessageEmbed,
} from "discord.js";
//TYPE DEFINITIONS //TYPE DEFINITIONS
interface CommandBuilder { interface CommandBuilder {
name: string, name: string;
aliases?: string[] | string, aliases?: string[] | string;
keywords?: string[] | string, keywords?: string[] | string;
description?: string, description?: string;
usage?: string, usage?: string;
permissionCheck?: PermissionCheckTypes, permissionCheck?: PermissionCheckTypes;
permissions?: PermissionResolvable, permissions?: PermissionResolvable;
visible?: boolean visible?: boolean;
function: (message?: Message, cmdArguments?: string[]) => void | string | MessageEmbed | Promise<void | string | MessageEmbed>; function: (
message?: Message,
cmdArguments?: string[]
) => void | string | MessageEmbed | Promise<void | string | MessageEmbed>;
} }
interface CommandMessageStructure { interface CommandMessageStructure {
name: string, name: string;
arguments: string[], arguments: string[];
command: Command | null command: Command | null;
} }
interface PhraseOccurrenceData { interface PhraseOccurrenceData {
command: Command, command: Command;
type: 'NAME' | 'ALIAS' type: "NAME" | "ALIAS";
} }
type GetMode = 'ALL' | 'PREFIX' | 'NO_PREFIX'; type GetMode = "ALL" | "PREFIX" | "NO_PREFIX";
type PermissionCheckTypes = 'ALL' | 'ANY'; type PermissionCheckTypes = "ALL" | "ANY";
//ERROR CLASSES //ERROR CLASSES
class PermissionsError { class PermissionsError {
@@ -48,7 +57,10 @@ class Command {
permissionCheck: PermissionCheckTypes; permissionCheck: PermissionCheckTypes;
permissions: Permissions; permissions: Permissions;
visible: boolean; visible: boolean;
private function: (message?: Message, cmdArguments?: string[]) => void | string | MessageEmbed | Promise<void | string | MessageEmbed>; private function: (
message?: Message,
cmdArguments?: string[]
) => void | string | MessageEmbed | Promise<void | string | MessageEmbed>;
/** /**
* Command constructor * Command constructor
@@ -65,12 +77,15 @@ class Command {
* @param {Function} options.function - function that will trigger when the commands gets called * @param {Function} options.function - function that will trigger when the commands gets called
*/ */
constructor(options: CommandBuilder) { constructor(options: CommandBuilder) {
this.name = options.name.split(' ').join('_'); this.name = options.name.split(" ").join("_");
this.aliases = Command.processPhrase(options.aliases); this.aliases = Command.processPhrase(options.aliases);
this.keywords = Command.processPhrase(options.keywords); this.keywords = Command.processPhrase(options.keywords);
this.description = options.description || "No description"; this.description = options.description || "No description";
this.usage = options.usage || ""; this.usage = options.usage || "";
this.permissionCheck = options.permissionCheck == 'ALL' || options.permissionCheck == 'ANY' ? options.permissionCheck : "ANY"; this.permissionCheck =
options.permissionCheck == "ALL" || options.permissionCheck == "ANY"
? options.permissionCheck
: "ANY";
this.permissions = new Permissions(options.permissions || 0); this.permissions = new Permissions(options.permissions || 0);
this.visible = options.visible != undefined ? options.visible : true; this.visible = options.visible != undefined ? options.visible : true;
this.function = options.function; this.function = options.function;
@@ -82,41 +97,42 @@ class Command {
* @param {string[]} [cmdArguments] - list of processed arguments passed in a Discord message * @param {string[]} [cmdArguments] - list of processed arguments passed in a Discord message
* @returns *Promise<void>* * @returns *Promise<void>*
*/ */
async start(message?: Message, cmdArguments?: string[]) : Promise<void> { async start(message?: Message, cmdArguments?: string[]): Promise<void> {
const memberPermissions : Readonly<Permissions> = message?.member?.permissions || new Permissions(0); const memberPermissions: Readonly<Permissions> =
if(this.permissionCheck == 'ALL' ? memberPermissions.has(this.permissions, true) : memberPermissions.any(this.permissions, true)) { message?.member?.permissions || new Permissions(0);
if (
this.permissionCheck == "ALL"
? memberPermissions.has(this.permissions, true)
: memberPermissions.any(this.permissions, true)
) {
const fnResult = await this.function(message, cmdArguments); const fnResult = await this.function(message, cmdArguments);
if(typeof fnResult == 'string') { if (typeof fnResult == "string") {
await message?.reply(fnResult); await message?.reply(fnResult);
} } else if (fnResult instanceof MessageEmbed) {
else if(fnResult instanceof MessageEmbed) {
await message?.channel.send(fnResult); await message?.channel.send(fnResult);
} }
} } else {
else {
throw new PermissionsError(this, message?.member); throw new PermissionsError(this, message?.member);
} }
} }
private static processPhrase(phrase?: string | string[]) : string[] { private static processPhrase(phrase?: string | string[]): string[] {
if(Array.isArray(phrase)) { if (Array.isArray(phrase)) {
const buff = phrase.map((p) => { const buff = phrase.map((p) => {
return p.split(' ').join('_'); return p.split(" ").join("_");
}); });
buff.map(e => { buff.map((e) => {
if(e == '' || e == ' ') { if (e == "" || e == " ") {
const i = buff.indexOf(e); const i = buff.indexOf(e);
buff.splice(i, 1); buff.splice(i, 1);
} }
}); });
return buff; return buff;
} } else if (typeof phrase == "string" && phrase != "" && phrase != " ") {
else if(typeof phrase == 'string' && phrase != '' && phrase != ' ') {
const buff = []; const buff = [];
buff.push(phrase.split(' ').join('_')); buff.push(phrase.split(" ").join("_"));
return buff; return buff;
} } else {
else {
return []; return [];
} }
} }
@@ -129,7 +145,7 @@ class CommandManager {
constructor(prefix: string, argumentSeparator?: string) { constructor(prefix: string, argumentSeparator?: string) {
this.list = []; this.list = [];
this.prefix = prefix; this.prefix = prefix;
this.argumentSeparator = argumentSeparator || ','; this.argumentSeparator = argumentSeparator || ",";
} }
/** /**
@@ -138,39 +154,39 @@ class CommandManager {
* @param {GetMode} [mode='ALL'] - specifies which types of command triggers will be used to find the command [*NO_PREFIX* - only keywords; *PREFIX* - names and aliases] * @param {GetMode} [mode='ALL'] - specifies which types of command triggers will be used to find the command [*NO_PREFIX* - only keywords; *PREFIX* - names and aliases]
* @returns *Command* | *null* * @returns *Command* | *null*
*/ */
get(phrase: string, mode?: GetMode) : Command | null { get(phrase: string, mode?: GetMode): Command | null {
if(!mode) mode = 'ALL'; if (!mode) mode = "ALL";
let command : Command | null = null; let command: Command | null = null;
this.list.map((c) => { this.list.map((c) => {
switch (mode) { switch (mode) {
case 'PREFIX': case "PREFIX":
if(c.name == phrase) { if (c.name == phrase) {
command = c; command = c;
} }
c.aliases.map(a => { c.aliases.map((a) => {
if(a == phrase) { if (a == phrase) {
command = c; command = c;
} }
}); });
break; break;
case 'NO_PREFIX': case "NO_PREFIX":
c.keywords.map(k => { c.keywords.map((k) => {
if(k == phrase) { if (k == phrase) {
command = c; command = c;
} }
}); });
break; break;
case 'ALL': case "ALL":
if(c.name == phrase) { if (c.name == phrase) {
command = c; command = c;
} }
c.aliases.map(a => { c.aliases.map((a) => {
if(a == phrase) { if (a == phrase) {
command = c; command = c;
} }
}); });
c.keywords.map(k => { c.keywords.map((k) => {
if(k == phrase) { if (k == phrase) {
command = c; command = c;
} }
}); });
@@ -185,27 +201,35 @@ class CommandManager {
* @param {Command} command - *Command* or *HelpMessage* object * @param {Command} command - *Command* or *HelpMessage* object
* @returns *boolean* * @returns *boolean*
*/ */
add(command: Command) : boolean { add(command: Command): boolean {
try { try {
if(!(command instanceof Command)) { if (!(command instanceof Command)) {
throw new TypeError('Inavlid argument type'); throw new TypeError("Inavlid argument type");
} }
const nameOccurrence: PhraseOccurrenceData | null = this.findPhraseOccurrence(command.name); const nameOccurrence: PhraseOccurrenceData | null =
if(nameOccurrence) { this.findPhraseOccurrence(command.name);
throw new Error(`The name "${command.name}" has already been registered as ${nameOccurrence.type} in the "${nameOccurrence.command.name}" command.`); if (nameOccurrence) {
throw new Error(
`The name "${command.name}" has already been registered as ${nameOccurrence.type} in the "${nameOccurrence.command.name}" command.`
);
} }
command.aliases.map(a => { command.aliases.map((a) => {
const aliasOccurrence: PhraseOccurrenceData | null = this.findPhraseOccurrence(a); const aliasOccurrence: PhraseOccurrenceData | null =
if(aliasOccurrence) { this.findPhraseOccurrence(a);
console.warn(`WARN! The name "${a}" is already registered as ${aliasOccurrence.type} in the "${aliasOccurrence.command.name}" command. It will be removed from the "${command.name}" command.`); if (aliasOccurrence) {
console.warn(
`WARN! The name "${a}" is already registered as ${aliasOccurrence.type} in the "${aliasOccurrence.command.name}" command. It will be removed from the "${command.name}" command.`
);
const iToRemove = command.aliases.indexOf(a); const iToRemove = command.aliases.indexOf(a);
command.aliases.splice(iToRemove, 1); command.aliases.splice(iToRemove, 1);
} }
}); });
this.list.map(c => { this.list.map((c) => {
command.keywords.map(k => { command.keywords.map((k) => {
if(c.keywords.indexOf(k) != -1) { if (c.keywords.indexOf(k) != -1) {
console.warn(`WARN! The name "${k}" is already a registered KEYWORD for the "${c.name}" command. It will be removed from the "${command.name}" command`); console.warn(
`WARN! The name "${k}" is already a registered KEYWORD for the "${c.name}" command. It will be removed from the "${command.name}" command`
);
const iToRemove = command.keywords.indexOf(k); const iToRemove = command.keywords.indexOf(k);
command.keywords.splice(iToRemove, 1); command.keywords.splice(iToRemove, 1);
} }
@@ -213,8 +237,7 @@ class CommandManager {
}); });
this.list.push(command); this.list.push(command);
return true; return true;
} } catch (e) {
catch(e) {
console.error(`ERROR! ${e.toString()}`); console.error(`ERROR! ${e.toString()}`);
return false; return false;
} }
@@ -225,66 +248,70 @@ class CommandManager {
* @param {Message} message - *Message* object * @param {Message} message - *Message* object
* @returns *CommandMessagesStructure* | *null* * @returns *CommandMessagesStructure* | *null*
*/ */
fetch(message: Message) : CommandMessageStructure | null { fetch(message: Message): CommandMessageStructure | null {
if(!message.author.bot && message.content.startsWith(this.prefix)) { if (!message.author.bot && message.content.startsWith(this.prefix)) {
let msgContent = message.content.replace(this.prefix, ''); let msgContent = message.content.replace(this.prefix, "");
const cmdName = msgContent.split(' ')[0]; const cmdName = msgContent.split(" ")[0];
const cmd: Command | null = this.get(cmdName, 'PREFIX'); const cmd: Command | null = this.get(cmdName, "PREFIX");
msgContent = msgContent.replace(cmdName, ''); msgContent = msgContent.replace(cmdName, "");
let cmdArguments: string[] = msgContent.split(this.argumentSeparator); let cmdArguments: string[] = msgContent.split(
this.argumentSeparator
);
cmdArguments = cmdArguments.map((a) => { cmdArguments = cmdArguments.map((a) => {
return a.replace(' ', ''); return a.replace(" ", "");
}); });
if((cmdArguments[0] == '' || cmdArguments[0] == ' ') && cmdArguments.length == 1) { if (
(cmdArguments[0] == "" || cmdArguments[0] == " ") &&
cmdArguments.length == 1
) {
cmdArguments = []; cmdArguments = [];
} }
return { return {
name: cmdName, name: cmdName,
arguments: cmdArguments, arguments: cmdArguments,
command: cmd command: cmd,
} };
} } else if (!message.author.bot) {
else if(!message.author.bot) { const cmdName = message.content.split(" ")[0];
const cmdName = message.content.split(' ')[0]; const cmd: Command | null = this.get(cmdName, "NO_PREFIX");
const cmd: Command | null = this.get(cmdName, 'NO_PREFIX'); if (cmd) {
if(cmd) { const cmdArgumentsStr = message.content.replace(cmdName, "");
const cmdArgumentsStr = message.content.replace(cmdName, ''); let cmdArguments: string[] = cmdArgumentsStr.split(",");
let cmdArguments: string[] = cmdArgumentsStr.split(',');
cmdArguments = cmdArguments.map((a) => { cmdArguments = cmdArguments.map((a) => {
return a.replace(' ', ''); return a.replace(" ", "");
}); });
if((cmdArguments[0] == '' || cmdArguments[0] == ' ') && cmdArguments.length == 1) { if (
(cmdArguments[0] == "" || cmdArguments[0] == " ") &&
cmdArguments.length == 1
) {
cmdArguments = []; cmdArguments = [];
} }
return { return {
name: cmdName, name: cmdName,
arguments: cmdArguments, arguments: cmdArguments,
command: cmd command: cmd,
} };
} } else {
else {
return null; return null;
} }
} } else {
else {
return null; return null;
} }
} }
private findPhraseOccurrence(phrase?: string) : PhraseOccurrenceData | null { private findPhraseOccurrence(phrase?: string): PhraseOccurrenceData | null {
let returnValue: PhraseOccurrenceData | null = null; let returnValue: PhraseOccurrenceData | null = null;
this.list.map(c => { this.list.map((c) => {
if(phrase == c.name) { if (phrase == c.name) {
returnValue = { returnValue = {
command: c, command: c,
type: 'NAME' type: "NAME",
} };
} } else if (c.aliases.indexOf(phrase || "") != -1) {
else if(c.aliases.indexOf(phrase || '') != -1) {
returnValue = { returnValue = {
command: c, command: c,
type: 'ALIAS' type: "ALIAS",
} };
} }
}); });
return returnValue; return returnValue;
@@ -292,4 +319,4 @@ class CommandManager {
} }
//EXPORTS //EXPORTS
export { Command, CommandManager, CommandMessageStructure, PermissionsError } export { Command, CommandManager, CommandMessageStructure, PermissionsError };
+55 -40
View File
@@ -1,76 +1,91 @@
import { ColorResolvable, MessageEmbed } from 'discord.js'; import { ColorResolvable, MessageEmbed } from "discord.js";
import { Command, CommandManager } from './Command.js'; import { Command, CommandManager } from "./Command.js";
interface HelpMessageParams { interface HelpMessageParams {
title: string, title: string;
bottomText: string bottomText: string;
color: ColorResolvable, color: ColorResolvable;
description: string, description: string;
usage: string usage: string;
} }
class HelpMessage extends Command { class HelpMessage extends Command {
constructor(cmdManager: CommandManager, params: HelpMessageParams, botName?: string) { constructor(
cmdManager: CommandManager,
params: HelpMessageParams,
botName?: string
) {
super({ super({
name: 'help', name: "help",
usage: params.usage, usage: params.usage,
permissions: 0, permissions: 0,
description: params.description, description: params.description,
function: (m, a) => { function: (m, a) => {
const helpMsg = new MessageEmbed() const helpMsg = new MessageEmbed();
helpMsg.setColor(params.color); helpMsg.setColor(params.color);
helpMsg.setTimestamp(); helpMsg.setTimestamp();
helpMsg.setFooter(botName || ''); helpMsg.setFooter(botName || "");
if(helpMsg != null) { if (helpMsg != null) {
if(a && a[0]) { if (a && a[0]) {
const cmd: Command | null = cmdManager.get(a[0], 'ALL'); const cmd: Command | null = cmdManager.get(a[0], "ALL");
if(cmd) { if (cmd) {
helpMsg.setTitle(`${cmd.name} ${cmd.visible ? '' : '[HIDDEN]'}`); helpMsg.setTitle(
`${cmd.name} ${cmd.visible ? "" : "[HIDDEN]"}`
);
helpMsg.setDescription(cmd.description); helpMsg.setDescription(cmd.description);
if(cmd.usage) helpMsg.addField('Usage:', `${cmdManager.prefix}${cmd.name} ${cmd.usage}`, false); if (cmd.usage)
if(cmd.permissions.toArray(false).length > 0) { helpMsg.addField(
let permList: string = ''; "Usage:",
cmd.permissions.toArray(false).map(p => { `${cmdManager.prefix}${cmd.name} ${cmd.usage}`,
permList += p + '\n'; false
);
if (cmd.permissions.toArray(false).length > 0) {
let permList: string = "";
cmd.permissions.toArray(false).map((p) => {
permList += p + "\n";
}); });
helpMsg.addField('Permissions:', permList, false); helpMsg.addField(
"Permissions:",
permList,
false
);
} }
if(cmd.aliases.length > 0) { if (cmd.aliases.length > 0) {
let aList: string = ''; let aList: string = "";
cmd.aliases.map(a => { cmd.aliases.map((a) => {
aList += a + '\n'; aList += a + "\n";
}); });
helpMsg.addField('Aliases:', aList, false); helpMsg.addField("Aliases:", aList, false);
} }
if(cmd.keywords.length > 0) { if (cmd.keywords.length > 0) {
let kwrdList: string = ''; let kwrdList: string = "";
cmd.keywords.map(k => { cmd.keywords.map((k) => {
kwrdList += k + '\n'; kwrdList += k + "\n";
}); });
helpMsg.addField('Keywords:', kwrdList, false); helpMsg.addField("Keywords:", kwrdList, false);
} }
} else {
throw new ReferenceError(
`Command "${a[0]}" does not exist`
);
} }
else { } else {
throw new ReferenceError(`Command "${a[0]}" does not exist`);
}
}
else {
helpMsg.setTitle(params.title); helpMsg.setTitle(params.title);
helpMsg.setDescription(params.bottomText); helpMsg.setDescription(params.bottomText);
cmdManager.list.map((c) => { cmdManager.list.map((c) => {
if(c.visible) { if (c.visible) {
helpMsg.addField( helpMsg.addField(
`${cmdManager.prefix}${c.name} ${c.usage}`, `${cmdManager.prefix}${c.name} ${c.usage}`,
c.description, c.description,
false false
) );
} }
}); });
} }
} }
return helpMsg; return helpMsg;
} },
}); });
} }
} }
+114 -65
View File
@@ -1,48 +1,59 @@
import { ColorResolvable, DMChannel, GuildMember, Message, MessageEmbed, NewsChannel, TextChannel, User } from 'discord.js'; import {
import { Command, PermissionsError } from './Command.js'; ColorResolvable,
DMChannel,
GuildMember,
Message,
MessageEmbed,
NewsChannel,
TextChannel,
User,
} from "discord.js";
import { Command, PermissionsError } from "./Command.js";
type MessageType = 'PERMISSION' | 'ERROR' | 'NOT_FOUND'; type MessageType = "PERMISSION" | "ERROR" | "NOT_FOUND";
interface SystemMessageAppearance { interface SystemMessageAppearance {
title: string, title: string;
bottomText?: string, bottomText?: string;
accentColor?: ColorResolvable, accentColor?: ColorResolvable;
showTimestamp?: boolean, showTimestamp?: boolean;
footer?: string footer?: string;
} }
interface SystemMessageData { interface SystemMessageData {
command?: Command, command?: Command;
phrase?: string, phrase?: string;
user?: GuildMember | User, user?: GuildMember | User;
error?: Error | PermissionsError | string error?: Error | PermissionsError | string;
} }
class SystemMessageManager { class SystemMessageManager {
enabled: boolean;
PERMISSION: SystemMessageAppearance; PERMISSION: SystemMessageAppearance;
ERROR: SystemMessageAppearance; ERROR: SystemMessageAppearance;
NOT_FOUND: SystemMessageAppearance; NOT_FOUND: SystemMessageAppearance;
deleteTimeout: number; deleteTimeout: number;
constructor(botName?: string) { constructor(botName?: string) {
this.enabled = true;
this.PERMISSION = { this.PERMISSION = {
title: '👮‍♂️ Insufficient permissions', title: "👮‍♂️ Insufficient permissions",
bottomText: "You don't have enough permissions to run this command", bottomText: "You don't have enough permissions to run this command",
accentColor: '#1d1dc4', accentColor: "#1d1dc4",
showTimestamp: true, showTimestamp: true,
footer: botName footer: botName,
} };
this.ERROR = { this.ERROR = {
title: '❌ An error occurred', title: "❌ An error occurred",
bottomText: 'Something went wrong while processing your request.', bottomText: "Something went wrong while processing your request.",
accentColor: '#ff0000', accentColor: "#ff0000",
showTimestamp: true, showTimestamp: true,
footer: botName footer: botName,
} };
this.NOT_FOUND = { this.NOT_FOUND = {
title: '🔍 Command not found', title: "🔍 Command not found",
accentColor: '#ff5500', accentColor: "#ff5500",
showTimestamp: true, showTimestamp: true,
footer: botName footer: botName,
} };
this.deleteTimeout = Infinity; this.deleteTimeout = Infinity;
} }
@@ -53,67 +64,105 @@ class SystemMessageManager {
* @param {TextChannel | DMChannel | NewsChannel} [channel] - if specified, the generated message will be sent in this channel * @param {TextChannel | DMChannel | NewsChannel} [channel] - if specified, the generated message will be sent in this channel
* @returns *Promise<MessageEmbed | Message | void>* * @returns *Promise<MessageEmbed | Message | void>*
*/ */
async send(type: MessageType, data?: SystemMessageData, channel?: TextChannel | DMChannel | NewsChannel) : Promise<MessageEmbed | Message | void> { async send(
if(this[type]) { type: MessageType,
data?: SystemMessageData,
channel?: TextChannel | DMChannel | NewsChannel
): Promise<MessageEmbed | Message | void> {
if (!this.enabled) {
return;
}
if (this[type]) {
const embed = new MessageEmbed(); const embed = new MessageEmbed();
embed.setTitle(this[type].title); embed.setTitle(this[type].title);
if(this[type].bottomText) embed.setDescription(this[type].bottomText); if (this[type].bottomText)
embed.setColor(this[type].accentColor || '#000'); embed.setDescription(this[type].bottomText);
if(this[type].showTimestamp) embed.setTimestamp(); embed.setColor(this[type].accentColor || "#000");
if(this[type].footer) embed.setFooter(this[type].footer); if (this[type].showTimestamp) embed.setTimestamp();
if(data) { if (this[type].footer) embed.setFooter(this[type].footer);
switch(type) { if (data) {
case 'ERROR': switch (type) {
if(data.command) { case "ERROR":
embed.addField('Command name:', data.command.name, false); if (data.command) {
embed.addField(
"Command name:",
data.command.name,
false
);
} }
if(data.error) { if (data.error) {
if(data.error instanceof Error || data.error instanceof PermissionsError) { if (
embed.addField('Error details:', data.error.toString(), false); data.error instanceof Error ||
} data.error instanceof PermissionsError
else if(typeof data.error == 'string') { ) {
embed.addField('Error details:', data.error, false); embed.addField(
"Error details:",
data.error.toString(),
false
);
} else if (typeof data.error == "string") {
embed.addField(
"Error details:",
data.error,
false
);
} }
} }
if(data.user) { if (data.user) {
embed.addField('User:', data.user.toString(), false); embed.addField(
"User:",
data.user.toString(),
false
);
} }
break; break;
case 'NOT_FOUND': case "NOT_FOUND":
if(data.phrase) { if (data.phrase) {
embed.addField('Phrase:', data.phrase, false); embed.addField("Phrase:", data.phrase, false);
} }
break; break;
case 'PERMISSION': case "PERMISSION":
if(data.user) { if (data.user) {
embed.addField('User:', data.user.toString(), false); embed.addField(
"User:",
data.user.toString(),
false
);
} }
if(data.command) { if (data.command) {
embed.addField('Command name:', data.command.name, false); embed.addField(
if(data.command.permissions) { "Command name:",
let permList: string = ''; data.command.name,
data.command.permissions.toArray(false).map(p => { false
permList += p + '\n'; );
}); if (data.command.permissions) {
embed.addField('Required permissions:', permList, false); let permList: string = "";
data.command.permissions
.toArray(false)
.map((p) => {
permList += p + "\n";
});
embed.addField(
"Required permissions:",
permList,
false
);
} }
} }
break; break;
} }
} }
if(channel) { if (channel) {
const message = await channel.send(embed); const message = await channel.send(embed);
if(this.deleteTimeout != Infinity && message.deletable) { if (this.deleteTimeout != Infinity && message.deletable) {
await message.delete({ timeout: this.deleteTimeout }); await message.delete({ timeout: this.deleteTimeout });
} }
return message; return message;
} } else {
else {
return embed; return embed;
} }
} } else {
else { console.error("ERROR! System message: Incorrect parameter");
console.error('ERROR! System message: Incorrect parameter');
return; return;
} }
} }