/** * PATCH /api/reservations/[id] - eigene Reservierung aendern. * DELETE /api/reservations/[id] - Reservierung loeschen (NUR Admin). * * Beide Operationen laufen atomar mit Kollisions- und Max-Dauerpruefung. * Normale User koennen Reservierungen anlegen und aendern, aber nicht * loeschen (canDeleteReservation). */ import { NextRequest, NextResponse } from 'next/server'; import { prisma } from '@/lib/db/client'; import { requireDbUser } from '@/lib/api/context'; import { updateReservationSchema } from '@/lib/validation'; import { canModifyReservation, canDeleteReservation, } from '@/lib/permissions/permissions'; import { updateReservationAtomically } from '@/lib/reservations/service'; import { errorResponse, forbiddenResponse, notFoundResponse } from '@/lib/api/responses'; interface RouteParams { params: Promise<{ id: string }>; } /** Laedt eine Reservierung samt Kalender-Referenz. */ async function loadReservation(reservationId: string) { return prisma.reservation.findUnique({ where: { id: reservationId }, select: { id: true, calendarId: true, userId: true, calendar: { select: { id: true, ownerId: true, isActive: true } }, }, }); } /** Ermittelt, ob der User Mitglied des Kalenders der Reservierung ist. */ async function isUserMemberOf(userId: string, calendarId: string): Promise { const membership = await prisma.calendarMember.findUnique({ where: { userId }, select: { calendarId: true }, }); return membership?.calendarId === calendarId; } export async function PATCH( request: NextRequest, { params }: RouteParams, ): Promise { try { const { id } = await params; const user = await requireDbUser(); const reservation = await loadReservation(id); if (!reservation) { return notFoundResponse('Reservierung nicht gefunden.'); } const isMember = await isUserMemberOf(user.id, reservation.calendarId); if (!canModifyReservation(user, reservation, reservation.calendar, isMember)) { return forbiddenResponse(); } const body = updateReservationSchema.parse(await request.json()); const updated = await updateReservationAtomically(id, body); return NextResponse.json({ reservation: updated }); } catch (error) { return errorResponse(error); } } export async function DELETE( _request: NextRequest, { params }: RouteParams, ): Promise { try { const { id } = await params; const user = await requireDbUser(); const reservation = await loadReservation(id); if (!reservation) { return notFoundResponse('Reservierung nicht gefunden.'); } // Loeschen ist ausschliesslich Admins vorbehalten. if (!canDeleteReservation(user, reservation, reservation.calendar)) { return forbiddenResponse(); } await prisma.reservation.delete({ where: { id } }); return NextResponse.json({ ok: true }); } catch (error) { return errorResponse(error); } }