aboutsummaryrefslogtreecommitdiff
path: root/src/lib/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/common')
-rw-r--r--src/lib/common/AutoMod.ts1
-rw-r--r--src/lib/common/ButtonPaginator.ts3
-rw-r--r--src/lib/common/DeleteButton.ts3
-rw-r--r--src/lib/common/Moderation.ts166
-rw-r--r--src/lib/common/util/Arg.ts56
5 files changed, 170 insertions, 59 deletions
diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts
index 932d457..e5487c3 100644
--- a/src/lib/common/AutoMod.ts
+++ b/src/lib/common/AutoMod.ts
@@ -261,6 +261,7 @@ export class AutoMod {
.addField('Message Content', `${await util.codeblock(this.message.content, 1024)}`)
.setColor(color)
.setTimestamp()
+ .setAuthor({name: this.message.author.tag, url: this.message.author.displayAvatarURL()})
],
components:
highestOffence.severity >= 2
diff --git a/src/lib/common/ButtonPaginator.ts b/src/lib/common/ButtonPaginator.ts
index 983eb56..d193b4d 100644
--- a/src/lib/common/ButtonPaginator.ts
+++ b/src/lib/common/ButtonPaginator.ts
@@ -1,4 +1,5 @@
import { DeleteButton, type BushMessage, type BushSlashMessage } from '#lib';
+import { CommandUtil } from 'discord-akairo';
import {
Constants,
MessageActionRow,
@@ -120,7 +121,7 @@ export class ButtonPaginator {
}
protected async end() {
- if (this.sentMessage && !this.sentMessage.deleted)
+ if (this.sentMessage && !CommandUtil.deletedMessages.has(this.sentMessage.id))
return await this.sentMessage
.edit({
content: this.text,
diff --git a/src/lib/common/DeleteButton.ts b/src/lib/common/DeleteButton.ts
index 38ce6df..e2509a9 100644
--- a/src/lib/common/DeleteButton.ts
+++ b/src/lib/common/DeleteButton.ts
@@ -1,4 +1,5 @@
import { PaginateEmojis, type BushMessage, type BushSlashMessage } from '#lib';
+import { CommandUtil } from 'discord-akairo';
import { Constants, MessageActionRow, MessageButton, type MessageComponentInteraction, type MessageOptions } from 'discord.js';
export class DeleteButton {
@@ -32,7 +33,7 @@ export class DeleteButton {
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 (msg.deletable && !msg.deleted) await msg.delete();
+ if (msg.deletable && !CommandUtil.deletedMessages.has(msg.id)) await msg.delete();
}
});
diff --git a/src/lib/common/Moderation.ts b/src/lib/common/Moderation.ts
index a7a037f..ab2943b 100644
--- a/src/lib/common/Moderation.ts
+++ b/src/lib/common/Moderation.ts
@@ -10,13 +10,18 @@ import {
} from '#lib';
import { type Snowflake } from 'discord.js';
+/**
+ * A utility class with moderation-related methods.
+ */
export class Moderation {
/**
* Checks if a moderator can perform a moderation action on another user.
- * @param moderator - The person trying to perform the action.
- * @param victim - The person getting punished.
- * @param type - The type of punishment - used to format the response.
- * @param checkModerator - Whether or not to check if the victim is a moderator.
+ * @param moderator The person trying to perform the action.
+ * @param victim The person getting punished.
+ * @param type The type of punishment - used to format the response.
+ * @param checkModerator Whether or not to check if the victim is a moderator.
+ * @param force Override permissions checks.
+ * @returns `true` if the moderator can perform the action otherwise a reason why they can't.
*/
public static async permissionCheck(
moderator: BushGuildMember,
@@ -61,17 +66,14 @@ export class Moderation {
return true;
}
+ /**
+ * Creates a modlog entry for a punishment.
+ * @param options Options for creating a modlog entry.
+ * @param getCaseNumber Whether or not to get the case number of the entry.
+ * @returns An object with the modlog and the case number.
+ */
public static async createModLogEntry(
- options: {
- type: ModLogType;
- user: BushGuildMemberResolvable;
- moderator: BushGuildMemberResolvable;
- reason: string | undefined | null;
- duration?: number;
- guild: BushGuildResolvable;
- pseudo?: boolean;
- evidence?: string;
- },
+ options: CreateModLogEntryOptions,
getCaseNumber = false
): Promise<{ log: ModLog | null; caseNum: number | null }> {
const user = (await util.resolveNonCachedUser(options.user))!.id;
@@ -111,14 +113,12 @@ export class Moderation {
return { log: saveResult, caseNum };
}
- public static async createPunishmentEntry(options: {
- type: 'mute' | 'ban' | 'role' | 'block';
- user: BushGuildMemberResolvable;
- duration: number | undefined;
- guild: BushGuildResolvable;
- modlog: string;
- extraInfo?: Snowflake;
- }): Promise<ActivePunishment | null> {
+ /**
+ * Creates a punishment entry.
+ * @param options Options for creating the punishment entry.
+ * @returns The database entry, or null if no entry is created.
+ */
+ public static async createPunishmentEntry(options: CreatePunishmentEntryOptions): Promise<ActivePunishment | null> {
const expires = options.duration ? new Date(+new Date() + options.duration ?? 0) : undefined;
const user = (await util.resolveNonCachedUser(options.user))!.id;
const guild = client.guilds.resolveId(options.guild)!;
@@ -135,12 +135,12 @@ export class Moderation {
});
}
- public static async removePunishmentEntry(options: {
- type: 'mute' | 'ban' | 'role' | 'block';
- user: BushGuildMemberResolvable;
- guild: BushGuildResolvable;
- extraInfo?: Snowflake;
- }): Promise<boolean> {
+ /**
+ * Destroys a punishment entry.
+ * @param options Options for destroying the punishment entry.
+ * @returns Whether or not the entry was destroyed.
+ */
+ public static async removePunishmentEntry(options: RemovePunishmentEntryOptions): Promise<boolean> {
const user = await util.resolveNonCachedUser(options.user);
const guild = client.guilds.resolveId(options.guild);
const type = this.findTypeEnum(options.type);
@@ -171,6 +171,11 @@ export class Moderation {
return success;
}
+ /**
+ * Returns the punishment type enum for the given type.
+ * @param type The type of the punishment.
+ * @returns The punishment type enum.
+ */
private static findTypeEnum(type: 'mute' | 'ban' | 'role' | 'block') {
const typeMap = {
['mute']: ActivePunishmentType.MUTE,
@@ -181,3 +186,108 @@ export class Moderation {
return typeMap[type];
}
}
+
+/**
+ * Options for creating a modlog entry.
+ */
+export interface CreateModLogEntryOptions {
+ /**
+ * The type of modlog entry.
+ */
+ type: ModLogType;
+
+ /**
+ * The user that a modlog entry is created for.
+ */
+ user: BushGuildMemberResolvable;
+
+ /**
+ * The moderator that created the modlog entry.
+ */
+ moderator: BushGuildMemberResolvable;
+
+ /**
+ * The reason for the punishment.
+ */
+ reason: string | undefined | null;
+
+ /**
+ * The duration of the punishment.
+ */
+ duration?: number;
+
+ /**
+ * The guild that the punishment is created for.
+ */
+ guild: BushGuildResolvable;
+
+ /**
+ * Whether the punishment is a pseudo punishment.
+ */
+ pseudo?: boolean;
+
+ /**
+ * The evidence for the punishment.
+ */
+ evidence?: string;
+}
+
+/**
+ * Options for creating a punishment entry.
+ */
+export interface CreatePunishmentEntryOptions {
+ /**
+ * The type of punishment.
+ */
+ type: 'mute' | 'ban' | 'role' | 'block';
+
+ /**
+ * The user that the punishment is created for.
+ */
+ user: BushGuildMemberResolvable;
+
+ /**
+ * The length of time the punishment lasts for.
+ */
+ duration: number | undefined;
+
+ /**
+ * The guild that the punishment is created for.
+ */
+ guild: BushGuildResolvable;
+
+ /**
+ * The id of the modlog that is linked to the punishment entry.
+ */
+ modlog: string;
+
+ /**
+ * The role id if the punishment is a role punishment.
+ */
+ extraInfo?: Snowflake;
+}
+
+/**
+ * Options for removing a punishment entry.
+ */
+export interface RemovePunishmentEntryOptions {
+ /**
+ * The type of punishment.
+ */
+ type: 'mute' | 'ban' | 'role' | 'block';
+
+ /**
+ * The user that the punishment is destroyed for.
+ */
+ user: BushGuildMemberResolvable;
+
+ /**
+ * The guild that the punishment was in.
+ */
+ guild: BushGuildResolvable;
+
+ /**
+ * The role id if the punishment is a role punishment.
+ */
+ extraInfo?: Snowflake;
+}
diff --git a/src/lib/common/util/Arg.ts b/src/lib/common/util/Arg.ts
index 9ce8b54..2577db9 100644
--- a/src/lib/common/util/Arg.ts
+++ b/src/lib/common/util/Arg.ts
@@ -1,7 +1,10 @@
import { BaseBushArgumentType, BushArgumentTypeCaster, BushSlashMessage, type BushArgumentType } from '#lib';
-import { Argument, type ArgumentTypeCaster, type Flag, type ParsedValuePredicate } from 'discord-akairo';
+import { Argument, type Flag, type ParsedValuePredicate } from 'discord-akairo';
import { type Message } from 'discord.js';
+/**
+ * A wrapper for the {@link Argument} class that adds custom typings.
+ */
export class Arg {
/**
* Casts a phrase to this argument's type.
@@ -11,14 +14,9 @@ export class Arg {
*/
public static async cast<T extends ATC>(type: T, message: Message | BushSlashMessage, phrase: string): Promise<ATCR<T>>;
public static async cast<T extends KBAT>(type: T, message: Message | BushSlashMessage, phrase: string): Promise<BAT[T]>;
- public static async cast<T extends AT | ATC>(type: T, message: Message | BushSlashMessage, phrase: string): Promise<any>;
+ public static async cast(type: AT | ATC, message: Message | BushSlashMessage, phrase: string): Promise<any>;
public static async cast(type: ATC | AT, message: Message | BushSlashMessage, phrase: string): Promise<any> {
- return Argument.cast(
- type as ArgumentTypeCaster | keyof BushArgumentType,
- client.commandHandler.resolver,
- message as Message,
- phrase
- );
+ return Argument.cast(type as any, client.commandHandler.resolver, message as Message, phrase);
}
/**
@@ -28,7 +26,7 @@ export class Arg {
*/
public static compose<T extends ATC>(...types: T[]): ATCATCR<T>;
public static compose<T extends KBAT>(...types: T[]): ATCBAT<T>;
- public static compose<T extends AT | ATC>(...types: T[]): ATC;
+ public static compose(...types: (AT | ATC)[]): ATC;
public static compose(...types: (AT | ATC)[]): ATC {
return Argument.compose(...(types as any));
}
@@ -40,7 +38,7 @@ export class Arg {
*/
public static composeWithFailure<T extends ATC>(...types: T[]): ATCATCR<T>;
public static composeWithFailure<T extends KBAT>(...types: T[]): ATCBAT<T>;
- public static composeWithFailure<T extends AT | ATC>(...types: T[]): ATC;
+ public static composeWithFailure(...types: (AT | ATC)[]): ATC;
public static composeWithFailure(...types: (AT | ATC)[]): ATC {
return Argument.composeWithFailure(...(types as any));
}
@@ -60,7 +58,7 @@ export class Arg {
*/
public static product<T extends ATC>(...types: T[]): ATCATCR<T>;
public static product<T extends KBAT>(...types: T[]): ATCBAT<T>;
- public static product<T extends AT | ATC>(...types: T[]): ATC;
+ public static product(...types: (AT | ATC)[]): ATC;
public static product(...types: (AT | ATC)[]): ATC {
return Argument.product(...(types as any));
}
@@ -74,7 +72,7 @@ export class Arg {
*/
public static range<T extends ATC>(type: T, min: number, max: number, inclusive?: boolean): ATCATCR<T>;
public static range<T extends KBAT>(type: T, min: number, max: number, inclusive?: boolean): ATCBAT<T>;
- public static range<T extends AT | ATC>(type: T, min: number, max: number, inclusive?: boolean): ATC;
+ public static range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC;
public static range(type: AT | ATC, min: number, max: number, inclusive?: boolean): ATC {
return Argument.range(type as any, min, max, inclusive);
}
@@ -87,7 +85,7 @@ export class Arg {
*/
public static tagged<T extends ATC>(type: T, tag?: any): ATCATCR<T>;
public static tagged<T extends KBAT>(type: T, tag?: any): ATCBAT<T>;
- public static tagged<T extends AT | ATC>(type: T, tag?: any): ATC;
+ public static tagged(type: AT | ATC, tag?: any): ATC;
public static tagged(type: AT | ATC, tag?: any): ATC {
return Argument.tagged(type as any, tag);
}
@@ -100,7 +98,7 @@ export class Arg {
*/
public static taggedUnion<T extends ATC>(...types: T[]): ATCATCR<T>;
public static taggedUnion<T extends KBAT>(...types: T[]): ATCBAT<T>;
- public static taggedUnion<T extends AT | ATC>(...types: T[]): ATC;
+ public static taggedUnion(...types: (AT | ATC)[]): ATC;
public static taggedUnion(...types: (AT | ATC)[]): ATC {
return Argument.taggedUnion(...(types as any));
}
@@ -113,7 +111,7 @@ export class Arg {
*/
public static taggedWithInput<T extends ATC>(type: T, tag?: any): ATCATCR<T>;
public static taggedWithInput<T extends KBAT>(type: T, tag?: any): ATCBAT<T>;
- public static taggedWithInput<T extends AT | ATC>(type: T, tag?: any): ATC;
+ public static taggedWithInput(type: AT | ATC, tag?: any): ATC;
public static taggedWithInput(type: AT | ATC, tag?: any): ATC {
return Argument.taggedWithInput(type as any, tag);
}
@@ -125,7 +123,7 @@ export class Arg {
*/
public static union<T extends ATC>(...types: T[]): ATCATCR<T>;
public static union<T extends KBAT>(...types: T[]): ATCBAT<T>;
- public static union<T extends AT | ATC>(...types: T[]): ATC;
+ public static union(...types: (AT | ATC)[]): ATC;
public static union(...types: (AT | ATC)[]): ATC {
return Argument.union(...(types as any));
}
@@ -138,7 +136,7 @@ export class Arg {
*/
public static validate<T extends ATC>(type: T, predicate: ParsedValuePredicate): ATCATCR<T>;
public static validate<T extends KBAT>(type: T, predicate: ParsedValuePredicate): ATCBAT<T>;
- public static validate<T extends AT | ATC>(type: T, predicate: ParsedValuePredicate): ATC;
+ public static validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC;
public static validate(type: AT | ATC, predicate: ParsedValuePredicate): ATC {
return Argument.validate(type as any, predicate);
}
@@ -150,39 +148,39 @@ export class Arg {
*/
public static withInput<T extends ATC>(type: T): ATC<ATCR<T>>;
public static withInput<T extends KBAT>(type: T): ATCBAT<T>;
- public static withInput<T extends AT | ATC>(type: T): ATC;
+ public static withInput(type: AT | ATC): ATC;
public static withInput(type: AT | ATC): ATC {
return Argument.withInput(type as any);
}
}
-type ArgumentTypeCasterReturn<R> = R extends BushArgumentTypeCaster<infer S> ? S : R;
+type BushArgumentTypeCasterReturn<R> = R extends BushArgumentTypeCaster<infer S> ? S : R;
/** ```ts
- * <R = unknown> = ArgumentTypeCaster<R>
+ * <R = unknown> = BushArgumentTypeCaster<R>
* ``` */
type ATC<R = unknown> = BushArgumentTypeCaster<R>;
/** ```ts
- * keyof BaseArgumentType
+ * keyof BaseBushArgumentType
* ``` */
type KBAT = keyof BaseBushArgumentType;
/** ```ts
- * <R> = ArgumentTypeCasterReturn<R>
+ * <R> = BushArgumentTypeCasterReturn<R>
* ``` */
-type ATCR<R> = ArgumentTypeCasterReturn<R>;
+type ATCR<R> = BushArgumentTypeCasterReturn<R>;
/** ```ts
- * keyof BaseBushArgumentType | string
+ * BushArgumentType
* ``` */
-type AT = BushArgumentTypeCaster | keyof BaseBushArgumentType | string;
+type AT = BushArgumentType;
/** ```ts
- * BaseArgumentType
+ * BaseBushArgumentType
* ``` */
type BAT = BaseBushArgumentType;
/** ```ts
- * <T extends ArgumentTypeCaster> = ArgumentTypeCaster<ArgumentTypeCasterReturn<T>>
+ * <T extends BushArgumentTypeCaster> = BushArgumentTypeCaster<BushArgumentTypeCasterReturn<T>>
* ``` */
-type ATCATCR<T extends BushArgumentTypeCaster> = BushArgumentTypeCaster<ArgumentTypeCasterReturn<T>>;
+type ATCATCR<T extends BushArgumentTypeCaster> = BushArgumentTypeCaster<BushArgumentTypeCasterReturn<T>>;
/** ```ts
- * <T extends keyof BaseArgumentType> = ArgumentTypeCaster<BaseArgumentType[T]>
+ * <T extends keyof BaseBushArgumentType> = BushArgumentTypeCaster<BaseBushArgumentType[T]>
* ``` */
type ATCBAT<T extends keyof BaseBushArgumentType> = BushArgumentTypeCaster<BaseBushArgumentType[T]>;