Introduce several new slash commands including ban, kick, timeout, and userinfo. Enhance existing commands like config and rank with new features and configurations. Add new listeners for welcome and goodbye messages. Implement XP tracking for user leveling and integrate it with role rewards. Update documentation to reflect these changes. Replit-Commit-Author: Agent Replit-Commit-Session-Id: aed2e46d-25bb-4b73-81a1-bb9e8437c261 Replit-Commit-Checkpoint-Type: intermediate_checkpoint Replit-Commit-Event-Id: 1be8d824-5029-4875-bed8-0bd1d810892d Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/3bdfff67-975a-46ad-9845-fbb6b4a4c4b5/aed2e46d-25bb-4b73-81a1-bb9e8437c261/SQxsvtx Replit-Helium-Checkpoint-Created: true
105 lines
3.4 KiB
JavaScript
105 lines
3.4 KiB
JavaScript
const { SlashCommandBuilder, EmbedBuilder, PermissionFlagsBits } = require('discord.js');
|
|
|
|
module.exports = {
|
|
data: new SlashCommandBuilder()
|
|
.setName('timeout')
|
|
.setDescription('Timeout a user')
|
|
.setDefaultMemberPermissions(PermissionFlagsBits.ModerateMembers)
|
|
.addUserOption(option =>
|
|
option.setName('user')
|
|
.setDescription('User to timeout')
|
|
.setRequired(true)
|
|
)
|
|
.addIntegerOption(option =>
|
|
option.setName('duration')
|
|
.setDescription('Duration in minutes')
|
|
.setRequired(true)
|
|
.setMinValue(1)
|
|
.setMaxValue(40320)
|
|
)
|
|
.addStringOption(option =>
|
|
option.setName('reason')
|
|
.setDescription('Reason for timeout')
|
|
.setRequired(false)
|
|
.setMaxLength(500)
|
|
),
|
|
|
|
async execute(interaction, supabase, client) {
|
|
const target = interaction.options.getUser('user');
|
|
const duration = interaction.options.getInteger('duration');
|
|
const reason = interaction.options.getString('reason') || 'No reason provided';
|
|
const moderator = interaction.user;
|
|
|
|
const member = await interaction.guild.members.fetch(target.id).catch(() => null);
|
|
|
|
if (!member) {
|
|
return interaction.reply({ content: 'User not found in this server.', ephemeral: true });
|
|
}
|
|
|
|
if (!member.moderatable) {
|
|
return interaction.reply({ content: 'I cannot timeout this user. They may have higher permissions.', ephemeral: true });
|
|
}
|
|
|
|
if (target.id === interaction.user.id) {
|
|
return interaction.reply({ content: 'You cannot timeout yourself.', ephemeral: true });
|
|
}
|
|
|
|
const durationMs = duration * 60 * 1000;
|
|
const endsAt = new Date(Date.now() + durationMs);
|
|
|
|
try {
|
|
await member.timeout(durationMs, `${reason} | By ${moderator.tag}`);
|
|
|
|
if (supabase) {
|
|
try {
|
|
await supabase.from('mod_actions').insert({
|
|
guild_id: interaction.guildId,
|
|
action: 'timeout',
|
|
user_id: target.id,
|
|
user_tag: target.tag,
|
|
moderator_id: moderator.id,
|
|
moderator_tag: moderator.tag,
|
|
reason: reason,
|
|
duration_minutes: duration,
|
|
});
|
|
} catch (e) {
|
|
console.warn('Failed to log timeout:', e.message);
|
|
}
|
|
}
|
|
|
|
const embed = new EmbedBuilder()
|
|
.setColor(0xfbbf24)
|
|
.setTitle('User Timed Out')
|
|
.setThumbnail(target.displayAvatarURL())
|
|
.addFields(
|
|
{ name: 'User', value: `${target.tag} (${target.id})`, inline: true },
|
|
{ name: 'Moderator', value: moderator.tag, inline: true },
|
|
{ name: 'Duration', value: `${duration} minutes`, inline: true },
|
|
{ name: 'Ends', value: `<t:${Math.floor(endsAt.getTime() / 1000)}:R>`, inline: true },
|
|
{ name: 'Reason', value: reason }
|
|
)
|
|
.setTimestamp();
|
|
|
|
await interaction.reply({ embeds: [embed] });
|
|
|
|
try {
|
|
await target.send({
|
|
embeds: [
|
|
new EmbedBuilder()
|
|
.setColor(0xfbbf24)
|
|
.setTitle(`Timed out in ${interaction.guild.name}`)
|
|
.addFields(
|
|
{ name: 'Duration', value: `${duration} minutes` },
|
|
{ name: 'Reason', value: reason }
|
|
)
|
|
.setTimestamp()
|
|
]
|
|
});
|
|
} catch (e) {}
|
|
|
|
} catch (error) {
|
|
console.error('Timeout error:', error);
|
|
await interaction.reply({ content: 'Failed to timeout user.', ephemeral: true });
|
|
}
|
|
},
|
|
};
|