mirror of
https://github.com/pupperpowell/bibdle.git
synced 2026-10-22 05:54:10 -04:00
Added verse-submission infrastructure
This commit is contained in:
1 parent
99552c57ad
commit
be0d7ad297
17 files changed
+1293
-26
No files matched your search
@@ -0,0 +1,97 @@
|
||||
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,
|
||||
};
|
||||
};
|
||||
Reference in new issue
Block a user