Add suggestion status update job and queue integration

- Introduced a new `SuggestionStatusUpdateJob` type and corresponding worker to handle suggestion status updates in the bot's job processing.
- Added `suggestionsQueue` and `suggestionsQueueEvents` for managing suggestion-related jobs in both the bot and WebUI.
- Implemented `runSuggestionStatusUpdateJob` to facilitate staff actions on suggestions via the WebUI, ensuring consistent behavior with existing commands.
- Enhanced error handling for suggestion actions to improve user experience and reliability.
This commit is contained in:
smueller
2026-07-22 15:39:31 +02:00
parent 0ac69ee840
commit 47b6cfabbc
16 changed files with 773 additions and 23 deletions

View File

@@ -7,6 +7,13 @@ import type {
} from '@nexumi/shared';
import type { Suggestion } from '@prisma/client';
import { prisma } from '../prisma';
import { addJobAndAwait, suggestionsQueue, suggestionsQueueEvents } from '../queues';
export class SuggestionActionTimeoutError extends Error {
constructor() {
super('The bot did not confirm the suggestion update in time. Reload the list shortly to check the result.');
}
}
async function ensureSuggestionConfig(guildId: string) {
await prisma.guild.upsert({ where: { id: guildId }, update: {}, create: { id: guildId } });
@@ -53,7 +60,7 @@ export async function updateSuggestionConfigDashboard(
return toConfigDashboard(updated);
}
function toSuggestionDashboard(suggestion: Suggestion): SuggestionDashboard {
function toDashboard(suggestion: Suggestion): SuggestionDashboard {
return {
id: suggestion.id,
authorId: suggestion.authorId,
@@ -75,25 +82,48 @@ export async function listSuggestions(
orderBy: { createdAt: 'desc' },
take: query.limit
});
return suggestions.map(toSuggestionDashboard);
return suggestions.map(toDashboard);
}
/**
* Staff actions (approve/deny/consider/implement) need to move or edit the
* suggestion's Discord embed and DM the author, which requires the bot's
* discord.js Client. The WebUI enqueues a `suggestionStatusUpdate` job on
* the same `suggestions` BullMQ queue the bot worker consumes (see
* `apps/bot/src/modules/suggestions/service.ts#runSuggestionStatusUpdateJob`)
* and waits (bounded) for it to finish.
*/
export async function applySuggestionAction(
guildId: string,
suggestionId: string,
action: SuggestionAction
): Promise<SuggestionDashboard | null> {
action: SuggestionAction,
_actorUserId: string
): Promise<SuggestionDashboard> {
const existing = await prisma.suggestion.findFirst({ where: { id: suggestionId, guildId } });
if (!existing) {
return null;
throw new SuggestionActionTimeoutError();
}
const updated = await prisma.suggestion.update({
where: { id: suggestionId },
data: {
const { confirmed } = await addJobAndAwait<{ id: string }>(
suggestionsQueue,
suggestionsQueueEvents,
'suggestionStatusUpdate',
{
suggestionId,
guildId,
status: action.status,
staffReason: action.staffReason ?? null
}
});
return toSuggestionDashboard(updated);
reason: action.staffReason ?? ''
},
{ removeOnComplete: true, removeOnFail: 25 }
);
if (!confirmed) {
throw new SuggestionActionTimeoutError();
}
const updated = await prisma.suggestion.findUnique({ where: { id: suggestionId } });
if (!updated) {
throw new SuggestionActionTimeoutError();
}
return toDashboard(updated);
}