import type { EffectivePermissions, Permission } from '@/lib/auth/permissions' import type { WriteCheck } from '@/lib/access/caseWrite' /** * Schreibgrenzen für Personalakten und Dokumente. * * Dieselbe Bauform wie `caseWrite.ts`: reine Funktionen, die auch dann greifen, * wenn die Oberfläche einen Knopf versehentlich stehen lässt. Jede Server * Action ruft sie auf, nicht nur die, die den Knopf zeichnet. */ /** Status, in denen ein Dokument nicht mehr verändert wird. */ export const READ_ONLY_DOCUMENT_STATUS = ['RETRACTED'] as const function requirePermission(p: EffectivePermissions, permission: Permission): WriteCheck { if (p.isAdmin || p.permissions.has(permission)) return { ok: true } return { ok: false, reason: 'no-permission', permission } } /** * Darf dieser Nutzer eine Personalakte mit dieser Klassifizierung anlegen oder * auf diese Stufe heben? Wie bei der Fallakte: nie über der eigenen Stufe. */ export function canWritePersonnel( p: EffectivePermissions, classification: number, ): WriteCheck { const permitted = requirePermission(p, 'personnel.edit') if (!permitted.ok) return permitted if (classification > p.clearanceLevel && !p.isAdmin) { return { ok: false, reason: 'clearance-too-low', required: classification } } return { ok: true } } /** * Darf dieser Nutzer ein Dokument mit dieser Klassifizierung anlegen? * * Der Besitzer ist vorher schon durch die Sichtbarkeitsprüfung gelaufen - was * man nicht sieht, kann man nicht bestücken. */ export function canCreateDocument( p: EffectivePermissions, classification: number, ): WriteCheck { const permitted = requirePermission(p, 'document.create') if (!permitted.ok) return permitted if (classification > p.clearanceLevel) { return { ok: false, reason: 'clearance-too-low', required: classification } } return { ok: true } } /** * Darf dieser Nutzer dieses Dokument ändern? * * Ein zurückgezogenes Dokument ist endgültig schreibgeschützt, auch für * Admins: es steht als Grabstein und darf nicht nachträglich zu etwas anderem * werden. Ein ausgefertigtes Dokument zu ändern setzt dasselbe Recht voraus, * das die Ausfertigung erlaubt hat. */ export function canEditDocument( p: EffectivePermissions, target: { status: string; classification: number }, ): WriteCheck { if ((READ_ONLY_DOCUMENT_STATUS as readonly string[]).includes(target.status)) { return { ok: false, reason: 'read-only', status: target.status } } const permitted = requirePermission(p, 'document.edit') if (!permitted.ok) return permitted if (target.classification > p.clearanceLevel && !p.isAdmin) { return { ok: false, reason: 'clearance-too-low', required: target.classification } } if (target.status === 'FINAL') { const final = requirePermission(p, 'document.finalize') if (!final.ok) return { ok: false, reason: 'closed' } } return { ok: true } } /** Ausfertigen: aus einem Entwurf wird ein gültiges Dokument. */ export function canFinalizeDocument( p: EffectivePermissions, target: { status: string; classification: number }, ): WriteCheck { if (target.status !== 'DRAFT') return { ok: false, reason: 'read-only', status: target.status } const permitted = requirePermission(p, 'document.finalize') if (!permitted.ok) return permitted if (target.classification > p.clearanceLevel && !p.isAdmin) { return { ok: false, reason: 'clearance-too-low', required: target.classification } } return { ok: true } } /** Zurückziehen. Löschen gibt es nicht, der Grabstein bleibt stehen. */ export function canRetractDocument( p: EffectivePermissions, target: { status: string; classification: number }, ): WriteCheck { if (target.status === 'RETRACTED') { return { ok: false, reason: 'read-only', status: target.status } } const permitted = requirePermission(p, 'document.retract') if (!permitted.ok) return permitted if (target.classification > p.clearanceLevel && !p.isAdmin) { return { ok: false, reason: 'clearance-too-low', required: target.classification } } return { ok: true } }