Fix security, transaction, and badge issues from final review

- Validate file URLs against S3 prefix in messages route (Fix 1)
- Guard attachment hrefs with https:// check in QuestionThread and QuestionSplitView (Fix 2)
- Wrap message create + updatedAt bump in prisma.$transaction (Fix 3)
- Add questionsBadge count query to curator layout for admin branch (Fix 4)
- Fire-and-forget email sends with void Promise.all (Fix 5)
- Wrap req.json() calls in try/catch returning 400 on parse failure (Fix 6)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-19 13:56:31 +05:00
parent 12e1785ff2
commit e5ba94cb33
5 changed files with 56 additions and 25 deletions
+12 -1
View File
@@ -5,6 +5,7 @@ import Link from "next/link";
import { LogoutButton } from "@/components/layout/logout-button";
import { AdminShell } from "@/components/admin/admin-shell";
import { getSetting } from "@/lib/settings";
import { prisma } from "@/lib/prisma";
export default async function CuratorLayout({ children }: { children: React.ReactNode }) {
const session = await auth.api.getSession({ headers: await headers() });
@@ -19,7 +20,17 @@ export default async function CuratorLayout({ children }: { children: React.Reac
// Admin uses the admin shell with sidebar
if (session.user.role === "admin") {
return <AdminShell userName={session.user.name}>{children}</AdminShell>;
const questionsBadge = await prisma.studentQuestion.count({
where: {
messages: {
some: {
isRead: false,
author: { role: "student" },
},
},
},
});
return <AdminShell userName={session.user.name} questionsBadge={questionsBadge}>{children}</AdminShell>;
}
return (