Implement maintenance mode and presence updates in bot and WebUI
- Added maintenance mode functionality in the bot, allowing for a custom message and DND status when enabled. - Updated the OwnerPresencePage to include read-only access for VIEWER roles, with save permissions restricted to ADMIN roles. - Enhanced the PresenceForm component to support immediate application of changes and added a confirmation for maintenance mode activation. - Introduced localization updates for presence-related messages in both English and German, improving user guidance. - Implemented a presence refresh queue to handle updates efficiently after configuration changes.
This commit is contained in:
@@ -5,6 +5,7 @@ import {
|
||||
type BotPresenceConfig
|
||||
} from '@nexumi/shared';
|
||||
import { prisma } from './prisma';
|
||||
import { getPresenceQueue } from './queues';
|
||||
import { redis } from './redis';
|
||||
|
||||
function mapRow(row: {
|
||||
@@ -63,5 +64,13 @@ export async function updatePresenceConfig(patch: unknown): Promise<BotPresenceC
|
||||
});
|
||||
const mapped = mapRow(row);
|
||||
await redis.set(PRESENCE_REDIS_KEY, JSON.stringify(mapped));
|
||||
await getPresenceQueue().add(
|
||||
'presenceRefresh',
|
||||
{},
|
||||
{
|
||||
removeOnComplete: 5,
|
||||
removeOnFail: 5
|
||||
}
|
||||
);
|
||||
return mapped;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export const suggestionsQueueName = 'suggestions';
|
||||
export const messagesQueueName = 'messages';
|
||||
export const verificationQueueName = 'verification';
|
||||
export const automodQueueName = 'automod';
|
||||
export const presenceQueueName = 'presence';
|
||||
|
||||
const globalForQueues = globalThis as unknown as {
|
||||
__nexumiGiveawayQueue?: Queue;
|
||||
@@ -30,6 +31,7 @@ const globalForQueues = globalThis as unknown as {
|
||||
__nexumiMessagesQueue?: Queue;
|
||||
__nexumiVerificationQueue?: Queue;
|
||||
__nexumiAutomodQueue?: Queue;
|
||||
__nexumiPresenceQueue?: Queue;
|
||||
__nexumiGiveawayQueueEvents?: QueueEvents;
|
||||
__nexumiGuildBackupQueueEvents?: QueueEvents;
|
||||
__nexumiSuggestionsQueueEvents?: QueueEvents;
|
||||
@@ -94,6 +96,13 @@ export function getAutomodQueue(): Queue {
|
||||
return globalForQueues.__nexumiAutomodQueue;
|
||||
}
|
||||
|
||||
export function getPresenceQueue(): Queue {
|
||||
globalForQueues.__nexumiPresenceQueue ??= new Queue(presenceQueueName, {
|
||||
connection: queueConnection()
|
||||
});
|
||||
return globalForQueues.__nexumiPresenceQueue;
|
||||
}
|
||||
|
||||
/**
|
||||
* QueueEvents instances are only needed for jobs where the dashboard needs
|
||||
* to wait for the bot to finish (e.g. ending a giveaway so the winners list
|
||||
|
||||
40
apps/webui/src/lib/welcome-preview-vars.ts
Normal file
40
apps/webui/src/lib/welcome-preview-vars.ts
Normal file
@@ -0,0 +1,40 @@
|
||||
import type { DashboardGuild, SessionUser } from '@nexumi/shared';
|
||||
|
||||
function discordDefaultAvatarUrl(userId: string): string {
|
||||
try {
|
||||
const index = Number((BigInt(userId) >> 22n) % 6n);
|
||||
return `https://cdn.discordapp.com/embed/avatars/${index}.png`;
|
||||
} catch {
|
||||
return 'https://cdn.discordapp.com/embed/avatars/0.png';
|
||||
}
|
||||
}
|
||||
|
||||
function userAvatarUrl(user: SessionUser): string {
|
||||
return user.avatar
|
||||
? `https://cdn.discordapp.com/avatars/${user.id}/${user.avatar}.png?size=256`
|
||||
: discordDefaultAvatarUrl(user.id);
|
||||
}
|
||||
|
||||
function guildIconUrl(guild: DashboardGuild): string {
|
||||
return guild.icon
|
||||
? `https://cdn.discordapp.com/icons/${guild.id}/${guild.icon}.png?size=128`
|
||||
: discordDefaultAvatarUrl(guild.id);
|
||||
}
|
||||
|
||||
/** Preview placeholders from the logged-in dashboard user and current guild. */
|
||||
export function buildWelcomePreviewVars(
|
||||
user: SessionUser,
|
||||
guild: DashboardGuild
|
||||
): Record<string, string> {
|
||||
const displayName = user.globalName?.trim() || user.username;
|
||||
return {
|
||||
user: `@${displayName}`,
|
||||
'user.name': displayName,
|
||||
'user.tag': user.username,
|
||||
'user.id': user.id,
|
||||
'user.avatar': userAvatarUrl(user),
|
||||
server: guild.name,
|
||||
'server.icon': guildIconUrl(guild),
|
||||
memberCount: '—'
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user