Implement self-role panel management with BullMQ integration

- Introduced a new `selfroles` queue to handle self-role panel creation, updates, and deletions via BullMQ jobs.
- Added types for self-role panel jobs, enhancing type safety and clarity in job handling.
- Implemented functions to create, update, and delete self-role panels, ensuring synchronization between the WebUI and Discord.
- Enhanced error handling for self-role panel operations, providing better feedback in case of failures.
- Updated the WebUI API to support self-role panel management, including error responses for synchronization issues.
This commit is contained in:
TheOnlyMace
2026-07-25 15:43:55 +02:00
parent 8513848440
commit ba2d144038
9 changed files with 423 additions and 67 deletions

View File

@@ -12,7 +12,13 @@ import { activateLockdown, deactivateLockdown } from './modules/automod/actions.
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 {
expireSelfRole,
runSelfRolePanelCreateJob,
runSelfRolePanelUpdateJob,
runSelfRolePanelDeleteJob
} from './modules/selfroles/index.js';
import type { SelfRoleBehavior, SelfRoleEntry, SelfRoleMode } from '@nexumi/shared';
import {
endGiveaway,
runGiveawayCreateJob,
@@ -48,6 +54,7 @@ import {
retentionQueue,
retentionQueueName,
scheduleQueueName,
selfrolesQueueName,
suggestionsQueueName,
ticketQueue,
ticketQueueName,
@@ -132,6 +139,36 @@ type SuggestionStatusUpdateJob = {
reason: string;
};
type SelfRolePanelCreateJob = {
guildId: string;
channelId: string;
title: string;
description?: string | null;
mode: SelfRoleMode;
behavior: SelfRoleBehavior;
roles: SelfRoleEntry[];
temporaryDurationMs?: number;
expiresAt?: string | null;
};
type SelfRolePanelUpdateJob = {
panelId: string;
guildId: string;
channelId?: string;
title?: string;
description?: string | null;
mode?: SelfRoleMode;
behavior?: SelfRoleBehavior;
roles?: SelfRoleEntry[];
temporaryDurationMs?: number;
expiresAt?: string | null;
};
type SelfRolePanelDeleteJob = {
panelId: string;
guildId: string;
};
export function startWorkers(context: BotContext): Worker[] {
const moderationWorker = new Worker<TempBanJob>(
moderationQueueName,
@@ -316,6 +353,29 @@ export function startWorkers(context: BotContext): Worker[] {
logger.error({ jobId: job?.id, error }, 'Ticket queue job failed');
});
const selfrolesWorker = new Worker<
SelfRolePanelCreateJob | SelfRolePanelUpdateJob | SelfRolePanelDeleteJob
>(
selfrolesQueueName,
async (job) => {
if (job.name === 'selfRolePanelCreate') {
return runSelfRolePanelCreateJob(context, job.data as SelfRolePanelCreateJob);
}
if (job.name === 'selfRolePanelUpdate') {
return runSelfRolePanelUpdateJob(context, job.data as SelfRolePanelUpdateJob);
}
if (job.name === 'selfRolePanelDelete') {
const data = job.data as SelfRolePanelDeleteJob;
await runSelfRolePanelDeleteJob(context, data.panelId, data.guildId);
}
},
{ connection: redis }
);
selfrolesWorker.on('failed', (job, error) => {
logger.error({ jobId: job?.id, error }, 'Self-roles queue job failed');
});
const giveawayWorker = new Worker<
GiveawayEndJob | GiveawayCreateJob | GiveawayPauseJob | GiveawayDeleteJob
>(
@@ -489,6 +549,7 @@ export function startWorkers(context: BotContext): Worker[] {
verificationWorker,
reminderWorker,
ticketWorker,
selfrolesWorker,
giveawayWorker,
birthdayWorker,
statsWorker,