diff options
Diffstat (limited to 'src/lib/common')
-rw-r--r-- | src/lib/common/AutoMod.ts | 2 | ||||
-rw-r--r-- | src/lib/common/ButtonPaginator.ts | 7 | ||||
-rw-r--r-- | src/lib/common/ConfirmationPrompt.ts | 2 | ||||
-rw-r--r-- | src/lib/common/DeleteButton.ts | 1 | ||||
-rw-r--r-- | src/lib/common/util/Moderation.ts | 124 |
5 files changed, 125 insertions, 11 deletions
diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts index 784085d..9024260 100644 --- a/src/lib/common/AutoMod.ts +++ b/src/lib/common/AutoMod.ts @@ -156,6 +156,7 @@ export class AutoMod { ? [ new ActionRow().addComponents( new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Danger) .setLabel('Ban User') .setCustomId(`automod;ban;${this.message.author.id};everyone mention and scam phrase`) @@ -277,6 +278,7 @@ export class AutoMod { ? [ new ActionRow().addComponents( new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Danger) .setLabel('Ban User') .setCustomId(`automod;ban;${this.message.author.id};${highestOffence.reason}`) diff --git a/src/lib/common/ButtonPaginator.ts b/src/lib/common/ButtonPaginator.ts index 0399e74..09e059c 100644 --- a/src/lib/common/ButtonPaginator.ts +++ b/src/lib/common/ButtonPaginator.ts @@ -1,6 +1,6 @@ import { DeleteButton, type BushMessage, type BushSlashMessage } from '#lib'; import { CommandUtil } from 'discord-akairo'; -import { APIEmbed } from 'discord-api-types'; +import { APIEmbed } from 'discord-api-types/v9'; import { ActionRow, ActionRowComponent, ButtonComponent, ButtonStyle, Embed, type MessageComponentInteraction } from 'discord.js'; /** @@ -173,26 +173,31 @@ export class ButtonPaginator { protected getPaginationRow(disableAll = false): ActionRow<ActionRowComponent> { return new ActionRow().addComponents( new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Primary) .setCustomId('paginate_beginning') .setEmoji(PaginateEmojis.BEGINNING) .setDisabled(disableAll || this.curPage === 0), new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Primary) .setCustomId('paginate_back') .setEmoji(PaginateEmojis.BACK) .setDisabled(disableAll || this.curPage === 0), new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Primary) .setCustomId('paginate_stop') .setEmoji(PaginateEmojis.STOP) .setDisabled(disableAll), new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Primary) .setCustomId('paginate_next') .setEmoji(PaginateEmojis.FORWARD) .setDisabled(disableAll || this.curPage === this.embeds.length - 1), new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Primary) .setCustomId('paginate_end') .setEmoji(PaginateEmojis.END) diff --git a/src/lib/common/ConfirmationPrompt.ts b/src/lib/common/ConfirmationPrompt.ts index bd11c5c..1f027ef 100644 --- a/src/lib/common/ConfirmationPrompt.ts +++ b/src/lib/common/ConfirmationPrompt.ts @@ -31,11 +31,13 @@ export class ConfirmationPrompt { this.messageOptions.components = [ new ActionRow().addComponents( new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Primary) .setCustomId('confirmationPrompt_confirm') .setEmoji({ id: util.emojisRaw.successFull, name: 'successFull', animated: false }) .setLabel('Yes'), new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Danger) .setCustomId('confirmationPrompt_cancel') .setEmoji({ id: util.emojisRaw.errorFull, name: 'errorFull', animated: false }) diff --git a/src/lib/common/DeleteButton.ts b/src/lib/common/DeleteButton.ts index cf3b416..f2e0ff3 100644 --- a/src/lib/common/DeleteButton.ts +++ b/src/lib/common/DeleteButton.ts @@ -68,6 +68,7 @@ export class DeleteButton { this.messageOptions.components = [ new ActionRow().addComponents( new ButtonComponent() + // @ts-expect-error: outdated @discord.js/builders .setStyle(ButtonStyle.Primary) .setCustomId('paginate__stop') .setEmoji(PaginateEmojis.STOP) diff --git a/src/lib/common/util/Moderation.ts b/src/lib/common/util/Moderation.ts index 0ba6fca..c2236ab 100644 --- a/src/lib/common/util/Moderation.ts +++ b/src/lib/common/util/Moderation.ts @@ -10,7 +10,33 @@ import { type BushUserResolvable, type ModLogType } from '#lib'; -import { Embed, PermissionFlagsBits, type Snowflake } from 'discord.js'; +import assert from 'assert'; +import { ActionRow, ButtonComponent, ButtonStyle, ComponentType, Embed, PermissionFlagsBits, type Snowflake } from 'discord.js'; + +enum punishMap { + 'warned' = 'warn', + 'muted' = 'mute', + 'unmuted' = 'unmute', + 'kicked' = 'kick', + 'banned' = 'ban', + 'unbanned' = 'unban', + 'timedout' = 'timeout', + 'untimedout' = 'untimeout', + 'blocked' = 'block', + 'unblocked' = 'unblock' +} +enum reversedPunishMap { + 'warn' = 'warned', + 'mute' = 'muted', + 'unmute' = 'unmuted', + 'kick' = 'kicked', + 'ban' = 'banned', + 'unban' = 'unbanned', + 'timeout' = 'timedout', + 'untimeout' = 'untimedout', + 'block' = 'blocked', + 'unblock' = 'unblocked' +} /** * A utility class with moderation-related methods. @@ -204,6 +230,19 @@ export class Moderation { return typeMap[type]; } + public static punishmentToPresentTense(punishment: PunishmentTypeDM): PunishmentTypePresent { + return punishMap[punishment]; + } + + public static punishmentToPastTense(punishment: PunishmentTypePresent): PunishmentTypeDM { + return reversedPunishMap[punishment]; + } + + /** + * Notifies the specified user of their punishment. + * @param options Options for notifying the user. + * @returns Whether or not the dm was successfully sent. + */ public static async punishDM(options: PunishDMOptions): Promise<boolean> { const ending = await options.guild.getSetting('punishmentEnding'); const dmEmbed = @@ -211,16 +250,45 @@ export class Moderation { ? new Embed().setDescription(ending).setColor(util.colors.newBlurple) : undefined; + const appealsEnabled = !!( + (await options.guild.hasFeature('punishmentAppeals')) && (await options.guild.getLogChannel('appeals')) + ); + + let content = `You have been ${options.punishment} `; + if (options.punishment.includes('blocked')) { + assert(options.channel); + content += `from <#${options.channel}> `; + } + content += `in ${util.format.input(options.guild.name)} `; + if (options.duration !== null && options.duration !== undefined) + content += options.duration ? `for ${util.humanizeDuration(options.duration)} ` : 'permanently '; + const reason = options.reason?.trim() ? options.reason?.trim() : 'No reason provided'; + content += `for ${util.format.input(reason)}.`; + + let components; + if (appealsEnabled && options.modlog) + components = [ + new ActionRow({ + type: ComponentType.ActionRow, + components: [ + // @ts-expect-error: outdated @discord.js/builders + new ButtonComponent({ + custom_id: `appeal;${this.punishmentToPresentTense(options.punishment)};${ + options.guild.id + };${client.users.resolveId(options.user)};${options.modlog}`, + style: ButtonStyle.Primary, + type: ComponentType.Button, + label: 'Appeal' + }) + ] + }) + ]; + const dmSuccess = await client.users .send(options.user, { - content: `You have been ${options.punishment} in **${options.guild.name}** ${ - options.duration !== null && options.duration !== undefined - ? options.duration - ? `for ${util.humanizeDuration(options.duration)} ` - : 'permanently ' - : '' - }for **${options.reason?.trim() ? options.reason?.trim() : 'No reason provided'}**.`, - embeds: dmEmbed ? [dmEmbed] : undefined + content, + embeds: dmEmbed ? [dmEmbed] : undefined, + components }) .catch(() => false); return !!dmSuccess; @@ -342,6 +410,11 @@ export interface RemovePunishmentEntryOptions { */ export interface PunishDMOptions { /** + * The modlog case id so the user can make an appeal. + */ + modlog?: string; + + /** * The guild that the punishment is taking place in. */ guild: BushGuild; @@ -354,7 +427,7 @@ export interface PunishDMOptions { /** * The punishment that the user has received. */ - punishment: string; + punishment: PunishmentTypeDM; /** * The reason the user's punishment. @@ -371,4 +444,35 @@ export interface PunishDMOptions { * @default true */ sendFooter: boolean; + + /** + * The channel that the user was (un)blocked from. + */ + channel?: Snowflake; } + +export type PunishmentTypeDM = + | 'warned' + | 'muted' + | 'unmuted' + | 'kicked' + | 'banned' + | 'unbanned' + | 'timedout' + | 'untimedout' + | 'blocked' + | 'unblocked'; + +export type PunishmentTypePresent = + | 'warn' + | 'mute' + | 'unmute' + | 'kick' + | 'ban' + | 'unban' + | 'timeout' + | 'untimeout' + | 'block' + | 'unblock'; + +export type AppealButtonId = `appeal;${PunishmentTypePresent};${Snowflake};${Snowflake};${string}`; |