diff options
Diffstat (limited to 'src/commands')
-rw-r--r-- | src/commands/info/help.ts | 5 | ||||
-rw-r--r-- | src/commands/utilities/highlight-!.ts | 150 | ||||
-rw-r--r-- | src/commands/utilities/highlight-add.ts | 82 | ||||
-rw-r--r-- | src/commands/utilities/highlight-block.ts | 69 | ||||
-rw-r--r-- | src/commands/utilities/highlight-clear.ts | 39 | ||||
-rw-r--r-- | src/commands/utilities/highlight-matches.ts | 0 | ||||
-rw-r--r-- | src/commands/utilities/highlight-remove.ts | 57 | ||||
-rw-r--r-- | src/commands/utilities/highlight-show.ts | 34 | ||||
-rw-r--r-- | src/commands/utilities/highlight-unblock.ts | 69 |
9 files changed, 504 insertions, 1 deletions
diff --git a/src/commands/info/help.ts b/src/commands/info/help.ts index e31153b..2383566 100644 --- a/src/commands/info/help.ts +++ b/src/commands/info/help.ts @@ -77,7 +77,10 @@ export default class HelpCommand extends BushCommand { if (command.channel == 'guild' && !message.guild && !args.showHidden) return false; if (command.ownerOnly && !isOwner) return false; if (command.superUserOnly && !isSuperUser) return false; - return !(command.restrictedGuilds?.includes(message.guild?.id ?? '') === false && !args.showHidden); + if (command.restrictedGuilds?.includes(message.guild?.id ?? '') === false && !args.showHidden) return false; + if (command.aliases.length === 0) return false; + + return true; }); const categoryNice = category.id .replace(/(\b\w)/gi, (lc) => lc.toUpperCase()) diff --git a/src/commands/utilities/highlight-!.ts b/src/commands/utilities/highlight-!.ts new file mode 100644 index 0000000..332af03 --- /dev/null +++ b/src/commands/utilities/highlight-!.ts @@ -0,0 +1,150 @@ +import { BushCommand, Highlight, HighlightWord, type BushSlashMessage } from '#lib'; +import { Flag, type ArgumentGeneratorReturn, type SlashOption } from 'discord-akairo'; +import { ApplicationCommandOptionType } from 'discord-api-types'; +import { ApplicationCommandSubCommandData, AutocompleteInteraction, CacheType } from 'discord.js'; + +type Unpacked<T> = T extends (infer U)[] ? U : T; + +export const highlightCommandArgs: { + [Command in keyof typeof highlightSubcommands]: (Unpacked<Required<ApplicationCommandSubCommandData['options']>> & { + retry?: string; + })[]; +} = { + add: [ + { + name: 'word', + description: 'What word do you want to highlight?', + retry: '{error} Enter a valid word.', + type: ApplicationCommandOptionType.String, + required: true + }, + { + name: 'regex', + description: 'Should the word be matched using regular expression?', + type: ApplicationCommandOptionType.Boolean, + required: false + } + ], + remove: [ + { + name: 'word', + description: 'Which word do you want to stop highlighting?', + retry: '{error} Enter a valid word.', + type: ApplicationCommandOptionType.String, + required: true, + autocomplete: true + } + ], + block: [ + { + name: 'target', + description: 'What user/channel would you like to prevent from triggering your highlights?', + retry: '{error} Enter a valid user or channel.', + type: ApplicationCommandOptionType.Mentionable, + required: true + } + ], + unblock: [ + { + name: 'target', + description: 'What user/channel would you like to allow triggering your highlights again?', + retry: '{error} Enter a valid user or channel.', + type: ApplicationCommandOptionType.Mentionable, + required: true + } + ], + show: [], + clear: [], + matches: [ + { + name: 'phrase', + description: 'What phrase would you like to test your highlighted words against?', + retry: '{error} Enter a valid phrase to test.', + type: ApplicationCommandOptionType.String, + required: true + } + ] +}; + +export const highlightSubcommands = { + add: 'Add a word to highlight.', + remove: 'Stop highting a word.', + block: 'Block a user or channel from triggering your highlights.', + unblock: 'Re-allow a user or channel to triggering your highlights.', + show: 'List all your current highlighted words.', + clear: 'Remove all of your highlighted words.', + matches: 'Test a phrase to see if it matches your current highlighted words.' +} as const; + +export default class HighlightCommand extends BushCommand { + public constructor() { + super('highlight', { + aliases: ['highlight', 'hl'], + category: 'utilities', + description: 'Command description.', + usage: ['template <requiredArg> [optionalArg]'], + examples: ['template 1 2'], + slashOptions: Object.entries(highlightSubcommands).map((args) => { + // typescript being annoying + const [subcommand, description] = args as [keyof typeof highlightSubcommands, typeof args[1]]; + + return { + name: subcommand, + description, + type: ApplicationCommandOptionType.Subcommand, + options: highlightCommandArgs[subcommand].map((arg) => ({ + name: arg.name, + description: arg.description, + type: arg.type, + required: arg.required, + autocomplete: arg.autocomplete + })) + } as SlashOption; + }), + slash: true, + channel: 'guild', + clientPermissions: (m) => util.clientSendAndPermCheck(m), + userPermissions: [], + ownerOnly: true + }); + } + + public override *args(): ArgumentGeneratorReturn { + const subcommand: keyof typeof highlightSubcommands = yield { + id: 'subcommand', + type: Object.keys(highlightSubcommands), + prompt: { + start: 'What sub command would you like to use?', + retry: `{error} Valid subcommands are: ${Object.keys(highlightSubcommands) + .map((s) => `\`${s}\``) + .join()}.` + } + }; + + return Flag.continue(`highlight-${subcommand}`); + } + + public override async execSlash(message: BushSlashMessage, args: { subcommand: keyof typeof highlightSubcommands }) { + // manual `Flag.continue` + const subcommand = this.handler.modules.get(`highlight-${args.subcommand}`)!; + return subcommand.exec(message, args); + } + + public override async autocomplete(interaction: AutocompleteInteraction<CacheType>) { + if (!interaction.inCachedGuild()) + return interaction.respond([{ name: 'You must be in a server to use this command.', value: 'error' }]); + + switch (interaction.options.getSubcommand(true)) { + case 'word': { + const { words } = (await Highlight.findOne({ + where: { + guild: interaction.guild.id, + user: interaction.user.id + } + })) ?? { words: [] as HighlightWord[] }; + if (!words.length) return interaction.respond([]); + return interaction.respond(words.map((w) => ({ name: w.word, value: w.word }))); + } + } + } +} diff --git a/src/commands/utilities/highlight-add.ts b/src/commands/utilities/highlight-add.ts new file mode 100644 index 0000000..ec5443c --- /dev/null +++ b/src/commands/utilities/highlight-add.ts @@ -0,0 +1,82 @@ +import { AllowedMentions, BushCommand, Highlight, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; +import assert from 'assert'; +import { ArgumentGeneratorReturn } from 'discord-akairo'; +import { highlightCommandArgs, highlightSubcommands } from './highlight-!'; + +export default class HighlightAddCommand extends BushCommand { + public constructor() { + super('highlight-add', { + aliases: [], + category: 'utilities', + description: highlightSubcommands.add, + usage: [], + examples: [], + clientPermissions: [], + userPermissions: [] + }); + } + + public override *args(): ArgumentGeneratorReturn { + const word: ArgType<'string'> = yield { + type: 'string', + match: 'rest', + prompt: { + start: highlightCommandArgs.add[0].description, + retry: highlightCommandArgs.add[0].retry, + optional: !highlightCommandArgs.add[0].required + } + }; + + const regex: boolean = yield { + match: 'flag', + flag: 'regex' + }; + + return { word, regex }; + } + + public override async exec( + message: BushMessage | BushSlashMessage, + args: { word: ArgType<'string'>; regex: ArgType<'boolean'> } + ) { + assert(message.inGuild()); + + if (!args.regex) { + if (args.word.length < 2) + return message.util.send(`${util.emojis.error} You can only highlight words that are longer than 2 characters.`); + if (args.word.length > 50) + return await message.util.reply(`${util.emojis.error} You can only highlight words that are shorter than 50 characters.`); + } else { + try { + new RegExp(args.word); + } catch (e) { + assert(e instanceof SyntaxError); + return message.util.send({ + content: `${util.emojis.error} Invalid regex ${util.format.inlineCode(e.message)}.`, + allowedMentions: AllowedMentions.none() + }); + } + } + + const [highlight] = await Highlight.findOrCreate({ + where: { + guild: message.guild.id, + user: message.author.id + } + }); + + if (highlight.words.some((w) => w.word === args.word)) + return await message.util.reply({ + content: `${util.emojis.error} You have already highlighted "${args.word}".`, + allowedMentions: AllowedMentions.none() + }); + + highlight.words = util.addToArray(highlight.words, { word: args.word, regex: args.regex }); + await highlight.save(); + + return await message.util.reply({ + content: `${util.emojis.success} Successfully added "${args.word}" to your highlight list.`, + allowedMentions: AllowedMentions.none() + }); + } +} diff --git a/src/commands/utilities/highlight-block.ts b/src/commands/utilities/highlight-block.ts new file mode 100644 index 0000000..5a18b8a --- /dev/null +++ b/src/commands/utilities/highlight-block.ts @@ -0,0 +1,69 @@ +import { AllowedMentions, BushCommand, Highlight, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; +import assert from 'assert'; +import { Argument, ArgumentGeneratorReturn } from 'discord-akairo'; +import { Channel, GuildMember } from 'discord.js'; +import { highlightCommandArgs, highlightSubcommands } from './highlight-!'; + +export default class HighlightBlockCommand extends BushCommand { + public constructor() { + super('highlight-block', { + aliases: [], + category: 'utilities', + description: highlightSubcommands.block, + usage: [], + examples: [], + clientPermissions: [], + userPermissions: [] + }); + } + + public override *args(): ArgumentGeneratorReturn { + const target: ArgType<'member'> | ArgType<'channel'> = yield { + type: Argument.union('member', 'channel'), + match: 'rest', + prompt: { + start: highlightCommandArgs.block[0].description, + retry: highlightCommandArgs.block[0].retry, + optional: !highlightCommandArgs.block[0].required + } + }; + + return { target }; + } + + public override async exec( + message: BushMessage | BushSlashMessage, + args: { target: ArgType<'user'> | ArgType<'role'> | ArgType<'member'> } + ) { + assert(message.inGuild()); + + if (!(args.target instanceof GuildMember || args.target instanceof Channel)) + return await message.util.reply(`${util.emojis.error} You can only block users or channels.`); + + if (args.target instanceof Channel && !args.target.isTextBased()) + return await message.util.reply(`${util.emojis.error} You can only block text-based channels.`); + + const [highlight] = await Highlight.findOrCreate({ + where: { + guild: message.guild.id, + user: message.author.id + } + }); + + const key = `blacklisted${args.target instanceof Channel ? 'Channels' : 'Users'}` as const; + + if (highlight[key].includes(args.target.id)) + return await message.util.reply({ + content: `${util.emojis.error} You have already blocked ${args.target}.`, + allowedMentions: AllowedMentions.none() + }); + + highlight[key] = util.addToArray(highlight[key], args.target.id); + await highlight.save(); + + return await message.util.reply({ + content: `${util.emojis.success} Successfully blocked ${args.target} from triggering your highlights.`, + allowedMentions: AllowedMentions.none() + }); + } +} diff --git a/src/commands/utilities/highlight-clear.ts b/src/commands/utilities/highlight-clear.ts new file mode 100644 index 0000000..aded467 --- /dev/null +++ b/src/commands/utilities/highlight-clear.ts @@ -0,0 +1,39 @@ +import { AllowedMentions, BushCommand, ConfirmationPrompt, Highlight, type BushMessage, type BushSlashMessage } from '#lib'; +import assert from 'assert'; +import { highlightSubcommands } from './highlight-!'; + +export default class HighlightClearCommand extends BushCommand { + public constructor() { + super('highlight-clear', { + aliases: [], + category: 'utilities', + description: highlightSubcommands.clear, + usage: [], + examples: [], + clientPermissions: [], + userPermissions: [] + }); + } + + public override async exec(message: BushMessage | BushSlashMessage) { + assert(message.inGuild()); + + const [highlight] = await Highlight.findOrCreate({ + where: { + guild: message.guild.id, + user: message.author.id + } + }); + + const confirm = await ConfirmationPrompt.send(message, { content: `Are you sure you want to clear your highlight list?` }); + if (!confirm) return await message.util.reply(`${util.emojis.warn} You decided not to clear your highlight list.`); + + highlight.words = []; + await highlight.save(); + + return await message.util.reply({ + content: `${util.emojis.success} Successfully cleared your highlight list.`, + allowedMentions: AllowedMentions.none() + }); + } +} diff --git a/src/commands/utilities/highlight-matches.ts b/src/commands/utilities/highlight-matches.ts new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/commands/utilities/highlight-matches.ts diff --git a/src/commands/utilities/highlight-remove.ts b/src/commands/utilities/highlight-remove.ts new file mode 100644 index 0000000..0432a16 --- /dev/null +++ b/src/commands/utilities/highlight-remove.ts @@ -0,0 +1,57 @@ +import { AllowedMentions, BushCommand, Highlight, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; +import assert from 'assert'; +import { ArgumentGeneratorReturn } from 'discord-akairo'; +import { highlightCommandArgs, highlightSubcommands } from './highlight-!'; + +export default class HighlightRemoveCommand extends BushCommand { + public constructor() { + super('highlight-remove', { + aliases: [], + category: 'utilities', + description: highlightSubcommands.remove, + usage: [], + examples: [], + clientPermissions: [], + userPermissions: [] + }); + } + + public override *args(): ArgumentGeneratorReturn { + const word: ArgType<'string'> = yield { + type: 'string', + match: 'rest', + prompt: { + start: highlightCommandArgs.remove[0].description, + retry: highlightCommandArgs.remove[0].retry, + optional: !highlightCommandArgs.remove[0].required + } + }; + + return { word }; + } + + public override async exec(message: BushMessage | BushSlashMessage, args: { word: ArgType<'string'> }) { + assert(message.inGuild()); + + const [highlight] = await Highlight.findOrCreate({ + where: { + guild: message.guild.id, + user: message.author.id + } + }); + + if (!highlight.words.some((w) => w.word === args.word)) + return await message.util.reply({ + content: `${util.emojis.error} You have not highlighted "${args.word}".`, + allowedMentions: AllowedMentions.none() + }); + + highlight.words = util.removeFromArray(highlight.words, highlight.words.find((w) => w.word === args.word)!); + await highlight.save(); + + return await message.util.reply({ + content: `${util.emojis.success} Successfully removed "${args.word}" from your highlight list.`, + allowedMentions: AllowedMentions.none() + }); + } +} diff --git a/src/commands/utilities/highlight-show.ts b/src/commands/utilities/highlight-show.ts new file mode 100644 index 0000000..ab7c0c5 --- /dev/null +++ b/src/commands/utilities/highlight-show.ts @@ -0,0 +1,34 @@ +import { AllowedMentions, BushCommand, Highlight, type BushMessage, type BushSlashMessage } from '#lib'; +import assert from 'assert'; +import { Embed } from 'discord.js'; +import { highlightSubcommands } from './highlight-!'; + +export default class HighlightShowCommand extends BushCommand { + public constructor() { + super('highlight-show', { + aliases: [], + category: 'utilities', + description: highlightSubcommands.show, + usage: [], + examples: [], + clientPermissions: [], + userPermissions: [] + }); + } + + public override async exec(message: BushMessage | BushSlashMessage) { + assert(message.inGuild()); + + const [highlight] = await Highlight.findOrCreate({ + where: { + guild: message.guild.id, + user: message.author.id + } + }); + + return await message.util.reply({ + embeds: [new Embed().setTitle('Highlight List').setDescription(highlight.words.join('\n')).setColor(util.colors.default)], + allowedMentions: AllowedMentions.none() + }); + } +} diff --git a/src/commands/utilities/highlight-unblock.ts b/src/commands/utilities/highlight-unblock.ts new file mode 100644 index 0000000..7e5c0fb --- /dev/null +++ b/src/commands/utilities/highlight-unblock.ts @@ -0,0 +1,69 @@ +import { AllowedMentions, BushCommand, Highlight, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; +import assert from 'assert'; +import { Argument, ArgumentGeneratorReturn } from 'discord-akairo'; +import { Channel, GuildMember } from 'discord.js'; +import { highlightCommandArgs, highlightSubcommands } from './highlight-!'; + +export default class HighlightUnblockCommand extends BushCommand { + public constructor() { + super('highlight-unblock', { + aliases: [], + category: 'utilities', + description: highlightSubcommands.unblock, + usage: [], + examples: [], + clientPermissions: [], + userPermissions: [] + }); + } + + public override *args(): ArgumentGeneratorReturn { + const target: ArgType<'member'> | ArgType<'channel'> = yield { + type: Argument.union('member', 'channel'), + match: 'rest', + prompt: { + start: highlightCommandArgs.unblock[0].description, + retry: highlightCommandArgs.unblock[0].retry, + optional: !highlightCommandArgs.unblock[0].required + } + }; + + return { target }; + } + + public override async exec( + message: BushMessage | BushSlashMessage, + args: { target: ArgType<'user'> | ArgType<'role'> | ArgType<'member'> } + ) { + assert(message.inGuild()); + + if (!(args.target instanceof GuildMember || args.target instanceof Channel)) + return await message.util.reply(`${util.emojis.error} You can only unblock users or channels.`); + + if (args.target instanceof Channel && !args.target.isTextBased()) + return await message.util.reply(`${util.emojis.error} You can only unblock text-based channels.`); + + const [highlight] = await Highlight.findOrCreate({ + where: { + guild: message.guild.id, + user: message.author.id + } + }); + + const key = `blacklisted${args.target instanceof Channel ? 'Channels' : 'Users'}` as const; + + if (!highlight[key].includes(args.target.id)) + return await message.util.reply({ + content: `${util.emojis.error} ${args.target} is not blocked so cannot be unblock.`, + allowedMentions: AllowedMentions.none() + }); + + highlight[key] = util.removeFromArray(highlight[key], args.target.id); + await highlight.save(); + + return await message.util.reply({ + content: `${util.emojis.success} Successfully blocked ${args.target} from triggering your highlights.`, + allowedMentions: AllowedMentions.none() + }); + } +} |