diff options
-rw-r--r-- | src/commands/admin/prefix.ts | 14 | ||||
-rw-r--r-- | src/commands/info/help.ts | 57 | ||||
-rw-r--r-- | src/commands/moderation/ban.ts | 112 | ||||
-rw-r--r-- | src/commands/moulberry-bush/capeperms.ts | 50 | ||||
-rw-r--r-- | src/commands/moulberry-bush/giveawayping.ts | 12 | ||||
-rw-r--r-- | src/commands/moulberry-bush/level.ts | 10 | ||||
-rw-r--r-- | src/commands/moulberry-bush/rule.ts | 86 | ||||
-rw-r--r-- | src/commands/owner/eval.ts | 2 | ||||
-rw-r--r-- | src/lib/extensions/Util.ts | 77 | ||||
-rw-r--r-- | src/lib/models/Ban.ts | 3 | ||||
-rw-r--r-- | src/lib/models/Guild.ts | 3 | ||||
-rw-r--r-- | src/lib/models/Modlog.ts | 3 | ||||
-rw-r--r-- | src/listeners/client/syncslashcommands.ts | 50 | ||||
-rw-r--r-- | src/listeners/commands/slashError.ts | 48 | ||||
-rw-r--r-- | yarn.lock | 140 |
15 files changed, 429 insertions, 238 deletions
diff --git a/src/commands/admin/prefix.ts b/src/commands/admin/prefix.ts index 6d0273b..112f6b8 100644 --- a/src/commands/admin/prefix.ts +++ b/src/commands/admin/prefix.ts @@ -1,6 +1,7 @@ import { ApplicationCommandOptionType } from 'discord-api-types'; import { CommandInteraction, Message, Guild as DiscordGuild } from 'discord.js'; import { BotCommand } from '../../lib/extensions/BotCommand'; +import { SlashCommandOption } from '../../lib/extensions/Util'; import { Guild } from '../../lib/models'; export default class PrefixCommand extends BotCommand { @@ -53,14 +54,13 @@ export default class PrefixCommand extends BotCommand { } } - async execSlash(message: CommandInteraction): Promise<void> { - const prefix = message.options.find((o) => o.name === 'prefix')?.value as - | string - | undefined; - - await this.changePrefix(message.guild, prefix); + async execSlash( + message: CommandInteraction, + { prefix }: { prefix?: SlashCommandOption<string> } + ): Promise<void> { + await this.changePrefix(message.guild, prefix?.value); if (prefix) { - await message.reply(`Sucessfully set prefix to \`${prefix}\``); + await message.reply(`Sucessfully set prefix to \`${prefix.value}\``); } else { await message.reply( `Sucessfully reset prefix to \`${this.client.config.prefix}\`` diff --git a/src/commands/info/help.ts b/src/commands/info/help.ts index cdddb51..116669c 100644 --- a/src/commands/info/help.ts +++ b/src/commands/info/help.ts @@ -3,6 +3,7 @@ import { BotCommand } from '../../lib/extensions/BotCommand'; import { stripIndent } from 'common-tags'; import { ApplicationCommandOptionType } from 'discord-api-types'; import { CommandInteraction } from 'discord.js'; +import { SlashCommandOption } from '../../lib/extensions/Util'; export default class HelpCommand extends BotCommand { constructor() { @@ -57,29 +58,29 @@ export default class HelpCommand extends BotCommand { ); } return embed; - } - - const embed = new MessageEmbed() - .setColor([155, 200, 200]) - .setTitle( - `\`${command.description.usage ? command.description.usage : ''}\`` - ) - .addField( - 'Description', - `${command.description.content ? command.description.content : ''} ${ - command.ownerOnly ? '\n__Owner Only__' : '' - }` - ); + } else { + const embed = new MessageEmbed() + .setColor([155, 200, 200]) + .setTitle( + `\`${command.description.usage ? command.description.usage : ''}\`` + ) + .addField( + 'Description', + `${command.description.content ? command.description.content : ''} ${ + command.ownerOnly ? '\n__Owner Only__' : '' + }` + ); - if (command.aliases.length > 1) - embed.addField('Aliases', `\`${command.aliases.join('` `')}\``, true); - if (command.description.examples && command.description.examples.length) - embed.addField( - 'Examples', - `\`${command.description.examples.join('`\n`')}\``, - true - ); - return embed; + if (command.aliases.length > 1) + embed.addField('Aliases', `\`${command.aliases.join('` `')}\``, true); + if (command.description.examples && command.description.examples.length) + embed.addField( + 'Examples', + `\`${command.description.examples.join('`\n`')}\``, + true + ); + return embed; + } } public async exec( @@ -89,13 +90,15 @@ export default class HelpCommand extends BotCommand { await message.util.send(this.generateEmbed(command)); } - public async execSlash(message: CommandInteraction): Promise<void> { - const command = message.options.find((o) => o.name === 'command')?.value as - | string - | undefined; + public async execSlash( + message: CommandInteraction, + { command }: { command: SlashCommandOption<string> } + ): Promise<void> { if (command) { await message.reply( - this.generateEmbed(this.handler.findCommand(command) as BotCommand) + this.generateEmbed( + this.handler.findCommand(command.value) as BotCommand + ) ); } else { await message.reply(this.generateEmbed()); diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts index 3858290..107de9d 100644 --- a/src/commands/moderation/ban.ts +++ b/src/commands/moderation/ban.ts @@ -4,6 +4,9 @@ import { BotCommand } from '../../lib/extensions/BotCommand'; import { Ban, Modlog, ModlogType } from '../../lib/models'; import moment from 'moment'; import { Message } from 'discord.js'; +import { CommandInteraction } from 'discord.js'; +// import { SlashCommandOption } from '../../lib/extensions/Util'; +// import { ApplicationCommandOptionType } from 'discord-api-types'; const durationAliases: Record<string, string[]> = { weeks: ['w', 'weeks', 'week', 'wk', 'wks'], @@ -12,7 +15,8 @@ const durationAliases: Record<string, string[]> = { minutes: ['m', 'min', 'mins', 'minutes', 'minute'], months: ['mo', 'month', 'months'] }; -const durationRegex = /(?:(\d+)(d(?:ays?)?|h(?:ours?|rs?)?|m(?:inutes?|ins?)?|mo(?:nths?)?|w(?:eeks?|ks?)?)(?: |$))/g; +const durationRegex = + /(?:(\d+)(d(?:ays?)?|h(?:ours?|rs?)?|m(?:inutes?|ins?)?|mo(?:nths?)?|w(?:eeks?|ks?)?)(?: |$))/g; export default class PrefixCommand extends BotCommand { constructor() { @@ -48,12 +52,35 @@ export default class PrefixCommand extends BotCommand { 'ban @Tyman being cool --time 7days' ] } + // slashCommandOptions: [ + // { + // type: ApplicationCommandOptionType.USER, + // name: 'user', + // description: 'The user to ban', + // required: true + // }, + // { + // type: ApplicationCommandOptionType.STRING, + // name: 'reason', + // description: 'The reason to show in modlogs and audit log', + // required: false + // }, + // { + // type: ApplicationCommandOptionType.STRING, + // name: 'time', + // description: + // 'The time the user should be banned for (default permanent)', + // required: false + // } + // ] }); } - async exec( - message: Message, - { user, reason, time }: { user: User; reason?: string; time?: string } - ): Promise<void> { + async *genResponses( + message: Message | CommandInteraction, + user: User, + reason?: string, + time?: string + ): AsyncIterable<string> { const duration = moment.duration(); let modlogEnry: Modlog; let banEntry: Ban; @@ -72,7 +99,7 @@ export default class PrefixCommand extends BotCommand { if (time) { const parsed = [...time.matchAll(durationRegex)]; if (parsed.length < 1) { - await message.util.send('Invalid time.'); + yield 'Invalid time.'; return; } for (const part of parsed) { @@ -91,7 +118,10 @@ export default class PrefixCommand extends BotCommand { reason, type: ModlogType.TEMPBAN, duration: duration.asMilliseconds(), - moderator: message.author.id + moderator: + message instanceof CommandInteraction + ? message.user.id + : message.author.id }); banEntry = Ban.build({ user: user.id, @@ -106,7 +136,10 @@ export default class PrefixCommand extends BotCommand { guild: message.guild.id, reason, type: ModlogType.BAN, - moderator: message.author.id + moderator: + message instanceof CommandInteraction + ? message.user.id + : message.author.id }); banEntry = Ban.build({ user: user.id, @@ -119,9 +152,7 @@ export default class PrefixCommand extends BotCommand { await banEntry.save(); } catch (e) { console.error(e); - await message.util.send( - 'Error saving to database. Please report this to a developer.' - ); + yield 'Error saving to database. Please report this to a developer.'; return; } try { @@ -133,25 +164,60 @@ export default class PrefixCommand extends BotCommand { } with reason \`${reason || 'No reason given'}\`` ); } catch (e) { - await message.channel.send('Error sending message to user'); + yield 'Error sending message to user'; } await message.guild.members.ban(user, { - reason: `Banned by ${message.author.tag} with ${ - reason ? `reason ${reason}` : 'no reason' - }` + reason: `Banned by ${ + message instanceof CommandInteraction + ? message.user.tag + : message.author.tag + } with ${reason ? `reason ${reason}` : 'no reason'}` }); - await message.util.send( - `Banned <@!${user.id}> ${ - translatedTime.length >= 1 - ? `for ${translatedTime.join(', ')}` - : 'permanently' - } with reason \`${reason || 'No reason given'}\`` - ); + yield `Banned <@!${user.id}> ${ + translatedTime.length >= 1 + ? `for ${translatedTime.join(', ')}` + : 'permanently' + } with reason \`${reason || 'No reason given'}\``; } catch { - await message.util.send('Error banning :/'); + yield 'Error banning :/'; await banEntry.destroy(); await modlogEnry.destroy(); return; } } + async exec( + message: Message, + { user, reason, time }: { user: User; reason?: string; time?: string } + ): Promise<void> { + for await (const response of this.genResponses( + message, + user, + reason, + time + )) { + await message.util.send(response); + } + } + + // async execSlash( + // message: CommandInteraction, + // { + // user, + // reason, + // time + // }: { + // user: SlashCommandOption<undefined>; + // reason: SlashCommandOption<string>; + // time: SlashCommandOption<string>; + // } + // ): Promise<void> { + // for await (const response of this.genResponses( + // message, + // user.user, + // reason?.value, + // time?.value + // )) { + // await message.reply(response); + // } + // } } diff --git a/src/commands/moulberry-bush/capeperms.ts b/src/commands/moulberry-bush/capeperms.ts index 0588696..7a79666 100644 --- a/src/commands/moulberry-bush/capeperms.ts +++ b/src/commands/moulberry-bush/capeperms.ts @@ -1,3 +1,6 @@ +import { ApplicationCommandOptionType } from 'discord-api-types'; +import { MessageEmbed } from 'discord.js'; +import { CommandInteraction } from 'discord.js'; import { Message } from 'discord.js'; import got from 'got'; import { BotCommand } from '../../lib/extensions/BotCommand'; @@ -61,20 +64,24 @@ export default class CapePermsCommand extends BotCommand { } ], clientPermissions: ['EMBED_LINKS', 'SEND_MESSAGES'], - channel: 'guild' + channel: 'guild', + slashCommandOptions: [ + { + type: ApplicationCommandOptionType.STRING, + name: 'user', + description: + 'The username of the player to see the cape permissions of', + required: true + } + ] }); } - public async exec( - message: Message, - { user }: { user: string } - ): Promise<Message> { + private async getResponse(user: string): Promise<string | MessageEmbed> { let capeperms: Capeperms, uuid: string; try { uuid = await this.client.util.mcUUID(user); } catch (e) { - return message.util.reply( - `<:error:837123021016924261> \`${user}\` doesn't appear to be a valid username.` - ); + return `<:error:837123021016924261> \`${user}\` doesn't appear to be a valid username.`; } try { @@ -85,27 +92,34 @@ export default class CapePermsCommand extends BotCommand { capeperms = null; } if (capeperms == null) { - return message.util.reply( - `<:error:837123021016924261> There was an error finding cape perms for \`${user}\`.` - ); + return `<:error:837123021016924261> There was an error finding cape perms for \`${user}\`.`; } else { if (capeperms?.perms) { const foundUser = capeperms.perms.find((u) => u._id === uuid); if (foundUser == null) - return message.util.reply( - `<:error:837123021016924261> \`${user}\` does not appear to have any capes.` - ); + return `<:error:837123021016924261> \`${user}\` does not appear to have any capes.`; const userPerm: string[] = foundUser.perms; const embed = this.client.util .createEmbed(this.client.util.colors.default) .setTitle(`${user}'s Capes`) .setDescription(userPerm.join('\n')); - await message.util.reply(embed); + return embed; } else { - return message.util.reply( - `<:error:837123021016924261> There was an error finding cape perms for ${user}.` - ); + return `<:error:837123021016924261> There was an error finding cape perms for ${user}.`; } } } + public async exec( + message: Message, + { user }: { user: string } + ): Promise<void> { + await message.reply(await this.getResponse(user)); + } + + public async execSlash( + message: CommandInteraction, + { user }: { user: string } + ): Promise<void> { + await message.reply(await this.getResponse(user)); + } } diff --git a/src/commands/moulberry-bush/giveawayping.ts b/src/commands/moulberry-bush/giveawayping.ts index e96b073..d99f475 100644 --- a/src/commands/moulberry-bush/giveawayping.ts +++ b/src/commands/moulberry-bush/giveawayping.ts @@ -43,14 +43,14 @@ export default class GiveawayPingCommand extends BotCommand { '<:error:837123021016924261> This command may only be run in giveaway channels.' ); await message.delete().catch(() => undefined); - const webhooks = await (message.channel as - | TextChannel - | NewsChannel).fetchWebhooks(); + const webhooks = await ( + message.channel as TextChannel | NewsChannel + ).fetchWebhooks(); let webhookClient: WebhookClient; if (webhooks.size < 1) { - const webhook = await (message.channel as - | TextChannel - | NewsChannel).createWebhook('Giveaway ping webhook'); + const webhook = await ( + message.channel as TextChannel | NewsChannel + ).createWebhook('Giveaway ping webhook'); webhookClient = new WebhookClient(webhook.id, webhook.token); } else { const webhook = webhooks.first(); diff --git a/src/commands/moulberry-bush/level.ts b/src/commands/moulberry-bush/level.ts index ab41f42..ab08361 100644 --- a/src/commands/moulberry-bush/level.ts +++ b/src/commands/moulberry-bush/level.ts @@ -1,5 +1,6 @@ import { ApplicationCommandOptionType } from 'discord-api-types'; import { Message } from 'discord.js'; +import { CommandInteractionOption } from 'discord.js'; import { CommandInteraction } from 'discord.js'; import { User } from 'discord.js'; import { BotCommand } from '../../lib/extensions/BotCommand'; @@ -51,9 +52,10 @@ export default class LevelCommand extends BotCommand { async exec(message: Message, { user }: { user?: User }): Promise<void> { await message.reply(await this.getResponse(user || message.author)); } - async execSlash(message: CommandInteraction): Promise<void> { - const user = - message.options.find((o) => o.name === 'user')?.user || message.user; - await message.reply(await this.getResponse(user)); + async execSlash( + message: CommandInteraction, + { user }: { user?: CommandInteractionOption } + ): Promise<void> { + await message.reply(await this.getResponse(user?.user || message.user)); } } diff --git a/src/commands/moulberry-bush/rule.ts b/src/commands/moulberry-bush/rule.ts index 4eac580..a9414ea 100644 --- a/src/commands/moulberry-bush/rule.ts +++ b/src/commands/moulberry-bush/rule.ts @@ -1,7 +1,9 @@ import { Argument } from 'discord-akairo'; import { Message, MessageEmbed, User } from 'discord.js'; -import AllowedMentions from '../../lib/utils/AllowedMentions'; import { BotCommand } from '../../lib/extensions/BotCommand'; +import { ApplicationCommandOptionType } from 'discord-api-types'; +import { CommandInteraction } from 'discord.js'; +import { SlashCommandOption } from '../../lib/extensions/Util'; export default class RuleCommand extends BotCommand { private rules = [ @@ -98,28 +100,43 @@ export default class RuleCommand extends BotCommand { } ], clientPermissions: ['EMBED_LINKS', 'SEND_MESSAGES'], - channel: 'guild' + channel: 'guild', + slashCommandOptions: [ + { + type: ApplicationCommandOptionType.STRING, + name: 'rule', + description: 'The rule to show', + required: false + }, + { + type: ApplicationCommandOptionType.USER, + name: 'user', + description: 'The user to ping', + required: false + } + ] }); } - public async exec( - message: Message, - { rule, user }: { rule: undefined | number; user: User } - ): Promise<unknown> { + private getResponse( + message: Message | CommandInteraction, + rule?: number, + user?: User + ): string | MessageEmbed | [string, MessageEmbed] { if ( message.guild.id !== '516977525906341928' && - !this.client.ownerID.includes(message.author.id) + !this.client.ownerID.includes( + message instanceof Message ? message.author.id : message.user.id + ) ) { - return message.util.reply( - "<:no:787549684196704257> This command can only be run in Moulberry's Bush." - ); + return "<:no:787549684196704257> This command can only be run in Moulberry's Bush."; } - const rulesEmbed = new MessageEmbed() - .setColor('ef3929') - .setFooter( + let rulesEmbed = new MessageEmbed().setColor('ef3929'); + if (message instanceof Message) { + rulesEmbed = rulesEmbed.setFooter( `Triggered by ${message.author.tag}`, message.author.avatarURL({ dynamic: true }) ); - + } if (rule) { const foundRule = this.rules[rule]; rulesEmbed.addField(foundRule.title, foundRule.description); @@ -129,19 +146,40 @@ export default class RuleCommand extends BotCommand { } } if (!user) { - return ( - // If the original message was a reply -> imamate it - message.util.send({ - embed: rulesEmbed, - allowedMentions: AllowedMentions.users() - }) - ); + return rulesEmbed; } else { - await message.util.send(`<@!${user.id}>`, { - embed: rulesEmbed, - allowedMentions: AllowedMentions.users() + return [`<@!${user.id}>`, rulesEmbed]; + } + } + public async exec( + message: Message, + { rule, user }: { rule?: number; user?: User } + ): Promise<void> { + const response = this.getResponse(message, rule, user); + if (Array.isArray(response)) { + await message.util.send(response[0], { + embed: response[1] }); + } else { + await message.util.send(response); } await message.delete().catch(() => undefined); } + + public async execSlash( + message: CommandInteraction, + { + rule, + user + }: { rule?: SlashCommandOption<number>; user?: SlashCommandOption<void> } + ): Promise<void> { + const response = this.getResponse(message, rule?.value, user?.user); + if (Array.isArray(response)) { + await message.reply(response[0], { + embeds: [response[1]] + }); + } else { + await message.reply(response); + } + } } diff --git a/src/commands/owner/eval.ts b/src/commands/owner/eval.ts index 44326b2..2d5eb2d 100644 --- a/src/commands/owner/eval.ts +++ b/src/commands/owner/eval.ts @@ -19,7 +19,7 @@ export default class EvalCommand extends BotCommand { category: 'dev', description: { content: 'Use the command to eval stuff in the bot.', - usage: 'eval [--depth #] <code> [--sudo] [--silent] [--delete]', + usage: 'eval <code> [--silent] [--depth #]', examples: ['eval message.guild.name', 'eval this.client.ownerID'] }, args: [ diff --git a/src/lib/extensions/Util.ts b/src/lib/extensions/Util.ts index 661392f..0aadc89 100644 --- a/src/lib/extensions/Util.ts +++ b/src/lib/extensions/Util.ts @@ -4,6 +4,16 @@ import { promisify } from 'util'; import { exec } from 'child_process'; import got from 'got'; import { MessageEmbed, GuildMember, User } from 'discord.js'; +import { CommandInteractionOption } from 'discord.js'; +import { + ApplicationCommandOptionType, + APIInteractionDataResolvedGuildMember, + APIInteractionDataResolvedChannel, + APIRole +} from 'discord-api-types'; +import { GuildChannel } from 'discord.js'; +import { Role } from 'discord.js'; +import chalk from 'chalk'; interface hastebinRes { key: string; @@ -32,6 +42,17 @@ export interface uuidRes { created_at: string; } +export interface SlashCommandOption<T> { + name: string; + type: ApplicationCommandOptionType; + value?: T; + options?: CommandInteractionOption[]; + user?: User; + member?: GuildMember | APIInteractionDataResolvedGuildMember; + channel?: GuildChannel | APIInteractionDataResolvedChannel; + role?: Role | APIRole; +} + export class Util extends ClientUtil { /** * The client of this ClientUtil @@ -88,9 +109,7 @@ export class Util extends ClientUtil { * @param command The shell command to run * @returns The stdout and stderr of the shell command */ - public async shell( - command: string - ): Promise<{ + public async shell(command: string): Promise<{ stdout: string; stderr: string; }> { @@ -225,6 +244,58 @@ export class Util extends ClientUtil { return apiRes.uuid; } + public async syncSlashCommands(force = false): Promise<void> { + try { + const registered = await this.client.application.commands.fetch(); + for (const [, registeredCommand] of registered) { + if ( + !this.client.commandHandler.modules.find( + (cmd) => cmd.id == registeredCommand.name + ) || + force + ) { + await this.client.application.commands.delete(registeredCommand.id); + this.client.logger.verbose( + chalk`{red Deleted slash command ${registeredCommand.name}}` + ); + } + } + + for (const [, botCommand] of this.client.commandHandler.modules) { + if (botCommand.execSlash) { + const found = registered.find((i) => i.name == botCommand.id); + + const slashdata = { + name: botCommand.id, + description: botCommand.description.content, + options: botCommand.options.slashCommandOptions + }; + + if (found?.id && !force) { + if (slashdata.description !== found.description) { + await this.client.application.commands.edit(found.id, slashdata); + this.client.logger.verbose( + chalk`{yellow Edited slash command ${botCommand.id}}` + ); + } + } else { + await this.client.application.commands.create(slashdata); + this.client.logger.verbose( + chalk`{green Created slash command ${botCommand.id}}` + ); + } + } + } + + return this.client.logger.log(chalk.green('Slash commands registered')); + } catch (e) { + console.log(chalk.red(e.stack)); + return this.client.logger.error( + chalk`{red Slash commands not registered, see above error.}` + ); + } + } + public moulberryBushRoleMap = [ { name: '*', id: '792453550768390194' }, { name: 'Admin Perms', id: '746541309853958186' }, diff --git a/src/lib/models/Ban.ts b/src/lib/models/Ban.ts index c30c4c5..3ce9c06 100644 --- a/src/lib/models/Ban.ts +++ b/src/lib/models/Ban.ts @@ -22,7 +22,8 @@ export interface BanModelCreationAttributes { export class Ban extends BaseModel<BanModel, BanModelCreationAttributes> - implements BanModel { + implements BanModel +{ /** * The ID of this ban (no real use just for a primary key) */ diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts index e4e317f..1cb3abb 100644 --- a/src/lib/models/Guild.ts +++ b/src/lib/models/Guild.ts @@ -10,7 +10,8 @@ export type GuildModelCreationAttributes = Optional<GuildModel, 'prefix'>; export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> - implements GuildModel { + implements GuildModel +{ id: string; prefix: string; static initModel(seqeulize: Sequelize, client: BotClient): void { diff --git a/src/lib/models/Modlog.ts b/src/lib/models/Modlog.ts index 6dd5e26..7efeeed 100644 --- a/src/lib/models/Modlog.ts +++ b/src/lib/models/Modlog.ts @@ -34,7 +34,8 @@ export interface ModlogModelCreationAttributes { export class Modlog extends BaseModel<ModlogModel, ModlogModelCreationAttributes> - implements ModlogModel { + implements ModlogModel +{ id: string; type: ModlogType; user: string; diff --git a/src/listeners/client/syncslashcommands.ts b/src/listeners/client/syncslashcommands.ts index eb65b97..66f530f 100644 --- a/src/listeners/client/syncslashcommands.ts +++ b/src/listeners/client/syncslashcommands.ts @@ -1,4 +1,3 @@ -import chalk from 'chalk'; import { BotListener } from '../../lib/extensions/BotListener'; export default class CreateSlashCommands extends BotListener { @@ -9,53 +8,6 @@ export default class CreateSlashCommands extends BotListener { }); } async exec(): Promise<void> { - try { - const registered = await this.client.application.commands.fetch(); - for (const [, registeredCommand] of registered) { - if ( - !this.client.commandHandler.modules.find( - (cmd) => cmd.id == registeredCommand.name - ) - ) { - await this.client.application.commands.delete(registeredCommand.id); - this.client.logger.verbose( - chalk`{red Deleted slash command ${registeredCommand.name}}` - ); - } - } - - for (const [, botCommand] of this.client.commandHandler.modules) { - if (botCommand.execSlash) { - const found = registered.find((i) => i.name == botCommand.id); - - const slashdata = { - name: botCommand.id, - description: botCommand.description.content, - options: botCommand.options.slashCommandOptions - }; - - if (found?.id) { - if (slashdata.description !== found.description) { - await this.client.application.commands.edit(found.id, slashdata); - this.client.logger.verbose( - chalk`{orange Edited slash command ${botCommand.id}}` - ); - } - } else { - await this.client.application.commands.create(slashdata); - this.client.logger.verbose( - chalk`{green Created slash command ${botCommand.id}}` - ); - } - } - } - - return this.client.logger.log(chalk.green('Slash commands registered')); - } catch (e) { - console.log(chalk.red(e)); - return this.client.logger.error( - chalk`{red Slash commands not registered, see above error.}` - ); - } + await this.client.util.syncSlashCommands(); } } diff --git a/src/listeners/commands/slashError.ts b/src/listeners/commands/slashError.ts new file mode 100644 index 0000000..3b174a3 --- /dev/null +++ b/src/listeners/commands/slashError.ts @@ -0,0 +1,48 @@ +import { BotCommand } from '../../lib/extensions/BotCommand'; +import { BotListener } from '../../lib/extensions/BotListener'; +import { stripIndents } from 'common-tags'; +import { MessageEmbed } from 'discord.js'; +import { TextChannel } from 'discord.js'; +import { CommandInteraction } from 'discord.js'; + +export default class CommandErrorListener extends BotListener { + constructor() { + super('slashError', { + emitter: 'commandHandler', + event: 'slashError' + }); + } + async exec( + error: Error, + message: CommandInteraction, + command: BotCommand + ): Promise<void> { + const errorNumber = Math.floor(Math.random() * 6969696969) + 69; // hehe funy numbers + const errorDevEmbed = this.client.util + .createEmbed(this.client.util.colors.error) + .setTitle(`Slash Error # \`${errorNumber}\`: An error occurred`) + .setDescription( + stripIndents`**User:** <@${message.user.id}> (${message.user.tag}) + **Slash Command:** ${command} + **Channel:** <#${message.channelID}> (${message.channelID}) + **Message:** [link](https://discord.com/${message.guildID}/${message.channelID}/${message.id})` + ) + .addField('Error', `${await this.client.util.haste(error.stack)}`); + let errorUserEmbed: MessageEmbed; + if (command) { + errorUserEmbed = this.client.util + .createEmbed(this.client.util.colors.error) + .setTitle('An error occurred') + .setDescription( + stripIndents`Whoops! It appears like something broke. + The developers have been notified of this. If you contact them, give them code \`${errorNumber}\`. + ` + ); + } + const channel = (await this.client.channels.fetch( + this.client.config.channels.log + )) as TextChannel; + await channel.send(errorDevEmbed); + if (errorUserEmbed) await message.reply(errorUserEmbed); + } +} @@ -37,10 +37,10 @@ combined-stream "^1.0.8" mime-types "^2.1.12" -"@eslint/eslintrc@^0.4.0": - version "0.4.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.0.tgz#99cc0a0584d72f1df38b900fb062ba995f395547" - integrity sha512-2ZPCc+uNbjV5ERJr+aKSPRwZgKd2z11x0EgLvb1PURmUrn9QNRXFqje0Ldq454PfAVyaJYyrDvvIKSFP4NnBog== +"@eslint/eslintrc@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-0.4.1.tgz#442763b88cecbe3ee0ec7ca6d6dd6168550cbf14" + integrity sha512-5v7TDE9plVhvxQeWLXDTvFvJBdH6pEsdnl2g/dAptmuFEPedQ4Erq5rsDsX+mvAM610IhNaO2W5V1dOOnDKxkQ== dependencies: ajv "^6.12.4" debug "^4.1.1" @@ -165,14 +165,14 @@ integrity sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw== "@types/node@*": - version "15.0.1" - resolved "https://registry.yarnpkg.com/@types/node/-/node-15.0.1.tgz#ef34dea0881028d11398be5bf4e856743e3dc35a" - integrity sha512-TMkXt0Ck1y0KKsGr9gJtWGjttxlZnnvDtphxUOSd0bfaR6Q1jle+sPvrzNR1urqYTWMinoKvjKfXUGsumaO1PA== + version "15.3.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.0.tgz#d6fed7d6bc6854306da3dea1af9f874b00783e26" + integrity sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ== "@types/node@^14.14.22": - version "14.14.43" - resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.43.tgz#26bcbb0595b305400e8ceaf9a127a7f905ae49c8" - integrity sha512-3pwDJjp1PWacPTpH0LcfhgjvurQvrZFBrC6xxjaUEZ7ifUtT32jtjPxEMMblpqd2Mvx+k8haqQJLQxolyGN/cQ== + version "14.14.45" + resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.45.tgz#ec2dfb5566ff814d061aef7e141575aedba245cf" + integrity sha512-DssMqTV9UnnoxDWu959sDLZzfvqCF0qDNRjaWeYSui9xkFe61kKo4l1TWNTQONpuXEm+gLMRvdlzvNHBamzmEw== "@types/qs@*": version "6.9.6" @@ -205,12 +205,12 @@ integrity sha512-eQ9qFW/fhfGJF8WKHGEHZEyVWfZxrT+6CLIJGBcZPfxUh/+BnEj+UCGYMlr9qZuX/2AltsvwrGqp0LhEW8D0zQ== "@typescript-eslint/eslint-plugin@^4.14.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.22.1.tgz#6bcdbaa4548553ab861b4e5f34936ead1349a543" - integrity sha512-kVTAghWDDhsvQ602tHBc6WmQkdaYbkcTwZu+7l24jtJiYvm9l+/y/b2BZANEezxPDiX5MK2ZecE+9BFi/YJryw== + version "4.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.23.0.tgz#29d3c9c81f6200b1fd6d8454cfb007ba176cde80" + integrity sha512-tGK1y3KIvdsQEEgq6xNn1DjiFJtl+wn8JJQiETtCbdQxw1vzjXyAaIkEmO2l6Nq24iy3uZBMFQjZ6ECf1QdgGw== dependencies: - "@typescript-eslint/experimental-utils" "4.22.1" - "@typescript-eslint/scope-manager" "4.22.1" + "@typescript-eslint/experimental-utils" "4.23.0" + "@typescript-eslint/scope-manager" "4.23.0" debug "^4.1.1" functional-red-black-tree "^1.0.1" lodash "^4.17.15" @@ -218,60 +218,60 @@ semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/experimental-utils@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.22.1.tgz#3938a5c89b27dc9a39b5de63a62ab1623ab27497" - integrity sha512-svYlHecSMCQGDO2qN1v477ax/IDQwWhc7PRBiwAdAMJE7GXk5stF4Z9R/8wbRkuX/5e9dHqbIWxjeOjckK3wLQ== +"@typescript-eslint/experimental-utils@4.23.0": + version "4.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.23.0.tgz#f2059434cd6e5672bfeab2fb03b7c0a20622266f" + integrity sha512-WAFNiTDnQfrF3Z2fQ05nmCgPsO5o790vOhmWKXbbYQTO9erE1/YsFot5/LnOUizLzU2eeuz6+U/81KV5/hFTGA== dependencies: "@types/json-schema" "^7.0.3" - "@typescript-eslint/scope-manager" "4.22.1" - "@typescript-eslint/types" "4.22.1" - "@typescript-eslint/typescript-estree" "4.22.1" + "@typescript-eslint/scope-manager" "4.23.0" + "@typescript-eslint/types" "4.23.0" + "@typescript-eslint/typescript-estree" "4.23.0" eslint-scope "^5.0.0" eslint-utils "^2.0.0" "@typescript-eslint/parser@^4.14.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.22.1.tgz#a95bda0fd01d994a15fc3e99dc984294f25c19cc" - integrity sha512-l+sUJFInWhuMxA6rtirzjooh8cM/AATAe3amvIkqKFeMzkn85V+eLzb1RyuXkHak4dLfYzOmF6DXPyflJvjQnw== + version "4.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.23.0.tgz#239315d38e42e852bef43a4b0b01bef78f78911c" + integrity sha512-wsvjksHBMOqySy/Pi2Q6UuIuHYbgAMwLczRl4YanEPKW5KVxI9ZzDYh3B5DtcZPQTGRWFJrfcbJ6L01Leybwug== dependencies: - "@typescript-eslint/scope-manager" "4.22.1" - "@typescript-eslint/types" "4.22.1" - "@typescript-eslint/typescript-estree" "4.22.1" + "@typescript-eslint/scope-manager" "4.23.0" + "@typescript-eslint/types" "4.23.0" + "@typescript-eslint/typescript-estree" "4.23.0" debug "^4.1.1" -"@typescript-eslint/scope-manager@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.22.1.tgz#5bb357f94f9cd8b94e6be43dd637eb73b8f355b4" - integrity sha512-d5bAiPBiessSmNi8Amq/RuLslvcumxLmyhf1/Xa9IuaoFJ0YtshlJKxhlbY7l2JdEk3wS0EnmnfeJWSvADOe0g== +"@typescript-eslint/scope-manager@4.23.0": + version "4.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.23.0.tgz#8792ef7eacac122e2ec8fa2d30a59b8d9a1f1ce4" + integrity sha512-ZZ21PCFxPhI3n0wuqEJK9omkw51wi2bmeKJvlRZPH5YFkcawKOuRMQMnI8mH6Vo0/DoHSeZJnHiIx84LmVQY+w== dependencies: - "@typescript-eslint/types" "4.22.1" - "@typescript-eslint/visitor-keys" "4.22.1" + "@typescript-eslint/types" "4.23.0" + "@typescript-eslint/visitor-keys" "4.23.0" -"@typescript-eslint/types@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.22.1.tgz#bf99c6cec0b4a23d53a61894816927f2adad856a" - integrity sha512-2HTkbkdAeI3OOcWbqA8hWf/7z9c6gkmnWNGz0dKSLYLWywUlkOAQ2XcjhlKLj5xBFDf8FgAOF5aQbnLRvgNbCw== +"@typescript-eslint/types@4.23.0": + version "4.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.23.0.tgz#da1654c8a5332f4d1645b2d9a1c64193cae3aa3b" + integrity sha512-oqkNWyG2SLS7uTWLZf6Sr7Dm02gA5yxiz1RP87tvsmDsguVATdpVguHr4HoGOcFOpCvx9vtCSCyQUGfzq28YCw== -"@typescript-eslint/typescript-estree@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.22.1.tgz#dca379eead8cdfd4edc04805e83af6d148c164f9" - integrity sha512-p3We0pAPacT+onSGM+sPR+M9CblVqdA9F1JEdIqRVlxK5Qth4ochXQgIyb9daBomyQKAXbygxp1aXQRV0GC79A== +"@typescript-eslint/typescript-estree@4.23.0": + version "4.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.23.0.tgz#0753b292097523852428a6f5a1aa8ccc1aae6cd9" + integrity sha512-5Sty6zPEVZF5fbvrZczfmLCOcby3sfrSPu30qKoY1U3mca5/jvU5cwsPb/CO6Q3ByRjixTMIVsDkqwIxCf/dMw== dependencies: - "@typescript-eslint/types" "4.22.1" - "@typescript-eslint/visitor-keys" "4.22.1" + "@typescript-eslint/types" "4.23.0" + "@typescript-eslint/visitor-keys" "4.23.0" debug "^4.1.1" globby "^11.0.1" is-glob "^4.0.1" semver "^7.3.2" tsutils "^3.17.1" -"@typescript-eslint/visitor-keys@4.22.1": - version "4.22.1" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.22.1.tgz#6045ae25a11662c671f90b3a403d682dfca0b7a6" - integrity sha512-WPkOrIRm+WCLZxXQHCi+WG8T2MMTUFR70rWjdWYddLT7cEfb2P4a3O/J2U1FBVsSFTocXLCoXWY6MZGejeStvQ== +"@typescript-eslint/visitor-keys@4.23.0": + version "4.23.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.23.0.tgz#7215cc977bd3b4ef22467b9023594e32f9e4e455" + integrity sha512-5PNe5cmX9pSifit0H+nPoQBXdbNzi5tOEec+3riK+ku4e3er37pKxMKDH5Ct5Y4fhWxcD4spnlYjxi9vXbSpwg== dependencies: - "@typescript-eslint/types" "4.22.1" + "@typescript-eslint/types" "4.23.0" eslint-visitor-keys "^2.0.0" abort-controller@^3.0.0: @@ -310,9 +310,9 @@ ajv@^6.10.0, ajv@^6.12.4: uri-js "^4.2.2" ajv@^8.0.1: - version "8.2.0" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.2.0.tgz#c89d3380a784ce81b2085f48811c4c101df4c602" - integrity sha512-WSNGFuyWd//XO8n/m/EaOlNLtO0yL8EXT/74LqT4khdhpZjP7lkj/kT5uwRmGitKEVp/Oj7ZUHeGfPtgHhQ5CA== + version "8.4.0" + resolved "https://registry.yarnpkg.com/ajv/-/ajv-8.4.0.tgz#48984fdb2ce225cab15795f0772a8d85669075e4" + integrity sha512-7QD2l6+KBSLwf+7MuYocbWvRPdOu63/trReTLu2KFwkgctnub1auoF+Y1WYcm09CTM7quuscrzqmASaLHC/K4Q== dependencies: fast-deep-equal "^3.1.1" json-schema-traverse "^1.0.0" @@ -599,8 +599,8 @@ dir-glob@^3.0.1: path-type "^4.0.0" discord-akairo@SkyBlockDev/discord-akairo: - version "8.1.1" - resolved "https://codeload.github.com/SkyBlockDev/discord-akairo/tar.gz/a1820abd0cb729db521dd7ff4b79ed8d5b3bf62c" + version "8.2.2" + resolved "https://codeload.github.com/SkyBlockDev/discord-akairo/tar.gz/f061db03014b1ef7ebdf118658c48fde482cd9a7" discord-api-types@^0.18.1: version "0.18.1" @@ -701,12 +701,12 @@ eslint-visitor-keys@^2.0.0: integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== eslint@^7.18.0: - version "7.25.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.25.0.tgz#1309e4404d94e676e3e831b3a3ad2b050031eb67" - integrity sha512-TVpSovpvCNpLURIScDRB6g5CYu/ZFq9GfX2hLNIV4dSBKxIWojeDODvYl3t0k0VtMxYeR8OXPCFE5+oHMlGfhw== + version "7.26.0" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.26.0.tgz#d416fdcdcb3236cd8f282065312813f8c13982f6" + integrity sha512-4R1ieRf52/izcZE7AlLy56uIHHDLT74Yzz2Iv2l6kDaYvEu9x+wMB5dZArVL8SYGXSYV2YAg70FcW5Y5nGGNIg== dependencies: "@babel/code-frame" "7.12.11" - "@eslint/eslintrc" "^0.4.0" + "@eslint/eslintrc" "^0.4.1" ajv "^6.10.0" chalk "^4.0.0" cross-spawn "^7.0.2" @@ -941,9 +941,9 @@ glob-parent@^5.0.0, glob-parent@^5.1.0: is-glob "^4.0.1" glob@^7.1.3: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== + version "7.1.7" + resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" inflight "^1.0.4" @@ -1178,11 +1178,6 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= -lodash.flatten@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.flatten/-/lodash.flatten-4.4.0.tgz#f31c22225a9632d2bbf8e4addbef240aa765a61f" - integrity sha1-8xwiIlqWMtK7+OSt2+8kCqdlph8= - lodash.truncate@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.truncate/-/lodash.truncate-4.4.2.tgz#5a350da0b1113b837ecfffd5812cbe58d6eae193" @@ -1473,9 +1468,9 @@ prelude-ls@^1.2.1: integrity sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g== prettier@^2.2.1: - version "2.2.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.2.1.tgz#795a1a78dd52f073da0cd42b21f9c91381923ff5" - integrity sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q== + version "2.3.0" + resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.3.0.tgz#b6a5bf1284026ae640f17f7ff5658a7567fc0d18" + integrity sha512-kXtO4s0Lz/DW/IJ9QdWhAf7/NmPWQXkFr/r/WkR3vyI+0v8amTDxiaQSLzs8NBlytfLWX/7uQUMIW677yLKl4w== prism-media@^1.2.2: version "1.2.9" @@ -1789,13 +1784,12 @@ supports-color@^7.1.0: has-flag "^4.0.0" table@^6.0.4: - version "6.6.0" - resolved "https://registry.yarnpkg.com/table/-/table-6.6.0.tgz#905654b79df98d9e9a973de1dd58682532c40e8e" - integrity sha512-iZMtp5tUvcnAdtHpZTWLPF0M7AgiQsURR2DwmxnJwSy8I3+cY+ozzVvYha3BOLG2TB+L0CqjIz+91htuj6yCXg== + version "6.7.1" + resolved "https://registry.yarnpkg.com/table/-/table-6.7.1.tgz#ee05592b7143831a8c94f3cee6aae4c1ccef33e2" + integrity sha512-ZGum47Yi6KOOFDE8m223td53ath2enHcYLgOCjGr5ngu8bdIARQk6mN/wRMv4yMRcHnCSnHbCEha4sobQx5yWg== dependencies: ajv "^8.0.1" lodash.clonedeep "^4.5.0" - lodash.flatten "^4.4.0" lodash.truncate "^4.4.2" slice-ansi "^4.0.0" string-width "^4.2.0" |