aboutsummaryrefslogtreecommitdiff
path: root/src/commands
diff options
context:
space:
mode:
Diffstat (limited to 'src/commands')
-rw-r--r--src/commands/info/help.ts5
-rw-r--r--src/commands/utilities/highlight-!.ts150
-rw-r--r--src/commands/utilities/highlight-add.ts82
-rw-r--r--src/commands/utilities/highlight-block.ts69
-rw-r--r--src/commands/utilities/highlight-clear.ts39
-rw-r--r--src/commands/utilities/highlight-matches.ts0
-rw-r--r--src/commands/utilities/highlight-remove.ts57
-rw-r--r--src/commands/utilities/highlight-show.ts34
-rw-r--r--src/commands/utilities/highlight-unblock.ts69
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()
+ });
+ }
+}