Add student questions API routes
Implements GET/POST /api/questions, GET /api/questions/[id] with read tracking, POST /api/questions/[id]/messages with email notifications, PATCH /api/questions/[id]/close for staff, and POST /api/student/question-upload for file attachments. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,88 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { headers } from "next/headers";
|
||||
import { auth } from "@/lib/auth";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
import { sendQuestionCreatedEmail } from "@/lib/email";
|
||||
|
||||
export async function GET() {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const isStaff = session.user.role === "admin" || session.user.role === "curator";
|
||||
|
||||
const questions = await prisma.studentQuestion.findMany({
|
||||
where: isStaff ? undefined : { userId: session.user.id },
|
||||
include: {
|
||||
user: { select: { id: true, name: true, email: true } },
|
||||
course: { select: { id: true, title: true } },
|
||||
_count: {
|
||||
select: {
|
||||
messages: {
|
||||
where: isStaff
|
||||
? { isRead: false, author: { role: "student" } }
|
||||
: { isRead: false, NOT: { authorId: session.user.id } },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
orderBy: { updatedAt: "desc" },
|
||||
});
|
||||
|
||||
return NextResponse.json(
|
||||
questions.map((q) => ({
|
||||
id: q.id,
|
||||
title: q.title,
|
||||
status: q.status,
|
||||
createdAt: q.createdAt,
|
||||
updatedAt: q.updatedAt,
|
||||
user: q.user,
|
||||
course: q.course,
|
||||
unreadCount: q._count.messages,
|
||||
}))
|
||||
);
|
||||
}
|
||||
|
||||
export async function POST(req: NextRequest) {
|
||||
const session = await auth.api.getSession({ headers: await headers() });
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
if (session.user.role !== "student") {
|
||||
return NextResponse.json({ error: "Forbidden" }, { status: 403 });
|
||||
}
|
||||
|
||||
const body = await req.json();
|
||||
const { title, text, courseId } = body as {
|
||||
title: string;
|
||||
text: string;
|
||||
courseId?: string;
|
||||
};
|
||||
|
||||
if (!title?.trim() || !text?.trim()) {
|
||||
return NextResponse.json({ error: "title and text are required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const question = await prisma.studentQuestion.create({
|
||||
data: {
|
||||
userId: session.user.id,
|
||||
courseId: courseId ?? null,
|
||||
title: title.trim(),
|
||||
messages: {
|
||||
create: {
|
||||
authorId: session.user.id,
|
||||
text: text.trim(),
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
const staff = await prisma.user.findMany({
|
||||
where: { role: { in: ["admin", "curator"] } },
|
||||
select: { email: true, name: true },
|
||||
});
|
||||
await Promise.all(
|
||||
staff.map((s) =>
|
||||
sendQuestionCreatedEmail(s.email, s.name, session.user.name, title.trim())
|
||||
)
|
||||
);
|
||||
|
||||
return NextResponse.json(question, { status: 201 });
|
||||
}
|
||||
Reference in New Issue
Block a user