From 70cb7d474596045cf490dd9192bd8d7414c097b0 Mon Sep 17 00:00:00 2001 From: trivernis Date: Sat, 13 Jun 2020 19:30:51 +0200 Subject: [PATCH] Add yell, say and die command --- .gitignore | 0 LICENSE | 0 README.md | 0 gulpfile.js | 1 - package.json | 0 src/Bot.ts | 9 +- src/commands/CommandCategory.ts | 5 + src/commands/global/index.ts | 9 +- src/commands/global/utility/Die.ts | 22 +++++ src/commands/global/utility/Help.ts | 99 +++++++++++++++++++ src/commands/global/utility/Ping.ts | 2 + src/commands/global/utility/Say.ts | 26 +++++ src/commands/global/utility/Yell.ts | 26 +++++ src/commands/guild/index.ts | 0 src/commands/guild/utility/AddAdminRoles.ts | 4 + .../guild/utility/RemoveAdminRoles.ts | 3 + src/commands/guild/utility/SetPrefix.ts | 4 + src/commands/private/index.ts | 0 src/index.ts | 0 src/lib/Command.ts | 12 ++- src/lib/CommandCollection.ts | 0 src/lib/CommandPermission.ts | 0 src/lib/DataHandler.ts | 0 src/lib/ExtendedMessage.ts | 26 +++++ src/lib/GuildCommand.ts | 0 src/lib/GuildHandler.ts | 14 ++- src/lib/GuildSettings.ts | 0 src/lib/models/Guild.ts | 0 src/lib/utils/BotError.ts | 0 src/lib/utils/BotLogger.ts | 0 src/lib/utils/Config.ts | 0 src/lib/utils/DefaultConfig.ts | 0 src/lib/utils/ProxyEventEmitter.ts | 0 src/lib/utils/index.ts | 0 tsconfig.json | 0 tslint.json | 0 yarn.lock | 0 37 files changed, 254 insertions(+), 8 deletions(-) mode change 100644 => 100755 .gitignore mode change 100644 => 100755 LICENSE mode change 100644 => 100755 README.md mode change 100644 => 100755 gulpfile.js mode change 100644 => 100755 package.json mode change 100644 => 100755 src/Bot.ts create mode 100755 src/commands/CommandCategory.ts mode change 100644 => 100755 src/commands/global/index.ts create mode 100755 src/commands/global/utility/Die.ts create mode 100755 src/commands/global/utility/Help.ts mode change 100644 => 100755 src/commands/global/utility/Ping.ts create mode 100755 src/commands/global/utility/Say.ts create mode 100755 src/commands/global/utility/Yell.ts mode change 100644 => 100755 src/commands/guild/index.ts mode change 100644 => 100755 src/commands/guild/utility/AddAdminRoles.ts mode change 100644 => 100755 src/commands/guild/utility/RemoveAdminRoles.ts mode change 100644 => 100755 src/commands/guild/utility/SetPrefix.ts mode change 100644 => 100755 src/commands/private/index.ts mode change 100644 => 100755 src/index.ts mode change 100644 => 100755 src/lib/Command.ts mode change 100644 => 100755 src/lib/CommandCollection.ts mode change 100644 => 100755 src/lib/CommandPermission.ts mode change 100644 => 100755 src/lib/DataHandler.ts create mode 100755 src/lib/ExtendedMessage.ts mode change 100644 => 100755 src/lib/GuildCommand.ts mode change 100644 => 100755 src/lib/GuildHandler.ts mode change 100644 => 100755 src/lib/GuildSettings.ts mode change 100644 => 100755 src/lib/models/Guild.ts mode change 100644 => 100755 src/lib/utils/BotError.ts mode change 100644 => 100755 src/lib/utils/BotLogger.ts mode change 100644 => 100755 src/lib/utils/Config.ts mode change 100644 => 100755 src/lib/utils/DefaultConfig.ts mode change 100644 => 100755 src/lib/utils/ProxyEventEmitter.ts mode change 100644 => 100755 src/lib/utils/index.ts mode change 100644 => 100755 tsconfig.json mode change 100644 => 100755 tslint.json mode change 100644 => 100755 yarn.lock diff --git a/.gitignore b/.gitignore old mode 100644 new mode 100755 diff --git a/LICENSE b/LICENSE old mode 100644 new mode 100755 diff --git a/README.md b/README.md old mode 100644 new mode 100755 diff --git a/gulpfile.js b/gulpfile.js old mode 100644 new mode 100755 index a6ffa41..476a40b --- a/gulpfile.js +++ b/gulpfile.js @@ -1,7 +1,6 @@ const {src, dest, watch, series, task} = require('gulp'); const ts = require('gulp-typescript'); const del = require('delete'); -const gulp = require('gulp'); function clearDist(cb) { del('dist/*', cb); diff --git a/package.json b/package.json old mode 100644 new mode 100755 diff --git a/src/Bot.ts b/src/Bot.ts old mode 100644 new mode 100755 index b09e160..d76fa0f --- a/src/Bot.ts +++ b/src/Bot.ts @@ -13,6 +13,8 @@ import {globalCommands} from "./commands/global"; import {privateCommands} from "./commands/private"; import {parseMessage} from "./lib/utils"; import {CommandPermission} from "./lib/CommandPermission"; +import {Help} from "./commands/global/utility/Help"; +import {ExtendedMessage} from "./lib/ExtendedMessage"; const configFile = "config.yaml"; @@ -31,6 +33,7 @@ export class Bot { * constructor */ constructor() { + globalCommands.add(Help); this.config = Bot.loadConfig(); this.logger = new BotLogger(this.config.logging.directory, this.config.logging.level); this.client = new Client(); @@ -87,7 +90,11 @@ export class Bot { this.config.prefix, userPermission); if (CommandClass) { const command = new CommandClass(this); - command.invoke(message); + try { + await command.invoke(message, new ExtendedMessage(message)); + } catch (err) { + this.logger.errorReport(err); + } } } } diff --git a/src/commands/CommandCategory.ts b/src/commands/CommandCategory.ts new file mode 100755 index 0000000..6f47f41 --- /dev/null +++ b/src/commands/CommandCategory.ts @@ -0,0 +1,5 @@ +export enum CommandCategory { + UTILITY = "Utility", + MUSIC = "Music", + MISC = "Misc", +} diff --git a/src/commands/global/index.ts b/src/commands/global/index.ts old mode 100644 new mode 100755 index 9476fdb..8b973b6 --- a/src/commands/global/index.ts +++ b/src/commands/global/index.ts @@ -1,6 +1,13 @@ import {CommandCollection} from "../../lib/CommandCollection"; import {Ping} from "./utility/Ping"; +import {Say} from "./utility/Say"; +import { Help } from "./utility/Help"; +import {Yell} from "./utility/Yell"; +import { Die } from "./utility/Die"; -export const globalCommands = new CommandCollection([ +export const globalCommands: CommandCollection = new CommandCollection([ Ping, + Say, + Yell, + Die, ]); diff --git a/src/commands/global/utility/Die.ts b/src/commands/global/utility/Die.ts new file mode 100755 index 0000000..8e0f866 --- /dev/null +++ b/src/commands/global/utility/Die.ts @@ -0,0 +1,22 @@ +import {Command} from "../../../lib/Command"; +import {CommandPermission} from "../../../lib/CommandPermission"; +import {Message} from "discord.js"; +import {CommandCategory} from "../../CommandCategory"; +import { Help } from "./Help"; + +export class Die extends Command { + public static commandName = "die"; + public static category = CommandCategory.UTILITY; + public static permission = CommandPermission.OWNER; + public static description = "Kills the bot."; + + /** + * Replies with the current ping. + * @param msg + */ + public async invoke(msg: Message): Promise { + await msg.channel.send("AAAAAARRRGGHHH..."); + await msg.client.destroy(); + process.exit(0); + } +} diff --git a/src/commands/global/utility/Help.ts b/src/commands/global/utility/Help.ts new file mode 100755 index 0000000..186a141 --- /dev/null +++ b/src/commands/global/utility/Help.ts @@ -0,0 +1,99 @@ +import {Command} from "../../../lib/Command"; +import {Message, RichEmbed} from "discord.js"; +import {CommandCollection} from "../../../lib/CommandCollection"; +import {globalCommands} from "../index"; +import {guildCommands} from "../../guild"; +import {privateCommands} from "../../private"; +import {CommandCategory} from "../../CommandCategory"; +import {ExtendedMessage} from "../../../lib/ExtendedMessage"; +import {CommandPermission} from "../../../lib/CommandPermission"; + +export class Help extends Command { + public static commandName = "help"; + public static description = "Shows a help for commands."; + public static usage = "help []"; + public static category = CommandCategory.UTILITY; + public allCommands: CommandCollection = new CommandCollection( + [...globalCommands, ...guildCommands, ...privateCommands]); + + /** + * Shows a help embed. + * If an argument is provided the specific help for that command is shown. + * @param msg + * @param exMsg + */ + public invoke(msg: Message, exMsg: ExtendedMessage): void { + const args = exMsg.args; + const helpEmbed = new RichEmbed(); + + helpEmbed.setTitle("Help"); + if (args.length === 0) { + msg.channel.send("", this.getOverviewHelpEmbed(exMsg)); + } else { + const commandHelp = this.getCommandHelpEmbed(exMsg); + if (commandHelp) { + msg.channel.send("", commandHelp); + } else { + msg.channel.send(`The command **${args[0]}** could not be found.`); + } + } + } + + /** + * Returns a help embed for the provided command. + * @param exMsg + */ + private getCommandHelpEmbed(exMsg: ExtendedMessage): RichEmbed { + const CommandClass = this.allCommands.findByName(exMsg.args[0]); + + if (CommandClass) { + const helpEmbed = new RichEmbed(); + helpEmbed.setTitle(`Help for **${CommandClass.commandName}**`); + helpEmbed.addField("Description", CommandClass.description || "*No description entity found.*"); + helpEmbed.addField("Usage", + `\`${exMsg.prefix}${CommandClass.usage || CommandClass.commandName}\``, true); + let permissionNeeded: string; + switch (CommandClass.permission as CommandPermission) { + case CommandPermission.OWNER: + permissionNeeded = "Owner"; + break; + case CommandPermission.ADMIN: + permissionNeeded = "Admin"; + break; + case CommandPermission.DJ: + permissionNeeded = "DJ"; + break; + case CommandPermission.REGULAR: + default: + permissionNeeded = "None"; + break; + } + helpEmbed.addField("Permission Level", permissionNeeded, true); + return helpEmbed; + } + } + + /** + * Returns a rich embed containing an overview of all the available commands. + * @param exMsg + */ + private getOverviewHelpEmbed(exMsg: ExtendedMessage): RichEmbed { + const helpEmbed = new RichEmbed(); + const commandsByCategory: any = {}; + helpEmbed.setDescription( + `Use \`${exMsg.prefix}\`help [command] for more info on a command.`); + for (const CommandClass of this.allCommands) { + const category: string = CommandClass.category; + if (!commandsByCategory[Help.category]) { + commandsByCategory[category] = ""; + } + commandsByCategory[category] += `\`${CommandClass.commandName}\`\t`; + } + for (const category in commandsByCategory) { + if (commandsByCategory.hasOwnProperty(category)) { + helpEmbed.addField(category, commandsByCategory[category]); + } + } + return helpEmbed; + } +} \ No newline at end of file diff --git a/src/commands/global/utility/Ping.ts b/src/commands/global/utility/Ping.ts old mode 100644 new mode 100755 index 96c4f6a..eb751a9 --- a/src/commands/global/utility/Ping.ts +++ b/src/commands/global/utility/Ping.ts @@ -1,9 +1,11 @@ import {Command} from "../../../lib/Command"; import {CommandPermission} from "../../../lib/CommandPermission"; import {Message} from "discord.js"; +import {CommandCategory} from "../../CommandCategory"; export class Ping extends Command { public static commandName = "ping"; + public static category = CommandCategory.UTILITY; public static permission = CommandPermission.REGULAR; public static description = "Replies with the bots ping."; diff --git a/src/commands/global/utility/Say.ts b/src/commands/global/utility/Say.ts new file mode 100755 index 0000000..97910ce --- /dev/null +++ b/src/commands/global/utility/Say.ts @@ -0,0 +1,26 @@ +import {Command} from "../../../lib/Command"; +import {CommandPermission} from "../../../lib/CommandPermission"; +import {Message} from "discord.js"; +import {CommandCategory} from "../../CommandCategory"; +import { Help } from "./Help"; + +export class Say extends Command { + public static commandName = "say"; + public static category = CommandCategory.UTILITY; + public static permission = CommandPermission.REGULAR; + public static description = "Replies with what you said."; + + /** + * Replies with the current ping. + * @param msg + */ + public invoke(msg: Message): void { + const msgContents = Say.getArgs(msg.content); + msgContents.shift(); + const replyContent = msgContents.join(" "); + + if (replyContent.replace(/\s/g, "").length > 0) { + msg.channel.send(replyContent); + } + } +} diff --git a/src/commands/global/utility/Yell.ts b/src/commands/global/utility/Yell.ts new file mode 100755 index 0000000..6efb745 --- /dev/null +++ b/src/commands/global/utility/Yell.ts @@ -0,0 +1,26 @@ +import {Command} from "../../../lib/Command"; +import {CommandPermission} from "../../../lib/CommandPermission"; +import {Message} from "discord.js"; +import {CommandCategory} from "../../CommandCategory"; +import { Help } from "./Help"; + +export class Yell extends Command { + public static commandName = "yell"; + public static category = CommandCategory.UTILITY; + public static permission = CommandPermission.REGULAR; + public static description = "Yells what you said."; + + /** + * Replies with the current ping. + * @param msg + */ + public invoke(msg: Message): void { + const msgContents = Yell.getArgs(msg.content); + msgContents.shift(); + const replyContent = msgContents.join(" "); + + if (replyContent.replace(/\s/g, "").length > 0) { + msg.channel.send(replyContent.toUpperCase()); + } + } +} diff --git a/src/commands/guild/index.ts b/src/commands/guild/index.ts old mode 100644 new mode 100755 diff --git a/src/commands/guild/utility/AddAdminRoles.ts b/src/commands/guild/utility/AddAdminRoles.ts old mode 100644 new mode 100755 index 0cf5571..525373a --- a/src/commands/guild/utility/AddAdminRoles.ts +++ b/src/commands/guild/utility/AddAdminRoles.ts @@ -1,10 +1,14 @@ import {Message} from "discord.js"; import {GuildCommand} from "../../../lib/GuildCommand"; import {CommandPermission} from "../../../lib/CommandPermission"; +import {CommandCategory} from "../../CommandCategory"; export class AddAdminRoles extends GuildCommand { public static commandName = "addAdminRoles"; + public static description = "Adds roles to the recognized admin roles for command permissions."; + public static usage = "addAdminRoles ..."; public static permission = CommandPermission.ADMIN; + public static category = CommandCategory.UTILITY; /** * Adds an admin role to the admin role setting on the server diff --git a/src/commands/guild/utility/RemoveAdminRoles.ts b/src/commands/guild/utility/RemoveAdminRoles.ts old mode 100644 new mode 100755 index 5e58faa..0b891f9 --- a/src/commands/guild/utility/RemoveAdminRoles.ts +++ b/src/commands/guild/utility/RemoveAdminRoles.ts @@ -1,11 +1,14 @@ import {CommandPermission} from "../../../lib/CommandPermission"; import {GuildCommand} from "../../../lib/GuildCommand"; import {Message} from "discord.js"; +import {CommandCategory} from "../../CommandCategory"; export class RemoveAdminRoles extends GuildCommand { public static commandName = "removeAdminRoles"; public static description = "Removes one or more roles from the configured roles"; + public static usage = "removeAdminRoles ..."; public static permission = CommandPermission.ADMIN; + public static category = CommandCategory.UTILITY; /** * Removes all specified roles from the admin roles. diff --git a/src/commands/guild/utility/SetPrefix.ts b/src/commands/guild/utility/SetPrefix.ts old mode 100644 new mode 100755 index 9aed402..f973210 --- a/src/commands/guild/utility/SetPrefix.ts +++ b/src/commands/guild/utility/SetPrefix.ts @@ -1,10 +1,14 @@ import {GuildCommand} from "../../../lib/GuildCommand"; import {CommandPermission} from "../../../lib/CommandPermission"; import {Message} from "discord.js"; +import {CommandCategory} from "../../CommandCategory"; export class SetPrefix extends GuildCommand { public static commandName = "setPrefix"; public static permission = CommandPermission.ADMIN; + public static category = CommandCategory.UTILITY; + public static description = "Sets the command prefix for the guild."; + public static usage = "setPrefix "; /** * Sets the prefix for a guild. diff --git a/src/commands/private/index.ts b/src/commands/private/index.ts old mode 100644 new mode 100755 diff --git a/src/index.ts b/src/index.ts old mode 100644 new mode 100755 diff --git a/src/lib/Command.ts b/src/lib/Command.ts old mode 100644 new mode 100755 index 89f8c99..9a512f1 --- a/src/lib/Command.ts +++ b/src/lib/Command.ts @@ -1,6 +1,9 @@ import {Message, MessageReaction} from "discord.js"; import {CommandPermission} from "./CommandPermission"; import {Bot} from "../Bot"; +import {basename} from "path"; +import {CommandCategory} from "../commands/CommandCategory"; +import {ExtendedMessage} from "./ExtendedMessage"; export abstract class Command { @@ -16,6 +19,11 @@ export abstract class Command { */ public static description: string; + /** + * The category of the command + */ + public static category: CommandCategory; + /** * The time to live in seconds before the instance is deleted. */ @@ -29,14 +37,14 @@ export abstract class Command { /** * The permission required to run this command */ - public static permission: CommandPermission; + public static permission: CommandPermission = CommandPermission.REGULAR; protected constructor(bot: Bot) { this.bot = bot; this.createdAt = Date.now(); } - public invoke?(msg: Message): Promise|void; + public invoke?(msg: Message, exMsg: ExtendedMessage): Promise|void; /** * A function that is executed when the answer to the command was sent. diff --git a/src/lib/CommandCollection.ts b/src/lib/CommandCollection.ts old mode 100644 new mode 100755 diff --git a/src/lib/CommandPermission.ts b/src/lib/CommandPermission.ts old mode 100644 new mode 100755 diff --git a/src/lib/DataHandler.ts b/src/lib/DataHandler.ts old mode 100644 new mode 100755 diff --git a/src/lib/ExtendedMessage.ts b/src/lib/ExtendedMessage.ts new file mode 100755 index 0000000..ad3d328 --- /dev/null +++ b/src/lib/ExtendedMessage.ts @@ -0,0 +1,26 @@ +import {Message} from "discord.js"; + +const messageRegex: RegExp = /^(.)(\w+)\s*(.*)$/; + +/** + * A class for parsing messages in an easier to handle format. + */ +export class ExtendedMessage { + + public readonly originalMessage: Message; + public readonly content: string; + public readonly prefix: string; + public readonly commandName: string; + public readonly argString: string; + public readonly args: string[]; + + constructor(message: Message) { + this.originalMessage = message; + this.content = message.content; + const matches = this.content.match(messageRegex); + this.prefix = matches[1]; + this.commandName = matches[2]; + this.argString = matches[3]; + this.args = matches[3].split(/\s+/).filter((s) => s.length > 0); + } +} diff --git a/src/lib/GuildCommand.ts b/src/lib/GuildCommand.ts old mode 100644 new mode 100755 diff --git a/src/lib/GuildHandler.ts b/src/lib/GuildHandler.ts old mode 100644 new mode 100755 index 6207a59..5ac1a93 --- a/src/lib/GuildHandler.ts +++ b/src/lib/GuildHandler.ts @@ -6,10 +6,11 @@ import {CommandPermission} from "./CommandPermission"; import {CommandCollection} from "./CommandCollection"; import {guildCommands} from "../commands/guild"; import {globalCommands} from "../commands/global"; -import {Command} from "./Command"; import {BotLogger} from "./utils/BotLogger"; import {ProxyEventEmitter} from "./utils/ProxyEventEmitter"; import {parseMessage} from "./utils"; +import {ExtendedMessage} from "./ExtendedMessage"; +import { Help } from "../commands/global/utility/Help"; /** * Handles all guild related tasks. @@ -69,7 +70,11 @@ export class GuildHandler { if (CommandClass) { const command = new CommandClass(this.bot, this); - await command.invoke(message); + try { + await command.invoke(message, new ExtendedMessage(message)); + } catch (err) { + this.logger.errorReport(err); + } } } @@ -88,7 +93,10 @@ export class GuildHandler { private getMembersHighestRole(guildMember: GuildMember) { const adminRoles = this.guildSettings.adminRoles; const djRoles = this.guildSettings.djRoles; - if (adminRoles.find((role) => GuildHandler.memberHasRole(guildMember, role))) { + + if (this.bot.config.owners.includes(guildMember.user.tag)) { + return CommandPermission.OWNER; + } else if (adminRoles.find((role) => GuildHandler.memberHasRole(guildMember, role))) { return CommandPermission.ADMIN; } else if (djRoles.find((role) => GuildHandler.memberHasRole(guildMember, role))) { return CommandPermission.DJ; diff --git a/src/lib/GuildSettings.ts b/src/lib/GuildSettings.ts old mode 100644 new mode 100755 diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts old mode 100644 new mode 100755 diff --git a/src/lib/utils/BotError.ts b/src/lib/utils/BotError.ts old mode 100644 new mode 100755 diff --git a/src/lib/utils/BotLogger.ts b/src/lib/utils/BotLogger.ts old mode 100644 new mode 100755 diff --git a/src/lib/utils/Config.ts b/src/lib/utils/Config.ts old mode 100644 new mode 100755 diff --git a/src/lib/utils/DefaultConfig.ts b/src/lib/utils/DefaultConfig.ts old mode 100644 new mode 100755 diff --git a/src/lib/utils/ProxyEventEmitter.ts b/src/lib/utils/ProxyEventEmitter.ts old mode 100644 new mode 100755 diff --git a/src/lib/utils/index.ts b/src/lib/utils/index.ts old mode 100644 new mode 100755 diff --git a/tsconfig.json b/tsconfig.json old mode 100644 new mode 100755 diff --git a/tslint.json b/tslint.json old mode 100644 new mode 100755 diff --git a/yarn.lock b/yarn.lock old mode 100644 new mode 100755