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

@@ -13,7 +13,13 @@ import { completeVerification } from './modules/verification/handlers.js';
import { closePoll } from './modules/utility/poll.js';
import { sendReminder } from './modules/utility/reminders.js';
import { expireSelfRole } from './modules/selfroles/service.js';
import { endGiveaway, runGiveawayCreateJob, GiveawayError } from './modules/giveaways/index.js';
import {
endGiveaway,
runGiveawayCreateJob,
runGiveawayPauseJob,
runGiveawayDeleteJob,
GiveawayError
} from './modules/giveaways/index.js';
import { closeInactiveTickets } from './modules/tickets/index.js';
import { expireBirthdayRole, runBirthdayCheck } from './modules/birthdays/index.js';
import { ensureStatsRecurringJobs, startStatsWorker } from './modules/stats/index.js';
@@ -87,6 +93,8 @@ type SelfRoleExpireJob = {
type GiveawayEndJob = {
giveawayId: string;
/** When true, end even if the giveaway is paused (dashboard/slash paths). */
force?: boolean;
};
type GiveawayCreateJob = {
@@ -101,6 +109,15 @@ type GiveawayCreateJob = {
requiredMemberDays?: number | null;
};
type GiveawayPauseJob = {
giveawayId: string;
paused: boolean;
};
type GiveawayDeleteJob = {
giveawayId: string;
};
type BirthdayRoleExpireJob = {
guildId: string;
@@ -299,12 +316,24 @@ export function startWorkers(context: BotContext): Worker[] {
logger.error({ jobId: job?.id, error }, 'Ticket queue job failed');
});
const giveawayWorker = new Worker<GiveawayEndJob | GiveawayCreateJob>(
const giveawayWorker = new Worker<
GiveawayEndJob | GiveawayCreateJob | GiveawayPauseJob | GiveawayDeleteJob
>(
giveawayQueueName,
async (job) => {
if (job.name === 'giveawayEnd') {
try {
await endGiveaway(context, (job.data as GiveawayEndJob).giveawayId);
const data = job.data as GiveawayEndJob;
if (!data.force) {
const current = await context.prisma.giveaway.findUnique({
where: { id: data.giveawayId }
});
// Timer/recover must not end a paused giveaway.
if (current?.paused) {
return;
}
}
await endGiveaway(context, data.giveawayId);
} catch (error) {
if (
error instanceof GiveawayError &&
@@ -319,6 +348,13 @@ export function startWorkers(context: BotContext): Worker[] {
if (job.name === 'giveawayCreate') {
return runGiveawayCreateJob(context, job.data as GiveawayCreateJob);
}
if (job.name === 'giveawayPause') {
const data = job.data as GiveawayPauseJob;
return runGiveawayPauseJob(context, data.giveawayId, data.paused);
}
if (job.name === 'giveawayDelete') {
await runGiveawayDeleteJob(context, (job.data as GiveawayDeleteJob).giveawayId);
}
},
{ connection: redis }
);