aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIRONM00N <64110067+IRONM00N@users.noreply.github.com>2021-07-14 13:12:32 -0400
committerIRONM00N <64110067+IRONM00N@users.noreply.github.com>2021-07-14 13:12:32 -0400
commit070b5f326d0647e7b105f99811e4bdc915c8652e (patch)
tree15c5e3366acb9f6056de83924db6dd9db961061a
parentcdb8b0297f806cb3147b3759b0fd234bffbcc3f9 (diff)
downloadtanzanite-070b5f326d0647e7b105f99811e4bdc915c8652e.tar.gz
tanzanite-070b5f326d0647e7b105f99811e4bdc915c8652e.tar.bz2
tanzanite-070b5f326d0647e7b105f99811e4bdc915c8652e.zip
revamped role command and some other stuff
-rw-r--r--src/commands/moderation/ban.ts45
-rw-r--r--src/commands/moderation/kick.ts40
-rw-r--r--src/commands/moderation/modlog.ts3
-rw-r--r--src/commands/moderation/mute.ts68
-rw-r--r--src/commands/moderation/role.ts176
-rw-r--r--src/commands/moderation/unban.ts41
-rw-r--r--src/commands/moderation/unmute.ts68
-rw-r--r--src/lib/extensions/discord-akairo/BushClientUtil.ts56
-rw-r--r--src/lib/extensions/discord.js/BushGuildMember.ts128
-rw-r--r--src/lib/models/Ban.ts8
-rw-r--r--src/lib/models/Global.ts33
-rw-r--r--src/lib/models/Guild.ts23
-rw-r--r--src/lib/models/Level.ts13
-rw-r--r--src/lib/models/ModLog.ts21
-rw-r--r--src/lib/models/Mute.ts8
-rw-r--r--src/lib/models/PunishmentRole.ts18
-rw-r--r--src/tasks/removePunishmentRole.ts32
-rw-r--r--src/tasks/unban.ts31
-rw-r--r--src/tasks/unmute.ts18
19 files changed, 497 insertions, 333 deletions
diff --git a/src/commands/moderation/ban.ts b/src/commands/moderation/ban.ts
index d713a15..c5833fc 100644
--- a/src/commands/moderation/ban.ts
+++ b/src/commands/moderation/ban.ts
@@ -1,4 +1,4 @@
-import { BushCommand, BushGuildMember, BushMessage, BushSlashMessage } from '@lib';
+import { AllowedMentions, BushCommand, BushGuildMember, BushMessage, BushSlashMessage } from '@lib';
import { Argument } from 'discord-akairo';
import { User } from 'discord.js';
@@ -99,36 +99,29 @@ export default class BanCommand extends BushCommand {
}
const parsedReason = reason.contentWithoutTime;
- const response = await member.bushBan({
+ const responseCode = await member.bushBan({
reason: parsedReason,
moderator: message.author,
duration: time,
deleteDays: days ?? 0
});
- switch (response) {
- case 'missing permissions':
- return message.util.reply(
- `${this.client.util.emojis.error} Could not ban **${member.user.tag}** because I do not have permissions`
- );
- case 'error banning':
- return message.util.reply(
- `${this.client.util.emojis.error} An error occurred while trying to ban **${member.user.tag}**.`
- );
- case 'error creating ban entry':
- return message.util.reply(
- `${this.client.util.emojis.error} While banning **${member.user.tag}**, there was an error creating a ban entry, please report this to my developers.`
- );
- case 'error creating modlog entry':
- return message.util.reply(
- `${this.client.util.emojis.error} While banning **${member.user.tag}**, there was an error creating a modlog entry, please report this to my developers.`
- );
- case 'failed to dm':
- return message.util.reply(
- `${this.client.util.emojis.warn} Banned **${member.user.tag}** however I could not send them a dm.`
- );
- case 'success':
- return message.util.reply(`${this.client.util.emojis.success} Successfully banned **${member.user.tag}**.`);
- }
+ const responseMessage = () => {
+ switch (responseCode) {
+ case 'missing permissions':
+ return `${this.client.util.emojis.error} Could not ban **${member.user.tag}** because I do not have permissions`;
+ case 'error banning':
+ return `${this.client.util.emojis.error} An error occurred while trying to ban **${member.user.tag}**.`;
+ case 'error creating ban entry':
+ return `${this.client.util.emojis.error} While banning **${member.user.tag}**, there was an error creating a ban entry, please report this to my developers.`;
+ case 'error creating modlog entry':
+ return `${this.client.util.emojis.error} While banning **${member.user.tag}**, there was an error creating a modlog entry, please report this to my developers.`;
+ case 'failed to dm':
+ return `${this.client.util.emojis.warn} Banned **${member.user.tag}** however I could not send them a dm.`;
+ case 'success':
+ return `${this.client.util.emojis.success} Successfully banned **${member.user.tag}**.`;
+ }
+ };
+ return await message.util.reply({ content: responseMessage(), allowedMentions: AllowedMentions.none() });
}
}
diff --git a/src/commands/moderation/kick.ts b/src/commands/moderation/kick.ts
index d70bbfb..ccf35a9 100644
--- a/src/commands/moderation/kick.ts
+++ b/src/commands/moderation/kick.ts
@@ -1,4 +1,4 @@
-import { BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '@lib';
+import { AllowedMentions, BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '@lib';
export default class KickCommand extends BushCommand {
public constructor() {
@@ -53,36 +53,30 @@ export default class KickCommand extends BushCommand {
async exec(message: BushMessage | BushSlashMessage, { user, reason }: { user: BushUser; reason?: string }): Promise<unknown> {
const member = message.guild.members.cache.get(user.id) as BushGuildMember;
const canModerateResponse = this.client.util.moderationPermissionCheck(message.member, member, 'kick');
- // const victimBoldTag = `**${member.user.tag}**`;
if (canModerateResponse !== true) {
return message.util.reply(canModerateResponse);
}
- const response = await member.bushKick({
+ const responseCode = await member.bushKick({
reason,
moderator: message.author
});
- switch (response) {
- case 'missing permissions':
- return message.util.reply(
- `${this.client.util.emojis.error} Could not kick **${member.user.tag}** because I am missing the \`Kick Members\` permission.`
- );
- case 'error kicking':
- return message.util.reply(
- `${this.client.util.emojis.error} An error occurred while trying to kick **${member.user.tag}**.`
- );
- case 'error creating modlog entry':
- return message.util.reply(
- `${this.client.util.emojis.error} While muting **${member.user.tag}**, there was an error creating a modlog entry, please report this to my developers.`
- );
- case 'failed to dm':
- return message.util.reply(
- `${this.client.util.emojis.warn} Kicked **${member.user.tag}** however I could not send them a dm.`
- );
- case 'success':
- return message.util.reply(`${this.client.util.emojis.success} Successfully kicked **${member.user.tag}**.`);
- }
+ const responseMessage = () => {
+ switch (responseCode) {
+ case 'missing permissions':
+ return `${this.client.util.emojis.error} Could not kick **${member.user.tag}** because I am missing the \`Kick Members\` permission.`;
+ case 'error kicking':
+ return `${this.client.util.emojis.error} An error occurred while trying to kick **${member.user.tag}**.`;
+ case 'error creating modlog entry':
+ return `${this.client.util.emojis.error} While muting **${member.user.tag}**, there was an error creating a modlog entry, please report this to my developers.`;
+ case 'failed to dm':
+ return `${this.client.util.emojis.warn} Kicked **${member.user.tag}** however I could not send them a dm.`;
+ case 'success':
+ return `${this.client.util.emojis.success} Successfully kicked **${member.user.tag}**.`;
+ }
+ };
+ return await message.util.reply({ content: responseMessage(), allowedMentions: AllowedMentions.none() });
}
}
diff --git a/src/commands/moderation/modlog.ts b/src/commands/moderation/modlog.ts
index c71f962..af5f563 100644
--- a/src/commands/moderation/modlog.ts
+++ b/src/commands/moderation/modlog.ts
@@ -1,7 +1,6 @@
import { BushCommand, BushMessage, BushSlashMessage, ModLog } from '@lib';
import { Argument } from 'discord-akairo';
import { MessageEmbed } from 'discord.js';
-import moment from 'moment';
export default class ModlogCommand extends BushCommand {
public constructor() {
@@ -43,7 +42,7 @@ export default class ModlogCommand extends BushCommand {
`**User**: <@!${log.user}> (${log.user})`,
`**Moderator**: <@!${log.moderator}> (${log.moderator})`
];
- if (log.duration) modLog.push(`**Duration**: ${moment.duration(log.duration, 'milliseconds').humanize()}`);
+ if (log.duration) modLog.push(`**Duration**: ${this.client.util.humanizeDuration(log.duration)}`);
modLog.push(`**Reason**: ${log.reason || 'No Reason Specified.'}`);
return modLog.join(`\n`);
}
diff --git a/src/commands/moderation/mute.ts b/src/commands/moderation/mute.ts
index 0eae547..7443c55 100644
--- a/src/commands/moderation/mute.ts
+++ b/src/commands/moderation/mute.ts
@@ -1,4 +1,4 @@
-import { BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '@lib';
+import { AllowedMentions, BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '@lib';
import { Argument } from 'discord-akairo';
export default class MuteCommand extends BushCommand {
@@ -73,51 +73,35 @@ export default class MuteCommand extends BushCommand {
}
const parsedReason = reason.contentWithoutTime;
- const response = await member.mute({
+ const responseCode = await member.mute({
reason: parsedReason,
moderator: message.author,
duration: time
});
- switch (response) {
- case 'missing permissions':
- return message.util.reply(
- `${error} Could not mute ${victimBoldTag} because I am missing the \`Manage Roles\` permission.`
- );
- case 'no mute role':
- return message.util.reply(
- `${error} Could not mute ${victimBoldTag}, you must set a mute role with \`${message.guild.getSetting(
- 'prefix'
- )}muterole\`.`
- );
- case 'invalid mute role':
- return message.util.reply(
- `${error} Could not mute ${victimBoldTag} because the current mute role no longer exists. Please set a new mute role with \`${message.guild.getSetting(
- 'prefix'
- )}muterole\`.`
- );
- case 'mute role not manageable':
- return message.util.reply(
- `${error} Could not mute ${victimBoldTag} because I cannot assign the current mute role, either change the role's position or set a new mute role with \`${message.guild.getSetting(
- 'prefix'
- )}muterole\`.`
- );
- case 'error giving mute role':
- return message.util.reply(`${error} Could not mute ${victimBoldTag}, there was an error assigning them the mute role.`);
- case 'error creating modlog entry':
- return message.util.reply(
- `${error} While muting ${victimBoldTag}, there was an error creating a modlog entry, please report this to my developers.`
- );
- case 'error creating mute entry':
- return message.util.reply(
- `${error} While muting ${victimBoldTag}, there was an error creating a mute entry, please report this to my developers.`
- );
- case 'failed to dm':
- return message.util.reply(
- `${this.client.util.emojis.warn} Muted **${member.user.tag}** however I could not send them a dm.`
- );
- case 'success':
- return message.util.reply(`${this.client.util.emojis.success} Successfully muted **${member.user.tag}**.`);
- }
+ const responseMessage = () => {
+ const prefix = message.guild.getSetting('prefix');
+ switch (responseCode) {
+ case 'missing permissions':
+ return `${error} Could not mute ${victimBoldTag} because I am missing the \`Manage Roles\` permission.`;
+ case 'no mute role':
+ return `${error} Could not mute ${victimBoldTag}, you must set a mute role with \`${prefix}muterole\`.`;
+ case 'invalid mute role':
+ return `${error} Could not mute ${victimBoldTag} because the current mute role no longer exists. Please set a new mute role with \`${prefix}muterole\`.`;
+ case 'mute role not manageable':
+ return `${error} Could not mute ${victimBoldTag} because I cannot assign the current mute role, either change the role's position or set a new mute role with \`${prefix}muterole\`.`;
+ case 'error giving mute role':
+ return `${error} Could not mute ${victimBoldTag}, there was an error assigning them the mute role.`;
+ case 'error creating modlog entry':
+ return `${error} There was an error creating a modlog entry, please report this to my developers.`;
+ case 'error creating mute entry':
+ return `${error} There was an error creating a punishment entry, please report this to my developers.`;
+ case 'failed to dm':
+ return `${this.client.util.emojis.warn} Muted **${member.user.tag}** however I could not send them a dm.`;
+ case 'success':
+ return `${this.client.util.emojis.success} Successfully muted **${member.user.tag}**.`;
+ }
+ };
+ return await message.util.reply({ content: responseMessage(), allowedMentions: AllowedMentions.none() });
}
}
diff --git a/src/commands/moderation/role.ts b/src/commands/moderation/role.ts
index 29913d5..3470ab9 100644
--- a/src/commands/moderation/role.ts
+++ b/src/commands/moderation/role.ts
@@ -8,9 +8,44 @@ export default class RoleCommand extends BushCommand {
category: 'moderation',
description: {
content: "Manages users' roles.",
- usage: 'role <add|remove> <user> <role>',
- examples: ['role add tyman adminperms']
+ usage: 'role <add|remove> <user> <role> [duration]',
+ examples: ['role add spammer nogiveaways 7days']
},
+ args: [
+ {
+ id: 'action',
+ type: [['add'], ['remove']],
+ prompt: {
+ start: 'Would you like to `add` or `remove` a role?',
+ retry: '{error} Choose whether you would you like to `add` or `remove` a role.'
+ }
+ },
+ {
+ id: 'user',
+ type: 'member',
+ prompt: {
+ start: `What user do you want to add/remove the role to/from?`,
+ retry: `{error} Choose a valid user to add/remove the role to/from.`
+ }
+ },
+ {
+ id: 'role',
+ type: 'role',
+ prompt: {
+ start: `What role do you want to add/remove to/from the user.?`,
+ retry: `{error} Choose a valid role to add/remove.`
+ }
+ },
+ {
+ id: 'duration',
+ type: 'duration',
+ prompt: {
+ start: 'How long would you like to role to last?',
+ retry: '{error} Choose a valid duration.',
+ optional: true
+ }
+ }
+ ],
slash: true,
slashOptions: [
{
@@ -31,15 +66,21 @@ export default class RoleCommand extends BushCommand {
},
{
name: 'user',
- description: 'The user you would like to add/remove the role from.',
+ description: 'What user do you want to add/remove the role to/from?',
type: 'USER',
required: true
},
{
name: 'role',
- description: 'The role you would like to add/remove from the user.',
+ description: 'The role you would like to add/remove from the to/from.',
type: 'ROLE',
required: true
+ },
+ {
+ name: 'duration',
+ description: 'How long would you like to role to last?',
+ type: 'STRING',
+ required: false
}
],
channel: 'guild',
@@ -49,44 +90,11 @@ export default class RoleCommand extends BushCommand {
});
}
- *args(): unknown {
- const action: 'add' | 'remove' = yield {
- id: 'action',
- type: [['add'], ['remove']],
- prompt: {
- start: 'Would you like to `add` or `remove` a role?',
- retry: '{error} Choose whether you would you like to `add` or `remove` a role.'
- }
- };
- let action2: 'to' | 'from';
- if (action === 'add') action2 = 'to';
- else if (action === 'remove') action2 = 'from';
- else return;
- const user = yield {
- id: 'user',
- type: 'member',
- prompt: {
- start: `What user do you want to ${action} the role ${action2}?`,
- retry: `{error} Choose a valid user to ${action} the role ${action2}.`
- }
- };
- const role = yield {
- id: 'role',
- type: 'role',
- match: 'restContent',
- prompt: {
- start: `What role do you want to ${action}?`,
- retry: `{error} Choose a valid role to ${action}.`
- }
- };
- return { action, user, role };
- }
-
public async exec(
message: BushMessage | BushSlashMessage,
- { action, user, role }: { action: 'add' | 'remove'; user: BushGuildMember; role: BushRole }
+ { action, user, role, duration }: { action: 'add' | 'remove'; user: BushGuildMember; role: BushRole; duration: number }
): Promise<unknown> {
- if (!message.member.permissions.has('MANAGE_ROLES') && !message.author.isOwner()) {
+ if (!message.member.permissions.has('MANAGE_ROLES')) {
const mappings = this.client.consts.mappings;
let mappedRole: { name: string; id: string };
for (let i = 0; i < mappings.roleMap.length; i++) {
@@ -111,53 +119,51 @@ export default class RoleCommand extends BushCommand {
allowedMentions: AllowedMentions.none()
});
}
- } else if (!message.author.isOwner()) {
- if (role.comparePositionTo(message.member.roles.highest) >= 0) {
- return await message.util.reply({
- content: `${this.client.util.emojis.error} <@&${role.id}> is higher or equal to your highest role.`,
- allowedMentions: AllowedMentions.none()
- });
- }
- if (role.comparePositionTo(message.guild.me.roles.highest) >= 0) {
- return await message.util.reply({
- content: `${this.client.util.emojis.error} <@&${role.id}> is higher or equal to my highest role.`,
- allowedMentions: AllowedMentions.none()
- });
- }
- if (role.managed) {
- return await message.util.reply({
- content: `${this.client.util.emojis.error} <@&${role.id}> is managed by an integration and cannot be managed.`,
- allowedMentions: AllowedMentions.none()
- });
- }
}
- // no checks if the user has MANAGE_ROLES
- if (action == 'remove') {
- const success = await user.roles.remove(role.id).catch(() => {});
- if (success) {
- return await message.util.reply({
- content: `${this.client.util.emojis.success} Successfully removed <@&${role.id}> from <@${user.id}>!`,
- allowedMentions: AllowedMentions.none()
- });
- } else {
- return await message.util.reply({
- content: `${this.client.util.emojis.error} Could not remove <@&${role.id}> from <@${user.id}>.`,
- allowedMentions: AllowedMentions.none()
- });
- }
- } else if (action == 'add') {
- const success = await user.roles.add(role.id).catch(() => {});
- if (success) {
- return await message.util.reply({
- content: `${this.client.util.emojis.success} Successfully added <@&${role.id}> to <@${user.id}>!`,
- allowedMentions: AllowedMentions.none()
- });
- } else {
- return await message.util.reply({
- content: `${this.client.util.emojis.error} Could not add <@&${role.id}> to <@${user.id}>.`,
- allowedMentions: AllowedMentions.none()
- });
+
+ const shouldLog = this.punishmentRoleNames.includes(role.name);
+
+ const responseCode =
+ action === 'add'
+ ? await user.addRole({ moderator: message.member, addToModlog: shouldLog, role, duration })
+ : await user.removeRole({ moderator: message.member, addToModlog: shouldLog, role, duration });
+
+ const responseMessage = () => {
+ switch (responseCode) {
+ case 'user hierarchy':
+ return `${this.client.util.emojis.error} <@&${role.id}> is higher or equal to your highest role.`;
+ case 'role managed':
+ return `${this.client.util.emojis.error} <@&${role.id}> is managed by an integration and cannot be managed.`;
+ case 'client hierarchy':
+ return `${this.client.util.emojis.error} <@&${role.id}> is higher or equal to my highest role.`;
+ case 'error creating modlog entry':
+ return `${this.client.util.emojis.error} There was an error creating a modlog entry, please report this to my developers.`;
+ case 'error creating role entry' || 'error removing role entry':
+ return `${this.client.util.emojis.error} There was an error ${
+ action === 'add' ? 'creating' : 'removing'
+ } a punishment entry, please report this to my developers.`;
+ case 'error adding role' || 'error removing role':
+ return `${this.client.util.emojis.error} An error occurred while trying to ${action} <@&${role.id}> ${
+ action === 'add' ? 'to' : 'from'
+ } **${user.user.tag}**.`;
+ case 'success':
+ return `${this.client.util.emojis.success} Successfully ${action === 'add' ? 'added' : 'removed'} <@&${role.id}> ${
+ action === 'add' ? 'to' : 'from'
+ } **${user.user.tag}**${duration ? ` for ${this.client.util.humanizeDuration(duration)}` : ''}.`;
}
- }
+ };
+
+ await message.util.reply({ content: responseMessage(), allowedMentions: AllowedMentions.none() });
}
+
+ punishmentRoleNames = [
+ 'No Files',
+ 'No Links',
+ 'No Reactions',
+ 'No Suggestions',
+ 'No Bots',
+ 'No VC',
+ 'No Giveaways',
+ 'No Support'
+ ];
}
diff --git a/src/commands/moderation/unban.ts b/src/commands/moderation/unban.ts
index 4f52666..0de2489 100644
--- a/src/commands/moderation/unban.ts
+++ b/src/commands/moderation/unban.ts
@@ -1,4 +1,4 @@
-import { BushCommand, BushMessage, BushSlashMessage } from '@lib';
+import { AllowedMentions, BushCommand, BushMessage, BushSlashMessage } from '@lib';
import { User } from 'discord.js';
export default class UnbanCommand extends BushCommand {
@@ -55,31 +55,28 @@ export default class UnbanCommand extends BushCommand {
if (!(user instanceof User)) {
user = this.client.util.resolveUser(user, this.client.users.cache);
}
- const response = await message.guild.unban({
+ const responseCode = await message.guild.unban({
user,
moderator: message.author,
reason
});
- switch (response) {
- case 'missing permissions':
- return message.util.reply(
- `${this.client.util.emojis.error} Could not unban **${user.tag}** because I do not have permissions`
- );
- case 'error unbanning':
- return message.util.reply(`${this.client.util.emojis.error} An error occurred while trying to unban **${user.tag}**.`);
- case 'error removing ban entry':
- return message.util.reply(
- `${this.client.util.emojis.error} While unbanning **${user.tag}**, there was an error removing their ban entry, please report this to my developers.`
- );
- case 'error creating modlog entry':
- return message.util.reply(
- `${this.client.util.emojis.error} While unbanning **${user.tag}**, there was an error creating a modlog entry, please report this to my developers.`
- );
- case 'user not banned':
- return message.util.reply(`${this.client.util.emojis.warn} **${user.tag}** but I tried to unban them anyways.`);
- case 'success':
- return message.util.reply(`${this.client.util.emojis.success} Successfully unbanned **${user.tag}**.`);
- }
+ const responseMessage = () => {
+ switch (responseCode) {
+ case 'missing permissions':
+ return `${this.client.util.emojis.error} Could not unban **${user.tag}** because I do not have permissions`;
+ case 'error unbanning':
+ return `${this.client.util.emojis.error} An error occurred while trying to unban **${user.tag}**.`;
+ case 'error removing ban entry':
+ return `${this.client.util.emojis.error} While unbanning **${user.tag}**, there was an error removing their ban entry, please report this to my developers.`;
+ case 'error creating modlog entry':
+ return `${this.client.util.emojis.error} While unbanning **${user.tag}**, there was an error creating a modlog entry, please report this to my developers.`;
+ case 'user not banned':
+ return `${this.client.util.emojis.warn} **${user.tag}** but I tried to unban them anyways.`;
+ case 'success':
+ return `${this.client.util.emojis.success} Successfully unbanned **${user.tag}**.`;
+ }
+ };
+ return await message.util.reply({ content: responseMessage(), allowedMentions: AllowedMentions.none() });
}
}
diff --git a/src/commands/moderation/unmute.ts b/src/commands/moderation/unmute.ts
index 4030fb7..277ca91 100644
--- a/src/commands/moderation/unmute.ts
+++ b/src/commands/moderation/unmute.ts
@@ -1,4 +1,4 @@
-import { BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '@lib';
+import { AllowedMentions, BushCommand, BushGuildMember, BushMessage, BushSlashMessage, BushUser } from '@lib';
export default class UnmuteCommand extends BushCommand {
public constructor() {
@@ -60,50 +60,34 @@ export default class UnmuteCommand extends BushCommand {
return message.util.reply(canModerateResponse);
}
- const response = await member.unmute({
+ const responseCode = await member.unmute({
reason,
moderator: message.author
});
- switch (response) {
- case 'missing permissions':
- return message.util.reply(
- `${error} Could not unmute ${victimBoldTag} because I am missing the \`Manage Roles\` permission.`
- );
- case 'no mute role':
- return message.util.reply(
- `${error} Could not unmute ${victimBoldTag}, you must set a mute role with \`${message.guild.getSetting(
- 'prefix'
- )}muterole\`.`
- );
- case 'invalid mute role':
- return message.util.reply(
- `${error} Could not unmute ${victimBoldTag} because the current mute role no longer exists. Please set a new mute role with \`${message.guild.getSetting(
- 'prefix'
- )}muterole\`.`
- );
- case 'mute role not manageable':
- return message.util.reply(
- `${error} Could not unmute ${victimBoldTag} because I cannot assign the current mute role, either change the role's position or set a new mute role with \`${message.guild.getSetting(
- 'prefix'
- )}muterole\`.`
- );
- case 'error removing mute role':
- return message.util.reply(`${error} Could not unmute ${victimBoldTag}, there was an error removing their mute role.`);
- case 'error creating modlog entry':
- return message.util.reply(
- `${error} While muting ${victimBoldTag}, there was an error creating a modlog entry, please report this to my developers.`
- );
- case 'error removing mute entry':
- return message.util.reply(
- `${error} While muting ${victimBoldTag}, there was an error removing their mute entry, please report this to my developers.`
- );
- case 'failed to dm':
- return message.util.reply(
- `${this.client.util.emojis.warn} unmuted **${member.user.tag}** however I could not send them a dm.`
- );
- case 'success':
- return message.util.reply(`${this.client.util.emojis.success} Successfully unmuted **${member.user.tag}**.`);
- }
+ const responseMessage = () => {
+ const prefix = message.guild.getSetting('prefix');
+ switch (responseCode) {
+ case 'missing permissions':
+ return `${error} Could not unmute ${victimBoldTag} because I am missing the \`Manage Roles\` permission.`;
+ case 'no mute role':
+ return `${error} Could not unmute ${victimBoldTag}, you must set a mute role with \`${prefix}muterole\`.`;
+ case 'invalid mute role':
+ return `${error} Could not unmute ${victimBoldTag} because the current mute role no longer exists. Please set a new mute role with \`${prefix}muterole\`.`;
+ case 'mute role not manageable':
+ return `${error} Could not unmute ${victimBoldTag} because I cannot assign the current mute role, either change the role's position or set a new mute role with \`${prefix}muterole\`.`;
+ case 'error removing mute role':
+ return `${error} Could not unmute ${victimBoldTag}, there was an error removing their mute role.`;
+ case 'error creating modlog entry':
+ return `${error} While muting ${victimBoldTag}, there was an error creating a modlog entry, please report this to my developers.`;
+ case 'error removing mute entry':
+ return `${error} While muting ${victimBoldTag}, there was an error removing their mute entry, please report this to my developers.`;
+ case 'failed to dm':
+ return `${this.client.util.emojis.warn} unmuted **${member.user.tag}** however I could not send them a dm.`;
+ case 'success':
+ return `${this.client.util.emojis.success} Successfully unmuted **${member.user.tag}**.`;
+ }
+ };
+ return await message.util.reply({ content: responseMessage(), allowedMentions: AllowedMentions.none() });
}
}
diff --git a/src/lib/extensions/discord-akairo/BushClientUtil.ts b/src/lib/extensions/discord-akairo/BushClientUtil.ts
index a981d30..b3c9953 100644
--- a/src/lib/extensions/discord-akairo/BushClientUtil.ts
+++ b/src/lib/extensions/discord-akairo/BushClientUtil.ts
@@ -1,6 +1,23 @@
/* eslint-disable @typescript-eslint/no-explicit-any */
/* eslint-disable @typescript-eslint/explicit-module-boundary-types */
+import {
+ Ban,
+ BushCache,
+ BushClient,
+ BushConstants,
+ BushGuildMember,
+ BushGuildMemberResolvable,
+ BushGuildResolvable,
+ BushMessage,
+ BushSlashMessage,
+ Global,
+ Guild,
+ ModLog,
+ ModLogType,
+ Mute,
+ PunishmentRole
+} from '@lib';
import { exec } from 'child_process';
import { ClientUtil } from 'discord-akairo';
import { APIMessage } from 'discord-api-types';
@@ -26,20 +43,8 @@ import {
} from 'discord.js';
import got from 'got';
import humanizeDuration from 'humanize-duration';
+import Op from 'sequelize/types/lib/operators';
import { promisify } from 'util';
-import { Ban } from '../../models/Ban';
-import { Global } from '../../models/Global';
-import { Guild } from '../../models/Guild';
-import { ModLog, ModLogType } from '../../models/ModLog';
-import { Mute } from '../../models/Mute';
-import { PunishmentRole } from '../../models/PunishmentRole';
-import { BushCache } from '../../utils/BushCache';
-import { BushConstants } from '../../utils/BushConstants';
-import { BushGuildResolvable } from '../discord.js/BushCommandInteraction';
-import { BushGuildMember } from '../discord.js/BushGuildMember';
-import { BushMessage } from '../discord.js/BushMessage';
-import { BushClient, BushGuildMemberResolvable } from './BushClient';
-import { BushSlashMessage } from './BushSlashMessage';
interface hastebinRes {
key: string;
@@ -87,6 +92,13 @@ interface bushColors {
black: '#000000';
orange: '#E86100';
}
+
+interface punishmentModels {
+ mute: Mute;
+ ban: Ban;
+ role: PunishmentRole;
+}
+
export class BushClientUtil extends ClientUtil {
/** The client of this ClientUtil */
public declare readonly client: BushClient;
@@ -689,7 +701,23 @@ export class BushClientUtil extends ClientUtil {
return success;
}
- private findPunishmentModel(type: 'mute' | 'ban' | 'role'): typeof Mute | typeof Ban | typeof PunishmentRole {
+ public async findExpiredEntries<K extends keyof punishmentModels>(type: K): Promise<punishmentModels[K][]> {
+ const dbModel = this.findPunishmentModel(type);
+ //@ts-ignore: stfu idc
+ return await dbModel.findAll({
+ where: {
+ [Op.and]: [
+ {
+ expires: {
+ [Op.lt]: new Date() // Find all rows with an expiry date before now
+ }
+ }
+ ]
+ }
+ });
+ }
+
+ private findPunishmentModel<K extends keyof punishmentModels>(type: K): typeof Mute | typeof Ban | typeof PunishmentRole {
switch (type) {
case 'mute':
return Mute;
diff --git a/src/lib/extensions/discord.js/BushGuildMember.ts b/src/lib/extensions/discord.js/BushGuildMember.ts
index adcae69..8e1c51a 100644
--- a/src/lib/extensions/discord.js/BushGuildMember.ts
+++ b/src/lib/extensions/discord.js/BushGuildMember.ts
@@ -1,8 +1,9 @@
/* eslint-disable @typescript-eslint/no-unused-vars */
-import { GuildMember, RoleResolvable } from 'discord.js';
+import { GuildMember, Role } from 'discord.js';
import { ModLogType } from '../../models/ModLog';
import { BushClient, BushUserResolvable } from '../discord-akairo/BushClient';
import { BushGuild } from './BushGuild';
+import { BushRole } from './BushRole';
import { BushUser } from './BushUser';
interface BushPunishmentOptions {
@@ -14,17 +15,39 @@ interface BushTimedPunishmentOptions extends BushPunishmentOptions {
duration?: number;
}
-interface BushPunishmentRoleOptions extends BushTimedPunishmentOptions {
- role: RoleResolvable;
+interface AddRoleOptions {
+ moderator?: BushUserResolvable;
+ duration?: number;
+ role: BushRole | Role;
+ addToModlog: boolean;
+}
+
+interface RemoveRoleOptions {
+ moderator?: BushUserResolvable;
+ duration?: number;
+ role: BushRole | Role;
+ addToModlog: boolean;
}
type PunishmentResponse = 'success' | 'error creating modlog entry' | 'failed to dm';
type WarnResponse = PunishmentResponse;
-type PunishmentRoleResponse = PunishmentResponse;
+type AddRoleResponse =
+ | PunishmentResponse
+ | 'user hierarchy'
+ | 'role managed'
+ | 'client hierarchy'
+ | 'error creating role entry'
+ | 'error adding role';
-type RemovePunishmentRoleResponse = PunishmentResponse;
+type RemoveRoleResponse =
+ | PunishmentResponse
+ | 'user hierarchy'
+ | 'role managed'
+ | 'client hierarchy'
+ | 'error removing role entry'
+ | 'error removing role';
type MuteResponse =
| PunishmentResponse
@@ -67,7 +90,7 @@ export class BushGuildMember extends GuildMember {
{
type: ModLogType.WARN,
user: this,
- moderator: options.moderator,
+ moderator: options.moderator || this.client.user.id,
reason: options.reason,
guild: this.guild
},
@@ -89,12 +112,85 @@ export class BushGuildMember extends GuildMember {
return { result: 'success', caseNum };
}
- public punishRole(options: BushPunishmentRoleOptions): Promise<PunishmentRoleResponse> {
- throw 'not implemented';
+ public async addRole(options: AddRoleOptions): Promise<AddRoleResponse> {
+ const ifShouldAddRole = this.checkIfShouldAddRole(options.role);
+ if (ifShouldAddRole !== true) return ifShouldAddRole;
+
+ const moderator = this.client.users.cache.get(this.client.users.resolveId(options.moderator || this.client.user));
+
+ if (options.addToModlog) {
+ const { log: modlog } = await this.client.util
+ .createModLogEntry({
+ type: options.duration ? ModLogType.TEMP_PUNISHMENT_ROLE : ModLogType.PERM_PUNISHMENT_ROLE,
+ guild: this.guild,
+ moderator: moderator.id,
+ user: this,
+ reason: 'N/A'
+ })
+ .catch(() => null);
+ if (!modlog) return 'error creating modlog entry';
+
+ const punishmentEntrySuccess = await this.client.util
+ .createPunishmentEntry({
+ type: 'role',
+ user: this,
+ guild: this.guild,
+ duration: options.duration,
+ modlog: modlog.id
+ })
+ .catch(() => null);
+ if (!punishmentEntrySuccess) return 'error creating role entry';
+ }
+
+ const removeRoleSuccess = await this.roles.remove(options.role, `${moderator.tag}`);
+ if (!removeRoleSuccess) return 'error adding role';
+
+ return 'success';
+ }
+
+ public async removeRole(options: RemoveRoleOptions): Promise<RemoveRoleResponse> {
+ const ifShouldAddRole = this.checkIfShouldAddRole(options.role);
+ if (ifShouldAddRole !== true) return ifShouldAddRole;
+
+ const moderator = this.client.users.cache.get(this.client.users.resolveId(options.moderator || this.client.user));
+
+ if (options.addToModlog) {
+ const { log: modlog } = await this.client.util
+ .createModLogEntry({
+ type: ModLogType.PERM_PUNISHMENT_ROLE,
+ guild: this.guild,
+ moderator: moderator.id,
+ user: this,
+ reason: 'N/A'
+ })
+ .catch(() => null);
+ if (!modlog) return 'error creating modlog entry';
+
+ const punishmentEntrySuccess = await this.client.util
+ .removePunishmentEntry({
+ type: 'role',
+ user: this,
+ guild: this.guild
+ })
+ .catch(() => null);
+ if (!punishmentEntrySuccess) return 'error removing role entry';
+ }
+
+ const removeRoleSuccess = await this.roles.remove(options.role, `${moderator.tag}`);
+ if (!removeRoleSuccess) return 'error removing role';
+
+ return 'success';
}
- public removePunishRole(options: BushPunishmentRoleOptions): Promise<RemovePunishmentRoleResponse> {
- throw 'not implemented';
+ private checkIfShouldAddRole(role: BushRole | Role) {
+ if (this.roles.highest.position <= role.position) {
+ return `user hierarchy`;
+ } else if (role.managed) {
+ return `role managed`;
+ } else if (this.guild.me.roles.highest.position <= role.position) {
+ return `client hierarchy`;
+ }
+ return true;
}
public async mute(options: BushTimedPunishmentOptions): Promise<MuteResponse> {
@@ -115,7 +211,7 @@ export class BushGuildMember extends GuildMember {
if (!muteSuccess) return 'error giving mute role';
// add modlog entry
- const modlog = await this.client.util
+ const { log: modlog } = await this.client.util
.createModLogEntry({
type: options.duration ? ModLogType.TEMP_MUTE : ModLogType.PERM_MUTE,
user: this,
@@ -170,7 +266,7 @@ export class BushGuildMember extends GuildMember {
if (!muteSuccess) return 'error removing mute role';
//remove modlog entry
- const modlog = await this.client.util
+ const { log: modlog } = await this.client.util
.createModLogEntry({
type: ModLogType.UNMUTE,
user: this,
@@ -220,7 +316,7 @@ export class BushGuildMember extends GuildMember {
if (!kickSuccess) return 'error kicking';
// add modlog entry
- const modlog = await this.client.util
+ const { log: modlog } = await this.client.util
.createModLogEntry({
type: ModLogType.KICK,
user: this,
@@ -256,7 +352,7 @@ export class BushGuildMember extends GuildMember {
if (!banSuccess) return 'error banning';
// add modlog entry
- const modlog = await this.client.util
+ const { log: modlog } = await this.client.util
.createModLogEntry({
type: options.duration ? ModLogType.TEMP_BAN : ModLogType.PERM_BAN,
user: this,
@@ -284,11 +380,11 @@ export class BushGuildMember extends GuildMember {
return 'success';
}
- public isOwner(): boolean {
+ public get isOwner(): boolean {
return this.client.isOwner(this);
}
- public isSuperUser(): boolean {
+ public get isSuperUser(): boolean {
return this.client.isSuperUser(this);
}
}
diff --git a/src/lib/models/Ban.ts b/src/lib/models/Ban.ts
index 54ca6ae..1bdda6f 100644
--- a/src/lib/models/Ban.ts
+++ b/src/lib/models/Ban.ts
@@ -5,15 +5,15 @@ import { BaseModel } from './BaseModel';
export interface BanModel {
id: string;
- user: string;
- guild: string;
+ user: Snowflake;
+ guild: Snowflake;
expires: Date;
modlog: string;
}
export interface BanModelCreationAttributes {
id?: string;
- user: string;
- guild: string;
+ user: Snowflake;
+ guild: Snowflake;
expires?: Date;
modlog: string;
}
diff --git a/src/lib/models/Global.ts b/src/lib/models/Global.ts
index 842f14b..ba77302 100644
--- a/src/lib/models/Global.ts
+++ b/src/lib/models/Global.ts
@@ -1,5 +1,5 @@
import { Snowflake } from 'discord.js';
-import { DataTypes, Optional, Sequelize } from 'sequelize';
+import { DataTypes, Sequelize } from 'sequelize';
import { BaseModel } from './BaseModel';
export interface GlobalModel {
@@ -10,17 +10,40 @@ export interface GlobalModel {
blacklistedGuilds: Snowflake[];
blacklistedChannels: Snowflake[];
}
-export type GlobalModelCreationAttributes = Optional<
- GlobalModel,
- 'superUsers' | 'disabledCommands' | 'blacklistedUsers' | 'blacklistedGuilds' | 'blacklistedChannels'
->;
+
+export interface GlobalModelCreationAttributes {
+ environment: 'production' | 'development';
+ superUsers?: Snowflake[];
+ disabledCommands?: string[];
+ blacklistedUsers?: Snowflake[];
+ blacklistedGuilds?: Snowflake[];
+ blacklistedChannels?: Snowflake[];
+}
export class Global extends BaseModel<GlobalModel, GlobalModelCreationAttributes> implements GlobalModel {
+ /**
+ * The bot's environment.
+ */
environment: 'production' | 'development';
+ /**
+ * Trusted users.
+ */
superUsers: Snowflake[];
+ /**
+ * Globally disabled commands.
+ */
disabledCommands: string[];
+ /**
+ * Globally blacklisted users.
+ */
blacklistedUsers: Snowflake[];
+ /**
+ * Guilds blacklisted from using the bot.
+ */
blacklistedGuilds: Snowflake[];
+ /**
+ * Channels where the bot is prevented from running.
+ */
blacklistedChannels: Snowflake[];
static initModel(sequelize: Sequelize): void {
Global.init(
diff --git a/src/lib/models/Guild.ts b/src/lib/models/Guild.ts
index 0fc3413..f6aa1a4 100644
--- a/src/lib/models/Guild.ts
+++ b/src/lib/models/Guild.ts
@@ -1,5 +1,5 @@
import { Snowflake } from 'discord.js';
-import { DataTypes, Optional, Sequelize } from 'sequelize';
+import { DataTypes, Sequelize } from 'sequelize';
import { BushClient } from '../extensions/discord-akairo/BushClient';
import { BaseModel } from './BaseModel';
@@ -13,14 +13,23 @@ export interface GuildModel {
punishmentEnding: string;
}
-export type GuildModelCreationAttributes = Optional<
- GuildModel,
- 'prefix' | 'autoPublishChannels' | 'blacklistedChannels' | 'welcomeChannel' | 'muteRole' | 'punishmentEnding'
->;
+// export type GuildModelCreationAttributes = Optional<
+// GuildModel,
+// 'prefix' | 'autoPublishChannels' | 'blacklistedChannels' | 'welcomeChannel' | 'muteRole' | 'punishmentEnding'
+// >;
+export interface GuildModelCreationAttributes {
+ id: string;
+ prefix?: string;
+ autoPublishChannels?: Snowflake[];
+ blacklistedChannels?: Snowflake[];
+ welcomeChannel?: Snowflake;
+ muteRole?: Snowflake;
+ punishmentEnding?: string;
+}
export class Guild extends BaseModel<GuildModel, GuildModelCreationAttributes> implements GuildModel {
- id: string;
- prefix: string;
+ id!: string;
+ prefix!: string;
autoPublishChannels: string[];
blacklistedChannels: Snowflake[];
welcomeChannel: Snowflake;
diff --git a/src/lib/models/Level.ts b/src/lib/models/Level.ts
index e1f30f4..b834992 100644
--- a/src/lib/models/Level.ts
+++ b/src/lib/models/Level.ts
@@ -1,18 +1,25 @@
+import { Snowflake } from 'discord.js';
import { DataTypes, Sequelize } from 'sequelize';
import { BaseModel } from './BaseModel';
export interface LevelModel {
- id: string;
+ id: Snowflake;
xp: number;
}
export interface LevelModelCreationAttributes {
- id: string;
+ id: Snowflake;
xp?: number;
}
export class Level extends BaseModel<LevelModel, LevelModelCreationAttributes> {
- public id: string;
+ /**
+ * The user's id.
+ */
+ public id: Snowflake;
+ /**
+ * The user's xp.
+ */
public xp: number;
get level(): number {
return Level.convertXpToLevel(this.xp);
diff --git a/src/lib/models/ModLog.ts b/src/lib/models/ModLog.ts
index 6261794..40dc86d 100644
--- a/src/lib/models/ModLog.ts
+++ b/src/lib/models/ModLog.ts
@@ -38,12 +38,33 @@ export interface ModLogModelCreationAttributes {
}
export class ModLog extends BaseModel<ModLogModel, ModLogModelCreationAttributes> implements ModLogModel {
+ /**
+ * The primary key of the modlog entry.
+ */
id: string;
+ /**
+ * The type of punishment.
+ */
type: ModLogType;
+ /**
+ * The user being punished.
+ */
user: Snowflake;
+ /**
+ * The user carrying out the punishment.
+ */
moderator: Snowflake;
+ /**
+ * The reason the user is getting punished
+ */
reason: string | null;
+ /**
+ * The amount of time the user is getting punished for.
+ */
duration: number | null;
+ /**
+ * The guild the user is getting punished in.
+ */
guild: Snowflake;
static initModel(sequelize: Sequelize): void {
diff --git a/src/lib/models/Mute.ts b/src/lib/models/Mute.ts
index 71a32e3..4208d02 100644
--- a/src/lib/models/Mute.ts
+++ b/src/lib/models/Mute.ts
@@ -5,15 +5,15 @@ import { BaseModel } from './BaseModel';
export interface MuteModel {
id: string;
- user: string;
- guild: string;
+ user: Snowflake;
+ guild: Snowflake;
expires: Date;
modlog: string;
}
export interface MuteModelCreationAttributes {
id?: string;
- user: string;
- guild: string;
+ user: Snowflake;
+ guild: Snowflake;
expires?: Date;
modlog: string;
}
diff --git a/src/lib/models/PunishmentRole.ts b/src/lib/models/PunishmentRole.ts
index 927cf28..0b54f31 100644
--- a/src/lib/models/PunishmentRole.ts
+++ b/src/lib/models/PunishmentRole.ts
@@ -5,15 +5,17 @@ import { BaseModel } from './BaseModel';
export interface PunishmentRoleModel {
id: string;
- user: string;
- guild: string;
+ user: Snowflake;
+ role: Snowflake;
+ guild: Snowflake;
expires: Date;
modlog: string;
}
export interface PunishmentRoleModelCreationAttributes {
id?: string;
- user: string;
- guild: string;
+ user: Snowflake;
+ role?: Snowflake;
+ guild: Snowflake;
expires?: Date;
modlog: string;
}
@@ -31,6 +33,10 @@ export class PunishmentRole
*/
user: Snowflake;
/**
+ * The role added to the user.
+ */
+ role: Snowflake;
+ /**
* The guild they received a role in
*/
guild: Snowflake;
@@ -56,6 +62,10 @@ export class PunishmentRole
type: DataTypes.STRING,
allowNull: false
},
+ role: {
+ type: DataTypes.STRING,
+ allowNull: false
+ },
guild: {
type: DataTypes.STRING,
allowNull: false,
diff --git a/src/tasks/removePunishmentRole.ts b/src/tasks/removePunishmentRole.ts
index e69de29..d957238 100644
--- a/src/tasks/removePunishmentRole.ts
+++ b/src/tasks/removePunishmentRole.ts
@@ -0,0 +1,32 @@
+import { BushGuildMember, BushTask } from '@lib';
+
+export default class RemovePunishmentRole extends BushTask {
+ public constructor() {
+ super('removePunishmentRole', {
+ delay: 30_000, // 1/2 min
+ runOnStart: true
+ });
+ }
+ async exec(): Promise<void> {
+ const expiredEntries = await this.client.util.findExpiredEntries('role');
+ this.client.logger.verbose(
+ `RemovePunishmentRoleTask`,
+ `Queried punishment roles, found <<${expiredEntries.length}>> expired punishment roles.`
+ );
+
+ for (const entry of expiredEntries) {
+ const guild = this.client.guilds.cache.get(entry.guild);
+ if (!guild) {
+ await entry.destroy();
+ continue;
+ }
+
+ const member = guild.members.cache.get(entry.user) as BushGuildMember;
+ const result = await member.removePunishRole({ reason: 'Punishment expired.', role: entry.role });
+ if (['success', 'failed to dm'].includes(result)) await entry.destroy();
+ else throw result;
+
+ this.client.logger.verbose(`RemovePunishmentRoleTask`, `Removed a punishment role from ${entry.user}.`);
+ }
+ }
+}
diff --git a/src/tasks/unban.ts b/src/tasks/unban.ts
index f5d6b53..136e6c2 100644
--- a/src/tasks/unban.ts
+++ b/src/tasks/unban.ts
@@ -1,6 +1,4 @@
-import { Ban, BushTask } from '@lib';
-import { DiscordAPIError } from 'discord.js';
-import { Op } from 'sequelize';
+import { BushGuild, BushTask } from '@lib';
export default class UnbanTask extends BushTask {
public constructor() {
@@ -10,32 +8,19 @@ export default class UnbanTask extends BushTask {
});
}
async exec(): Promise<void> {
- const rows = await Ban.findAll({
- where: {
- [Op.and]: [
- {
- expires: {
- [Op.lt]: new Date() // Find all rows with an expiry date before now
- }
- }
- ]
- }
- });
+ const rows = await this.client.util.findExpiredEntries('mute');
this.client.logger.verbose(`UnbanTask`, `Queried bans, found <<${rows.length}>> expired bans.`);
+
for (const row of rows) {
- const guild = this.client.guilds.cache.get(row.guild);
+ const guild = this.client.guilds.cache.get(row.guild) as BushGuild;
if (!guild) {
await row.destroy();
continue;
}
- try {
- await guild.members.unban(row.user, `Unbanning user because tempban expired`);
- } catch (e) {
- if (e instanceof DiscordAPIError) {
- // Member not banned, ignore
- } else throw e;
- }
- await row.destroy();
+
+ const result = await guild.unban({ user: row.user, reason: 'Punishment expired.' });
+ if (['success', 'user not banned'].includes(result)) await row.destroy();
+ else throw result;
this.client.logger.verbose(`UnbanTask`, `Unbanned ${row.user}`);
}
}
diff --git a/src/tasks/unmute.ts b/src/tasks/unmute.ts
index 7a04360..c61c6e9 100644
--- a/src/tasks/unmute.ts
+++ b/src/tasks/unmute.ts
@@ -1,5 +1,4 @@
-import { BushTask, Guild, Mute } from '@lib';
-import { DiscordAPIError } from 'discord.js';
+import { BushGuildMember, BushTask, Mute } from '@lib';
import { Op } from 'sequelize';
export default class UnmuteTask extends BushTask {
@@ -24,19 +23,16 @@ export default class UnmuteTask extends BushTask {
this.client.logger.verbose(`UnmuteTask`, `Queried mutes, found <<${rows.length}>> expired mutes.`);
for (const row of rows) {
const guild = this.client.guilds.cache.get(row.guild);
- const muteRole = (await Guild.findByPk(row.guild))?.muteRole;
if (!guild) {
await row.destroy();
continue;
}
- try {
- await (await guild.members.fetch(row.user)).roles.remove(muteRole);
- } catch (e) {
- if (e instanceof DiscordAPIError) {
- // ignore
- } else throw e;
- }
- await row.destroy();
+
+ const member = guild.members.cache.get(row.user) as BushGuildMember;
+ const result = await member.unmute({ reason: 'Punishment expired.' });
+ if (['success', 'failed to dm'].includes(result)) await row.destroy();
+ else throw result;
+
this.client.logger.verbose(`UnmuteTask`, `Unmuted ${row.user}`);
}
}