diff options
-rw-r--r-- | src/commands/config/config.ts | 2 | ||||
-rw-r--r-- | src/commands/moderation/lockdown.ts | 8 | ||||
-rw-r--r-- | src/lib/common/ConfirmationPrompt.ts | 16 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushClientEvents.d.ts | 8 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushDMChannel.ts | 15 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushGuild.ts | 62 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushGuildMember.ts | 15 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushThreadChannel.ts | 8 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushThreadManager.d.ts | 2 | ||||
-rw-r--r-- | src/lib/utils/BushLogger.ts | 7 | ||||
-rw-r--r-- | src/listeners/client/akairoDebug.ts | 6 | ||||
-rw-r--r-- | src/listeners/client/interactionCreate.ts | 5 | ||||
-rw-r--r-- | src/listeners/guild-custom/bushLockdown.ts | 9 | ||||
-rw-r--r-- | src/listeners/guild-custom/bushUnlockdown.ts | 9 |
14 files changed, 110 insertions, 62 deletions
diff --git a/src/commands/config/config.ts b/src/commands/config/config.ts index 87397ee..1251f1f 100644 --- a/src/commands/config/config.ts +++ b/src/commands/config/config.ts @@ -320,7 +320,7 @@ export default class SettingsCommand extends BushCommand { } } - assert(typeof feat === 'string', `feat is not a string: ${util.inspect(feat)}`); + assert(typeof feat === 'string' || Array.isArray(feat), `feat is not a string: ${util.inspect(feat)}`); return Array.isArray(feat) ? feat.length diff --git a/src/commands/moderation/lockdown.ts b/src/commands/moderation/lockdown.ts index ae9a62b..87a2f05 100644 --- a/src/commands/moderation/lockdown.ts +++ b/src/commands/moderation/lockdown.ts @@ -79,6 +79,7 @@ export default class LockdownCommand extends BushCommand { action: 'lockdown' | 'unlockdown' ) { assert(message.inGuild()); + if (message.util.isSlashMessage(message)) await message.interaction.deferReply(); if (args.channel && args.all) return await message.util.reply(`${util.emojis.error} You can't specify a channel and set all to true at the same time.`); @@ -94,10 +95,9 @@ export default class LockdownCommand extends BushCommand { const confirmation = await ConfirmationPrompt.send(message, { content: `Are you sure you want to ${action} all channels?` }); - if (!confirmation) return message.util.send(`${util.emojis.error} Lockdown cancelled.`); + if (!confirmation) return message.util.sendNew(`${util.emojis.error} Lockdown cancelled.`); } - client.console.debug('right before lockdown'); const response = await message.guild.lockdown({ moderator: message.author, channel: channel ?? undefined, @@ -107,7 +107,7 @@ export default class LockdownCommand extends BushCommand { }); if (response instanceof Collection) { - return await message.util.send({ + return await message.util.sendNew({ content: `${util.emojis.error} The following channels failed to ${action}:`, embeds: [ { @@ -138,7 +138,7 @@ export default class LockdownCommand extends BushCommand { } assert(messageResponse); - return await message.util.send({ content: messageResponse, allowedMentions: AllowedMentions.none() }); + return await message.util.sendNew({ content: messageResponse, allowedMentions: AllowedMentions.none() }); } } } diff --git a/src/lib/common/ConfirmationPrompt.ts b/src/lib/common/ConfirmationPrompt.ts index 9e790c7..a4acf83 100644 --- a/src/lib/common/ConfirmationPrompt.ts +++ b/src/lib/common/ConfirmationPrompt.ts @@ -33,38 +33,36 @@ export class ConfirmationPrompt { new MessageActionRow().addComponents( new MessageButton({ style: MessageButtonStyles.SUCCESS, - customId: 'confirmationPrompt__confirm', + customId: 'confirmationPrompt_confirm', emoji: util.emojis.successFull, label: 'Yes' }), new MessageButton({ style: MessageButtonStyles.DANGER, - customId: 'confirmationPrompt__deny', + customId: 'confirmationPrompt_deny', emoji: util.emojis.errorFull, label: 'No' }) ) ]; - const msg = (await this.message.util.reply(this.messageOptions)) as BushMessage; + const msg = (await this.message.util.sendNew(this.messageOptions)) as BushMessage; return await new Promise<boolean>((resolve) => { let responded = false; const collector = msg.createMessageComponentCollector({ - filter: (interaction) => - ['confirmationPrompt__confirm', 'confirmationPrompt__deny'].includes(interaction.customId) && - interaction.message?.id == msg.id, - time: 300000 + filter: (interaction) => interaction.message?.id == msg.id, + time: 300_000 }); collector.on('collect', async (interaction: MessageComponentInteraction) => { await interaction.deferUpdate().catch(() => undefined); if (interaction.user.id == this.message.author.id || client.config.owners.includes(interaction.user.id)) { - if (interaction.id === 'confirmationPrompt__confirm') { + if (interaction.customId === 'confirmationPrompt_confirm') { resolve(true); responded = true; collector.stop(); - } else if (interaction.id === 'confirmationPrompt__deny') { + } else if (interaction.customId === 'confirmationPrompt_deny') { resolve(false); responded = true; collector.stop(); diff --git a/src/lib/extensions/discord.js/BushClientEvents.d.ts b/src/lib/extensions/discord.js/BushClientEvents.d.ts index 6dc94a1..16eccd4 100644 --- a/src/lib/extensions/discord.js/BushClientEvents.d.ts +++ b/src/lib/extensions/discord.js/BushClientEvents.d.ts @@ -306,14 +306,14 @@ export interface BushClientEvents extends AkairoClientEvents { ]; bushLockdown: [ moderator: BushGuildMember, - reason?: string | undefined, - channel?: BushGuildTextBasedChannel, + reason: string | undefined, + channelsSuccessMap: Collection<Snowflake, boolean>, all?: boolean ]; bushUnlockdown: [ moderator: BushGuildMember, - reason?: string | undefined, - channel?: BushGuildTextBasedChannel, + reason: string | undefined, + channelsSuccessMap: Collection<Snowflake, boolean>, all?: boolean ]; } diff --git a/src/lib/extensions/discord.js/BushDMChannel.ts b/src/lib/extensions/discord.js/BushDMChannel.ts index 9df9275..1af3ca1 100644 --- a/src/lib/extensions/discord.js/BushDMChannel.ts +++ b/src/lib/extensions/discord.js/BushDMChannel.ts @@ -1,4 +1,11 @@ -import type { BushClient, BushMessageManager, BushUser } from '#lib'; +import type { + BushBaseGuildVoiceChannel, + BushClient, + BushMessageManager, + BushTextBasedChannel, + BushThreadChannel, + BushUser +} from '#lib'; import { DMChannel } from 'discord.js'; import type { RawDMChannelData } from 'discord.js/typings/rawDataTypes'; @@ -14,3 +21,9 @@ export class BushDMChannel extends DMChannel { super(client, data); } } + +export interface BushDMChannel extends DMChannel { + isText(): this is BushTextBasedChannel; + isVoice(): this is BushBaseGuildVoiceChannel; + isThread(): this is BushThreadChannel; +} diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts index d182be4..ea8b67e 100644 --- a/src/lib/extensions/discord.js/BushGuild.ts +++ b/src/lib/extensions/discord.js/BushGuild.ts @@ -157,7 +157,7 @@ export class BushGuild extends Guild { * @param options Options for banning the user. * @returns A string status message of the ban. */ - public async bushBan(options: BushBanOptions): Promise<BanResponse> { + public async bushBan(options: GuildBushBanOptions): Promise<GuildBanResponse> { // checks if (!this.me!.permissions.has('BAN_MEMBERS')) return 'missing permissions'; @@ -213,7 +213,7 @@ export class BushGuild extends Guild { * @param options Options for unbanning the user. * @returns A status message of the unban. */ - public async bushUnban(options: BushUnbanOptions): Promise<UnbanResponse> { + public async bushUnban(options: GuildBushUnbanOptions): Promise<GuildUnbanResponse> { let caseID: string | undefined = undefined; let dmSuccessEvent: boolean | undefined = undefined; const user = (await util.resolveNonCachedUser(options.user))!; @@ -291,17 +291,23 @@ export class BushGuild extends Guild { 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> => { - const errors = new Collection<Snowflake, Error>(); - let successCount = 0; - for (const _channel of mappedChannels) { const channel = _channel!; + if (!channel.isText() && !channel.isThread()) { + errors.set(channel.id, new Error('wrong channel type')); + success.set(channel.id, false); + continue; + } if (!channel.permissionsFor(this.me!.id)?.has(['MANAGE_CHANNELS'])) { errors.set(channel.id, new Error('client no permission')); + success.set(channel.id, false); continue; } else if (!channel.permissionsFor(options.moderator)?.has(['MANAGE_CHANNELS'])) { errors.set(channel.id, new Error('moderator no permission')); + success.set(channel.id, false); continue; } @@ -309,26 +315,36 @@ export class BushGuild extends Guild { options.reason ?? 'No reason provided' }`; - if (channel.isThread()) { - const lockdownSuccess = await channel.parent?.permissionOverwrites - .edit(this.id, { SEND_MESSAGES_IN_THREADS: options.unlock ? null : false }, { reason }) - .catch((e) => e); - if (lockdownSuccess instanceof Error) errors.set(channel.id, lockdownSuccess); - else successCount++; + const permissionOverwrites = channel.isThread() ? channel.parent!.permissionOverwrites : channel.permissionOverwrites; + const perms = { [channel.isThread() ? 'SEND_MESSAGES_IN_THREADS' : 'SEND_MESSAGES']: options.unlock ? null : false }; + const permsForMe = { [channel.isThread() ? 'SEND_MESSAGES_IN_THREADS' : 'SEND_MESSAGES']: 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 { - const lockdownSuccess = await channel.permissionOverwrites - .edit(this.id, { SEND_MESSAGES: options.unlock ? null : false }, { reason }) - .catch((e) => e); - if (lockdownSuccess instanceof Error) errors.set(channel.id, lockdownSuccess); - else successCount++; + success.set(channel.id, true); + await permissionOverwrites.edit(this.me!, permsForMe, { reason }); + await channel.send({ + embeds: [ + { + author: { name: moderator.user.tag, iconURL: moderator.displayAvatarURL({ dynamic: true }) }, + title: `This channel has been ${options.unlock ? 'un' : ''}locked`, + description: options.reason ?? 'No reason provided', + color: options.unlock ? util.colors.discord.GREEN : util.colors.discord.RED, + timestamp: Date.now() + } + ] + }); } } if (errors.size) return errors; - else return `success: ${successCount}`; + else return `success: ${success.filter((c) => c === true).size}`; })(); - client.emit(options.unlock ? 'bushUnlockdown' : 'bushLockdown', moderator, options.reason, options.channel); + client.emit(options.unlock ? 'bushUnlockdown' : 'bushLockdown', moderator, options.reason, success, options.all); return ret; } } @@ -336,7 +352,7 @@ export class BushGuild extends Guild { /** * Options for unbanning a user */ -export interface BushUnbanOptions { +export interface GuildBushUnbanOptions { /** * The user to unban */ @@ -356,7 +372,7 @@ export interface BushUnbanOptions { /** * Options for banning a user */ -export interface BushBanOptions { +export interface GuildBushBanOptions { /** * The user to ban */ @@ -388,17 +404,17 @@ export interface BushBanOptions { evidence?: string; } -export type PunishmentResponse = 'success' | 'missing permissions' | 'error creating modlog entry'; +export type GuildPunishmentResponse = 'success' | 'missing permissions' | 'error creating modlog entry'; /** * Response returned when banning a user */ -export type BanResponse = PunishmentResponse | 'error banning' | 'error creating ban entry'; +export type GuildBanResponse = GuildPunishmentResponse | 'error banning' | 'error creating ban entry'; /** * Response returned when unbanning a user */ -export type UnbanResponse = PunishmentResponse | 'user not banned' | 'error unbanning' | 'error removing ban entry'; +export type GuildUnbanResponse = GuildPunishmentResponse | 'user not banned' | 'error unbanning' | 'error removing ban entry'; /** * Options for locking down channel(s) diff --git a/src/lib/extensions/discord.js/BushGuildMember.ts b/src/lib/extensions/discord.js/BushGuildMember.ts index ffca507..e7df926 100644 --- a/src/lib/extensions/discord.js/BushGuildMember.ts +++ b/src/lib/extensions/discord.js/BushGuildMember.ts @@ -1,14 +1,14 @@ /* eslint-disable @typescript-eslint/no-unused-vars */ import { BushClientEvents, - BushGuildTextBasedChannel, - BushGuildTextChannelResolvable, - BushThreadChannelResolvable, Moderation, ModLogType, type BushClient, type BushGuild, + type BushGuildTextBasedChannel, + type BushGuildTextChannelResolvable, type BushRole, + type BushThreadChannelResolvable, type BushUser } from '#lib'; import { GuildMember, MessageEmbed, type Partialize, type Role } from 'discord.js'; @@ -44,7 +44,8 @@ export class BushGuildMember extends GuildMember { const dmSuccess = await this.send({ content: `You have been ${punishment} in **${this.guild.name}** ${ duration !== null && duration !== undefined ? (duration ? `for ${util.humanizeDuration(duration)} ` : 'permanently ') : '' - }for **${reason?.trim() ?? 'No reason provided'}**.`, + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + }for **${reason?.trim() || 'No reason provided'}**.`, embeds: dmEmbed ? [dmEmbed] : undefined }).catch(() => false); return !!dmSuccess; @@ -559,7 +560,8 @@ export class BushGuildMember extends GuildMember { ? `for ${util.humanizeDuration(options.duration)} ` : 'permanently ' : '' - }for **${options.reason?.trim() ?? 'No reason provided'}**.` + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + }for **${options.reason?.trim() || 'No reason provided'}**.` }).catch(() => false); dmSuccessEvent = !!dmSuccess; @@ -633,7 +635,8 @@ export class BushGuildMember extends GuildMember { // dm user const dmSuccess = await this.send({ content: `You have been unblocked from <#${channel.id}> in **${this.guild.name}** for **${ - options.reason?.trim() ?? 'No reason provided' + // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing + options.reason?.trim() || 'No reason provided' }**.` }).catch(() => false); dmSuccessEvent = !!dmSuccess; diff --git a/src/lib/extensions/discord.js/BushThreadChannel.ts b/src/lib/extensions/discord.js/BushThreadChannel.ts index 4310e83..3c8859c 100644 --- a/src/lib/extensions/discord.js/BushThreadChannel.ts +++ b/src/lib/extensions/discord.js/BushThreadChannel.ts @@ -1,9 +1,11 @@ import type { + BushBaseGuildVoiceChannel, BushClient, BushGuild, BushGuildMember, BushMessageManager, BushNewsChannel, + BushTextBasedChannel, BushTextChannel, BushThreadMemberManager } from '#lib'; @@ -25,3 +27,9 @@ export class BushThreadChannel extends ThreadChannel { super(guild, data, client, fromInteraction); } } + +export interface BushThreadChannel extends ThreadChannel { + isText(): this is BushTextBasedChannel; + isVoice(): this is BushBaseGuildVoiceChannel; + isThread(): this is BushThreadChannel; +} diff --git a/src/lib/extensions/discord.js/BushThreadManager.d.ts b/src/lib/extensions/discord.js/BushThreadManager.d.ts index 1366d68..6b3340d 100644 --- a/src/lib/extensions/discord.js/BushThreadManager.d.ts +++ b/src/lib/extensions/discord.js/BushThreadManager.d.ts @@ -64,7 +64,7 @@ export class BushThreadManager<AllowedThreadType> extends CachedManager<Snowflak * .then(channel => console.log(channel.name)) * .catch(console.error); */ - public fetch(options: ThreadChannelResolvable, cacheOptions?: BaseFetchOptions): Promise<ThreadChannel | null>; + public fetch(options: ThreadChannelResolvable, cacheOptions?: BaseFetchOptions): Promise<BushThreadChannel | null>; public fetch(options?: FetchThreadsOptions, cacheOptions?: { cache?: boolean }): Promise<FetchedThreads>; /** diff --git a/src/lib/utils/BushLogger.ts b/src/lib/utils/BushLogger.ts index e05f5d6..476a86d 100644 --- a/src/lib/utils/BushLogger.ts +++ b/src/lib/utils/BushLogger.ts @@ -169,10 +169,7 @@ export class BushLogger { if (!client.config.logging.verbose) return; const newContent = this.#inspectContent(content, depth, true); console.info( - `${chalk.bgHex('#8423b8')(this.#getTimeStamp())} ${chalk.hex('#8423b8')(`[${header}]`)} ${this.#parseFormatting( - newContent, - 'blackBright' - )}` + `${chalk.bgHex('#949494')(this.#getTimeStamp())} ${chalk.hex('#949494')(`[${header}]`)} ${chalk.hex('#b3b3b3')(newContent)}` ); } @@ -183,7 +180,7 @@ export class BushLogger { */ public static async superVerboseRaw(header: string, ...content: any[]): Promise<void> { if (!client.config.logging.verbose) return; - console.info(`${chalk.bgHex('#8423b8')(this.#getTimeStamp())} ${chalk.hex('#8423b8')(`[${header}]`)}`, ...content); + console.info(`${chalk.bgHex('#a3a3a3')(this.#getTimeStamp())} ${chalk.hex('#a3a3a3')(`[${header}]`)}`, ...content); } /** diff --git a/src/listeners/client/akairoDebug.ts b/src/listeners/client/akairoDebug.ts index c8a28c4..0cb57a5 100644 --- a/src/listeners/client/akairoDebug.ts +++ b/src/listeners/client/akairoDebug.ts @@ -9,7 +9,9 @@ export default class DiscordJsDebugListener extends BushListener { }); } - public override async exec(...[message, ..._other]: BushClientEvents['debug']): Promise<void> { - void client.console.superVerboseRaw('akairoDebug', message); + public override async exec(...[message, ...other]: BushClientEvents['debug']): Promise<void> { + if (other.length && !message.includes('[registerInteractionCommands]')) + void client.console.superVerboseRaw('akairoDebug', message, ...other); + else void client.console.superVerbose('akairoDebug', message); } } diff --git a/src/listeners/client/interactionCreate.ts b/src/listeners/client/interactionCreate.ts index 26aa0a9..7eb2f10 100644 --- a/src/listeners/client/interactionCreate.ts +++ b/src/listeners/client/interactionCreate.ts @@ -20,8 +20,9 @@ export default class InteractionCreateListener extends BushListener { if (interaction.isCommand()) { return; } else if (interaction.isButton()) { - if (interaction.customId.startsWith('paginate_') || interaction.customId.startsWith('command_')) return; - else if (interaction.customId.startsWith('automod;')) void AutoMod.handleInteraction(interaction as BushButtonInteraction); + const id = interaction.customId; + if (id.startsWith('paginate_') || id.startsWith('command_') || id.startsWith('confirmationPrompt_')) return; + else if (id.startsWith('automod;')) void AutoMod.handleInteraction(interaction as BushButtonInteraction); else return await interaction.reply({ content: 'Buttons go brrr', ephemeral: true }); } else if (interaction.isSelectMenu()) { if (interaction.customId.startsWith('command_')) return; diff --git a/src/listeners/guild-custom/bushLockdown.ts b/src/listeners/guild-custom/bushLockdown.ts index be55a07..d48ddf1 100644 --- a/src/listeners/guild-custom/bushLockdown.ts +++ b/src/listeners/guild-custom/bushLockdown.ts @@ -10,7 +10,7 @@ export default class BushLockdownListener extends BushListener { }); } - public override async exec(...[moderator, reason, channel, _all]: BushClientEvents['bushLockdown']) { + public override async exec(...[moderator, reason, channelsSuccessMap, _all]: BushClientEvents['bushLockdown']) { const logChannel = await moderator.guild.getLogChannel('moderation'); if (!logChannel) return; @@ -21,7 +21,12 @@ export default class BushLockdownListener extends BushListener { .addField('**Moderator**', `${moderator} (${moderator.user.tag})`) // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing .addField('**Reason**', `${reason || '[No Reason Provided]'}`) - .addField('**Channel**', `${channel?.id ? `<#${channel.id}>` : '[All Configured Channels]'}`); + .addField( + `**Channel${channelsSuccessMap.size > 1 ? 's' : ''}**`, + channelsSuccessMap + .map((success, channel) => `<#${channel}> ${success ? util.emojis.success : util.emojis.error}`) + .join('\n') + ); return await logChannel.send({ embeds: [logEmbed] }); } } diff --git a/src/listeners/guild-custom/bushUnlockdown.ts b/src/listeners/guild-custom/bushUnlockdown.ts index d5831c6..cfddc2f 100644 --- a/src/listeners/guild-custom/bushUnlockdown.ts +++ b/src/listeners/guild-custom/bushUnlockdown.ts @@ -10,7 +10,7 @@ export default class BushUnlockdownListener extends BushListener { }); } - public override async exec(...[moderator, reason, channel, _all]: BushClientEvents['bushUnlockdown']) { + public override async exec(...[moderator, reason, channelsSuccessMap, _all]: BushClientEvents['bushUnlockdown']) { const logChannel = await moderator.guild.getLogChannel('moderation'); if (!logChannel) return; @@ -21,7 +21,12 @@ export default class BushUnlockdownListener extends BushListener { .addField('**Moderator**', `${moderator} (${moderator.user.tag})`) // eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing .addField('**Reason**', `${reason || '[No Reason Provided]'}`) - .addField('**Channel**', `${channel?.id ? `<#${channel.id}>` : '[All Configured Channels]'}`); + .addField( + `**Channel${channelsSuccessMap.size > 1 ? 's' : ''}**`, + channelsSuccessMap + .map((success, channel) => `<#${channel}> ${success ? util.emojis.success : util.emojis.error}`) + .join('\n') + ); return await logChannel.send({ embeds: [logEmbed] }); } } |