aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commands/config/config.ts2
-rw-r--r--src/commands/moderation/lockdown.ts8
-rw-r--r--src/lib/common/ConfirmationPrompt.ts16
-rw-r--r--src/lib/extensions/discord.js/BushClientEvents.d.ts8
-rw-r--r--src/lib/extensions/discord.js/BushDMChannel.ts15
-rw-r--r--src/lib/extensions/discord.js/BushGuild.ts62
-rw-r--r--src/lib/extensions/discord.js/BushGuildMember.ts15
-rw-r--r--src/lib/extensions/discord.js/BushThreadChannel.ts8
-rw-r--r--src/lib/extensions/discord.js/BushThreadManager.d.ts2
-rw-r--r--src/lib/utils/BushLogger.ts7
-rw-r--r--src/listeners/client/akairoDebug.ts6
-rw-r--r--src/listeners/client/interactionCreate.ts5
-rw-r--r--src/listeners/guild-custom/bushLockdown.ts9
-rw-r--r--src/listeners/guild-custom/bushUnlockdown.ts9
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] });
}
}