diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/commands/config/blacklist.ts | 2 | ||||
-rw-r--r-- | src/commands/config/config.ts | 38 | ||||
-rw-r--r-- | src/commands/config/disable.ts | 2 | ||||
-rw-r--r-- | src/commands/config/features.ts | 3 | ||||
-rw-r--r-- | src/commands/config/log.ts | 3 | ||||
-rw-r--r-- | src/commands/info/botInfo.ts | 2 | ||||
-rw-r--r-- | src/commands/moderation/evidence.ts | 92 | ||||
-rw-r--r-- | src/commands/moderation/hideCase.ts | 14 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClient.ts | 4 | ||||
-rw-r--r-- | src/lib/extensions/discord-akairo/BushClientUtil.ts | 3 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushClientEvents.d.ts | 72 | ||||
-rw-r--r-- | src/lib/extensions/discord.js/BushGuild.ts | 22 | ||||
-rw-r--r-- | src/lib/models/Guild.ts | 12 | ||||
-rw-r--r-- | src/listeners/client/ready.ts | 2 | ||||
-rw-r--r-- | src/listeners/custom/bushUpdateModlog.ts | 33 | ||||
-rw-r--r-- | src/listeners/custom/bushUpdateSettings.ts | 36 | ||||
-rw-r--r-- | src/listeners/guild/guildMemberRemove.ts | 5 |
17 files changed, 258 insertions, 87 deletions
diff --git a/src/commands/config/blacklist.ts b/src/commands/config/blacklist.ts index ff34567..5dea36a 100644 --- a/src/commands/config/blacklist.ts +++ b/src/commands/config/blacklist.ts @@ -115,7 +115,7 @@ export default class BlacklistCommand extends BushCommand { targetID ); const success = await message.guild - .setSetting(target instanceof User ? 'blacklistedUsers' : 'blacklistedChannels', newValue) + .setSetting(target instanceof User ? 'blacklistedUsers' : 'blacklistedChannels', newValue, message.member!) .catch(() => false); if (!success) return await message.util.reply({ diff --git a/src/commands/config/config.ts b/src/commands/config/config.ts index 0c466e6..cba4468 100644 --- a/src/commands/config/config.ts +++ b/src/commands/config/config.ts @@ -49,7 +49,11 @@ export default class SettingsCommand extends BushCommand { description: `What would you like to add to the server's ${guildSettingsObj[ setting ].name.toLowerCase()}?'`, - type: guildSettingsObj[setting].type.replace('-array', '').toUpperCase() as 'ROLE' | 'STRING' | 'CHANNEL', + type: guildSettingsObj[setting].type.replace('-array', '').toUpperCase() as + | 'ROLE' + | 'STRING' + | 'CHANNEL' + | 'USER', required: true } ] @@ -64,7 +68,11 @@ export default class SettingsCommand extends BushCommand { description: `What would you like to remove from the server's ${guildSettingsObj[ setting ].name.toLowerCase()}?'`, - type: guildSettingsObj[setting].type.replace('-array', '').toUpperCase() as 'ROLE' | 'STRING' | 'CHANNEL', + type: guildSettingsObj[setting].type.replace('-array', '').toUpperCase() as + | 'ROLE' + | 'STRING' + | 'CHANNEL' + | 'USER', required: true } ] @@ -86,7 +94,7 @@ export default class SettingsCommand extends BushCommand { description: `What would you like to set the server's ${guildSettingsObj[ setting ].name.toLowerCase()} to?'`, - type: guildSettingsObj[setting].type.toUpperCase() as 'ROLE' | 'STRING' | 'CHANNEL', + type: guildSettingsObj[setting].type.toUpperCase() as 'ROLE' | 'STRING' | 'CHANNEL' | 'USER', required: true } ] @@ -183,7 +191,7 @@ export default class SettingsCommand extends BushCommand { if (!message.guild) return await message.util.reply(`${util.emojis.error} This command can only be used in servers.`); if (!message.member?.permissions.has('MANAGE_GUILD')) return await message.util.reply( - `${util.emojis.error} You must have the **MANAGE_GUILD** permissions to run this command.` + `${util.emojis.error} You must have the **MANAGE_GUILD** permission to run this command.` ); const setting = message.util.isSlash ? (_.camelCase(args.subcommandGroup)! as GuildSettings) : args.setting!; const action = message.util.isSlash ? args.subcommand! : args.action!; @@ -217,13 +225,13 @@ export default class SettingsCommand extends BushCommand { case 'remove': { const existing = (await message.guild.getSetting(setting)) as string[]; const updated = util.addOrRemoveFromArray('add', existing, parseVal(value)); - await message.guild.setSetting(setting, updated); + await message.guild.setSetting(setting, updated, message.member); const messageOptions = await this.generateMessageOptions(message, setting); msg = (await message.util.reply(messageOptions)) as Message; break; } case 'set': { - await message.guild.setSetting(setting, parseVal(value)); + await message.guild.setSetting(setting, parseVal(value), message.member); const messageOptions = await this.generateMessageOptions(message, setting); msg = (await message.util.reply(messageOptions)) as Message; break; @@ -289,11 +297,11 @@ export default class SettingsCommand extends BushCommand { } else { settingsEmbed.setTitle(guildSettingsObj[setting].name); const generateCurrentValue = async ( - type: 'string' | 'channel' | 'channel-array' | 'role' | 'role-array' + type: 'string' | 'channel' | 'channel-array' | 'role' | 'role-array' | 'user' | 'user-array' | 'custom' ): Promise<string> => { const feat = await message.guild!.getSetting(setting); - switch (type.replace('-array', '') as 'string' | 'channel' | 'role') { + switch (type.replace('-array', '') as 'string' | 'channel' | 'role' | 'user' | 'custom') { case 'string': { return Array.isArray(feat) ? feat.length @@ -308,14 +316,24 @@ export default class SettingsCommand extends BushCommand { ? feat.length ? feat.map((feat) => `<#${feat}>`).join('\n') : '[Empty Array]' - : `<#${feat}>`; + : `<#${feat as string}>`; } case 'role': { return Array.isArray(feat) ? feat.length ? feat.map((feat) => `<@&${feat}>`).join('\n') : '[Empty Array]' - : `<@&${feat}>`; + : `<@&${feat as string}>`; + } + case 'user': { + return Array.isArray(feat) + ? feat.length + ? feat.map((feat) => `<@${feat}>`).join('\n') + : '[Empty Array]' + : `<@${feat as string}>`; + } + case 'custom': { + return util.inspectAndRedact(feat); } } }; diff --git a/src/commands/config/disable.ts b/src/commands/config/disable.ts index bc6ed47..db4909a 100644 --- a/src/commands/config/disable.ts +++ b/src/commands/config/disable.ts @@ -103,7 +103,7 @@ export default class DisableCommand extends BushCommand { action = disabledCommands.includes(commandID) ? 'disable' : 'enable'; } const newValue = util.addOrRemoveFromArray(action === 'disable' ? 'remove' : 'add', disabledCommands, commandID); - const success = await message.guild!.setSetting('disabledCommands', newValue).catch(() => false); + const success = await message.guild!.setSetting('disabledCommands', newValue, message.member!).catch(() => false); if (!success) return await message.util.reply({ content: `${util.emojis.error} There was an error **${action.substr( diff --git a/src/commands/config/features.ts b/src/commands/config/features.ts index 3c607c7..2169177 100644 --- a/src/commands/config/features.ts +++ b/src/commands/config/features.ts @@ -42,12 +42,11 @@ export default class FeaturesCommand extends BushCommand { if (!guildFeaturesArr.includes(selected)) throw new Error('Invalid guild feature selected'); - const newEnabledFeatures = await message.guild.toggleFeature(selected); + const newEnabledFeatures = await message.guild.toggleFeature(selected, message.member!); this.generateDescription(guildFeaturesArr, newEnabledFeatures, featureEmbed); await interaction.update({ embeds: [featureEmbed] }).catch(() => undefined); - return; } else { return await interaction?.deferUpdate().catch(() => undefined); diff --git a/src/commands/config/log.ts b/src/commands/config/log.ts index 0bc2189..49db6f8 100644 --- a/src/commands/config/log.ts +++ b/src/commands/config/log.ts @@ -72,7 +72,8 @@ export default class LogCommand extends BushCommand { action ? (currentLogs[args.log_type] = args.channel.id) : delete currentLogs[args.log_type]; - const success = await message.guild.setSetting('logChannels', currentLogs); + const success = await message.guild.setSetting('logChannels', currentLogs, message.member!); + return await message.util.reply( `${ success diff --git a/src/commands/info/botInfo.ts b/src/commands/info/botInfo.ts index 45c3dd8..30bfeb4 100644 --- a/src/commands/info/botInfo.ts +++ b/src/commands/info/botInfo.ts @@ -39,7 +39,7 @@ export default class BotInfoCommand extends BushCommand { repoUrl = repoUrl.substring(0, repoUrl.length - 4); const embed = new MessageEmbed() .setTitle('Bot Info:') - .addField('**Uptime**', util.humanizeDuration(client.uptime!), true) + .addField('**Uptime**', util.humanizeDuration(client.uptime!, 2), true) .addField( '**Memory Usage**', `System: ${prettyBytes(os.totalmem() - os.freemem(), { binary: true })}/${prettyBytes(os.totalmem(), { diff --git a/src/commands/moderation/evidence.ts b/src/commands/moderation/evidence.ts index ae0a128..71a52b2 100644 --- a/src/commands/moderation/evidence.ts +++ b/src/commands/moderation/evidence.ts @@ -1,4 +1,5 @@ -import { BushCommand, BushMessage, BushSlashMessage } from '@lib'; +import { BushCommand, BushMessage, BushSlashMessage, ModLog } from '@lib'; +import { ArgumentOptions, Flag } from 'discord-akairo'; export default class EvidenceCommand extends BushCommand { public constructor() { @@ -7,54 +8,81 @@ export default class EvidenceCommand extends BushCommand { category: 'moderation', description: { content: 'Add evidence to a modlog case.', - usage: 'evidence <caseID> <evidence>', + usage: 'evidence <case_id> <evidence>', examples: ['evidence '] }, - args: [ - { - id: 'case', - type: 'string', - prompt: { - start: 'What would you like to set your first argument to be?', - retry: '{error} Pick a valid argument.', - optional: false - } - }, - { - id: 'evidence', - type: 'string', - prompt: { - start: 'What would you like to set your second argument to be?', - retry: '{error} Pick a valid argument.', - optional: true - } - } - ], slash: true, slashOptions: [ { - name: 'case', - description: 'What would you like to set your first argument to be?', + name: 'case_id', + description: 'What case would you like to modify the evidence of?', type: 'STRING', required: true }, { name: 'evidence', - description: 'What would you like to set your second argument to be?', + description: 'What would you like to modify the evidence to?', type: 'STRING', - required: false + required: true } ], - superUserOnly: true, - ownerOnly: true, channel: 'guild', - hidden: true, clientPermissions: ['SEND_MESSAGES'], - userPermissions: ['SEND_MESSAGES'] + userPermissions: ['SEND_MESSAGES', 'MANAGE_MESSAGES'] }); } - public override async exec(message: BushMessage | BushSlashMessage): Promise<unknown> { - return await message.util.reply(`${util.emojis.error} Soon:tm:.`); + *args(message: BushMessage): IterableIterator<ArgumentOptions | Flag> { + const case_id = yield { + id: 'case_id', + type: 'string', + prompt: { + start: 'What case would you like to modify the evidence of?', + retry: '{error} Pick a valid case to modify the evidence of.', + optional: false + } + }; + + const evidence = yield { + id: 'evidence', + type: 'string', + match: 'restContent', + prompt: { + start: 'What would you like to modify the evidence to?', + retry: '{error} Pick a valid argument.', + optional: !!message.attachments.some((attachment) => !!attachment.contentType?.includes('image')) + } + }; + + return { case_id, evidence }; + } + + public override async exec( + message: BushMessage | BushSlashMessage, + { case_id: caseID, evidence }: { case_id: string; evidence?: string } + ): Promise<unknown> { + const entry = await ModLog.findByPk(caseID); + 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; + + entry.evidence = _evidence.trim(); + await entry.save(); + + client.emit('bushUpdateModlog', message.member!, entry.id, 'evidence', oldEntry, entry.evidence); + + return message.util.reply(`${util.emojis.success} Successfully updated the evidence for case \`${caseID}\`.`); } } diff --git a/src/commands/moderation/hideCase.ts b/src/commands/moderation/hideCase.ts index 6cd8e31..2529531 100644 --- a/src/commands/moderation/hideCase.ts +++ b/src/commands/moderation/hideCase.ts @@ -7,12 +7,12 @@ export default class HideCaseCommand extends BushCommand { category: 'moderation', description: { content: 'Hide a particular modlog case from the modlog command unless the `--hidden` flag is specified', - usage: 'hideCase <caseID>', + usage: 'hideCase <case_id>', examples: ['hideCase 9210b1ea-91f5-4ea2-801b-02b394469c77'] }, args: [ { - id: 'case', + id: 'case_id', type: 'string', prompt: { start: 'What modlog case would you like to hide?', @@ -24,7 +24,7 @@ export default class HideCaseCommand extends BushCommand { slash: true, slashOptions: [ { - name: 'case', + name: 'case_id', description: 'What modlog case would you like to hide?', type: 'STRING', required: true @@ -34,7 +34,10 @@ export default class HideCaseCommand extends BushCommand { }); } - public override async exec(message: BushMessage | BushSlashMessage, { case: caseID }: { case: string }): Promise<unknown> { + public override async exec( + message: BushMessage | BushSlashMessage, + { case_id: caseID }: { case_id: string } + ): Promise<unknown> { if (message.author.id === '496409778822709251') return await message.util.reply(`${util.emojis.error} This command is Bestower proof.`); const entry = await ModLog.findByPk(caseID); @@ -42,9 +45,12 @@ export default class HideCaseCommand extends BushCommand { if (entry.guild !== message.guild!.id) return message.util.reply(`${util.emojis.error} This modlog is from another server.`); const action = entry.hidden ? 'no longer hidden' : 'now hidden'; + const oldEntry = entry.hidden; entry.hidden = !entry.hidden; await entry.save(); + client.emit('bushUpdateModlog', message.member!, entry.id, 'hidden', oldEntry, entry.hidden); + return await message.util.reply(`${util.emojis.success} CaseID \`${caseID}\` is ${action}.`); } } diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts index 59c4df8..d488525 100644 --- a/src/lib/extensions/discord-akairo/BushClient.ts +++ b/src/lib/extensions/discord-akairo/BushClient.ts @@ -9,6 +9,7 @@ import { MessageEditOptions, MessageOptions, MessagePayload, + Options, PartialDMChannel, ReplyMessageOptions, Snowflake, @@ -219,7 +220,8 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re status: 'online' }, http: { api: 'https://canary.discord.com/api' }, - allowedMentions: AllowedMentions.users() // No everyone or role mentions by default + allowedMentions: AllowedMentions.users(), // No everyone or role mentions by default + makeCache: Options.cacheWithLimits({}) }); this.token = config.token; diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts index 4028517..38e1a06 100644 --- a/src/lib/extensions/discord-akairo/BushClientUtil.ts +++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts @@ -1169,7 +1169,8 @@ export class BushClientUtil extends ClientUtil { if (!getCaseNumber) return { log: saveResult, caseNum: null }; - const caseNum = (await ModLog.findAll({ where: { type: options.type, user: user, guild: guild, hidden: false } }))?.length; + const caseNum = (await ModLog.findAll({ where: { type: options.type, user: user, guild: guild, hidden: 'false' } })) + ?.length; return { log: saveResult, caseNum }; } diff --git a/src/lib/extensions/discord.js/BushClientEvents.d.ts b/src/lib/extensions/discord.js/BushClientEvents.d.ts index b797698..0406015 100644 --- a/src/lib/extensions/discord.js/BushClientEvents.d.ts +++ b/src/lib/extensions/discord.js/BushClientEvents.d.ts @@ -1,4 +1,31 @@ import { + BushApplicationCommand, + BushClient, + BushDMChannel, + BushGuild, + BushGuildChannel, + BushGuildEmoji, + BushGuildMember, + BushMessage, + BushMessageReaction, + BushNewsChannel, + BushPresence, + BushRole, + BushStageInstance, + BushTextBasedChannels, + BushTextChannel, + BushThreadChannel, + BushThreadMember, + BushUser, + BushVoiceState, + Guild, + GuildSettings, + PartialBushGuildMember, + PartialBushMessage, + PartialBushMessageReaction, + PartialBushUser +} from '@lib'; +import { ClientEvents, Collection, Interaction, @@ -9,31 +36,7 @@ import { Sticker, Typing } from 'discord.js'; -import { - BushClient, - BushTextBasedChannels -} from '../discord-akairo/BushClient'; -import { BushApplicationCommand } from './BushApplicationCommand'; -import { BushDMChannel } from './BushDMChannel'; -import { BushGuild } from './BushGuild'; import { BushGuildBan } from './BushGuildBan'; -import { BushGuildChannel } from './BushGuildChannel'; -import { BushGuildEmoji } from './BushGuildEmoji'; -import { BushGuildMember, PartialBushGuildMember } from './BushGuildMember'; -import { BushMessage, PartialBushMessage } from './BushMessage'; -import { - BushMessageReaction, - PartialBushMessageReaction -} from './BushMessageReaction'; -import { BushNewsChannel } from './BushNewsChannel'; -import { BushPresence } from './BushPresence'; -import { BushRole } from './BushRole'; -import { BushStageInstance } from './BushStageInstance'; -import { BushTextChannel } from './BushTextChannel'; -import { BushThreadChannel } from './BushThreadChannel'; -import { BushThreadMember } from './BushThreadMember'; -import { BushUser, PartialBushUser } from './BushUser'; -import { BushVoiceState } from './BushVoiceState'; export interface BushClientEvents extends ClientEvents { applicationCommandCreate: [command: BushApplicationCommand]; @@ -205,6 +208,20 @@ export interface BushClientEvents extends ClientEvents { caseID: string, dmSuccess: boolean ]; + bushUpdateModlog: [ + moderator: BushGuildMember, + modlogID: string, + key: 'evidence' | 'hidden', + oldModlog: string | boolean, + newModlog: string | boolean + ]; + bushUpdateSettings: [ + setting: Setting, + guild: BushGuild, + oldValue: Guild[Setting], + newValue: Guild[Setting], + moderator?: BushGuildMember + ]; bushWarn: [ victim: BushGuildMember, moderator: BushUser, @@ -214,3 +231,10 @@ export interface BushClientEvents extends ClientEvents { dmSuccess: boolean ]; } + +type Setting = + | GuildSettings + | 'enabledFeatures' + | 'blacklistedChannels' + | 'blacklistedUsers' + | 'disabledCommands'; diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts index 18f6542..256b9dc 100644 --- a/src/lib/extensions/discord.js/BushGuild.ts +++ b/src/lib/extensions/discord.js/BushGuild.ts @@ -21,20 +21,22 @@ export class BushGuild extends Guild { return features.includes(feature); } - public async addFeature(feature: GuildFeatures): Promise<GuildModel['enabledFeatures']> { + public async addFeature(feature: GuildFeatures, moderator?: BushGuildMember): Promise<GuildModel['enabledFeatures']> { const features = await this.getSetting('enabledFeatures'); const newFeatures = util.addOrRemoveFromArray('add', features, feature); - return (await this.setSetting('enabledFeatures', newFeatures)).enabledFeatures; + return (await this.setSetting('enabledFeatures', newFeatures, moderator)).enabledFeatures; } - public async removeFeature(feature: GuildFeatures): Promise<GuildModel['enabledFeatures']> { + public async removeFeature(feature: GuildFeatures, moderator?: BushGuildMember): Promise<GuildModel['enabledFeatures']> { const features = await this.getSetting('enabledFeatures'); const newFeatures = util.addOrRemoveFromArray('remove', features, feature); - return (await this.setSetting('enabledFeatures', newFeatures)).enabledFeatures; + return (await this.setSetting('enabledFeatures', newFeatures, moderator)).enabledFeatures; } - public async toggleFeature(feature: GuildFeatures): Promise<GuildModel['enabledFeatures']> { - return (await this.hasFeature(feature)) ? await this.removeFeature(feature) : await this.addFeature(feature); + public async toggleFeature(feature: GuildFeatures, moderator?: BushGuildMember): Promise<GuildModel['enabledFeatures']> { + return (await this.hasFeature(feature)) + ? await this.removeFeature(feature, moderator) + : await this.addFeature(feature, moderator); } public async getSetting<K extends keyof GuildModel>(setting: K): Promise<GuildModel[K]> { @@ -44,10 +46,16 @@ export class BushGuild extends Guild { ); } - public async setSetting<K extends keyof GuildModel>(setting: K, value: GuildDB[K]): Promise<GuildDB> { + public async setSetting<K extends Exclude<keyof GuildModel, 'id'>>( + setting: K, + value: GuildDB[K], + moderator?: BushGuildMember + ): Promise<GuildDB> { const row = (await GuildDB.findByPk(this.id)) ?? GuildDB.build({ id: this.id }); + const oldValue = row[setting] as GuildDB[K]; row[setting] = value; client.cache.guilds.set(this.id, row.toJSON() as GuildDB); + client.emit('bushUpdateSettings', setting, this, oldValue, row[setting], moderator); return await row.save(); } diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts index b155330..9b283ab 100644 --- a/src/lib/models/Guild.ts +++ b/src/lib/models/Guild.ts @@ -52,6 +52,18 @@ export const guildSettingsObj = { description: 'These users will be able to use commands in channels blacklisted.', type: 'user-array', configurable: true + }, + logChannels: { + name: 'Log Channels', + description: 'The channel were logs are sent.', + type: 'custom', + configurable: false + }, + autoModPhases: { + name: 'Automod Phases', + description: 'Custom phrases to be detected by automod.', + type: 'custom', + configurable: false } }; export type GuildSettings = keyof typeof guildSettingsObj; diff --git a/src/listeners/client/ready.ts b/src/listeners/client/ready.ts index fc71bb9..386d132 100644 --- a/src/listeners/client/ready.ts +++ b/src/listeners/client/ready.ts @@ -6,7 +6,7 @@ export default class ReadyListener extends BushListener { super('ready', { emitter: 'client', event: 'ready', - type: 'once' + type: 'on' }); } diff --git a/src/listeners/custom/bushUpdateModlog.ts b/src/listeners/custom/bushUpdateModlog.ts new file mode 100644 index 0000000..16e0dbf --- /dev/null +++ b/src/listeners/custom/bushUpdateModlog.ts @@ -0,0 +1,33 @@ +import { BushListener } from '@lib'; +import { MessageEmbed } from 'discord.js'; +import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents'; + +export default class BushUpdateModlogListener extends BushListener { + public constructor() { + super('bushUpdateModlog', { + emitter: 'client', + event: 'bushUpdateModlog', + category: 'custom' + }); + } + + public override async exec( + ...[moderator, modlogID, key, oldModlog, newModlog]: BushClientEvents['bushUpdateModlog'] + ): Promise<unknown> { + const logChannel = await moderator.guild.getLogChannel('moderation'); + if (!logChannel) return; + + const logEmbed = new MessageEmbed() + .setColor(util.colors.discord.BLURPLE) + .setTimestamp() + .setAuthor(moderator.user.tag, moderator.user.avatarURL({ dynamic: true, format: 'png', size: 4096 }) ?? undefined) + .addField('**Action**', `${'Update Modlog'}`) + .addField('**Moderator**', `${moderator} (${moderator.user.tag})`) + .addField('**ModLog Changed**', modlogID) + .addField('**Value Changed**', key) + .addField('**Old Value**', await util.inspectCleanRedactCodeblock(oldModlog, undefined, undefined, 1024)) + .addField('**New Value**', await util.inspectCleanRedactCodeblock(newModlog, undefined, undefined, 1024)); + + return await logChannel.send({ embeds: [logEmbed] }); + } +} diff --git a/src/listeners/custom/bushUpdateSettings.ts b/src/listeners/custom/bushUpdateSettings.ts new file mode 100644 index 0000000..eae3062 --- /dev/null +++ b/src/listeners/custom/bushUpdateSettings.ts @@ -0,0 +1,36 @@ +import { BushListener } from '@lib'; +import { MessageEmbed } from 'discord.js'; +import { BushClientEvents } from '../../lib/extensions/discord.js/BushClientEvents'; + +export default class BushUpdateSettingsListener extends BushListener { + public constructor() { + super('bushUpdateSettings', { + emitter: 'client', + event: 'bushUpdateSettings', + category: 'custom' + }); + } + + public override async exec( + ...[setting, guild, oldSettings, newSettings, moderator]: BushClientEvents['bushUpdateSettings'] + ): Promise<unknown> { + const logChannel = await guild.getLogChannel('moderation'); + if (!logChannel) return; + + const logEmbed = new MessageEmbed().setColor(util.colors.discord.BLURPLE).setTimestamp(); + + if (moderator) + logEmbed.setAuthor( + moderator.user.tag, + moderator.user.avatarURL({ dynamic: true, format: 'png', size: 4096 }) ?? undefined + ); + logEmbed.addField('**Action**', `${'Update Settings'}`); + if (moderator) logEmbed.addField('**Moderator**', `${moderator} (${moderator.user.tag})`); + logEmbed + .addField('**Setting Changed**', setting) + .addField('**Old Value**', await util.inspectCleanRedactCodeblock(oldSettings, 'js', undefined, 1024)) + .addField('**New Value**', await util.inspectCleanRedactCodeblock(newSettings, 'js', undefined, 1024)); + + return await logChannel.send({ embeds: [logEmbed] }); + } +} diff --git a/src/listeners/guild/guildMemberRemove.ts b/src/listeners/guild/guildMemberRemove.ts index 74404a3..90634d6 100644 --- a/src/listeners/guild/guildMemberRemove.ts +++ b/src/listeners/guild/guildMemberRemove.ts @@ -42,7 +42,10 @@ export default class GuildMemberRemoveListener extends BushListener { public async stickyRoles(member: BushGuildMember | PartialBushGuildMember): Promise<void> { if (!(await member.guild.hasFeature('stickyRoles'))) return; - if (member.partial) throw new Error('Partial member, cannot save sticky roles.'); + if (member.partial) { + await member.guild.members.fetch(); // try to prevent in the future + throw new Error(`${member.id} is a partial member, cannot save sticky roles.`); + } const rolesArray = member.roles.cache.filter((role) => role.name !== '@everyone').map((role) => role.id); const nickname = member.nickname; if (rolesArray) { |