aboutsummaryrefslogtreecommitdiff
path: root/src/lib/extensions
diff options
context:
space:
mode:
authorIRONM00N <64110067+IRONM00N@users.noreply.github.com>2021-09-05 20:24:50 -0400
committerIRONM00N <64110067+IRONM00N@users.noreply.github.com>2021-09-05 20:24:50 -0400
commitc4c1d9ffeb179e208792c88dd099caea5030581b (patch)
treedc075bda115de5f6cec925c398f3c9547d1bad55 /src/lib/extensions
parentc238b0279c7686ca45506b0909e376f241cf0e30 (diff)
downloadtanzanite-c4c1d9ffeb179e208792c88dd099caea5030581b.tar.gz
tanzanite-c4c1d9ffeb179e208792c88dd099caea5030581b.tar.bz2
tanzanite-c4c1d9ffeb179e208792c88dd099caea5030581b.zip
add moderation logging, fixes, hide modlog, jank
Diffstat (limited to 'src/lib/extensions')
-rw-r--r--src/lib/extensions/discord-akairo/BushClient.ts46
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts9
-rw-r--r--src/lib/extensions/discord-akairo/BushCommand.ts8
-rw-r--r--src/lib/extensions/discord.js/BushClientEvents.d.ts139
-rw-r--r--src/lib/extensions/discord.js/BushGuild.ts171
-rw-r--r--src/lib/extensions/discord.js/BushGuildMember.ts454
6 files changed, 558 insertions, 269 deletions
diff --git a/src/lib/extensions/discord-akairo/BushClient.ts b/src/lib/extensions/discord-akairo/BushClient.ts
index 5c1cb35..59c4df8 100644
--- a/src/lib/extensions/discord-akairo/BushClient.ts
+++ b/src/lib/extensions/discord-akairo/BushClient.ts
@@ -1,6 +1,7 @@
import chalk from 'chalk';
import { AkairoClient, ContextMenuCommandHandler } from 'discord-akairo';
import {
+ Awaited,
Collection,
Intents,
InteractionReplyOptions,
@@ -48,6 +49,7 @@ import { BushButtonInteraction } from '../discord.js/BushButtonInteraction';
import { BushCategoryChannel } from '../discord.js/BushCategoryChannel';
import { BushChannel } from '../discord.js/BushChannel';
import { BushChannelManager } from '../discord.js/BushChannelManager';
+import { BushClientEvents } from '../discord.js/BushClientEvents';
import { BushClientUser } from '../discord.js/BushClientUser';
import { BushCommandInteraction } from '../discord.js/BushCommandInteraction';
import { BushDMChannel } from '../discord.js/BushDMChannel';
@@ -159,6 +161,50 @@ export class BushClient<Ready extends boolean = boolean> extends AkairoClient<Re
public logger = BushLogger;
public constants = BushConstants;
public cache = BushCache;
+
+ public override on<K extends keyof BushClientEvents>(
+ event: K,
+ listener: (...args: BushClientEvents[K]) => Awaited<void>
+ ): this;
+ public override on<S extends string | symbol>(
+ event: Exclude<S, keyof BushClientEvents>,
+ listener: (...args: any[]) => Awaited<void>
+ ): this {
+ return super.on(event as any, listener);
+ }
+
+ public override once<K extends keyof BushClientEvents>(
+ event: K,
+ listener: (...args: BushClientEvents[K]) => Awaited<void>
+ ): this;
+ public override once<S extends string | symbol>(
+ event: Exclude<S, keyof BushClientEvents>,
+ listener: (...args: any[]) => Awaited<void>
+ ): this {
+ return super.once(event as any, listener);
+ }
+
+ public override emit<K extends keyof BushClientEvents>(event: K, ...args: BushClientEvents[K]): boolean;
+ public override emit<S extends string | symbol>(event: Exclude<S, keyof BushClientEvents>, ...args: unknown[]): boolean {
+ return super.emit(event as any, ...args);
+ }
+
+ public override off<K extends keyof BushClientEvents>(
+ event: K,
+ listener: (...args: BushClientEvents[K]) => Awaited<void>
+ ): this;
+ public override off<S extends string | symbol>(
+ event: Exclude<S, keyof BushClientEvents>,
+ listener: (...args: any[]) => Awaited<void>
+ ): this {
+ return super.off(event as any, listener);
+ }
+
+ public override removeAllListeners<K extends keyof BushClientEvents>(event?: K): this;
+ public override removeAllListeners<S extends string | symbol>(event?: Exclude<S, keyof BushClientEvents>): this {
+ return super.removeAllListeners(event as any);
+ }
+
public constructor(config: Config) {
super({
ownerID: config.owners,
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index 3f9e0b6..fec0174 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -8,6 +8,7 @@ import {
BushGuildResolvable,
BushMessage,
BushSlashMessage,
+ BushUser,
Global,
Guild,
ModLog,
@@ -576,7 +577,7 @@ export class BushClientUtil extends ClientUtil {
if (content.length > 400_000 && !substr) {
void this.handleError('haste', new Error(`content over 400,000 characters (${content.length.toLocaleString()})`));
return { error: 'content too long' };
- } else {
+ } else if (content.length > 400_000) {
content = content.substr(0, 400_000);
isSubstr = true;
}
@@ -876,7 +877,7 @@ export class BushClientUtil extends ClientUtil {
const haste = await this.haste(code, substr);
hasteOut = `Too large to display. ${
haste.url
- ? `Hastebin: ${haste.url}${haste.error ? `(${haste.error})` : ''}`
+ ? `Hastebin: ${haste.url}${haste.error ? ` - ${haste.error}` : ''}`
: `${this.emojis.error} Hastebin: ${haste.error}`
}`;
}
@@ -969,7 +970,7 @@ export class BushClientUtil extends ClientUtil {
public async inspectCleanRedactHaste(input: any, inspectOptions?: BushInspectOptions) {
input = typeof input !== 'string' ? this.inspect(input, inspectOptions ?? undefined) : input;
input = this.redact(input);
- return this.haste(input);
+ return this.haste(input, true);
}
public inspectAndRedact(input: any, inspectOptions?: BushInspectOptions) {
@@ -1413,7 +1414,7 @@ export class BushClientUtil extends ClientUtil {
});
}
- public async resolveNonCachedUser(user: UserResolvable | undefined | null): Promise<User | undefined> {
+ public async resolveNonCachedUser(user: UserResolvable | undefined | null): Promise<BushUser | undefined> {
if (!user) return undefined;
const id =
user instanceof User || user instanceof GuildMember || user instanceof ThreadMember
diff --git a/src/lib/extensions/discord-akairo/BushCommand.ts b/src/lib/extensions/discord-akairo/BushCommand.ts
index 495a454..1c8ea5b 100644
--- a/src/lib/extensions/discord-akairo/BushCommand.ts
+++ b/src/lib/extensions/discord-akairo/BushCommand.ts
@@ -147,7 +147,7 @@ export interface BushCommandOptions extends CommandOptions {
};
args?: BushArgumentOptions[] & CustomBushArgumentOptions[];
category: string;
- completelyHide?: boolean;
+ pseudo?: boolean;
}
export class BushCommand extends Command {
@@ -166,8 +166,8 @@ export class BushCommand extends Command {
/** Whether the command is hidden from the help command. */
public hidden: boolean;
- /** Completely hide this command from the help command. */
- public completelyHide: boolean;
+ /** A fake command, completely hidden from the help command. */
+ public pseudo: boolean;
public constructor(id: string, options: BushCommandOptions) {
if (options.args && typeof options.args !== 'function') {
@@ -184,7 +184,7 @@ export class BushCommand extends Command {
this.hidden = options.hidden ?? false;
this.restrictedChannels = options.restrictedChannels!;
this.restrictedGuilds = options.restrictedGuilds!;
- this.completelyHide = options.completelyHide!;
+ this.pseudo = options.pseudo!;
}
public override exec(message: BushMessage, args: any): any;
diff --git a/src/lib/extensions/discord.js/BushClientEvents.d.ts b/src/lib/extensions/discord.js/BushClientEvents.d.ts
index ae9b186..8695e7a 100644
--- a/src/lib/extensions/discord.js/BushClientEvents.d.ts
+++ b/src/lib/extensions/discord.js/BushClientEvents.d.ts
@@ -9,7 +9,10 @@ import {
Sticker,
Typing
} from 'discord.js';
-import { BushClient, BushTextBasedChannels } from '../discord-akairo/BushClient';
+import {
+ BushClient,
+ BushTextBasedChannels
+} from '../discord-akairo/BushClient';
import { BushApplicationCommand } from './BushApplicationCommand';
import { BushDMChannel } from './BushDMChannel';
import { BushGuild } from './BushGuild';
@@ -18,7 +21,11 @@ import { BushGuildChannel } from './BushGuildChannel';
import { BushGuildEmoji } from './BushGuildEmoji';
import { BushGuildMember, PartialBushGuildMember } from './BushGuildMember';
import { BushMessage, PartialBushMessage } from './BushMessage';
-import { BushMessageReaction, PartialBushMessageReaction } from './BushMessageReaction';
+import {
+ BushMessageReaction,
+ PartialBushMessageReaction
+} from './BushMessageReaction';
+import { BushNewsChannel } from './BushNewsChannel';
import { BushPresence } from './BushPresence';
import { BushRole } from './BushRole';
import { BushStageInstance } from './BushStageInstance';
@@ -31,11 +38,17 @@ import { BushVoiceState } from './BushVoiceState';
export interface BushClientEvents extends ClientEvents {
applicationCommandCreate: [command: BushApplicationCommand];
applicationCommandDelete: [command: BushApplicationCommand];
- applicationCommandUpdate: [oldCommand: BushApplicationCommand | null, newCommand: BushApplicationCommand];
+ applicationCommandUpdate: [
+ oldCommand: BushApplicationCommand | null,
+ newCommand: BushApplicationCommand
+ ];
channelCreate: [channel: BushGuildChannel];
channelDelete: [channel: BushDMChannel | BushGuildChannel];
channelPinsUpdate: [channel: BushTextBasedChannels, date: Date];
- channelUpdate: [oldChannel: BushDMChannel | BushGuildChannel, newChannel: BushDMChannel | BushGuildChannel];
+ channelUpdate: [
+ oldChannel: BushDMChannel | BushGuildChannel,
+ newChannel: BushDMChannel | BushGuildChannel
+ ];
debug: [message: string];
warn: [message: string];
emojiCreate: [emoji: BushGuildEmoji];
@@ -54,20 +67,40 @@ export interface BushClientEvents extends ClientEvents {
guildMembersChunk: [
members: Collection<Snowflake, BushGuildMember>,
guild: BushGuild,
- data: { count: number; index: number; nonce: string | undefined }
+ data: {
+ count: number;
+ index: number;
+ nonce: string | undefined;
+ }
+ ];
+ guildMemberUpdate: [
+ oldMember: BushGuildMember | PartialBushGuildMember,
+ newMember: BushGuildMember
];
- guildMemberUpdate: [oldMember: BushGuildMember | PartialBushGuildMember, newMember: BushGuildMember];
guildUpdate: [oldGuild: BushGuild, newGuild: BushGuild];
inviteCreate: [invite: Invite];
inviteDelete: [invite: Invite];
messageCreate: [message: BushMessage];
messageDelete: [message: BushMessage | PartialBushMessage];
messageReactionRemoveAll: [message: BushMessage | PartialBushMessage];
- messageReactionRemoveEmoji: [reaction: BushMessageReaction | PartialBushMessageReaction];
- messageDeleteBulk: [messages: Collection<Snowflake, BushMessage | PartialBushMessage>];
- messageReactionAdd: [reaction: BushMessageReaction | PartialBushMessageReaction, user: BushUser | PartialBushUser];
- messageReactionRemove: [reaction: BushMessageReaction | PartialBushMessageReaction, user: BushUser | PartialBushUser];
- messageUpdate: [oldMessage: BushMessage | PartialBushMessage, newMessage: BushMessage | PartialBushMessage];
+ messageReactionRemoveEmoji: [
+ reaction: BushMessageReaction | PartialBushMessageReaction
+ ];
+ messageDeleteBulk: [
+ messages: Collection<Snowflake, BushMessage | PartialBushMessage>
+ ];
+ messageReactionAdd: [
+ reaction: BushMessageReaction | PartialBushMessageReaction,
+ user: BushUser | PartialBushUser
+ ];
+ messageReactionRemove: [
+ reaction: BushMessageReaction | PartialBushMessageReaction,
+ user: BushUser | PartialBushUser
+ ];
+ messageUpdate: [
+ oldMessage: BushMessage | PartialBushMessage,
+ newMessage: BushMessage | PartialBushMessage
+ ];
presenceUpdate: [oldPresence: BushPresence | null, newPresence: BushPresence];
rateLimit: [rateLimitData: RateLimitData];
invalidRequestWarning: [invalidRequestWarningData: InvalidRequestWarningData];
@@ -79,7 +112,10 @@ export interface BushClientEvents extends ClientEvents {
threadCreate: [thread: BushThreadChannel];
threadDelete: [thread: BushThreadChannel];
threadListSync: [threads: Collection<Snowflake, BushThreadChannel>];
- threadMemberUpdate: [oldMember: BushThreadMember, newMember: BushThreadMember];
+ threadMemberUpdate: [
+ oldMember: BushThreadMember,
+ newMember: BushThreadMember
+ ];
threadMembersUpdate: [
oldMembers: Collection<Snowflake, BushThreadMember>,
mewMembers: Collection<Snowflake, BushThreadMember>
@@ -95,9 +131,86 @@ export interface BushClientEvents extends ClientEvents {
shardReconnecting: [shardId: number];
shardResume: [shardId: number, replayedEvents: number];
stageInstanceCreate: [stageInstance: BushStageInstance];
- stageInstanceUpdate: [oldStageInstance: BushStageInstance | null, newStageInstance: BushStageInstance];
+ stageInstanceUpdate: [
+ oldStageInstance: BushStageInstance | null,
+ newStageInstance: BushStageInstance
+ ];
stageInstanceDelete: [stageInstance: BushStageInstance];
stickerCreate: [sticker: Sticker];
stickerDelete: [sticker: Sticker];
stickerUpdate: [oldSticker: Sticker, newSticker: Sticker];
+ /* Custom */
+ bushBan: [
+ victim: BushGuildMember | BushUser,
+ moderator: BushUser,
+ guild: BushGuild,
+ reason: string | undefined,
+ caseID: string,
+ duration: number,
+ dmSuccess?: boolean
+ ];
+ bushKick: [
+ victim: BushGuildMember,
+ moderator: BushUser,
+ guild: BushGuild,
+ reason: string | undefined,
+ caseID: string,
+ dmSuccess: boolean
+ ];
+ bushMute: [
+ victim: BushGuildMember,
+ moderator: BushUser,
+ guild: BushGuild,
+ reason: string | undefined,
+ caseID: string,
+ duration: number,
+ dmSuccess: boolean
+ ];
+ bushPunishRole: [
+ victim: BushGuildMember,
+ moderator: BushUser,
+ guild: BushGuild,
+ reason: string | undefined,
+ caseID: string,
+ duration: number,
+ role: BushRole
+ ];
+ bushPunishRoleRemove: [
+ victim: BushGuildMember,
+ moderator: BushUser,
+ guild: BushGuild,
+ caseID: string,
+ reason: string | undefined,
+ role: BushRole
+ ];
+ bushPurge: [
+ moderator: BushUser,
+ guild: BushGuild,
+ channel: BushTextChannel | BushNewsChannel | BushThreadChannel,
+ messages: Collection<Snowflake, BushMessage>
+ ];
+ bushUnban: [
+ victim: BushUser,
+ moderator: BushUser,
+ guild: BushGuild,
+ reason: string | undefined,
+ caseID: string,
+ dmSuccess: boolean
+ ];
+ bushUnmute: [
+ victim: BushGuildMember,
+ moderator: BushUser,
+ guild: BushGuild,
+ reason: string | undefined,
+ caseID: string,
+ dmSuccess: boolean
+ ];
+ bushWarn: [
+ victim: BushGuildMember,
+ moderator: BushUser,
+ guild: BushGuild,
+ reason: string | undefined,
+ caseID: string,
+ dmSuccess: boolean
+ ];
}
diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts
index efecdcd..18f6542 100644
--- a/src/lib/extensions/discord.js/BushGuild.ts
+++ b/src/lib/extensions/discord.js/BushGuild.ts
@@ -1,10 +1,11 @@
import { Guild, UserResolvable } from 'discord.js';
import { RawGuildData } from 'discord.js/typings/rawDataTypes';
-import { Guild as GuildDB, GuildFeatures, GuildModel } from '../../models/Guild';
+import { Guild as GuildDB, GuildFeatures, GuildLogType, GuildModel } from '../../models/Guild';
import { ModLogType } from '../../models/ModLog';
import { BushClient, BushUserResolvable } from '../discord-akairo/BushClient';
import { BushGuildMember } from './BushGuildMember';
import { BushGuildMemberManager } from './BushGuildMemberManager';
+import { BushTextChannel } from './BushTextChannel';
import { BushUser } from './BushUser';
export class BushGuild extends Guild {
@@ -50,7 +51,17 @@ export class BushGuild extends Guild {
return await row.save();
}
- public async ban(options: {
+ public async getLogChannel(logType: GuildLogType): Promise<BushTextChannel | undefined> {
+ const channelId = (await this.getSetting('logChannels'))[logType];
+ if (!channelId) return undefined;
+ return (
+ (this.channels.cache.get(channelId) as BushTextChannel | undefined) ??
+ ((await this.channels.fetch(channelId)) as BushTextChannel | null) ??
+ undefined
+ );
+ }
+
+ public async bushBan(options: {
user: BushUserResolvable | UserResolvable;
reason?: string | null;
moderator?: BushUserResolvable;
@@ -62,42 +73,51 @@ export class BushGuild extends Guild {
// checks
if (!this.me!.permissions.has('BAN_MEMBERS')) return 'missing permissions';
+ let caseID: string | undefined = undefined;
+ const user = (await util.resolveNonCachedUser(options.user))!;
const moderator = (await util.resolveNonCachedUser(options.moderator!)) ?? client.user!;
- // ban
- const banSuccess = await this.bans
- .create(options.user, {
- reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`,
- days: options.deleteDays
- })
- .catch(() => false);
- if (!banSuccess) return 'error banning';
-
- // add modlog entry
- const { log: modlog } = await util.createModLogEntry({
- type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
- user: options.user as BushUserResolvable,
- moderator: moderator.id,
- reason: options.reason,
- duration: options.duration,
- guild: this
- });
- if (!modlog) return 'error creating modlog entry';
-
- // add punishment entry so they can be unbanned later
- const punishmentEntrySuccess = await util.createPunishmentEntry({
- type: 'ban',
- user: options.user as BushUserResolvable,
- guild: this,
- duration: options.duration,
- modlog: modlog.id
- });
- if (!punishmentEntrySuccess) return 'error creating ban entry';
-
- return 'success';
+ const ret = await (async () => {
+ // ban
+ const banSuccess = await this.bans
+ .create(user?.id ?? options.user, {
+ reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`,
+ days: options.deleteDays
+ })
+ .catch(() => false);
+ if (!banSuccess) return 'error banning';
+
+ // add modlog entry
+ const { log: modlog } = await util.createModLogEntry({
+ type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
+ user: user,
+ moderator: moderator.id,
+ reason: options.reason,
+ duration: options.duration,
+ guild: this
+ });
+ if (!modlog) return 'error creating modlog entry';
+ caseID = modlog.id;
+
+ // add punishment entry so they can be unbanned later
+ const punishmentEntrySuccess = await util.createPunishmentEntry({
+ type: 'ban',
+ user: user,
+ guild: this,
+ duration: options.duration,
+ modlog: modlog.id
+ });
+ if (!punishmentEntrySuccess) return 'error creating ban entry';
+
+ return 'success';
+ })();
+
+ if (!['error banning', 'error creating modlog entry', 'error creating ban entry'].includes(ret))
+ client.emit('bushBan', user, moderator, this, options.reason ?? undefined, caseID!, options.duration ?? 0);
+ return ret;
}
- public async unban(options: {
+ public async bushUnban(options: {
user: BushUserResolvable | BushUser;
reason?: string | null;
moderator?: BushUserResolvable;
@@ -109,48 +129,59 @@ export class BushGuild extends Guild {
| 'error creating modlog entry'
| 'error removing ban entry'
> {
+ let caseID: string | undefined = undefined;
+ let dmSuccessEvent: boolean | undefined = undefined;
const user = (await util.resolveNonCachedUser(options.user))!;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.me))!;
- 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;
+ 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 'user not banned';
+ if (!unbanSuccess) return 'error unbanning';
+
+ // add modlog entry
+ const { log: modlog } = await util.createModLogEntry({
+ type: ModLogType.UNBAN,
+ user: user.id,
+ moderator: moderator.id,
+ reason: options.reason,
+ guild: this
});
+ if (!modlog) return 'error creating modlog entry';
+ caseID = modlog.id;
+
+ // remove punishment entry
+ const removePunishmentEntrySuccess = await util.removePunishmentEntry({
+ type: 'ban',
+ user: user.id,
+ guild: this
+ });
+ if (!removePunishmentEntrySuccess) return 'error removing ban entry';
- if (!unbanSuccess) return 'error unbanning';
-
- // add modlog entry
- const modlog = await util.createModLogEntry({
- type: ModLogType.UNBAN,
- user: user.id,
- moderator: moderator.id,
- reason: options.reason,
- guild: this
- });
- if (!modlog) return 'error creating modlog entry';
-
- // remove punishment entry
- const removePunishmentEntrySuccess = await util.removePunishmentEntry({
- type: 'ban',
- user: user.id,
- guild: this
- });
- if (!removePunishmentEntrySuccess) return 'error removing ban entry';
-
- const userObject = client.users.cache.get(user.id);
+ const userObject = client.users.cache.get(user.id);
- userObject?.send(`You have been unbanned from **${this}** for **${options.reason ?? 'No reason provided'}**.`);
+ const dmSuccess = await userObject
+ ?.send(`You have been unbanned from **${this}** for **${options.reason ?? 'No reason provided'}**.`)
+ .catch(() => false);
+ dmSuccessEvent = !!dmSuccess;
- if (notBanned) return 'user not banned';
- return 'success';
+ return 'success';
+ })();
+ if (!['error unbanning', 'error creating modlog entry', 'error removing ban entry'].includes(ret))
+ client.emit('bushUnban', user, moderator, this, options.reason ?? undefined, caseID!, dmSuccessEvent!);
+ return ret;
}
}
diff --git a/src/lib/extensions/discord.js/BushGuildMember.ts b/src/lib/extensions/discord.js/BushGuildMember.ts
index ab4eee4..4dd1a5d 100644
--- a/src/lib/extensions/discord.js/BushGuildMember.ts
+++ b/src/lib/extensions/discord.js/BushGuildMember.ts
@@ -105,96 +105,140 @@ export class BushGuildMember extends GuildMember {
}
public async warn(options: BushPunishmentOptions): Promise<{ result: WarnResponse | null; caseNum: number | null }> {
+ let caseID: string | undefined = undefined;
+ let dmSuccessEvent: boolean | undefined = undefined;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.guild.me))!;
- // add modlog entry
- const result = await util.createModLogEntry(
- {
- type: ModLogType.WARN,
- user: this,
- moderator: moderator.id,
- reason: options.reason,
- guild: this.guild
- },
- true
- );
- if (!result || !result.log) return { result: 'error creating modlog entry', caseNum: null };
-
- // dm user
- const dmSuccess = await this.punishDM('warned', options.reason);
- if (!dmSuccess) return { result: 'failed to dm', caseNum: result.caseNum };
-
- return { result: 'success', caseNum: result.caseNum };
+ const ret = await (async () => {
+ // add modlog entry
+ const result = await util.createModLogEntry(
+ {
+ type: ModLogType.WARN,
+ user: this,
+ moderator: moderator.id,
+ reason: options.reason,
+ guild: this.guild
+ },
+ true
+ );
+ caseID = result.log?.id;
+ if (!result || !result.log) return { result: 'error creating modlog entry', caseNum: null };
+
+ // dm user
+ const dmSuccess = await this.punishDM('warned', options.reason);
+ dmSuccessEvent = dmSuccess;
+ if (!dmSuccess) return { result: 'failed to dm', caseNum: result.caseNum };
+
+ return { result: 'success', caseNum: result.caseNum };
+ })();
+ if (!['error creating modlog entry'].includes(ret.result))
+ client.emit('bushWarn', this, moderator, this.guild, options.reason ?? undefined, caseID!, dmSuccessEvent!);
+ return ret as { result: WarnResponse | null; caseNum: number | null };
}
public async addRole(options: AddRoleOptions): Promise<AddRoleResponse> {
const ifShouldAddRole = this.#checkIfShouldAddRole(options.role);
if (ifShouldAddRole !== true) return ifShouldAddRole;
+ let caseID: string | undefined = undefined;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.guild.me))!;
- if (options.addToModlog || options.duration) {
- const { log: modlog } = options.addToModlog
- ? await util.createModLogEntry({
- type: options.duration ? ModLogType.TEMP_PUNISHMENT_ROLE : ModLogType.PERM_PUNISHMENT_ROLE,
- guild: this.guild,
- moderator: moderator.id,
- user: this,
- reason: 'N/A'
- })
- : { log: null };
-
- if (!modlog && options.addToModlog) return 'error creating modlog entry';
-
+ const ret = await (async () => {
if (options.addToModlog || options.duration) {
- const punishmentEntrySuccess = await util.createPunishmentEntry({
- type: 'role',
- user: this,
- guild: this.guild,
- modlog: modlog?.id ?? undefined,
- duration: options.duration,
- extraInfo: options.role.id
- });
- if (!punishmentEntrySuccess) return 'error creating role entry';
+ const { log: modlog } = options.addToModlog
+ ? await util.createModLogEntry({
+ type: options.duration ? ModLogType.TEMP_PUNISHMENT_ROLE : ModLogType.PERM_PUNISHMENT_ROLE,
+ guild: this.guild,
+ moderator: moderator.id,
+ user: this,
+ reason: 'N/A'
+ })
+ : { log: null };
+ caseID = modlog?.id;
+
+ if (!modlog && options.addToModlog) return 'error creating modlog entry';
+
+ if (options.addToModlog || options.duration) {
+ const punishmentEntrySuccess = await util.createPunishmentEntry({
+ type: 'role',
+ user: this,
+ guild: this.guild,
+ modlog: modlog?.id ?? undefined,
+ duration: options.duration,
+ extraInfo: options.role.id
+ });
+ if (!punishmentEntrySuccess) return 'error creating role entry';
+ }
}
- }
-
- const removeRoleSuccess = await this.roles.add(options.role, `${moderator.tag}`);
- if (!removeRoleSuccess) return 'error adding role';
- return 'success';
+ const removeRoleSuccess = await this.roles.add(options.role, `${moderator.tag}`);
+ if (!removeRoleSuccess) return 'error adding role';
+
+ return 'success';
+ })();
+ if (!['error adding role', 'error creating modlog entry', 'error creating role entry'].includes(ret) && options.addToModlog)
+ client.emit(
+ 'bushPunishRole',
+ this,
+ moderator,
+ this.guild,
+ options.reason ?? undefined,
+ caseID!,
+ options.duration ?? 0,
+ options.role as BushRole
+ );
+ return ret;
}
public async removeRole(options: RemoveRoleOptions): Promise<RemoveRoleResponse> {
const ifShouldAddRole = this.#checkIfShouldAddRole(options.role);
if (ifShouldAddRole !== true) return ifShouldAddRole;
+ let caseID: string | undefined = undefined;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.guild.me))!;
- if (options.addToModlog) {
- const { log: modlog } = await util.createModLogEntry({
- type: ModLogType.PERM_PUNISHMENT_ROLE,
- guild: this.guild,
- moderator: moderator.id,
- user: this,
- reason: 'N/A'
- });
-
- if (!modlog) return 'error creating modlog entry';
+ const ret = await (async () => {
+ if (options.addToModlog) {
+ const { log: modlog } = await util.createModLogEntry({
+ type: ModLogType.PERM_PUNISHMENT_ROLE,
+ guild: this.guild,
+ moderator: moderator.id,
+ user: this,
+ reason: 'N/A'
+ });
- const punishmentEntrySuccess = await util.removePunishmentEntry({
- type: 'role',
- user: this,
- guild: this.guild
- });
+ if (!modlog) return 'error creating modlog entry';
+ caseID = modlog.id;
- if (!punishmentEntrySuccess) return 'error removing role entry';
- }
+ const punishmentEntrySuccess = await util.removePunishmentEntry({
+ type: 'role',
+ user: this,
+ guild: this.guild
+ });
- const removeRoleSuccess = await this.roles.remove(options.role, `${moderator.tag}`);
- if (!removeRoleSuccess) return 'error removing role';
+ if (!punishmentEntrySuccess) return 'error removing role entry';
+ }
- return 'success';
+ const removeRoleSuccess = await this.roles.remove(options.role, `${moderator.tag}`);
+ if (!removeRoleSuccess) return 'error removing role';
+
+ return 'success';
+ })();
+
+ if (
+ !['error removing role', 'error creating modlog entry', 'error removing role entry'].includes(ret) &&
+ options.addToModlog
+ )
+ client.emit(
+ 'bushPunishRoleRemove',
+ this,
+ moderator,
+ this.guild,
+ caseID!,
+ options.reason ?? undefined,
+ options.role as BushRole
+ );
+ return ret;
}
#checkIfShouldAddRole(role: BushRole | Role): true | 'user hierarchy' | 'role managed' | 'client hierarchy' {
@@ -217,47 +261,66 @@ export class BushGuildMember extends GuildMember {
if (!muteRole) return 'invalid mute role';
if (muteRole.position >= this.guild.me!.roles.highest.position || muteRole.managed) return 'mute role not manageable';
+ let caseID: string | undefined = undefined;
+ let dmSuccessEvent: boolean | undefined = undefined;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.guild.me))!;
- // add role
- const muteSuccess = await this.roles
- .add(muteRole, `[Mute] ${moderator.tag} | ${options.reason ?? 'No reason provided.'}`)
- .catch(async (e) => {
- await client.console.warn('muteRoleAddError', e);
- client.console.debug(e);
- return false;
- });
- if (!muteSuccess) return 'error giving mute role';
-
- // add modlog entry
- const { log: modlog } = await util.createModLogEntry({
- type: options.duration ? ModLogType.TEMP_MUTE : ModLogType.PERM_MUTE,
- user: this,
- moderator: moderator.id,
- reason: options.reason,
- duration: options.duration,
- guild: this.guild
- });
-
- if (!modlog) return 'error creating modlog entry';
-
- // add punishment entry so they can be unmuted later
- const punishmentEntrySuccess = await util.createPunishmentEntry({
- type: 'mute',
- user: this,
- guild: this.guild,
- duration: options.duration,
- modlog: modlog.id
- });
+ const ret = await (async () => {
+ // add role
+ const muteSuccess = await this.roles
+ .add(muteRole, `[Mute] ${moderator.tag} | ${options.reason ?? 'No reason provided.'}`)
+ .catch(async (e) => {
+ await client.console.warn('muteRoleAddError', e);
+ client.console.debug(e);
+ return false;
+ });
+ if (!muteSuccess) return 'error giving mute role';
- if (!punishmentEntrySuccess) return 'error creating mute entry';
+ // add modlog entry
+ const { log: modlog } = await util.createModLogEntry({
+ type: options.duration ? ModLogType.TEMP_MUTE : ModLogType.PERM_MUTE,
+ user: this,
+ moderator: moderator.id,
+ reason: options.reason,
+ duration: options.duration,
+ guild: this.guild
+ });
- // dm user
- const dmSuccess = await this.punishDM('muted', options.reason, options.duration ?? 0);
+ if (!modlog) return 'error creating modlog entry';
+ caseID = modlog.id;
- if (!dmSuccess) return 'failed to dm';
+ // add punishment entry so they can be unmuted later
+ const punishmentEntrySuccess = await util.createPunishmentEntry({
+ type: 'mute',
+ user: this,
+ guild: this.guild,
+ duration: options.duration,
+ modlog: modlog.id
+ });
- return 'success';
+ if (!punishmentEntrySuccess) return 'error creating mute entry';
+
+ // dm user
+ const dmSuccess = await this.punishDM('muted', options.reason, options.duration ?? 0);
+ dmSuccessEvent = dmSuccess;
+
+ if (!dmSuccess) return 'failed to dm';
+
+ return 'success';
+ })();
+
+ if (!['error giving mute role', 'error creating modlog entry', 'error creating mute entry'].includes(ret))
+ client.emit(
+ 'bushMute',
+ this,
+ moderator,
+ this.guild,
+ options.reason ?? undefined,
+ caseID!,
+ options.duration ?? 0,
+ dmSuccessEvent!
+ );
+ return ret;
}
public async unmute(options: BushPunishmentOptions): Promise<UnmuteResponse> {
@@ -269,110 +332,145 @@ export class BushGuildMember extends GuildMember {
if (!muteRole) return 'invalid mute role';
if (muteRole.position >= this.guild.me!.roles.highest.position || muteRole.managed) return 'mute role not manageable';
+ let caseID: string | undefined = undefined;
+ let dmSuccessEvent: boolean | undefined = undefined;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.guild.me))!;
- //remove role
- const muteSuccess = await this.roles
- .remove(muteRole, `[Unmute] ${moderator.tag} | ${options.reason ?? 'No reason provided.'}`)
- .catch(async (e) => {
- await client.console.warn('muteRoleAddError', e?.stack || e);
- return false;
+ const ret = await (async () => {
+ //remove role
+ const muteSuccess = await this.roles
+ .remove(muteRole, `[Unmute] ${moderator.tag} | ${options.reason ?? 'No reason provided.'}`)
+ .catch(async (e) => {
+ await client.console.warn('muteRoleAddError', e?.stack || e);
+ return false;
+ });
+ if (!muteSuccess) return 'error removing mute role';
+
+ //remove modlog entry
+ const { log: modlog } = await util.createModLogEntry({
+ type: ModLogType.UNMUTE,
+ user: this,
+ moderator: moderator.id,
+ reason: options.reason,
+ guild: this.guild
});
- if (!muteSuccess) return 'error removing mute role';
- //remove modlog entry
- const { log: modlog } = await util.createModLogEntry({
- type: ModLogType.UNMUTE,
- user: this,
- moderator: moderator.id,
- reason: options.reason,
- guild: this.guild
- });
+ if (!modlog) return 'error creating modlog entry';
+ caseID = modlog.id;
- if (!modlog) return 'error creating modlog entry';
+ // remove mute entry
+ const removePunishmentEntrySuccess = await util.removePunishmentEntry({
+ type: 'mute',
+ user: this,
+ guild: this.guild
+ });
- // remove mute entry
- const removePunishmentEntrySuccess = await util.removePunishmentEntry({
- type: 'mute',
- user: this,
- guild: this.guild
- });
+ if (!removePunishmentEntrySuccess) return 'error removing mute entry';
- if (!removePunishmentEntrySuccess) return 'error removing mute entry';
+ //dm user
+ const dmSuccess = await this.punishDM('unmuted', options.reason, undefined, false);
+ dmSuccessEvent = dmSuccess;
- //dm user
- const dmSuccess = await this.punishDM('unmuted', options.reason, undefined, false);
+ if (!dmSuccess) return 'failed to dm';
- if (!dmSuccess) return 'failed to dm';
+ return 'success';
+ })();
- return 'success';
+ if (!['error removing mute role', 'error creating modlog entry', 'error removing mute entry'].includes(ret))
+ client.emit('bushUnmute', this, moderator, this.guild, options.reason ?? undefined, caseID!, dmSuccessEvent!);
+ return ret;
}
public async bushKick(options: BushPunishmentOptions): Promise<KickResponse> {
// checks
if (!this.guild.me?.permissions.has('KICK_MEMBERS') || !this.kickable) return 'missing permissions';
+ let caseID: string | undefined = undefined;
+ let dmSuccessEvent: boolean | undefined = undefined;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.guild.me))!;
+ const ret = await (async () => {
+ // dm user
+ const dmSuccess = await this.punishDM('kicked', options.reason);
+ dmSuccessEvent = dmSuccess;
- // dm user
- const dmSuccess = await this.punishDM('kicked', options.reason);
-
- // kick
- const kickSuccess = await this.kick(`${moderator?.tag} | ${options.reason ?? 'No reason provided.'}`).catch(() => false);
- if (!kickSuccess) return 'error kicking';
-
- // add modlog entry
- const { log: modlog } = await util.createModLogEntry({
- type: ModLogType.KICK,
- user: this,
- moderator: moderator.id,
- reason: options.reason,
- guild: this.guild
- });
- if (!modlog) return 'error creating modlog entry';
- if (!dmSuccess) return 'failed to dm';
- return 'success';
+ // kick
+ const kickSuccess = await this.kick(`${moderator?.tag} | ${options.reason ?? 'No reason provided.'}`).catch(() => false);
+ if (!kickSuccess) return 'error kicking';
+
+ // add modlog entry
+ const { log: modlog } = await util.createModLogEntry({
+ type: ModLogType.KICK,
+ user: this,
+ moderator: moderator.id,
+ reason: options.reason,
+ guild: this.guild
+ });
+ if (!modlog) return 'error creating modlog entry';
+ caseID = modlog.id;
+ if (!dmSuccess) return 'failed to dm';
+ return 'success';
+ })();
+ if (!['error kicking', 'error creating modlog entry'].includes(ret))
+ client.emit('bushKick', this, moderator, this.guild, options.reason ?? undefined, caseID!, dmSuccessEvent!);
+ return ret;
}
public async bushBan(options: BushBanOptions): Promise<BanResponse> {
// checks
if (!this.guild.me!.permissions.has('BAN_MEMBERS') || !this.bannable) return 'missing permissions';
+ let caseID: string | undefined = undefined;
+ let dmSuccessEvent: boolean | undefined = undefined;
const moderator = (await util.resolveNonCachedUser(options.moderator ?? this.guild.me))!;
+ const ret = await (async () => {
+ // dm user
+ const dmSuccess = await this.punishDM('banned', options.reason, options.duration ?? 0);
+ dmSuccessEvent = dmSuccess;
+
+ // ban
+ const banSuccess = await this.ban({
+ reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`,
+ days: options.deleteDays
+ }).catch(() => false);
+ if (!banSuccess) return 'error banning';
+
+ // add modlog entry
+ const { log: modlog } = await util.createModLogEntry({
+ type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
+ user: this,
+ moderator: moderator.id,
+ reason: options.reason,
+ duration: options.duration,
+ guild: this.guild
+ });
+ if (!modlog) return 'error creating modlog entry';
+ caseID = modlog.id;
- // dm user
- const dmSuccess = await this.punishDM('banned', options.reason, options.duration ?? 0);
-
- // ban
- const banSuccess = await this.ban({
- reason: `${moderator.tag} | ${options.reason ?? 'No reason provided.'}`,
- days: options.deleteDays
- }).catch(() => false);
- if (!banSuccess) return 'error banning';
-
- // add modlog entry
- const { log: modlog } = await util.createModLogEntry({
- type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
- user: this,
- moderator: moderator.id,
- reason: options.reason,
- duration: options.duration,
- guild: this.guild
- });
- if (!modlog) return 'error creating modlog entry';
-
- // add punishment entry so they can be unbanned later
- const punishmentEntrySuccess = await util.createPunishmentEntry({
- type: 'ban',
- user: this,
- guild: this.guild,
- duration: options.duration,
- modlog: modlog.id
- });
- if (!punishmentEntrySuccess) return 'error creating ban entry';
-
- if (!dmSuccess) return 'failed to dm';
- return 'success';
+ // add punishment entry so they can be unbanned later
+ const punishmentEntrySuccess = await util.createPunishmentEntry({
+ type: 'ban',
+ user: this,
+ guild: this.guild,
+ duration: options.duration,
+ modlog: modlog.id
+ });
+ if (!punishmentEntrySuccess) return 'error creating ban entry';
+
+ if (!dmSuccess) return 'failed to dm';
+ return 'success';
+ })();
+ if (!['error banning', 'error creating modlog entry', 'error creating ban entry'].includes(ret))
+ client.emit(
+ 'bushBan',
+ this,
+ moderator,
+ this.guild,
+ options.reason ?? undefined,
+ caseID!,
+ options.duration ?? 0,
+ dmSuccessEvent!
+ );
+ return ret;
}
public get isOwner(): boolean {