Implement Owner Panel features and maintenance mode handling

- Introduced the Owner Panel with new routes and UI components for managing guilds, user blacklists, feature flags, and bot presence.
- Added maintenance mode functionality to prevent non-owner users from executing commands during maintenance periods.
- Enhanced localization with new keys for Owner Panel features in both English and German.
- Updated job processing to include a presence refresh job, ensuring the bot's status is regularly updated.
- Improved environment configuration to support owner user IDs for access control.
This commit is contained in:
smueller
2026-07-22 16:10:30 +02:00
parent bcbfa07697
commit 8a8aefb4fb
42 changed files with 2385 additions and 50 deletions

View File

@@ -0,0 +1,67 @@
import {
BotPresenceConfigPatchSchema,
BotPresenceConfigSchema,
PRESENCE_REDIS_KEY,
type BotPresenceConfig
} from '@nexumi/shared';
import { prisma } from './prisma';
import { redis } from './redis';
function mapRow(row: {
status: string;
activityType: string;
activityText: string;
rotatingMessages: unknown;
maintenanceMode: boolean;
maintenanceMessage: string | null;
}): BotPresenceConfig {
const rotating = Array.isArray(row.rotatingMessages)
? row.rotatingMessages.filter((item): item is string => typeof item === 'string')
: [];
return BotPresenceConfigSchema.parse({
status: row.status,
activityType: row.activityType,
activityText: row.activityText,
rotatingMessages: rotating,
maintenanceMode: row.maintenanceMode,
maintenanceMessage: row.maintenanceMessage
});
}
export async function getPresenceConfig(): Promise<BotPresenceConfig> {
const row = await prisma.botPresenceConfig.upsert({
where: { id: 'singleton' },
create: { id: 'singleton' },
update: {}
});
return mapRow(row);
}
export async function updatePresenceConfig(patch: unknown): Promise<BotPresenceConfig> {
const data = BotPresenceConfigPatchSchema.parse(patch);
const current = await getPresenceConfig();
const next = { ...current, ...data };
const row = await prisma.botPresenceConfig.upsert({
where: { id: 'singleton' },
create: {
id: 'singleton',
status: next.status,
activityType: next.activityType,
activityText: next.activityText,
rotatingMessages: next.rotatingMessages,
maintenanceMode: next.maintenanceMode,
maintenanceMessage: next.maintenanceMessage
},
update: {
status: next.status,
activityType: next.activityType,
activityText: next.activityText,
rotatingMessages: next.rotatingMessages,
maintenanceMode: next.maintenanceMode,
maintenanceMessage: next.maintenanceMessage
}
});
const mapped = mapRow(row);
await redis.set(PRESENCE_REDIS_KEY, JSON.stringify(mapped));
return mapped;
}