io
This commit is contained in:
132
app/api/admin/quiz/route.ts
Normal file
132
app/api/admin/quiz/route.ts
Normal file
@@ -0,0 +1,132 @@
|
||||
import { NextRequest, NextResponse } from "next/server";
|
||||
import { db } from "@/lib/db";
|
||||
import { getServerSession } from "next-auth";
|
||||
import { authOptions } from "@/lib/auth";
|
||||
import { Prisma } from "@prisma/client";
|
||||
|
||||
async function adminOnly(req: NextRequest) {
|
||||
const session = await getServerSession(authOptions);
|
||||
if (!session || (session.user as any).role !== "ADMIN") return null;
|
||||
return session;
|
||||
}
|
||||
|
||||
function validateTierConfig(input: {
|
||||
goldWinnersCount: number;
|
||||
silverWinnersCount: number;
|
||||
bronzeWinnersCount: number;
|
||||
goldMinCorrect: number | null;
|
||||
silverMinCorrect: number | null;
|
||||
bronzeMinCorrect: number | null;
|
||||
}) {
|
||||
if (input.goldWinnersCount < 0 || input.silverWinnersCount < 0 || input.bronzeWinnersCount < 0) {
|
||||
return "Winner counts cannot be negative";
|
||||
}
|
||||
|
||||
if (input.goldWinnersCount + input.silverWinnersCount + input.bronzeWinnersCount <= 0) {
|
||||
return "At least one winner must be configured";
|
||||
}
|
||||
|
||||
if (input.goldWinnersCount > 0 && input.goldMinCorrect == null) {
|
||||
return "Gold minimum correct answers is required";
|
||||
}
|
||||
|
||||
if (input.silverWinnersCount > 0 && input.silverMinCorrect == null) {
|
||||
return "Silver minimum correct answers is required";
|
||||
}
|
||||
|
||||
if (input.bronzeWinnersCount > 0 && input.bronzeMinCorrect == null) {
|
||||
return "Bronze minimum correct answers is required";
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
// GET /api/admin/quiz - list all quizzes
|
||||
export async function GET(req: NextRequest) {
|
||||
const session = await adminOnly(req);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const quizzes = await db.dailyQuiz.findMany({
|
||||
orderBy: { date: "desc" },
|
||||
include: {
|
||||
questions: { orderBy: { order: "asc" } },
|
||||
_count: { select: { submissions: true } },
|
||||
},
|
||||
});
|
||||
|
||||
return NextResponse.json(quizzes);
|
||||
}
|
||||
|
||||
// POST /api/admin/quiz - create quiz
|
||||
export async function POST(req: NextRequest) {
|
||||
try {
|
||||
const session = await adminOnly(req);
|
||||
if (!session) return NextResponse.json({ error: "Unauthorized" }, { status: 401 });
|
||||
|
||||
const {
|
||||
date,
|
||||
windowStart,
|
||||
windowEnd,
|
||||
goldWinnersCount,
|
||||
silverWinnersCount,
|
||||
bronzeWinnersCount,
|
||||
goldMinCorrect,
|
||||
silverMinCorrect,
|
||||
bronzeMinCorrect,
|
||||
questions,
|
||||
} = await req.json();
|
||||
|
||||
const parsedInput = {
|
||||
goldWinnersCount: Number(goldWinnersCount),
|
||||
silverWinnersCount: Number(silverWinnersCount),
|
||||
bronzeWinnersCount: Number(bronzeWinnersCount),
|
||||
goldMinCorrect: goldMinCorrect == null ? null : Number(goldMinCorrect),
|
||||
silverMinCorrect: silverMinCorrect == null ? null : Number(silverMinCorrect),
|
||||
bronzeMinCorrect: bronzeMinCorrect == null ? null : Number(bronzeMinCorrect),
|
||||
};
|
||||
|
||||
const validationError = validateTierConfig(parsedInput);
|
||||
if (validationError) {
|
||||
return NextResponse.json({ error: validationError }, { status: 400 });
|
||||
}
|
||||
|
||||
if (!Array.isArray(questions) || questions.length === 0) {
|
||||
return NextResponse.json({ error: "At least one question is required" }, { status: 400 });
|
||||
}
|
||||
|
||||
const quiz = await db.dailyQuiz.create({
|
||||
data: {
|
||||
date: new Date(`${date}T00:00:00.000Z`),
|
||||
windowStart: new Date(windowStart),
|
||||
windowEnd: new Date(windowEnd),
|
||||
goldWinnersCount: parsedInput.goldWinnersCount,
|
||||
silverWinnersCount: parsedInput.silverWinnersCount,
|
||||
bronzeWinnersCount: parsedInput.bronzeWinnersCount,
|
||||
goldMinCorrect: parsedInput.goldMinCorrect,
|
||||
silverMinCorrect: parsedInput.silverMinCorrect,
|
||||
bronzeMinCorrect: parsedInput.bronzeMinCorrect,
|
||||
questions: {
|
||||
create: questions.map((q: any, i: number) => ({
|
||||
questionText: q.questionText,
|
||||
options: q.options,
|
||||
correctAnswer: Number(q.correctAnswer),
|
||||
order: i,
|
||||
})),
|
||||
},
|
||||
},
|
||||
include: { questions: true },
|
||||
});
|
||||
|
||||
return NextResponse.json(quiz, { status: 201 });
|
||||
} catch (error) {
|
||||
console.error("Failed to create quiz", error);
|
||||
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError) {
|
||||
if (error.code === "P2002") {
|
||||
return NextResponse.json({ error: "Quiz date already exists" }, { status: 409 });
|
||||
}
|
||||
}
|
||||
|
||||
return NextResponse.json({ error: "Failed to create quiz" }, { status: 500 });
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user