diff options
author | IRONM00N <64110067+IRONM00N@users.noreply.github.com> | 2022-02-23 21:38:40 -0500 |
---|---|---|
committer | IRONM00N <64110067+IRONM00N@users.noreply.github.com> | 2022-02-23 21:38:40 -0500 |
commit | 084a815f3799764d2dd697e8c693c7f80e0c7ab7 (patch) | |
tree | 7c62c41824d8ab25a67fe35016b6514744d33402 /src | |
parent | d64563e89034b8e016d1b0a24e2b44280900b14c (diff) | |
download | tanzanite-084a815f3799764d2dd697e8c693c7f80e0c7ab7.tar.gz tanzanite-084a815f3799764d2dd697e8c693c7f80e0c7ab7.tar.bz2 tanzanite-084a815f3799764d2dd697e8c693c7f80e0c7ab7.zip |
feat(hl): make functional, no cool downs yet, restrcited to su
Diffstat (limited to 'src')
-rw-r--r-- | src/commands/utilities/highlight-!.ts | 6 | ||||
-rw-r--r-- | src/commands/utilities/highlight-add.ts | 61 | ||||
-rw-r--r-- | src/commands/utilities/highlight-block.ts | 11 | ||||
-rw-r--r-- | src/commands/utilities/highlight-clear.ts | 13 | ||||
-rw-r--r-- | src/commands/utilities/highlight-matches.ts | 56 | ||||
-rw-r--r-- | src/commands/utilities/highlight-remove.ts | 46 | ||||
-rw-r--r-- | src/commands/utilities/highlight-show.ts | 33 | ||||
-rw-r--r-- | src/lib/common/HighlightManager.ts | 192 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClient.ts | 1 | ||||
-rw-r--r-- | src/lib/models/instance/Guild.ts | 5 | ||||
-rw-r--r-- | src/listeners/message/highlight.ts | 9 |
11 files changed, 340 insertions, 93 deletions
diff --git a/src/commands/utilities/highlight-!.ts b/src/commands/utilities/highlight-!.ts index 687990f..dd6da8d 100644 --- a/src/commands/utilities/highlight-!.ts +++ b/src/commands/utilities/highlight-!.ts @@ -40,7 +40,7 @@ export const highlightCommandArgs: { 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, + type: ApplicationCommandOptionType.String, required: true } ], @@ -49,7 +49,7 @@ export const highlightCommandArgs: { 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, + type: ApplicationCommandOptionType.String, required: true } ], @@ -105,7 +105,7 @@ export default class HighlightCommand extends BushCommand { channel: 'guild', clientPermissions: (m) => util.clientSendAndPermCheck(m), userPermissions: [], - ownerOnly: true + superUserOnly: true }); } diff --git a/src/commands/utilities/highlight-add.ts b/src/commands/utilities/highlight-add.ts index 316a931..9c7506e 100644 --- a/src/commands/utilities/highlight-add.ts +++ b/src/commands/utilities/highlight-add.ts @@ -1,6 +1,5 @@ -import { AllowedMentions, BushCommand, Highlight, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; +import { AllowedMentions, BushCommand, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; import assert from 'assert'; -import { ArgumentGeneratorReturn } from 'discord-akairo'; import { highlightCommandArgs, highlightSubcommands } from './highlight-!.js'; export default class HighlightAddCommand extends BushCommand { @@ -9,6 +8,28 @@ export default class HighlightAddCommand extends BushCommand { aliases: [], category: 'utilities', description: highlightSubcommands.add, + args: [ + { + id: 'word', + description: highlightCommandArgs.add[0].description, + type: 'string', + match: 'rest', + prompt: highlightCommandArgs.add[0].description, + retry: highlightCommandArgs.add[0].retry, + optional: !highlightCommandArgs.add[0].required, + only: 'text', + slashType: false + }, + { + id: 'regex', + description: highlightCommandArgs.add[1].description, + match: 'flag', + flag: '--regex', + prompt: highlightCommandArgs.add[1].description, + only: 'text', + slashType: false + } + ], usage: [], examples: [], clientPermissions: [], @@ -16,25 +37,6 @@ export default class HighlightAddCommand extends BushCommand { }); } - 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'> } @@ -58,22 +60,19 @@ export default class HighlightAddCommand extends BushCommand { } } - const [highlight] = await Highlight.findOrCreate({ - where: { - guild: message.guild.id, - user: message.author.id - } + const res = await client.highlightManager.addHighlight(message.guild.id, message.author.id, { + word: args.word, + regex: args.regex }); - if (highlight.words.some((w) => w.word === args.word)) + if (typeof res === 'string') + return await message.util.reply({ content: `${util.emojis.error} ${res}`, allowedMentions: AllowedMentions.none() }); + else if (!res) return await message.util.reply({ - content: `${util.emojis.error} You have already highlighted "${args.word}".`, + content: `${util.emojis.error} There was an error highlighting "${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 index f546958..efc5437 100644 --- a/src/commands/utilities/highlight-block.ts +++ b/src/commands/utilities/highlight-block.ts @@ -33,11 +33,16 @@ export default class HighlightBlockCommand extends BushCommand { public override async exec( message: BushMessage | BushSlashMessage, - args: { target: ArgType<'user'> | ArgType<'role'> | ArgType<'member'> } + args: { target: string | ArgType<'member'> | ArgType<'channel'> } ) { assert(message.inGuild()); - if (!(args.target instanceof GuildMember || args.target instanceof Channel)) + args.target = + typeof args.target === 'string' + ? (await util.arg.cast(util.arg.union('member', 'channel'), message, args.target))! + : args.target; + + if (!args.target || !(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()) @@ -54,6 +59,7 @@ export default class HighlightBlockCommand extends BushCommand { if (highlight[key].includes(args.target.id)) return await message.util.reply({ + // eslint-disable-next-line @typescript-eslint/no-base-to-string content: `${util.emojis.error} You have already blocked ${args.target}.`, allowedMentions: AllowedMentions.none() }); @@ -62,6 +68,7 @@ export default class HighlightBlockCommand extends BushCommand { await highlight.save(); return await message.util.reply({ + // eslint-disable-next-line @typescript-eslint/no-base-to-string 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 index e1cce2d..33893b9 100644 --- a/src/commands/utilities/highlight-clear.ts +++ b/src/commands/utilities/highlight-clear.ts @@ -1,4 +1,4 @@ -import { AllowedMentions, BushCommand, ConfirmationPrompt, Highlight, type BushMessage, type BushSlashMessage } from '#lib'; +import { AllowedMentions, BushCommand, ConfirmationPrompt, type BushMessage, type BushSlashMessage } from '#lib'; import assert from 'assert'; import { highlightSubcommands } from './highlight-!.js'; @@ -18,18 +18,13 @@ export default class HighlightClearCommand extends BushCommand { public override async exec(message: BushMessage | BushSlashMessage) { assert(message.inGuild()); - const [highlight] = await Highlight.findOrCreate({ - where: { - guild: message.guild.id, - user: message.author.id - } - }); + if (message.util.isSlashMessage(message)) await message.interaction.deferReply(); 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(); + const success = await client.highlightManager.removeAllHighlights(message.author.id, message.guild.id); + if (!success) return await message.util.reply(`${util.emojis.error} There was an error clearing your highlight list.`); return await message.util.reply({ content: `${util.emojis.success} Successfully cleared your highlight list.`, diff --git a/src/commands/utilities/highlight-matches.ts b/src/commands/utilities/highlight-matches.ts index e69de29..aa8308c 100644 --- a/src/commands/utilities/highlight-matches.ts +++ b/src/commands/utilities/highlight-matches.ts @@ -0,0 +1,56 @@ +import { BushCommand, ButtonPaginator, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; +import assert from 'assert'; +import { ArgumentGeneratorReturn } from 'discord-akairo'; +import { APIEmbed } from 'discord-api-types/v9'; +import { highlightCommandArgs, highlightSubcommands } from './highlight-!.js'; + +export default class HighlightMatchesCommand extends BushCommand { + public constructor() { + super('highlight-matches', { + aliases: [], + category: 'utilities', + description: highlightSubcommands.matches, + usage: [], + examples: [], + clientPermissions: [], + userPermissions: [] + }); + } + + public override *args(): ArgumentGeneratorReturn { + const phrase: ArgType<'string'> = yield { + type: 'string', + match: 'rest', + prompt: { + start: highlightCommandArgs.matches[0].description, + retry: highlightCommandArgs.matches[0].retry, + optional: !highlightCommandArgs.matches[0].required + } + }; + + return { phrase }; + } + + public override async exec(message: BushMessage | BushSlashMessage, args: { phrase: ArgType<'string'> }) { + assert(message.inGuild()); + + const res = await client.highlightManager.checkPhrase(message.guild.id, message.author.id, args.phrase); + + if (!res.size) return await message.util.reply(`${util.emojis.error} You are not highlighting any words`); + + const lines = res.map( + (passed, hl) => `${passed ? util.emojis.check : util.emojis.cross} ${hl.regex ? `/${hl.word}/gi` : hl.word}` + ); + const chunked = util.chunk(lines, 10); + + const pages = chunked.map( + (chunk): APIEmbed => ({ + title: `Matches`, + description: chunk.join('\n'), + color: util.colors.default + }) + ); + + return pages.length > 1 ? await ButtonPaginator.send(message, pages) : message.util.send({ embeds: pages }); + } +} diff --git a/src/commands/utilities/highlight-remove.ts b/src/commands/utilities/highlight-remove.ts index 1f7c4c0..7e8c416 100644 --- a/src/commands/utilities/highlight-remove.ts +++ b/src/commands/utilities/highlight-remove.ts @@ -1,6 +1,5 @@ -import { AllowedMentions, BushCommand, Highlight, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; +import { AllowedMentions, BushCommand, type ArgType, type BushMessage, type BushSlashMessage } from '#lib'; import assert from 'assert'; -import { ArgumentGeneratorReturn } from 'discord-akairo'; import { highlightCommandArgs, highlightSubcommands } from './highlight-!.js'; export default class HighlightRemoveCommand extends BushCommand { @@ -9,6 +8,19 @@ export default class HighlightRemoveCommand extends BushCommand { aliases: [], category: 'utilities', description: highlightSubcommands.remove, + args: [ + { + id: 'word', + description: highlightCommandArgs.remove[0].description, + type: 'string', + match: 'rest', + prompt: highlightCommandArgs.remove[0].description, + retry: highlightCommandArgs.remove[0].retry, + optional: !highlightCommandArgs.remove[0].required, + only: 'text', + slashType: false + } + ], usage: [], examples: [], clientPermissions: [], @@ -16,39 +28,19 @@ export default class HighlightRemoveCommand extends BushCommand { }); } - 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 - } - }); + const res = await client.highlightManager.removeHighlight(message.guild.id, message.author.id, args.word); - if (!highlight.words.some((w) => w.word === args.word)) + if (typeof res === 'string') + return await message.util.reply({ content: `${util.emojis.error} ${res}`, allowedMentions: AllowedMentions.none() }); + else if (!res) return await message.util.reply({ - content: `${util.emojis.error} You have not highlighted "${args.word}".`, + content: `${util.emojis.error} There was an error unhighlighting "${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 index b9f414f..c3c6723 100644 --- a/src/commands/utilities/highlight-show.ts +++ b/src/commands/utilities/highlight-show.ts @@ -26,8 +26,39 @@ export default class HighlightShowCommand extends BushCommand { } }); + if (!highlight.words.length) return message.util.reply(`${util.emojis.error} You are not highlighting any words.`); + + const embed = new Embed() + .setTitle('Highlight List') + .setDescription( + highlight.words + .map((hl) => (hl.regex ? `/${hl.word}/gi` : hl.word)) + .join('\n') + .substring(0, 4096) + ) + .setColor(util.colors.default); + + if (highlight.blacklistedChannels.length) + embed.addField({ + name: 'Ignored Channels', + value: highlight.blacklistedChannels + .map((c) => `<#${c}>`) + .join('\n') + .substring(0, 1024), + inline: true + }); + if (highlight.blacklistedUsers.length) + embed.addField({ + name: 'Ignored Users', + value: highlight.blacklistedUsers + .map((u) => `<@!${u}>`) + .join('\n') + .substring(0, 1024), + inline: true + }); + return await message.util.reply({ - embeds: [new Embed().setTitle('Highlight List').setDescription(highlight.words.join('\n')).setColor(util.colors.default)], + embeds: [embed], allowedMentions: AllowedMentions.none() }); } diff --git a/src/lib/common/HighlightManager.ts b/src/lib/common/HighlightManager.ts index a74ce9e..6194255 100644 --- a/src/lib/common/HighlightManager.ts +++ b/src/lib/common/HighlightManager.ts @@ -1,19 +1,48 @@ import { Highlight, type BushMessage, type HighlightWord } from '#lib'; -import type { Snowflake } from 'discord.js'; +import assert from 'assert'; +import { Collection, type Snowflake } from 'discord.js'; export class HighlightManager { - public cachedHighlights: Map</* guild */ Snowflake, Map</* word */ HighlightWord, /* users */ Set<Snowflake>>> = new Map(); - public userLastTalkedCooldown = new Map<Snowflake, Map<Snowflake, Date>>(); - public lastedDMedUserCooldown = new Map</* user */ Snowflake, /* last dm */ Date>(); + /** + * Cached highlights: guildId -> word -> userId + */ + public readonly cachedHighlights = new Collection< + /* guild */ Snowflake, + Collection</* word */ HighlightWord, /* users */ Set<Snowflake>> + >(); - public async syncCache() { + /** + * A collection of cooldowns of when a user last sent a message in a particular guild. + */ + public readonly userLastTalkedCooldown = new Collection< + /* guild */ Snowflake, + Collection</* user */ Snowflake, /* last message */ Date> + >(); + + /** + * Users that users have blocked + */ + public readonly userBlocks = new Collection< + /* guild */ Snowflake, + Collection</* word */ Snowflake, /* users */ Set<Snowflake>> + >(); + + /** + * A collection of cooldowns of when the bot last sent each user a highlight message. + */ + public readonly lastedDMedUserCooldown = new Collection</* user */ Snowflake, /* last dm */ Date>(); + + /** + * Sync the cache with the database. + */ + public async syncCache(): Promise<void> { const highlights = await Highlight.findAll(); this.cachedHighlights.clear(); for (const highlight of highlights) { highlight.words.forEach((word) => { - if (!this.cachedHighlights.has(highlight.guild)) this.cachedHighlights.set(highlight.guild, new Map()); + if (!this.cachedHighlights.has(highlight.guild)) this.cachedHighlights.set(highlight.guild, new Collection()); const guildCache = this.cachedHighlights.get(highlight.guild)!; if (!guildCache.get(word)) guildCache.set(word, new Set()); guildCache.get(word)!.add(highlight.user); @@ -21,9 +50,14 @@ export class HighlightManager { } } - public checkMessage(message: BushMessage): Map<Snowflake, string> { + /** + * Checks a message for highlights. + * @param message The message to check. + * @returns A collection users mapped to the highlight matched + */ + public checkMessage(message: BushMessage): Collection<Snowflake, HighlightWord> { // even if there are multiple matches, only the first one is returned - const ret = new Map<Snowflake, string>(); + const ret = new Collection<Snowflake, HighlightWord>(); if (!message.content || !message.inGuild()) return ret; if (!this.cachedHighlights.has(message.guildId)) return ret; @@ -32,7 +66,7 @@ export class HighlightManager { for (const [word, users] of guildCache.entries()) { if (this.isMatch(message.content, word)) { for (const user of users) { - if (!ret.has(user)) ret.set(user, word.word); + if (!ret.has(user)) ret.set(user, word); } } } @@ -40,32 +74,150 @@ export class HighlightManager { return ret; } - public async checkPhraseForUser(guild: Snowflake, user: Snowflake, phrase: string): Promise<Map<string, boolean>> { + /** + * Checks a user provided phrase for their highlights. + * @param guild The guild to check in. + * @param user The user to get the highlights for. + * @param phrase The phrase for highlights in. + * @returns A collection of the user's highlights mapped to weather or not it was matched. + */ + public async checkPhrase(guild: Snowflake, user: Snowflake, phrase: string): Promise<Collection<HighlightWord, boolean>> { const highlights = await Highlight.findAll({ where: { guild, user } }); - const results = new Map<string, boolean>(); + const results = new Collection<HighlightWord, boolean>(); for (const highlight of highlights) { for (const word of highlight.words) { - if (this.isMatch(phrase, word)) { - results.set(word.word, true); - } + results.set(word, this.isMatch(phrase, word)); } } return results; } - private isMatch(phrase: string, word: HighlightWord) { - if (word.regex) { - return new RegExp(word.word, 'gi').test(phrase); + /** + * Checks a particular highlight for a match within a phrase. + * @param phrase The phrase to check for the word in. + * @param hl The highlight to check for. + * @returns Whether or not the highlight was matched. + */ + private isMatch(phrase: string, hl: HighlightWord): boolean { + if (hl.regex) { + return new RegExp(hl.word, 'gi').test(phrase); } else { - if (word.word.includes(' ')) { - return phrase.includes(word.word); + if (hl.word.includes(' ')) { + return phrase.toLocaleLowerCase().includes(hl.word.toLocaleLowerCase()); } else { const words = phrase.split(/\s*\b\s/); - return words.includes(word.word); + return words.includes(hl.word); } } } + + /** + * Adds a new highlight to a user in a particular guild. + * @param guild The guild to add the highlight to. + * @param user The user to add the highlight to. + * @param hl The highlight to add. + * @returns A string representing a user error or a boolean indicating the database success. + */ + public async addHighlight(guild: Snowflake, user: Snowflake, hl: HighlightWord): Promise<string | boolean> { + if (!this.cachedHighlights.has(guild)) this.cachedHighlights.set(guild, new Collection()); + const guildCache = this.cachedHighlights.get(guild)!; + + if (!guildCache.has(hl)) guildCache.set(hl, new Set()); + guildCache.get(hl)!.add(user); + + const [highlight] = await Highlight.findOrCreate({ where: { guild, user } }); + + if (highlight.words.some((w) => w.word === hl.word)) return `You have already highlighted "${hl.word}".`; + + highlight.words = util.addToArray(highlight.words, hl); + + return !!(await highlight.save().catch(() => false)); + } + + /** + * Removes a highlighted word for a user in a particular guild. + * @param guild The guild to remove the highlight from. + * @param user The user to remove the highlight from. + * @param hl The word to remove. + * @returns A string representing a user error or a boolean indicating the database success. + */ + public async removeHighlight(guild: Snowflake, user: Snowflake, hl: string): Promise<string | boolean> { + if (!this.cachedHighlights.has(guild)) this.cachedHighlights.set(guild, new Collection()); + const guildCache = this.cachedHighlights.get(guild)!; + + const wordCache = guildCache.find((_, key) => key.word === hl); + + if (!wordCache?.has(user)) return `You have not highlighted "${hl}".`; + + wordCache!.delete(user); + + const [highlight] = await Highlight.findOrCreate({ where: { guild, user } }); + + const toRemove = highlight.words.find((w) => w.word === hl); + if (!toRemove) return `Uhhhhh... This shouldn't happen.`; + + highlight.words = util.removeFromArray(highlight.words, toRemove); + + return !!(await highlight.save().catch(() => false)); + } + + /** + * Remove all highlight words for a user in a particular guild. + * @param guild The guild to remove the highlights from. + * @param user The user to remove the highlights from. + * @returns A boolean indicating the database success. + */ + public async removeAllHighlights(guild: Snowflake, user: Snowflake): Promise<boolean> { + if (!this.cachedHighlights.has(guild)) this.cachedHighlights.set(guild, new Collection()); + const guildCache = this.cachedHighlights.get(guild)!; + + for (const [word, users] of guildCache.entries()) { + if (users.has(user)) users.delete(user); + if (!users.size) guildCache.delete(word); + } + + const [highlight] = await Highlight.findOrCreate({ where: { guild, user } }); + + highlight.words = []; + + return !!(await highlight.save().catch(() => false)); + } + + public async notify(message: BushMessage, user: Snowflake, hl: HighlightWord): Promise<boolean> { + assert(message.inGuild()); + const recentMessages = message.channel.messages.cache + .filter((m) => m.createdTimestamp <= message.createdTimestamp && m.id !== message.id) + .filter((m) => m.cleanContent?.trim().length > 0) + .sort((a, b) => b.createdTimestamp - a.createdTimestamp) + .first(4) + .reverse(); + + return client.users + .send(user, { + // eslint-disable-next-line @typescript-eslint/no-base-to-string + content: `In ${util.format.input(message.guild.name)} ${message.channel}, your highlight "${hl.word}" was matched:`, + embeds: [ + { + description: [...recentMessages, message] + .map( + (m) => + `${util.timestamp(m.createdAt, 't')} ${util.format.input(`${m.author.tag}:`)} ${m.cleanContent + .trim() + .substring(0, 512)}` + ) + .join('\n'), + author: { name: hl.regex ? `/${hl.word}/gi` : hl.word }, + fields: [{ name: 'Source message', value: `[Jump to message](${message.url})` }], + color: util.colors.default, + footer: { text: 'Triggered' }, + timestamp: message.createdAt.toISOString() + } + ] + }) + .then(() => true) + .catch(() => false); + } } diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts index e46e701..266680a 100644 --- a/src/lib/extensions/discord-akairo/BushClient.ts +++ b/src/lib/extensions/discord-akairo/BushClient.ts @@ -467,6 +467,7 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re }); try { + await this.highlightManager.syncCache(); await UpdateCacheTask.init(this); void this.console.success('startup', `Successfully created <<cache>>.`, false); this.stats.commandsUsed = await UpdateStatsTask.init(); diff --git a/src/lib/models/instance/Guild.ts b/src/lib/models/instance/Guild.ts index cdf3552..7fe7ac1 100644 --- a/src/lib/models/instance/Guild.ts +++ b/src/lib/models/instance/Guild.ts @@ -399,6 +399,11 @@ export const guildFeaturesObj = asGuildFeature({ description: 'Use the Perspective API to detect toxicity.', default: false, notConfigurable: true + }, + highlight: { + name: 'Highlight', + description: 'Allows the highlight command to be used.', + default: true } }); diff --git a/src/listeners/message/highlight.ts b/src/listeners/message/highlight.ts index 25c8364..d3d7bfb 100644 --- a/src/listeners/message/highlight.ts +++ b/src/listeners/message/highlight.ts @@ -11,5 +11,14 @@ export default class HighlightListener extends BushListener { public override async exec(...[message]: BushClientEvents['messageCreate']) { if (!message.inGuild()) return; + if (message.author.bot) return; + if (!(await message.guild.hasFeature('highlight'))) return; // allows highlighting to be disabled on a guild-by-guild basis + + const res = client.highlightManager.checkMessage(message); + + for (const [user, hl] of res.entries()) { + if (message.author.id === user) continue; + void client.highlightManager.notify(message, user, hl); + } } } |