import { NextRequest, NextResponse } from 'next/server'; import { PrismaClient, Prisma } from '@prisma/client'; import bcrypt from 'bcryptjs'; import { requireAdminAuth } from '@/lib/auth'; const prisma = new PrismaClient(); export async function GET(request: NextRequest) { // Only admin may list and manage curators const authError = await requireAdminAuth(request); if (authError) return authError; const curators = await prisma.curator.findMany({ include: { genres: true, specials: true, }, orderBy: { username: 'asc' }, }); return NextResponse.json( curators.map(c => ({ id: c.id, username: c.username, isGlobalCurator: c.isGlobalCurator, genreIds: c.genres.map(g => g.genreId), specialIds: c.specials.map(s => s.specialId), })) ); } export async function POST(request: NextRequest) { const authError = await requireAdminAuth(request); if (authError) return authError; const { username, password, isGlobalCurator = false, genreIds = [], specialIds = [] } = await request.json(); if (!username || !password) { return NextResponse.json({ error: 'username and password are required' }, { status: 400 }); } const passwordHash = await bcrypt.hash(password, 10); try { const curator = await prisma.curator.create({ data: { username, passwordHash, isGlobalCurator: Boolean(isGlobalCurator), genres: { create: (genreIds as number[]).map(id => ({ genreId: id })), }, specials: { create: (specialIds as number[]).map(id => ({ specialId: id })), }, }, include: { genres: true, specials: true, }, }); return NextResponse.json({ id: curator.id, username: curator.username, isGlobalCurator: curator.isGlobalCurator, genreIds: curator.genres.map(g => g.genreId), specialIds: curator.specials.map(s => s.specialId), }); } catch (error) { console.error('Error creating curator:', error); // Handle unique username constraint violation explicitly if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') { return NextResponse.json( { error: 'A curator with this username already exists.' }, { status: 409 } ); } return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); } } export async function PUT(request: NextRequest) { const authError = await requireAdminAuth(request); if (authError) return authError; const { id, username, password, isGlobalCurator, genreIds, specialIds } = await request.json(); if (!id) { return NextResponse.json({ error: 'id is required' }, { status: 400 }); } const data: any = {}; if (username !== undefined) data.username = username; if (isGlobalCurator !== undefined) data.isGlobalCurator = Boolean(isGlobalCurator); if (password) { data.passwordHash = await bcrypt.hash(password, 10); } try { const updated = await prisma.$transaction(async (tx) => { const curator = await tx.curator.update({ where: { id: Number(id) }, data, include: { genres: true, specials: true, }, }); if (Array.isArray(genreIds)) { await tx.curatorGenre.deleteMany({ where: { curatorId: curator.id }, }); if (genreIds.length > 0) { await tx.curatorGenre.createMany({ data: (genreIds as number[]).map(gid => ({ curatorId: curator.id, genreId: gid, })), }); } } if (Array.isArray(specialIds)) { await tx.curatorSpecial.deleteMany({ where: { curatorId: curator.id }, }); if (specialIds.length > 0) { await tx.curatorSpecial.createMany({ data: (specialIds as number[]).map(sid => ({ curatorId: curator.id, specialId: sid, })), }); } } const finalCurator = await tx.curator.findUnique({ where: { id: curator.id }, include: { genres: true, specials: true, }, }); if (!finalCurator) { throw new Error('Curator not found after update'); } return finalCurator; }); return NextResponse.json({ id: updated.id, username: updated.username, isGlobalCurator: updated.isGlobalCurator, genreIds: updated.genres.map(g => g.genreId), specialIds: updated.specials.map(s => s.specialId), }); } catch (error) { console.error('Error updating curator:', error); // Handle unique username constraint violation explicitly for updates if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') { return NextResponse.json( { error: 'A curator with this username already exists.' }, { status: 409 } ); } return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); } } export async function DELETE(request: NextRequest) { const authError = await requireAdminAuth(request); if (authError) return authError; const { id } = await request.json(); if (!id) { return NextResponse.json({ error: 'id is required' }, { status: 400 }); } try { await prisma.curator.delete({ where: { id: Number(id) }, }); return NextResponse.json({ success: true }); } catch (error) { console.error('Error deleting curator:', error); return NextResponse.json({ error: 'Internal Server Error' }, { status: 500 }); } }