Fix API routes: closed-question guard, file validation, files sanitization, follow-up email
- Add CLOSED status guard in messages POST (returns 409) - Add extension allowlist check in upload route + text/x-markdown MIME type - Sanitize files JSON array before DB write - Add sendQuestionFollowUpEmail helper and use it for student follow-up replies - Scope email field to staff only in questions list query Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -2,7 +2,7 @@ import { NextRequest, NextResponse } from "next/server";
|
||||
import { headers } from "next/headers";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { sendQuestionCreatedEmail, sendQuestionReplyEmail } from "@/lib/email";
|
||||
import { sendQuestionFollowUpEmail, sendQuestionReplyEmail } from "@/lib/email";
|
||||
|
||||
interface FileAttachment {
|
||||
name: string;
|
||||
@@ -29,6 +29,9 @@ export async function POST(
|
||||
if (!isStaff && question.userId !== session.user.id) {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
if (question.status === "CLOSED") {
|
||||
return NextResponse.json({ error: "Question is closed" }, { status: 409 });
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const { text, files } = body as { text: string; files?: FileAttachment[] };
|
||||
@@ -37,12 +40,21 @@ export async function POST(
|
||||
return NextResponse.json({ error: "text is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const safeFiles = files
|
||||
?.filter(
|
||||
(f) =>
|
||||
typeof f.name === "string" &&
|
||||
typeof f.url === "string" &&
|
||||
typeof f.size === "number"
|
||||
)
|
||||
.map((f) => ({ name: f.name.slice(0, 255), url: f.url, size: Math.max(0, f.size) }));
|
||||
|
||||
const message = await prisma.studentQuestionMessage.create({
|
||||
data: {
|
||||
questionId: id,
|
||||
authorId: session.user.id,
|
||||
text: text.trim(),
|
||||
files: files?.length ? (files as object[]) : undefined,
|
||||
files: safeFiles?.length ? (safeFiles as object[]) : undefined,
|
||||
},
|
||||
include: { author: { select: { id: true, name: true, role: true } } },
|
||||
});
|
||||
@@ -68,7 +80,7 @@ export async function POST(
|
||||
});
|
||||
await Promise.all(
|
||||
staff.map((s) =>
|
||||
sendQuestionCreatedEmail(s.email, s.name, session.user.name, question.title)
|
||||
sendQuestionFollowUpEmail(s.email, s.name, session.user.name, question.title)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user