diff options
-rw-r--r-- | src/commands/info/botInfo.ts | 1 | ||||
-rw-r--r-- | src/commands/moderation/evidence.ts | 32 | ||||
-rw-r--r-- | src/commands/moderation/massEvidence.ts | 97 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushClientEvents.ts | 6 | ||||
-rw-r--r-- | src/listeners/member-custom/massBan.ts | 2 | ||||
-rw-r--r-- | src/listeners/member-custom/massEvidence.ts | 31 |
6 files changed, 160 insertions, 9 deletions
diff --git a/src/commands/info/botInfo.ts b/src/commands/info/botInfo.ts index 3338824..e67ae5a 100644 --- a/src/commands/info/botInfo.ts +++ b/src/commands/info/botInfo.ts @@ -56,6 +56,7 @@ export default class BotInfoCommand extends BushCommand { { name: '**CPU Usage**', value: `${client.stats.cpu}%`, inline: true }, { name: '**Platform**', value: Platform[process.platform], inline: true }, { name: '**Commands Used**', value: `${client.stats.commandsUsed.toLocaleString()}`, inline: true }, + { name: '**Slash Commands Used**', value: `${client.stats.slashCommandsUsed.toLocaleString()}`, inline: true }, { name: '**Servers**', value: client.guilds.cache.size.toLocaleString(), inline: true }, { name: '**Users**', value: client.users.cache.size.toLocaleString(), inline: true }, { name: '**Discord.js Version**', value: discordJSVersion, inline: true }, diff --git a/src/commands/moderation/evidence.ts b/src/commands/moderation/evidence.ts index 362f471..68d7edc 100644 --- a/src/commands/moderation/evidence.ts +++ b/src/commands/moderation/evidence.ts @@ -1,4 +1,4 @@ -import { BushCommand, ModLog, type BushMessage, type BushSlashMessage } from '#lib'; +import { BushCommand, ModLog, OptionalArgType, type BushMessage, type BushSlashMessage } from '#lib'; import assert from 'assert'; import { ArgumentGeneratorReturn } from 'discord-akairo'; import { ArgumentTypeCasterReturn } from 'discord-akairo/dist/src/struct/commands/arguments/Argument.js'; @@ -64,7 +64,7 @@ export default class EvidenceCommand extends BushCommand { public override async exec( message: BushMessage | BushSlashMessage, - { case_id: caseID, evidence }: { case_id: string; evidence?: string } + { case_id: caseID, evidence }: { case_id: string; evidence: OptionalArgType<'string'> } ) { assert(message.inGuild()); @@ -72,14 +72,11 @@ export default class EvidenceCommand extends BushCommand { if (!entry || entry.pseudo) return message.util.send(`${util.emojis.error} Invalid modlog entry.`); if (entry.guild !== message.guild.id) return message.util.reply(`${util.emojis.error} This modlog is from another server.`); - if (evidence && (message as BushMessage).attachments?.size) - return message.util.reply(`${util.emojis.error} Please either attach an image or a reason not both.`); - - const _evidence = evidence ? evidence : !message.util.isSlash ? (message as BushMessage).attachments.first()?.url : undefined; - if (!_evidence) return message.util.reply(`${util.emojis.error} You must provide evidence for this modlog.`); - const oldEntry = entry.evidence; + const _evidence = EvidenceCommand.getEvidence(message, evidence); + if (!_evidence) return; + entry.evidence = _evidence.trim(); await entry.save(); @@ -87,4 +84,23 @@ export default class EvidenceCommand extends BushCommand { return message.util.reply(`${util.emojis.success} Successfully updated the evidence for case ${util.format.input(caseID)}.`); } + + public static getEvidence(message: BushMessage | BushSlashMessage, evidenceArg: OptionalArgType<'string'>): null | string { + if (evidenceArg && (message as BushMessage).attachments?.size) { + void message.util.reply(`${util.emojis.error} Please either attach an image or a reason not both.`); + return null; + } + + const _evidence = evidenceArg + ? evidenceArg + : !message.util.isSlash + ? (message as BushMessage).attachments.first()?.url + : undefined; + if (!_evidence) { + void message.util.reply(`${util.emojis.error} You must provide evidence for this modlog.`); + return null; + } + + return _evidence; + } } diff --git a/src/commands/moderation/massEvidence.ts b/src/commands/moderation/massEvidence.ts new file mode 100644 index 0000000..0fc3ad0 --- /dev/null +++ b/src/commands/moderation/massEvidence.ts @@ -0,0 +1,97 @@ +import { BushCommand, ModLog, type ArgType, type BushMessage, type BushSlashMessage, type OptionalArgType } from '#lib'; +import assert from 'assert'; +import { ApplicationCommandOptionType, PermissionFlagsBits } from 'discord.js'; +import { EvidenceCommand } from '../index.js'; + +export default class MassEvidenceCommand extends BushCommand { + public constructor() { + super('massEvidence', { + aliases: ['mass-evidence'], + category: 'moderation', + description: 'Add evidence to the last punishment of multiple users.', + usage: ['mass-ban <...users> [--evidence "<evidence>"]'], + examples: [ + 'mass-evidence 311294982898057217 792202575851814942 792199864510447666 792201010118131713 --evidence "ironmoon said so"' + ], + args: [ + { + id: 'users', + description: 'The ids of users to add evidence to each of their last punishment.', + type: 'string', + match: 'rest', + prompt: 'What are the ids of all the users you would like add evidence to their last punishment?', + retry: '{error} Choose a valid list of user ids to add evidence to their last punishment.', + slashType: ApplicationCommandOptionType.String + }, + { + id: 'evidence', + description: 'The evidence for the punishment.', + flag: ['--evidence'], + match: 'option', + prompt: 'What is the evidence for the punishment?', + retry: '{error} Provide valid evidence for the punishment.', + optional: true, + slashType: ApplicationCommandOptionType.String + } + ], + quoted: true, + slash: true, + channel: 'guild', + clientPermissions: (m) => util.clientSendAndPermCheck(m), + userPermissions: [PermissionFlagsBits.ManageMessages], + lock: 'user' + }); + } + + public override async exec( + message: BushMessage | BushSlashMessage, + args: { users: ArgType<'string'>; evidence: OptionalArgType<'string'> } + ) { + assert(message.inGuild()); + + const evidence = EvidenceCommand.getEvidence(message, args.evidence); + if (!evidence) return; + + const ids = args.users.split(/\n| /).filter((id) => id.length > 0); + if (ids.length === 0) return message.util.send(`${util.emojis.error} You must provide at least one user id.`); + for (const id of ids) { + if (!client.constants.regex.snowflake.test(id)) + return message.util.send(`${util.emojis.error} ${id} is not a valid snowflake.`); + } + + const caseMap = ( + await Promise.all( + ids.map((id) => + ModLog.findOne({ + where: { guild: message.guild.id, user: id }, + order: [['createdAt', 'ASC']] + }).catch(() => null) + ) + ) + ).map((c, i) => [ids[i], c] as const); + + const cases = caseMap.filter(([, c]) => c && !c.pseudo).map(([id, c]) => [id, c!] as const); + + const promises = cases.map(([, c]) => ((c.evidence = evidence), c.save())); + + const res = await Promise.all(promises); + + const lines = ids.map((_, i) => { + const case_ = res[i]; + if (!case_) return `${util.emojis.error} ${i} - no case found.`; + return `${util.emojis.success} ${i} - ${case_.id}`; + }); + + client.emit('massEvidence', message.member!, message.guild, evidence, lines); + + const embeds = util.overflowEmbed( + { + color: util.colors.DarkRed, + title: 'Mass Evidence' + }, + lines + ); + + return message.util.send({ embeds }); + } +} diff --git a/src/lib/extensions/discord.js/BushClientEvents.ts b/src/lib/extensions/discord.js/BushClientEvents.ts index fc9993e..e1a9954 100644 --- a/src/lib/extensions/discord.js/BushClientEvents.ts +++ b/src/lib/extensions/discord.js/BushClientEvents.ts @@ -327,6 +327,12 @@ export interface BushClientEvents extends AkairoClientEvents { reason: string | undefined, results: Collection<Snowflake, BanResponse> ]; + massEvidence: [ + moderator: BushGuildMember, + guild: BushGuild, + evidence: string, + lines: string[] + ]; /* components */ button: [button: BushButtonInteraction]; selectMenu: [selectMenu: BushSelectMenuInteraction]; diff --git a/src/listeners/member-custom/massBan.ts b/src/listeners/member-custom/massBan.ts index 693c09c..29f7ce3 100644 --- a/src/listeners/member-custom/massBan.ts +++ b/src/listeners/member-custom/massBan.ts @@ -1,6 +1,6 @@ import { BanResponse, banResponse, BushListener, type BushClientEvents } from '#lib'; -export default class BushBanListener extends BushListener { +export default class MassBanListener extends BushListener { public constructor() { super('massBan', { emitter: 'client', diff --git a/src/listeners/member-custom/massEvidence.ts b/src/listeners/member-custom/massEvidence.ts new file mode 100644 index 0000000..4a45ee7 --- /dev/null +++ b/src/listeners/member-custom/massEvidence.ts @@ -0,0 +1,31 @@ +import { BushListener, type BushClientEvents } from '#lib'; + +export default class MassEvidenceListener extends BushListener { + public constructor() { + super('massEvidence', { + emitter: 'client', + event: 'massEvidence', + category: 'member-custom' + }); + } + + public override async exec(...[moderator, guild, evidence, lines]: BushClientEvents['massEvidence']) { + const logChannel = await guild.getLogChannel('moderation'); + if (!logChannel) return; + + const embeds = util.overflowEmbed( + { + color: util.colors.DarkRed, + title: 'Mass Evidence', + timestamp: new Date().toISOString(), + fields: [ + { name: '**Moderator**', value: `${moderator} (${moderator.user.tag})` }, + { name: '**Evidence**', value: `${evidence}` } + ] + }, + lines + ); + + return await logChannel.send({ embeds }); + } +} |