Feature: Plugin UI, event hooks, DB notifications, web push, webhook retry, games pages, rate limiting, tests
Local Build and Deploy / deploy (push) Successful in 1m5s
Local Build and Deploy / deploy (push) Successful in 1m5s
- Plugin admin UI: enable/disable per plugin with config forms - Event hooks system: HookManager with on/off/emit for plugin events - Database notifications: persistent via WebsiteNotification table + Redis pub/sub - Notification preferences: per-user settings with API endpoints - Web Push API: browser push notification subscription - Webhook retry: 3 attempts with exponential backoff (1s/3s/9s) + delivery logs - Webhook test button + paginated delivery log viewer - Games: rank/challenge/reward admin pages - Games: public frontend leaderboard - Rate limiting: search API (30/min), notification stream dedup - Unit tests: 28 new tests (registry, notifications, webhooks) - Prisma migration 0017: website_notifications, website_notification_preferences, website_webhook_logs
This commit is contained in:
1 parent
8bf48f46e7
commit
83f4585167
30 files changed
+2196
-51
No files matched your search
@@ -0,0 +1,80 @@
|
||||
import "server-only";
|
||||
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export interface NotificationPreferences {
|
||||
emailEnabled: boolean;
|
||||
pushEnabled: boolean;
|
||||
friendRequest: boolean;
|
||||
messages: boolean;
|
||||
guildInvite: boolean;
|
||||
events: boolean;
|
||||
alerts: boolean;
|
||||
achievements: boolean;
|
||||
radio: boolean;
|
||||
}
|
||||
|
||||
const DEFAULTS: NotificationPreferences = {
|
||||
emailEnabled: true,
|
||||
pushEnabled: true,
|
||||
friendRequest: true,
|
||||
messages: true,
|
||||
guildInvite: true,
|
||||
events: true,
|
||||
alerts: true,
|
||||
achievements: true,
|
||||
radio: true,
|
||||
};
|
||||
|
||||
export async function getPreferences(
|
||||
userId: number,
|
||||
): Promise<NotificationPreferences> {
|
||||
try {
|
||||
const prefs = await prisma.websiteNotificationPreference.findUnique({
|
||||
where: { userId: BigInt(userId) },
|
||||
});
|
||||
if (!prefs) return { ...DEFAULTS };
|
||||
return {
|
||||
emailEnabled: prefs.emailEnabled,
|
||||
pushEnabled: prefs.pushEnabled,
|
||||
friendRequest: prefs.friendRequest,
|
||||
messages: prefs.messages,
|
||||
guildInvite: prefs.guildInvite,
|
||||
events: prefs.events,
|
||||
alerts: prefs.alerts,
|
||||
achievements: prefs.achievements,
|
||||
radio: prefs.radio,
|
||||
};
|
||||
} catch {
|
||||
return { ...DEFAULTS };
|
||||
}
|
||||
}
|
||||
|
||||
export async function updatePreferences(
|
||||
userId: number,
|
||||
prefs: Partial<NotificationPreferences>,
|
||||
): Promise<void> {
|
||||
try {
|
||||
const existing = await prisma.websiteNotificationPreference.findUnique({
|
||||
where: { userId: BigInt(userId) },
|
||||
});
|
||||
|
||||
const data = {
|
||||
emailEnabled: prefs.emailEnabled ?? existing?.emailEnabled ?? true,
|
||||
pushEnabled: prefs.pushEnabled ?? existing?.pushEnabled ?? true,
|
||||
friendRequest: prefs.friendRequest ?? existing?.friendRequest ?? true,
|
||||
messages: prefs.messages ?? existing?.messages ?? true,
|
||||
guildInvite: prefs.guildInvite ?? existing?.guildInvite ?? true,
|
||||
events: prefs.events ?? existing?.events ?? true,
|
||||
alerts: prefs.alerts ?? existing?.alerts ?? true,
|
||||
achievements: prefs.achievements ?? existing?.achievements ?? true,
|
||||
radio: prefs.radio ?? existing?.radio ?? true,
|
||||
};
|
||||
|
||||
await prisma.websiteNotificationPreference.upsert({
|
||||
where: { userId: BigInt(userId) },
|
||||
update: data,
|
||||
create: { userId: BigInt(userId), ...data },
|
||||
});
|
||||
} catch {}
|
||||
}
|
||||
Reference in new issue
Block a user