diff options
Diffstat (limited to 'src/lib/extensions/discord.js/ExtendedGuild.ts')
-rw-r--r-- | src/lib/extensions/discord.js/ExtendedGuild.ts | 916 |
1 files changed, 0 insertions, 916 deletions
diff --git a/src/lib/extensions/discord.js/ExtendedGuild.ts b/src/lib/extensions/discord.js/ExtendedGuild.ts deleted file mode 100644 index 3dce7ca..0000000 --- a/src/lib/extensions/discord.js/ExtendedGuild.ts +++ /dev/null @@ -1,916 +0,0 @@ -import { - AllowedMentions, - banResponse, - colors, - dmResponse, - emojis, - permissionsResponse, - punishmentEntryRemove, - type BanResponse, - type GuildFeatures, - type GuildLogType, - type GuildModel -} from '#lib'; -import assert from 'assert/strict'; -import { - AttachmentBuilder, - AttachmentPayload, - Collection, - Guild, - JSONEncodable, - Message, - MessageType, - PermissionFlagsBits, - SnowflakeUtil, - ThreadChannel, - type APIMessage, - type GuildMember, - type GuildMemberResolvable, - type GuildTextBasedChannel, - type MessageOptions, - type MessagePayload, - type NewsChannel, - type Snowflake, - type TextChannel, - type User, - type UserResolvable, - type VoiceChannel, - type Webhook, - type WebhookMessageOptions -} from 'discord.js'; -import _ from 'lodash'; -import * as Moderation from '../../common/util/Moderation.js'; -import { Guild as GuildDB } from '../../models/instance/Guild.js'; -import { ModLogType } from '../../models/instance/ModLog.js'; -import { addOrRemoveFromArray } from '../../utils/BushUtils.js'; - -declare module 'discord.js' { - export interface Guild { - /** - * Checks if the guild has a certain custom feature. - * @param feature The feature to check for - */ - hasFeature(feature: GuildFeatures): Promise<boolean>; - /** - * Adds a custom feature to the guild. - * @param feature The feature to add - * @param moderator The moderator responsible for adding a feature - */ - addFeature(feature: GuildFeatures, moderator?: GuildMember): Promise<GuildDB['enabledFeatures']>; - /** - * Removes a custom feature from the guild. - * @param feature The feature to remove - * @param moderator The moderator responsible for removing a feature - */ - removeFeature(feature: GuildFeatures, moderator?: GuildMember): Promise<GuildDB['enabledFeatures']>; - /** - * Makes a custom feature the opposite of what it was before - * @param feature The feature to toggle - * @param moderator The moderator responsible for toggling a feature - */ - toggleFeature(feature: GuildFeatures, moderator?: GuildMember): Promise<GuildDB['enabledFeatures']>; - /** - * Fetches a custom setting for the guild - * @param setting The setting to get - */ - getSetting<K extends keyof GuildModel>(setting: K): Promise<GuildModel[K]>; - /** - * Sets a custom setting for the guild - * @param setting The setting to change - * @param value The value to change the setting to - * @param moderator The moderator to responsible for changing the setting - */ - setSetting<K extends Exclude<keyof GuildModel, 'id'>>( - setting: K, - value: GuildModel[K], - moderator?: GuildMember - ): Promise<GuildModel>; - /** - * Get a the log channel configured for a certain log type. - * @param logType The type of log channel to get. - * @returns Either the log channel or undefined if not configured. - */ - getLogChannel(logType: GuildLogType): Promise<TextChannel | undefined>; - /** - * Sends a message to the guild's specified logging channel - * @param logType The corresponding channel that the message will be sent to - * @param message The parameters for {@link BushTextChannel.send} - */ - sendLogChannel(logType: GuildLogType, message: string | MessagePayload | MessageOptions): Promise<Message | null | undefined>; - /** - * Sends a formatted error message in a guild's error log channel - * @param title The title of the error embed - * @param message The description of the error embed - */ - error(title: string, message: string): Promise<void>; - /** - * Bans a user, dms them, creates a mod log entry, and creates a punishment entry. - * @param options Options for banning the user. - * @returns A string status message of the ban. - */ - bushBan(options: GuildBushBanOptions): Promise<BanResponse>; - /** - * {@link bushBan} with less resolving and checks - * @param options Options for banning the user. - * @returns A string status message of the ban. - * **Preconditions:** - * - {@link me} has the `BanMembers` permission - * **Warning:** - * - Doesn't emit bushBan Event - */ - massBanOne(options: GuildMassBanOneOptions): Promise<BanResponse>; - /** - * Unbans a user, dms them, creates a mod log entry, and destroys the punishment entry. - * @param options Options for unbanning the user. - * @returns A status message of the unban. - */ - bushUnban(options: GuildBushUnbanOptions): Promise<UnbanResponse>; - /** - * Denies send permissions in specified channels - * @param options The options for locking down the guild - */ - lockdown(options: LockdownOptions): Promise<LockdownResponse>; - quote(rawQuote: APIMessage, channel: GuildTextBasedChannel): Promise<Message | null>; - } -} - -/** - * Represents a guild (or a server) on Discord. - * <info>It's recommended to see if a guild is available before performing operations or reading data from it. You can - * check this with {@link ExtendedGuild.available}.</info> - */ -export class ExtendedGuild extends Guild { - /** - * Checks if the guild has a certain custom feature. - * @param feature The feature to check for - */ - public override async hasFeature(feature: GuildFeatures): Promise<boolean> { - const features = await this.getSetting('enabledFeatures'); - return features.includes(feature); - } - - /** - * Adds a custom feature to the guild. - * @param feature The feature to add - * @param moderator The moderator responsible for adding a feature - */ - public override async addFeature(feature: GuildFeatures, moderator?: GuildMember): Promise<GuildModel['enabledFeatures']> { - const features = await this.getSetting('enabledFeatures'); - const newFeatures = addOrRemoveFromArray('add', features, feature); - return (await this.setSetting('enabledFeatures', newFeatures, moderator)).enabledFeatures; - } - - /** - * Removes a custom feature from the guild. - * @param feature The feature to remove - * @param moderator The moderator responsible for removing a feature - */ - public override async removeFeature(feature: GuildFeatures, moderator?: GuildMember): Promise<GuildModel['enabledFeatures']> { - const features = await this.getSetting('enabledFeatures'); - const newFeatures = addOrRemoveFromArray('remove', features, feature); - return (await this.setSetting('enabledFeatures', newFeatures, moderator)).enabledFeatures; - } - - /** - * Makes a custom feature the opposite of what it was before - * @param feature The feature to toggle - * @param moderator The moderator responsible for toggling a feature - */ - public override async toggleFeature(feature: GuildFeatures, moderator?: GuildMember): Promise<GuildModel['enabledFeatures']> { - return (await this.hasFeature(feature)) - ? await this.removeFeature(feature, moderator) - : await this.addFeature(feature, moderator); - } - - /** - * Fetches a custom setting for the guild - * @param setting The setting to get - */ - public override async getSetting<K extends keyof GuildModel>(setting: K): Promise<GuildModel[K]> { - return ( - this.client.cache.guilds.get(this.id)?.[setting] ?? - ((await GuildDB.findByPk(this.id)) ?? GuildDB.build({ id: this.id }))[setting] - ); - } - - /** - * Sets a custom setting for the guild - * @param setting The setting to change - * @param value The value to change the setting to - * @param moderator The moderator to responsible for changing the setting - */ - public override async setSetting<K extends Exclude<keyof GuildModel, 'id'>>( - setting: K, - value: GuildDB[K], - moderator?: GuildMember - ): Promise<GuildDB> { - const row = (await GuildDB.findByPk(this.id)) ?? GuildDB.build({ id: this.id }); - const oldValue = row[setting] as GuildDB[K]; - row[setting] = value; - this.client.cache.guilds.set(this.id, row.toJSON() as GuildDB); - this.client.emit('bushUpdateSettings', setting, this, oldValue, row[setting], moderator); - return await row.save(); - } - - /** - * Get a the log channel configured for a certain log type. - * @param logType The type of log channel to get. - * @returns Either the log channel or undefined if not configured. - */ - public override async getLogChannel(logType: GuildLogType): Promise<TextChannel | undefined> { - const channelId = (await this.getSetting('logChannels'))[logType]; - if (!channelId) return undefined; - return ( - (this.channels.cache.get(channelId) as TextChannel | undefined) ?? - ((await this.channels.fetch(channelId)) as TextChannel | null) ?? - undefined - ); - } - - /** - * Sends a message to the guild's specified logging channel - * @param logType The corresponding channel that the message will be sent to - * @param message The parameters for {@link BushTextChannel.send} - */ - public override async sendLogChannel( - logType: GuildLogType, - message: string | MessagePayload | MessageOptions - ): Promise<Message | null | undefined> { - const logChannel = await this.getLogChannel(logType); - if (!logChannel || !logChannel.isTextBased()) return; - if ( - !logChannel - .permissionsFor(this.members.me!.id) - ?.has([PermissionFlagsBits.ViewChannel, PermissionFlagsBits.SendMessages, PermissionFlagsBits.EmbedLinks]) - ) - return; - - return await logChannel.send(message).catch(() => null); - } - - /** - * Sends a formatted error message in a guild's error log channel - * @param title The title of the error embed - * @param message The description of the error embed - */ - public override async error(title: string, message: string): Promise<void> { - void this.client.console.info(_.camelCase(title), message.replace(/\*\*(.*?)\*\*/g, '<<$1>>')); - void this.sendLogChannel('error', { embeds: [{ title: title, description: message, color: colors.error }] }); - } - - /** - * Bans a user, dms them, creates a mod log entry, and creates a punishment entry. - * @param options Options for banning the user. - * @returns A string status message of the ban. - */ - public override async bushBan(options: GuildBushBanOptions): Promise<BanResponse> { - // checks - if (!this.members.me!.permissions.has(PermissionFlagsBits.BanMembers)) return banResponse.MISSING_PERMISSIONS; - - let caseID: string | undefined = undefined; - let dmSuccessEvent: boolean | undefined = undefined; - const user = await this.client.utils.resolveNonCachedUser(options.user); - const moderator = this.client.users.resolve(options.moderator ?? this.client.user!); - if (!user || !moderator) return banResponse.CANNOT_RESOLVE_USER; - - if ((await this.bans.fetch()).has(user.id)) return banResponse.ALREADY_BANNED; - - const ret = await (async () => { - // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ - client: this.client, - type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN, - user: user, - moderator: moderator.id, - reason: options.reason, - duration: options.duration, - guild: this, - evidence: options.evidence - }); - if (!modlog) return banResponse.MODLOG_ERROR; - caseID = modlog.id; - - // dm user - dmSuccessEvent = await Moderation.punishDM({ - client: this.client, - modlog: modlog.id, - guild: this, - user: user, - punishment: 'banned', - duration: options.duration ?? 0, - reason: options.reason ?? undefined, - sendFooter: true - }); - - // ban - const banSuccess = await this.bans - .create(user?.id ?? options.user, { - reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`, - deleteMessageDays: options.deleteDays - }) - .catch(() => false); - if (!banSuccess) return banResponse.ACTION_ERROR; - - // add punishment entry so they can be unbanned later - const punishmentEntrySuccess = await Moderation.createPunishmentEntry({ - client: this.client, - type: 'ban', - user: user, - guild: this, - duration: options.duration, - modlog: modlog.id - }); - if (!punishmentEntrySuccess) return banResponse.PUNISHMENT_ENTRY_ADD_ERROR; - - if (!dmSuccessEvent) return banResponse.DM_ERROR; - return banResponse.SUCCESS; - })(); - - if (!([banResponse.ACTION_ERROR, banResponse.MODLOG_ERROR, banResponse.PUNISHMENT_ENTRY_ADD_ERROR] as const).includes(ret)) - this.client.emit( - 'bushBan', - user, - moderator, - this, - options.reason ?? undefined, - caseID!, - options.duration ?? 0, - dmSuccessEvent, - options.evidence - ); - return ret; - } - - /** - * {@link bushBan} with less resolving and checks - * @param options Options for banning the user. - * @returns A string status message of the ban. - * **Preconditions:** - * - {@link me} has the `BanMembers` permission - * **Warning:** - * - Doesn't emit bushBan Event - */ - public override async massBanOne(options: GuildMassBanOneOptions): Promise<BanResponse> { - if (this.bans.cache.has(options.user)) return banResponse.ALREADY_BANNED; - - const ret = await (async () => { - // add modlog entry - const { log: modlog } = await Moderation.createModLogEntrySimple({ - client: this.client, - type: ModLogType.PERM_BAN, - user: options.user, - moderator: options.moderator, - reason: options.reason, - duration: 0, - guild: this.id - }); - if (!modlog) return banResponse.MODLOG_ERROR; - - let dmSuccessEvent: boolean | undefined = undefined; - // dm user - if (this.members.cache.has(options.user)) { - dmSuccessEvent = await Moderation.punishDM({ - client: this.client, - modlog: modlog.id, - guild: this, - user: options.user, - punishment: 'banned', - duration: 0, - reason: options.reason ?? undefined, - sendFooter: true - }); - } - - // ban - const banSuccess = await this.bans - .create(options.user, { - reason: `${options.moderator} | ${options.reason}`, - deleteMessageDays: options.deleteDays - }) - .catch(() => false); - if (!banSuccess) return banResponse.ACTION_ERROR; - - // add punishment entry so they can be unbanned later - const punishmentEntrySuccess = await Moderation.createPunishmentEntry({ - client: this.client, - type: 'ban', - user: options.user, - guild: this, - duration: 0, - modlog: modlog.id - }); - if (!punishmentEntrySuccess) return banResponse.PUNISHMENT_ENTRY_ADD_ERROR; - - if (!dmSuccessEvent) return banResponse.DM_ERROR; - return banResponse.SUCCESS; - })(); - return ret; - } - - /** - * Unbans a user, dms them, creates a mod log entry, and destroys the punishment entry. - * @param options Options for unbanning the user. - * @returns A status message of the unban. - */ - public override async bushUnban(options: GuildBushUnbanOptions): Promise<UnbanResponse> { - // checks - if (!this.members.me!.permissions.has(PermissionFlagsBits.BanMembers)) return unbanResponse.MISSING_PERMISSIONS; - - let caseID: string | undefined = undefined; - let dmSuccessEvent: boolean | undefined = undefined; - const user = await this.client.utils.resolveNonCachedUser(options.user); - const moderator = this.client.users.resolve(options.moderator ?? this.client.user!); - if (!user || !moderator) return unbanResponse.CANNOT_RESOLVE_USER; - - const ret = await (async () => { - const bans = await this.bans.fetch(); - - let notBanned = false; - if (!bans.has(user.id)) notBanned = true; - - const unbanSuccess = await this.bans - .remove(user, `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`) - .catch((e) => { - if (e?.code === 'UNKNOWN_BAN') { - notBanned = true; - return true; - } else return false; - }); - - if (notBanned) return unbanResponse.NOT_BANNED; - if (!unbanSuccess) return unbanResponse.ACTION_ERROR; - - // add modlog entry - const { log: modlog } = await Moderation.createModLogEntry({ - client: this.client, - type: ModLogType.UNBAN, - user: user.id, - moderator: moderator.id, - reason: options.reason, - guild: this, - evidence: options.evidence - }); - if (!modlog) return unbanResponse.MODLOG_ERROR; - caseID = modlog.id; - - // remove punishment entry - const removePunishmentEntrySuccess = await Moderation.removePunishmentEntry({ - client: this.client, - type: 'ban', - user: user.id, - guild: this - }); - if (!removePunishmentEntrySuccess) return unbanResponse.PUNISHMENT_ENTRY_REMOVE_ERROR; - - // dm user - dmSuccessEvent = await Moderation.punishDM({ - client: this.client, - guild: this, - user: user, - punishment: 'unbanned', - reason: options.reason ?? undefined, - sendFooter: false - }); - - if (!dmSuccessEvent) return unbanResponse.DM_ERROR; - return unbanResponse.SUCCESS; - })(); - if ( - !([unbanResponse.ACTION_ERROR, unbanResponse.MODLOG_ERROR, unbanResponse.PUNISHMENT_ENTRY_REMOVE_ERROR] as const).includes( - ret - ) - ) - this.client.emit( - 'bushUnban', - user, - moderator, - this, - options.reason ?? undefined, - caseID!, - dmSuccessEvent!, - options.evidence - ); - return ret; - } - - /** - * Denies send permissions in specified channels - * @param options The options for locking down the guild - */ - public override async lockdown(options: LockdownOptions): Promise<LockdownResponse> { - if (!options.all && !options.channel) return 'all not chosen and no channel specified'; - const channelIds = options.all ? await this.getSetting('lockdownChannels') : [options.channel!.id]; - - if (!channelIds.length) return 'no channels configured'; - const mappedChannels = channelIds.map((id) => this.channels.cache.get(id)); - - const invalidChannels = mappedChannels.filter((c) => c === undefined); - if (invalidChannels.length) return `invalid channel configured: ${invalidChannels.join(', ')}`; - - const moderator = this.members.resolve(options.moderator); - if (!moderator) return 'moderator not found'; - - const errors = new Collection<Snowflake, Error>(); - const success = new Collection<Snowflake, boolean>(); - const ret = await (async (): Promise<LockdownResponse> => { - for (const _channel of mappedChannels) { - const channel = _channel!; - if (!channel.isTextBased()) { - errors.set(channel.id, new Error('wrong channel type')); - success.set(channel.id, false); - continue; - } - if (!channel.permissionsFor(this.members.me!.id)?.has([PermissionFlagsBits.ManageChannels])) { - errors.set(channel.id, new Error('client no permission')); - success.set(channel.id, false); - continue; - } else if (!channel.permissionsFor(moderator)?.has([PermissionFlagsBits.ManageChannels])) { - errors.set(channel.id, new Error('moderator no permission')); - success.set(channel.id, false); - continue; - } - - const reason = `[${options.unlock ? 'Unlockdown' : 'Lockdown'}] ${moderator.user.tag} | ${ - options.reason ?? 'No reason provided' - }`; - - const permissionOverwrites = channel.isThread() ? channel.parent!.permissionOverwrites : channel.permissionOverwrites; - const perms = { - SendMessagesInThreads: options.unlock ? null : false, - SendMessages: options.unlock ? null : false - }; - const permsForMe = { - [channel.isThread() ? 'SendMessagesInThreads' : 'SendMessages']: options.unlock ? null : true - }; // so I can send messages in the channel - - const changePermSuccess = await permissionOverwrites.edit(this.id, perms, { reason }).catch((e) => e); - if (changePermSuccess instanceof Error) { - errors.set(channel.id, changePermSuccess); - success.set(channel.id, false); - } else { - success.set(channel.id, true); - await permissionOverwrites.edit(this.members.me!, permsForMe, { reason }); - await channel.send({ - embeds: [ - { - author: { name: moderator.user.tag, icon_url: moderator.displayAvatarURL() }, - title: `This channel has been ${options.unlock ? 'un' : ''}locked`, - description: options.reason ?? 'No reason provided', - color: options.unlock ? colors.Green : colors.Red, - timestamp: new Date().toISOString() - } - ] - }); - } - } - - if (errors.size) return errors; - else return `success: ${success.filter((c) => c === true).size}`; - })(); - - this.client.emit(options.unlock ? 'bushUnlockdown' : 'bushLockdown', moderator, options.reason, success, options.all); - return ret; - } - - public override async quote(rawQuote: APIMessage, channel: GuildTextBasedChannel): Promise<Message | null> { - if (!channel.isTextBased() || channel.isDMBased() || channel.guildId !== this.id || !this.members.me) return null; - if (!channel.permissionsFor(this.members.me).has('ManageWebhooks')) return null; - - const quote = new Message(this.client, rawQuote); - - const target = channel instanceof ThreadChannel ? channel.parent : channel; - if (!target) return null; - - const webhooks: Collection<string, Webhook> = await target.fetchWebhooks().catch((e) => e); - if (!(webhooks instanceof Collection)) return null; - - // find a webhook that we can use - let webhook = webhooks.find((w) => !!w.token) ?? null; - if (!webhook) - webhook = await target - .createWebhook({ - name: `${this.client.user!.username} Quotes #${target.name}`, - avatar: this.client.user!.displayAvatarURL({ size: 2048 }), - reason: 'Creating a webhook for quoting' - }) - .catch(() => null); - - if (!webhook) return null; - - const sendOptions: Omit<WebhookMessageOptions, 'flags'> = {}; - - const displayName = quote.member?.displayName ?? quote.author.username; - - switch (quote.type) { - case MessageType.Default: - case MessageType.Reply: - case MessageType.ChatInputCommand: - case MessageType.ContextMenuCommand: - case MessageType.ThreadStarterMessage: - sendOptions.content = quote.content || undefined; - sendOptions.threadId = channel instanceof ThreadChannel ? channel.id : undefined; - sendOptions.embeds = quote.embeds.length ? quote.embeds : undefined; - //@ts-expect-error: jank - sendOptions.attachments = quote.attachments.size - ? [...quote.attachments.values()].map((a) => AttachmentBuilder.from(a as JSONEncodable<AttachmentPayload>)) - : undefined; - - if (quote.stickers.size && !(quote.content || quote.embeds.length || quote.attachments.size)) - sendOptions.content = '[[This message has a sticker but not content]]'; - - break; - case MessageType.RecipientAdd: { - const recipient = rawQuote.mentions[0]; - if (!recipient) { - sendOptions.content = `${emojis.error} Cannot resolve recipient.`; - break; - } - - if (quote.channel.isThread()) { - const recipientDisplay = quote.guild?.members.cache.get(recipient.id)?.displayName ?? recipient.username; - sendOptions.content = `${emojis.join} ${displayName} added ${recipientDisplay} to the thread.`; - } else { - // this should never happen - sendOptions.content = `${emojis.join} ${displayName} added ${recipient.username} to the group.`; - } - - break; - } - case MessageType.RecipientRemove: { - const recipient = rawQuote.mentions[0]; - if (!recipient) { - sendOptions.content = `${emojis.error} Cannot resolve recipient.`; - break; - } - - if (quote.channel.isThread()) { - const recipientDisplay = quote.guild?.members.cache.get(recipient.id)?.displayName ?? recipient.username; - sendOptions.content = `${emojis.leave} ${displayName} removed ${recipientDisplay} from the thread.`; - } else { - // this should never happen - sendOptions.content = `${emojis.leave} ${displayName} removed ${recipient.username} from the group.`; - } - - break; - } - - case MessageType.ChannelNameChange: - sendOptions.content = `<:pencil:957988608994861118> ${displayName} changed the channel name: **${quote.content}**`; - - break; - - case MessageType.ChannelPinnedMessage: - throw new Error('Not implemented yet: MessageType.ChannelPinnedMessage case'); - case MessageType.UserJoin: { - const messages = [ - '{username} joined the party.', - '{username} is here.', - 'Welcome, {username}. We hope you brought pizza.', - 'A wild {username} appeared.', - '{username} just landed.', - '{username} just slid into the server.', - '{username} just showed up!', - 'Welcome {username}. Say hi!', - '{username} hopped into the server.', - 'Everyone welcome {username}!', - "Glad you're here, {username}.", - 'Good to see you, {username}.', - 'Yay you made it, {username}!' - ]; - - const timestamp = SnowflakeUtil.timestampFrom(quote.id); - - // this is the same way that the discord client decides what message to use. - const message = messages[timestamp % messages.length].replace(/{username}/g, displayName); - - sendOptions.content = `${emojis.join} ${message}`; - break; - } - case MessageType.GuildBoost: - sendOptions.content = `<:NitroBoost:585558042309820447> ${displayName} just boosted the server${ - quote.content ? ` **${quote.content}** times` : '' - }!`; - - break; - case MessageType.GuildBoostTier1: - case MessageType.GuildBoostTier2: - case MessageType.GuildBoostTier3: - sendOptions.content = `<:NitroBoost:585558042309820447> ${displayName} just boosted the server${ - quote.content ? ` **${quote.content}** times` : '' - }! ${quote.guild?.name} has achieved **Level ${quote.type - 8}!**`; - - break; - case MessageType.ChannelFollowAdd: - sendOptions.content = `${displayName} has added **${quote.content}** to this channel. Its most important updates will show up here.`; - - break; - case MessageType.GuildDiscoveryDisqualified: - sendOptions.content = - '<:SystemMessageCross:842172192418693173> This server has been removed from Server Discovery because it no longer passes all the requirements. Check Server Settings for more details.'; - - break; - case MessageType.GuildDiscoveryRequalified: - sendOptions.content = - '<:SystemMessageCheck:842172191801212949> This server is eligible for Server Discovery again and has been automatically relisted!'; - - break; - case MessageType.GuildDiscoveryGracePeriodInitialWarning: - sendOptions.content = - '<:SystemMessageWarn:842172192401915971> This server has failed Discovery activity requirements for 1 week. If this server fails for 4 weeks in a row, it will be automatically removed from Discovery.'; - - break; - case MessageType.GuildDiscoveryGracePeriodFinalWarning: - sendOptions.content = - '<:SystemMessageWarn:842172192401915971> This server has failed Discovery activity requirements for 3 weeks in a row. If this server fails for 1 more week, it will be removed from Discovery.'; - - break; - case MessageType.ThreadCreated: { - const threadId = rawQuote.message_reference?.channel_id; - - sendOptions.content = `<:thread:865033845753249813> ${displayName} started a thread: **[${quote.content}](https://discord.com/channels/${quote.guildId}/${threadId} - )**. See all threads.`; - - break; - } - case MessageType.GuildInviteReminder: - sendOptions.content = 'Wondering who to invite? Start by inviting anyone who can help you build the server!'; - - break; - // todo: use enum for this - case 24 as MessageType: { - const embed = quote.embeds[0]; - // eslint-disable-next-line deprecation/deprecation - assert.equal(embed.data.type, 'auto_moderation_message'); - const ruleName = embed.fields!.find((f) => f.name === 'rule_name')!.value; - const channelId = embed.fields!.find((f) => f.name === 'channel_id')!.value; - const keyword = embed.fields!.find((f) => f.name === 'keyword')!.value; - - sendOptions.username = `AutoMod (${quote.member?.displayName ?? quote.author.username})`; - sendOptions.content = `Automod has blocked a message in <#${channelId}>`; - sendOptions.embeds = [ - { - title: quote.member?.displayName ?? quote.author.username, - description: embed.description ?? 'There is no content???', - footer: { - text: `Keyword: ${keyword} • Rule: ${ruleName}` - }, - color: 0x36393f - } - ]; - - break; - } - case MessageType.ChannelIconChange: - case MessageType.Call: - default: - sendOptions.content = `${emojis.error} I cannot quote messages of type **${ - MessageType[quote.type] || quote.type - }** messages, please report this to my developers.`; - - break; - } - - sendOptions.allowedMentions = AllowedMentions.none(); - sendOptions.username ??= quote.member?.displayName ?? quote.author.username; - sendOptions.avatarURL = quote.member?.displayAvatarURL({ size: 2048 }) ?? quote.author.displayAvatarURL({ size: 2048 }); - - return await webhook.send(sendOptions); /* .catch((e: any) => e); */ - } -} - -/** - * Options for unbanning a user - */ -export interface GuildBushUnbanOptions { - /** - * The user to unban - */ - user: UserResolvable | User; - - /** - * The reason for unbanning the user - */ - reason?: string | null; - - /** - * The moderator who unbanned the user - */ - moderator?: UserResolvable; - - /** - * The evidence for the unban - */ - evidence?: string; -} - -export interface GuildMassBanOneOptions { - /** - * The user to ban - */ - user: Snowflake; - - /** - * The reason to ban the user - */ - reason: string; - - /** - * The moderator who banned the user - */ - moderator: Snowflake; - - /** - * The number of days to delete the user's messages for - */ - deleteDays?: number; -} - -/** - * Options for banning a user - */ -export interface GuildBushBanOptions { - /** - * The user to ban - */ - user: UserResolvable; - - /** - * The reason to ban the user - */ - reason?: string | null; - - /** - * The moderator who banned the user - */ - moderator?: UserResolvable; - - /** - * The duration of the ban - */ - duration?: number; - - /** - * The number of days to delete the user's messages for - */ - deleteDays?: number; - - /** - * The evidence for the ban - */ - evidence?: string; -} - -type ValueOf<T> = T[keyof T]; - -export const unbanResponse = Object.freeze({ - ...dmResponse, - ...permissionsResponse, - ...punishmentEntryRemove, - NOT_BANNED: 'user not banned' -} as const); - -/** - * Response returned when unbanning a user - */ -export type UnbanResponse = ValueOf<typeof unbanResponse>; - -/** - * Options for locking down channel(s) - */ -export interface LockdownOptions { - /** - * The moderator responsible for the lockdown - */ - moderator: GuildMemberResolvable; - - /** - * Whether to lock down all (specified) channels - */ - all: boolean; - - /** - * Reason for the lockdown - */ - reason?: string; - - /** - * A specific channel to lockdown - */ - channel?: ThreadChannel | NewsChannel | TextChannel | VoiceChannel; - - /** - * Whether or not to unlock the channel(s) instead of locking them - */ - unlock?: boolean; -} - -/** - * Response returned when locking down a channel - */ -export type LockdownResponse = - | `success: ${number}` - | 'all not chosen and no channel specified' - | 'no channels configured' - | `invalid channel configured: ${string}` - | 'moderator not found' - | Collection<string, Error>; |