mirror of
https://github.com/ahmadk953/poixpixel-discord-bot.git
synced 2025-05-10 10:43:06 +00:00
feat: add kick, mute, and unmute commands
This commit is contained in:
parent
49d274f2be
commit
20af09b279
8 changed files with 395 additions and 7 deletions
88
src/commands/moderation/kick.ts
Normal file
88
src/commands/moderation/kick.ts
Normal file
|
@ -0,0 +1,88 @@
|
|||
import { PermissionsBitField, SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
import { updateMemberModerationHistory } from '@/db/db.js';
|
||||
import { OptionsCommand } from '@/types/CommandTypes.js';
|
||||
import logAction from '@/util/logging/logAction.js';
|
||||
|
||||
const command: OptionsCommand = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('kick')
|
||||
.setDescription('Kick a member from the server')
|
||||
.addUserOption((option) =>
|
||||
option
|
||||
.setName('member')
|
||||
.setDescription('The member to kick')
|
||||
.setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('reason')
|
||||
.setDescription('The reason for the kick')
|
||||
.setRequired(true),
|
||||
),
|
||||
execute: async (interaction) => {
|
||||
const moderator = await interaction.guild?.members.fetch(
|
||||
interaction.user.id,
|
||||
);
|
||||
const member = await interaction.guild?.members.fetch(
|
||||
interaction.options.get('member')!.value as string,
|
||||
);
|
||||
const reason = interaction.options.get('reason')?.value as string;
|
||||
|
||||
if (
|
||||
!interaction.memberPermissions?.has(
|
||||
PermissionsBitField.Flags.KickMembers,
|
||||
) ||
|
||||
moderator!.roles.highest.position <= member!.roles.highest.position ||
|
||||
!member?.kickable
|
||||
) {
|
||||
await interaction.reply({
|
||||
content:
|
||||
'You do not have permission to kick members or this member cannot be kicked.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
try {
|
||||
await member.user.send(
|
||||
`You have been kicked from ${interaction.guild!.name}. Reason: ${reason}. You can join back at: \nhttps://discord.gg/KRTGjxx7gY`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Failed to send DM to kicked user:', error);
|
||||
}
|
||||
|
||||
await member.kick(reason);
|
||||
|
||||
await updateMemberModerationHistory({
|
||||
discordId: member.id,
|
||||
moderatorDiscordId: interaction.user.id,
|
||||
action: 'kick',
|
||||
reason,
|
||||
duration: '',
|
||||
createdAt: new Date(),
|
||||
});
|
||||
|
||||
await logAction({
|
||||
guild: interaction.guild!,
|
||||
action: 'kick',
|
||||
target: member,
|
||||
moderator: moderator!,
|
||||
reason,
|
||||
});
|
||||
|
||||
await interaction.reply({
|
||||
content: `<@${member.id}> has been kicked. Reason: ${reason}`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Kick command error:', error);
|
||||
await interaction.reply({
|
||||
content: 'Unable to kick member.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
115
src/commands/moderation/mute.ts
Normal file
115
src/commands/moderation/mute.ts
Normal file
|
@ -0,0 +1,115 @@
|
|||
import { PermissionsBitField, SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
import { updateMember, updateMemberModerationHistory } from '@/db/db.js';
|
||||
import { parseDuration } from '@/util/helpers.js';
|
||||
import { OptionsCommand } from '@/types/CommandTypes.js';
|
||||
import logAction from '@/util/logging/logAction.js';
|
||||
|
||||
const command: OptionsCommand = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('mute')
|
||||
.setDescription('Timeout a member in the server')
|
||||
.addUserOption((option) =>
|
||||
option
|
||||
.setName('member')
|
||||
.setDescription('The member to timeout')
|
||||
.setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('reason')
|
||||
.setDescription('The reason for the timeout')
|
||||
.setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('duration')
|
||||
.setDescription(
|
||||
'The duration of the timeout (ex. 5m, 1h, 1d, 1w). Max 28 days.',
|
||||
)
|
||||
.setRequired(true),
|
||||
),
|
||||
execute: async (interaction) => {
|
||||
const moderator = await interaction.guild?.members.fetch(
|
||||
interaction.user.id,
|
||||
);
|
||||
const member = await interaction.guild?.members.fetch(
|
||||
interaction.options.get('member')!.value as string,
|
||||
);
|
||||
const reason = interaction.options.get('reason')?.value as string;
|
||||
const muteDuration = interaction.options.get('duration')?.value as string;
|
||||
|
||||
if (
|
||||
!interaction.memberPermissions?.has(
|
||||
PermissionsBitField.Flags.ModerateMembers,
|
||||
) ||
|
||||
moderator!.roles.highest.position <= member!.roles.highest.position ||
|
||||
!member?.moderatable
|
||||
) {
|
||||
await interaction.reply({
|
||||
content:
|
||||
'You do not have permission to timeout members or this member cannot be timed out.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
const durationMs = parseDuration(muteDuration);
|
||||
const maxTimeout = 28 * 24 * 60 * 60 * 1000;
|
||||
|
||||
if (durationMs > maxTimeout) {
|
||||
await interaction.reply({
|
||||
content: 'Timeout duration cannot exceed 28 days.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
await member.user.send(
|
||||
`You have been timed out in ${interaction.guild!.name} for ${muteDuration}. Reason: ${reason}.`,
|
||||
);
|
||||
|
||||
await member.timeout(durationMs, reason);
|
||||
|
||||
const expiresAt = new Date(Date.now() + durationMs);
|
||||
|
||||
await updateMemberModerationHistory({
|
||||
discordId: member.id,
|
||||
moderatorDiscordId: interaction.user.id,
|
||||
action: 'mute',
|
||||
reason,
|
||||
duration: muteDuration,
|
||||
createdAt: new Date(),
|
||||
expiresAt,
|
||||
active: true,
|
||||
});
|
||||
|
||||
await updateMember({
|
||||
discordId: member.id,
|
||||
currentlyMuted: true,
|
||||
});
|
||||
|
||||
await logAction({
|
||||
guild: interaction.guild!,
|
||||
action: 'mute',
|
||||
target: member,
|
||||
moderator: moderator!,
|
||||
reason,
|
||||
duration: muteDuration,
|
||||
});
|
||||
|
||||
await interaction.reply({
|
||||
content: `<@${member.id}> has been timed out for ${muteDuration}. Reason: ${reason}`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Mute command error:', error);
|
||||
await interaction.reply({
|
||||
content: 'Unable to timeout member.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
65
src/commands/moderation/unmute.ts
Normal file
65
src/commands/moderation/unmute.ts
Normal file
|
@ -0,0 +1,65 @@
|
|||
import { PermissionsBitField, SlashCommandBuilder } from 'discord.js';
|
||||
|
||||
import { executeUnmute } from '@/util/helpers.js';
|
||||
import { OptionsCommand } from '@/types/CommandTypes.js';
|
||||
|
||||
const command: OptionsCommand = {
|
||||
data: new SlashCommandBuilder()
|
||||
.setName('unmute')
|
||||
.setDescription('Remove a timeout from a member')
|
||||
.addUserOption((option) =>
|
||||
option
|
||||
.setName('member')
|
||||
.setDescription('The member to unmute')
|
||||
.setRequired(true),
|
||||
)
|
||||
.addStringOption((option) =>
|
||||
option
|
||||
.setName('reason')
|
||||
.setDescription('The reason for removing the timeout')
|
||||
.setRequired(true),
|
||||
),
|
||||
execute: async (interaction) => {
|
||||
const moderator = await interaction.guild?.members.fetch(
|
||||
interaction.user.id,
|
||||
);
|
||||
const member = await interaction.guild?.members.fetch(
|
||||
interaction.options.get('member')!.value as string,
|
||||
);
|
||||
const reason = interaction.options.get('reason')?.value as string;
|
||||
|
||||
if (
|
||||
!interaction.memberPermissions?.has(
|
||||
PermissionsBitField.Flags.ModerateMembers,
|
||||
)
|
||||
) {
|
||||
await interaction.reply({
|
||||
content: 'You do not have permission to unmute members.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
await executeUnmute(
|
||||
interaction.client,
|
||||
interaction.guild!.id,
|
||||
member!.id,
|
||||
reason,
|
||||
moderator,
|
||||
);
|
||||
|
||||
await interaction.reply({
|
||||
content: `<@${member!.id}>'s timeout has been removed. Reason: ${reason}`,
|
||||
});
|
||||
} catch (error) {
|
||||
console.error('Unmute command error:', error);
|
||||
await interaction.reply({
|
||||
content: 'Unable to unmute member.',
|
||||
flags: ['Ephemeral'],
|
||||
});
|
||||
}
|
||||
},
|
||||
};
|
||||
|
||||
export default command;
|
|
@ -54,9 +54,6 @@ const command: OptionsCommand = {
|
|||
await member!.user.send(
|
||||
`You have been warned in **${interaction?.guild?.name}**. Reason: **${reason}**.`,
|
||||
);
|
||||
await interaction.reply(
|
||||
`<@${member!.user.id}> has been warned. Reason: ${reason}`,
|
||||
);
|
||||
await logAction({
|
||||
guild: interaction.guild!,
|
||||
action: 'warn',
|
||||
|
@ -64,6 +61,9 @@ const command: OptionsCommand = {
|
|||
moderator: moderator!,
|
||||
reason: reason,
|
||||
});
|
||||
await interaction.reply(
|
||||
`<@${member!.user.id}> has been warned. Reason: ${reason}`,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
await interaction.reply({
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue