mirror of
https://github.com/pupperpowell/bibdle.git
synced 2026-10-22 05:54:10 -04:00
98 lines
2.9 KiB
TypeScript
98 lines
2.9 KiB
TypeScript
import { db } from '$lib/server/db';
|
|
import { verseSubmissions, dailyVerses, user } from '$lib/server/db/schema';
|
|
import { eq, asc } from 'drizzle-orm';
|
|
import { getBookById } from '$lib/server/bible';
|
|
import { isAdmin } from '$lib/server/admin';
|
|
import type { PageServerLoad } from './$types';
|
|
|
|
export type ScheduledVerseRow = {
|
|
scheduledDate: string;
|
|
reference: string | null;
|
|
verseText: string | null;
|
|
bookId: string | null;
|
|
bookName: string | null;
|
|
selectedBookId: string;
|
|
selectedChapter: number;
|
|
selectedVerse: number;
|
|
submittedAt: number; // server UTC millis
|
|
submitterEmail: string | null;
|
|
submitterName: string | null;
|
|
submitterDeleted: boolean;
|
|
};
|
|
|
|
export const load: PageServerLoad = async ({ locals }) => {
|
|
// Not authenticated → signal the client to show the sign-in flow
|
|
// (same pattern as /progress, /stats).
|
|
if (!locals.user) {
|
|
return {
|
|
rows: [] as ScheduledVerseRow[],
|
|
requiresAuth: true,
|
|
authorized: false,
|
|
user: null,
|
|
session: null,
|
|
};
|
|
}
|
|
|
|
// Authenticated but wrong account → plain access-denied state. Don't leak
|
|
// the existence of privileged data; just render "not authorized".
|
|
if (!isAdmin(locals.user.email)) {
|
|
return {
|
|
rows: [] as ScheduledVerseRow[],
|
|
requiresAuth: false,
|
|
authorized: false,
|
|
user: locals.user,
|
|
session: locals.session,
|
|
};
|
|
}
|
|
|
|
const joined = await db
|
|
.select({
|
|
scheduledDate: verseSubmissions.scheduledDate,
|
|
selectedBookId: verseSubmissions.selectedBookId,
|
|
selectedChapter: verseSubmissions.selectedChapter,
|
|
selectedVerse: verseSubmissions.selectedVerse,
|
|
submittedAt: verseSubmissions.submittedAt,
|
|
dailyDate: dailyVerses.date,
|
|
bookId: dailyVerses.bookId,
|
|
reference: dailyVerses.reference,
|
|
verseText: dailyVerses.verseText,
|
|
userId: verseSubmissions.userId,
|
|
userEmail: user.email,
|
|
userFirstName: user.firstName,
|
|
userLastName: user.lastName,
|
|
})
|
|
.from(verseSubmissions)
|
|
// LEFT JOINs so deleted accounts (ON DELETE SET NULL) still render —
|
|
// the scheduled verse plays out regardless.
|
|
.leftJoin(dailyVerses, eq(verseSubmissions.scheduledDate, dailyVerses.date))
|
|
.leftJoin(user, eq(verseSubmissions.userId, user.id))
|
|
.orderBy(asc(verseSubmissions.scheduledDate));
|
|
|
|
const rows: ScheduledVerseRow[] = joined.map((r) => {
|
|
const book = r.bookId ? getBookById(r.bookId) : undefined;
|
|
return {
|
|
scheduledDate: r.scheduledDate,
|
|
reference: r.reference,
|
|
verseText: r.verseText,
|
|
bookId: r.bookId,
|
|
bookName: book?.name ?? null,
|
|
selectedBookId: r.selectedBookId,
|
|
selectedChapter: r.selectedChapter,
|
|
selectedVerse: r.selectedVerse,
|
|
submittedAt: r.submittedAt,
|
|
submitterEmail: r.userEmail,
|
|
submitterName: [r.userFirstName, r.userLastName].filter(Boolean).join(' ') || null,
|
|
// userId is null when the account was deleted (ON DELETE SET NULL)
|
|
submitterDeleted: r.userId === null,
|
|
};
|
|
});
|
|
|
|
return {
|
|
rows,
|
|
requiresAuth: false,
|
|
authorized: true,
|
|
user: locals.user,
|
|
session: locals.session,
|
|
};
|
|
};
|