/** * Hilfsfunktionen fuer API-Routen: laedt den Benutzer samt relevanten * Beziehungen aus der Datenbank und stellt den Kontext fuer die * Berechtigungspruefungen bereit. * * Wichtig (plan.md Abschnitt 2): Berechtigungen werden IMMER * serverseitig geprueft, nie nur im Frontend versteckt. */ import { prisma } from '@/lib/db/client'; import { getAuthenticatedUser } from '@/lib/auth/session'; import { UnauthorizedError } from '@/lib/auth/session'; import type { AuthenticatedUser } from '@/lib/permissions/permissions'; export interface CalendarContext { user: AuthenticatedUser; calendar: { id: string; ownerId: string; isActive: boolean; title: string; description: string | null; timezone: string; /** Maximale Reservierungsdauer in Minuten; 0 = unbegrenzt. */ maxReservationMinutes: number; /** Duerven Nicht-Admins die Titel fremder Reservierungen sehen? */ showTitleToMembers: boolean; /** Duerven Nicht-Admins die Notizen fremder Reservierungen sehen? */ showNotesToMembers: boolean; }; /** Ist der angemeldete User Mitglied dieses Kalenders? */ isMember: boolean; } /** Laedt den vollstaendigen DB-Benutzer zur aktuellen Session. */ export async function requireDbUser() { const authUser = await getAuthenticatedUser(); const user = await prisma.user.findUnique({ where: { id: authUser.id }, select: { id: true, email: true, username: true, role: true }, }); if (!user) { // Session gueltig, aber Benutzer geloescht -> Session ist ungueltig. throw new UnauthorizedError(); } return user; } /** * Laedt einen Kalender samt Mitgliedschaft des Users. * Wirft UnauthorizedError, wenn der User den Kalender ueberhaupt * nicht sehen darf - so werden Daten anderer Kalender niemals ueber * die API preisgegeben. * * Zugriff hat (konsistent mit canViewCalendar in der zentralen * Berechtigungsschicht): * - ADMIN: alle Kalender (Verwaltungsrolle, auch die anderer User) * - USER: nur der eine Kalender, in dem er Mitglied ist */ export async function requireCalendarContext( calendarId: string, ): Promise { const user = await requireDbUser(); const calendar = await prisma.calendar.findUnique({ where: { id: calendarId }, select: { id: true, ownerId: true, isActive: true, title: true, description: true, timezone: true, maxReservationMinutes: true, showTitleToMembers: true, showNotesToMembers: true, }, }); if (!calendar) { throw new UnauthorizedError(); } const isOwner = calendar.ownerId === user.id; const membership = await prisma.calendarMember.findUnique({ where: { userId: user.id }, select: { calendarId: true }, }); const isMember = membership?.calendarId === calendar.id; // Admins duerfen alle Kalender sehen und verwalten (canViewCalendar / // canManageCalendar). User nur ihren eigenen (Mitgliedschaft). const canAccess = user.role === 'ADMIN' || isOwner || isMember; if (!canAccess) { // Bewusst 401 statt 404: Es wird nicht verraten, dass der // Kalender existiert (plan.md Abschnitt 2). throw new UnauthorizedError(); } return { user, calendar, isMember }; }