aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/commands/moderation/ban.ts2
-rw-r--r--src/lib/common/AutoMod.ts18
-rw-r--r--src/lib/extensions/discord.js/BushGuild.ts2
-rw-r--r--src/lib/extensions/discord.js/BushGuildMember.ts5
-rw-r--r--src/listeners/guild/guildMemberAdd.ts80
-rw-r--r--src/listeners/guild/guildMemberRemove.ts4
-rw-r--r--src/listeners/guild/joinRoles.ts119
7 files changed, 141 insertions, 89 deletions
diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts
index 7f0b91f..aeb03f0 100644
--- a/src/commands/moderation/ban.ts
+++ b/src/commands/moderation/ban.ts
@@ -127,6 +127,8 @@ export default class BanCommand extends BushCommand {
const responseMessage = (): string => {
const victim = util.format.input(user.tag);
switch (responseCode) {
+ case banResponse.ALREADY_BANNED:
+ return `${util.emojis.error} ${victim} is already banned.`;
case banResponse.MISSING_PERMISSIONS:
return `${util.emojis.error} Could not ban ${victim} because I am missing the **Ban Members** permission.`;
case banResponse.ACTION_ERROR:
diff --git a/src/lib/common/AutoMod.ts b/src/lib/common/AutoMod.ts
index 50f5d3e..7a30820 100644
--- a/src/lib/common/AutoMod.ts
+++ b/src/lib/common/AutoMod.ts
@@ -1,4 +1,4 @@
-import { Moderation, type BushButtonInteraction, type BushMessage } from '#lib';
+import { banResponse, Moderation, type BushButtonInteraction, type BushMessage } from '#lib';
import { GuildMember, MessageActionRow, MessageButton, MessageEmbed, type TextChannel } from 'discord.js';
/**
@@ -308,18 +308,20 @@ export class AutoMod {
evidence: (interaction.message as BushMessage).url ?? undefined
});
- if (result === 'success')
+ const victimUserFormatted = (await util.resolveNonCachedUser(userId))?.tag ?? userId;
+ if (result === banResponse.SUCCESS)
return interaction.reply({
- content: `${util.emojis.success} Successfully banned **${
- interaction.guild?.members.cache.get(userId)?.user.tag ?? userId
- }**.`,
+ content: `${util.emojis.success} Successfully banned **${victimUserFormatted}**.`,
+ ephemeral: true
+ });
+ else if (result === banResponse.DM_ERROR)
+ return interaction.reply({
+ content: `${util.emojis.warn} Banned ${victimUserFormatted} however I could not send them a dm.`,
ephemeral: true
});
else
return interaction.reply({
- content: `${util.emojis.error} Could not ban **${
- interaction.guild?.members.cache.get(userId)?.user.tag ?? userId
- }**: \`${result}\` .`,
+ content: `${util.emojis.error} Could not ban **${victimUserFormatted}**: \`${result}\` .`,
ephemeral: true
});
}
diff --git a/src/lib/extensions/discord.js/BushGuild.ts b/src/lib/extensions/discord.js/BushGuild.ts
index 0011ce6..33ee3fc 100644
--- a/src/lib/extensions/discord.js/BushGuild.ts
+++ b/src/lib/extensions/discord.js/BushGuild.ts
@@ -163,6 +163,8 @@ export class BushGuild extends Guild {
const user = (await util.resolveNonCachedUser(options.user))!;
const moderator = client.users.resolve(options.moderator ?? client.user!)!;
+ if ((await this.bans.fetch()).has(user.id)) return banResponse.ALREADY_BANNED;
+
const ret = await (async () => {
// dm user
dmSuccessEvent = await Moderation.punishDM({
diff --git a/src/lib/extensions/discord.js/BushGuildMember.ts b/src/lib/extensions/discord.js/BushGuildMember.ts
index 6a95ebf..54fb3f0 100644
--- a/src/lib/extensions/discord.js/BushGuildMember.ts
+++ b/src/lib/extensions/discord.js/BushGuildMember.ts
@@ -465,7 +465,7 @@ export class BushGuildMember extends GuildMember {
* @returns A status message for banning the user.
* @emits {@link BushClientEvents.bushBan}
*/
- public async bushBan(options: BushBanOptions): Promise<BanResponse> {
+ public async bushBan(options: BushBanOptions): Promise<Exclude<BanResponse, typeof banResponse['ALREADY_BANNED']>> {
// checks
if (!this.guild.me!.permissions.has('BAN_MEMBERS') || !this.bannable) return banResponse.MISSING_PERMISSIONS;
@@ -1025,7 +1025,8 @@ export const kickResponse = Object.freeze({
export const banResponse = Object.freeze({
...dmResponse,
...permissionsResponse,
- ...punishmentEntryAdd
+ ...punishmentEntryAdd,
+ ALREADY_BANNED: 'already banned'
} as const);
export const blockResponse = Object.freeze({
diff --git a/src/listeners/guild/guildMemberAdd.ts b/src/listeners/guild/guildMemberAdd.ts
index 4c7d498..22961e9 100644
--- a/src/listeners/guild/guildMemberAdd.ts
+++ b/src/listeners/guild/guildMemberAdd.ts
@@ -1,5 +1,5 @@
-import { BushListener, StickyRole, type BushClientEvents, type BushGuildMember, type BushTextChannel } from '#lib';
-import { MessageEmbed, type Snowflake } from 'discord.js';
+import { BushListener, type BushClientEvents, type BushGuildMember, type BushTextChannel } from '#lib';
+import { MessageEmbed } from 'discord.js';
export default class GuildMemberAddListener extends BushListener {
public constructor() {
@@ -12,10 +12,9 @@ export default class GuildMemberAddListener extends BushListener {
public override async exec(...[member]: BushClientEvents['guildMemberAdd']) {
void this.sendWelcomeMessage(member);
- void this.joinAndStickyRoles(member);
}
- public async sendWelcomeMessage(member: BushGuildMember) {
+ private async sendWelcomeMessage(member: BushGuildMember) {
if (client.config.isDevelopment) return;
const welcomeChannel = await member.guild.getSetting('welcomeChannel');
if (!welcomeChannel) return;
@@ -44,77 +43,4 @@ export default class GuildMemberAddListener extends BushListener {
)
);
}
-
- public async joinAndStickyRoles(member: BushGuildMember) {
- if (client.config.isDevelopment) return;
- if (await member.guild.hasFeature('stickyRoles')) {
- const hadRoles = await StickyRole.findOne({ where: { guild: member.guild.id, user: member.id } });
- if (hadRoles?.roles?.length) {
- const rolesArray = hadRoles.roles
- .map((roleID: Snowflake) => {
- const role = member.guild.roles.cache.get(roleID);
- if (role && !member.roles.cache.has(roleID)) {
- if (role.name !== '@everyone' || !role.managed) return role.id;
- }
- })
- .filter((role) => role) as Snowflake[];
- if (hadRoles.nickname && member.manageable) {
- void member.setNickname(hadRoles.nickname).catch(() => {});
- }
- if (rolesArray?.length) {
- const addedRoles = await member.roles.add(rolesArray, "Returning member's previous roles.").catch(() =>
- member.guild.sendLogChannel('error', {
- embeds: [
- {
- title: 'Sticky Roles Error',
- description: `There was an error returning ${util.format.input(member.user.tag)}'s roles.`,
- color: util.colors.error
- }
- ]
- })
- );
- if (addedRoles) {
- void client.console.info(
- 'guildMemberAdd',
- `Assigned sticky roles to ${util.format.inputLog(member.user.tag)} in ${util.format.inputLog(member.guild.name)}.`
- );
- } else if (!addedRoles) {
- const failedRoles: string[] = [];
- for (let i = 0; i < rolesArray.length; i++) {
- await member.roles
- .add(rolesArray[i], "[Fallback] Returning member's previous roles.")
- .catch(() => failedRoles.push(rolesArray[i]));
- }
- if (failedRoles.length) {
- void client.console.warn('guildMemberAdd', `Failed assigning the following roles on Fallback: ${failedRoles}`);
- } else {
- void client.console.info(
- 'guildMemberAdd',
- `[Fallback] Assigned sticky roles to ${util.format.inputLog(member.user.tag)} in ${util.format.inputLog(
- member.guild.name
- )}.`
- );
- }
- }
- }
- } else {
- const joinRoles = await member.guild.getSetting('joinRoles');
- if (!joinRoles || !joinRoles.length) return;
- await member.roles
- .add(joinRoles, 'Join roles.')
- .then(() =>
- client.console.info(
- 'guildMemberAdd',
- `Assigned join roles to ${util.format.inputLog(member.user.tag)} in ${util.format.inputLog(member.guild.name)}.`
- )
- )
- .catch(() =>
- member.guild.error(
- 'Join Roles Error',
- `Failed to assign join roles to ${util.format.input(member.user.tag)}, in ${util.format.input(member.guild.name)}.`
- )
- );
- }
- }
- }
}
diff --git a/src/listeners/guild/guildMemberRemove.ts b/src/listeners/guild/guildMemberRemove.ts
index ae4c4df..323bd24 100644
--- a/src/listeners/guild/guildMemberRemove.ts
+++ b/src/listeners/guild/guildMemberRemove.ts
@@ -22,7 +22,7 @@ export default class GuildMemberRemoveListener extends BushListener {
void this.stickyRoles(member);
}
- public async sendWelcomeMessage(member: BushGuildMember | PartialBushGuildMember) {
+ private async sendWelcomeMessage(member: BushGuildMember | PartialBushGuildMember) {
if (client.config.isDevelopment) return;
const user = member.partial ? await client.users.fetch(member.id) : member.user;
await util.sleep(0.05); // ban usually triggers after member leave
@@ -54,7 +54,7 @@ export default class GuildMemberRemoveListener extends BushListener {
);
}
- public async stickyRoles(member: BushGuildMember | PartialBushGuildMember) {
+ private async stickyRoles(member: BushGuildMember | PartialBushGuildMember) {
if (!(await member.guild.hasFeature('stickyRoles'))) return;
if (member.partial) {
await member.guild.members.fetch(); // try to prevent in the future
diff --git a/src/listeners/guild/joinRoles.ts b/src/listeners/guild/joinRoles.ts
new file mode 100644
index 0000000..a50f7ed
--- /dev/null
+++ b/src/listeners/guild/joinRoles.ts
@@ -0,0 +1,119 @@
+import { BushListener, StickyRole, type BushClientEvents, type BushGuildMember } from '#lib';
+import { type Snowflake } from 'discord.js';
+
+export default class JoinRolesListener extends BushListener {
+ public constructor() {
+ super('joinRoles', {
+ emitter: 'client',
+ event: 'guildMemberUpdate', // listens to guildMemberUpdate so that the role's aren't given before the member accepts the welcome screen
+ category: 'guild'
+ });
+ }
+
+ public override async exec(...[oldMember, newMember]: BushClientEvents['guildMemberUpdate']) {
+ if (client.config.isDevelopment) return;
+ if (oldMember.pending === false && newMember.pending === true) {
+ const feat = {
+ stickyRoles: await newMember.guild.hasFeature('stickyRoles'),
+ joinRoles: (await newMember.guild.getSetting('joinRoles')).length > 0
+ };
+
+ if (!feat.stickyRoles && !feat.joinRoles) return;
+
+ let addJoinRoles = true;
+ if (feat.stickyRoles) {
+ const addedStickyRoles = await this.stickyRoles(newMember);
+ if (addedStickyRoles) addJoinRoles = false;
+ }
+
+ if (feat.joinRoles && addJoinRoles) {
+ void this.joinRoles(newMember);
+ }
+ }
+ }
+
+ /**
+ * Adds sticky roles to a user.
+ * @param member The member to add sticky roles to.
+ * @returns Whether or not sticky roles were added.
+ */
+ private async stickyRoles(member: BushGuildMember): Promise<boolean> {
+ const hadRoles = await StickyRole.findOne({ where: { guild: member.guild.id, user: member.id } });
+
+ if (hadRoles?.roles?.length) {
+ const rolesArray = hadRoles.roles
+ .map((roleID: Snowflake) => {
+ const role = member.guild.roles.cache.get(roleID);
+ if (role && !member.roles.cache.has(roleID)) {
+ if (role.name !== '@everyone' || !role.managed) return role.id;
+ }
+ })
+ .filter((role) => role) as Snowflake[];
+ if (hadRoles.nickname && member.manageable) {
+ void member.setNickname(hadRoles.nickname).catch(() => {});
+ }
+ if (rolesArray?.length) {
+ const addedRoles = await member.roles.add(rolesArray, "Returning member's previous roles.").catch(() => {
+ void member.guild.sendLogChannel('error', {
+ embeds: [
+ {
+ title: 'Sticky Roles Error',
+ description: `There was an error returning ${util.format.input(member.user.tag)}'s roles.`,
+ color: util.colors.error
+ }
+ ]
+ });
+ return false as const;
+ });
+ if (addedRoles) {
+ void client.console.info(
+ 'guildMemberAdd',
+ `Assigned sticky roles to ${util.format.inputLog(member.user.tag)} in ${util.format.inputLog(member.guild.name)}.`
+ );
+ } else if (!addedRoles) {
+ const failedRoles: string[] = [];
+ for (let i = 0; i < rolesArray.length; i++) {
+ await member.roles
+ .add(rolesArray[i], "[Fallback] Returning member's previous roles.")
+ .catch(() => failedRoles.push(rolesArray[i]));
+ }
+ if (failedRoles.length) {
+ void client.console.warn('guildMemberAdd', `Failed assigning the following roles on Fallback: ${failedRoles}`);
+ } else {
+ void client.console.info(
+ 'guildMemberAdd',
+ `[Fallback] Assigned sticky roles to ${util.format.inputLog(member.user.tag)} in ${util.format.inputLog(
+ member.guild.name
+ )}.`
+ );
+ }
+ }
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /**
+ * Add the guild's join roles to the member.
+ * @param member The member to add the join roles to.
+ */
+ private async joinRoles(member: BushGuildMember): Promise<void> {
+ const joinRoles = await member.guild.getSetting('joinRoles');
+ if (!joinRoles || !joinRoles.length) return;
+ await member.roles
+ .add(joinRoles, 'Join roles.')
+ .then(() =>
+ client.console.info(
+ 'guildMemberAdd',
+ `Assigned join roles to ${util.format.inputLog(member.user.tag)} in ${util.format.inputLog(member.guild.name)}.`
+ )
+ )
+ .catch(() =>
+ member.guild.error(
+ 'Join Roles Error',
+ `Failed to assign join roles to ${util.format.input(member.user.tag)}, in ${util.format.input(member.guild.name)}.`
+ )
+ );
+ }
+}