Implement command cooldown management and enhance command execution flow

- Introduced `applyCommandCooldown` function to manage per-command cooldowns after execution, improving command rate limiting.
- Updated command execution flow to include cooldown application, ensuring users are informed of cooldown status.
- Enhanced error handling in interaction replies, allowing for more graceful error management and user feedback.
- Improved the handling of interaction responses across various commands, ensuring consistent user experience.
- Added permission checks for new commands, ensuring only authorized users can execute specific actions.
This commit is contained in:
TheOnlyMace
2026-07-25 15:37:56 +02:00
parent 57cdf847f5
commit 8513848440
42 changed files with 856 additions and 160 deletions

View File

@@ -53,6 +53,8 @@ export async function executeBan(
}
}
await interaction.deferUpdate();
await guild.members.ban(payload.userId, { reason: payload.reason });
const modCase = await createCase(context, {
guildId: guild.id,
@@ -73,7 +75,7 @@ export async function executeBan(
await scheduleTempBanExpire(guild.id, payload.userId, durationMs, payload.reason);
}
await interaction.update({
await interaction.editReply({
content: tf(locale, 'moderation.success.case', { caseNumber: modCase.caseNumber }),
components: []
});
@@ -91,6 +93,8 @@ export async function executePurge(
return;
}
await interaction.deferUpdate();
const channel = await guild.channels.fetch(payload.channelId);
let deletedCount = 0;
const regex = payload.regex ? new RegExp(payload.regex, 'i') : null;
@@ -134,7 +138,7 @@ export async function executePurge(
}
});
await interaction.update({
await interaction.editReply({
content: tf(locale, 'moderation.purge.done', {
deletedCount,
caseNumber: modCase.caseNumber

View File

@@ -48,7 +48,7 @@ async function ensureMod(
await interaction.reply({ content: t(locale, 'generic.guildOnly'), ephemeral: true });
return false;
}
return requirePermission(interaction, permission, locale);
return requirePermission(interaction, permission, locale, { botPermissions: permission });
}
async function replySuccessCase(
@@ -56,8 +56,13 @@ async function replySuccessCase(
locale: 'de' | 'en',
caseNumber: number
): Promise<void> {
const content = tf(locale, 'moderation.success.case', { caseNumber });
if (interaction.deferred || interaction.replied) {
await interaction.editReply({ content });
return;
}
await interaction.reply({
content: tf(locale, 'moderation.success.case', { caseNumber }),
content,
ephemeral: true
});
}
@@ -460,6 +465,7 @@ const lockCommand: SlashCommand = {
const guild = interaction.guild!;
if (serverWide) {
await interaction.deferReply({ ephemeral: true });
for (const channel of guild.channels.cache.values()) {
if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement) {
continue;
@@ -495,6 +501,7 @@ const unlockCommand: SlashCommand = {
const guild = interaction.guild!;
if (serverWide) {
await interaction.deferReply({ ephemeral: true });
for (const channel of guild.channels.cache.values()) {
if (channel.type !== ChannelType.GuildText && channel.type !== ChannelType.GuildAnnouncement) {
continue;

View File

@@ -1,8 +1,9 @@
import { moderationQueue } from '../../queues.js';
import type { BotContext } from '../../types.js';
import { PermissionFlagsBits, type ChatInputCommandInteraction } from 'discord.js';
import type { Prisma } from '@prisma/client';
import { buildCaseMetadata, type CaseAuditSource, t, type Locale } from '@nexumi/shared';
import { safeRemoveBullJob } from '../../lib/safe-remove-job.js';
import { moderationQueue } from '../../queues.js';
import type { BotContext } from '../../types.js';
import { MAX_TIMEOUT_MS } from './duration.js';
type CreateCaseInput = {
@@ -96,9 +97,7 @@ export async function scheduleTempBanExpire(
) {
const jobId = tempBanJobId(guildId, userId);
const existing = await moderationQueue.getJob(jobId);
if (existing) {
await existing.remove();
}
await safeRemoveBullJob(existing, { label: 'tempBanExpire', jobId });
await moderationQueue.add(
'tempBanExpire',