Close remaining web gaps: rich profile, login history, lightbox/slider, flash client, admin chatlog/DJ/chart/WYSIWYG, niche API
- Rich profile (/u/[username]): wallet (credits/duckets/diamonds), friends grid (messenger_friendships), and owned rooms sections. - Login history: new website_login_logs table (model + migration 0007), recorded on every successful sign-in (ip + user-agent), surfaced on a new /settings/sessions page (with failed-attempt list from failed_logins). - Photos lightbox + home article slider (client components, no Swiper dep). - /client/flash launcher (SSO ticket like the Nitro page). - Admin: private chatlogs section in /admin/logs, /admin/radio/moderation (shout moderation), a "users by rank" inline bar chart on the dashboard, and a TinyMCE rich-text editor on the article admin forms. - Niche API: /api/values/[id], /api/guilds(+/[id]), /api/radio/auto-play. Verified live (prod, amx_test): login recorded → /settings/sessions shows it with device; profile renders wallet/friends/rooms; dashboard chart + private-chat logs + /client/flash + /api/guilds all OK. Reverted test data. tsc 0, vitest 49/49, next build 0.
This commit is contained in:
1 parent
f7b3845131
commit
4dfe698009
25 files changed
+1463
-64
No files matched your search
@@ -0,0 +1,38 @@
|
||||
// Public REST: whether the radio player should auto-play on load. Reads the
|
||||
// radio_auto_play website setting (the key the admin radio settings page
|
||||
// writes), falling back to the legacy radio_autoplay alias if present. Booleans
|
||||
// are stored as the strings '1' / '0'. Returns { autoplay: boolean }.
|
||||
import { apiJson } from "@/lib/api";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
|
||||
export const dynamic = "force-dynamic";
|
||||
|
||||
const AUTOPLAY_KEYS = ["radio_auto_play", "radio_autoplay"];
|
||||
|
||||
function truthy(value: string | undefined): boolean {
|
||||
if (value === undefined) return false;
|
||||
const s = value.trim().toLowerCase();
|
||||
return s === "1" || s === "true";
|
||||
}
|
||||
|
||||
export async function GET(_req: Request) {
|
||||
try {
|
||||
const rows = await prisma.websiteSetting.findMany({
|
||||
where: { key: { in: AUTOPLAY_KEYS } },
|
||||
select: { key: true, value: true },
|
||||
});
|
||||
|
||||
const map: Record<string, string> = {};
|
||||
for (const row of rows) {
|
||||
map[row.key] = row.value;
|
||||
}
|
||||
|
||||
// Prefer the canonical key the settings page uses; fall back to the alias.
|
||||
const autoplay = truthy(map.radio_auto_play ?? map.radio_autoplay);
|
||||
|
||||
return apiJson({ autoplay });
|
||||
} catch {
|
||||
// DB unavailable — default to no autoplay rather than a 500.
|
||||
return apiJson({ autoplay: false }, { status: 200 });
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user