Files
Harlekin e0b03ea336
Prüfung / Lint, Typen, Tests (push) Canceled after 0s
Prüfung / Images bauen (pdf) (push) Canceled after 0s
Prüfung / Images bauen (web) (push) Canceled after 0s
Prüfung / Images bauen (worker) (push) Canceled after 0s
Images / bauen (pdf, docker/pdf.Dockerfile) (push) Canceled after 0s
Images / bauen (web, docker/web.Dockerfile) (push) Canceled after 0s
Images / bauen (worker, docker/worker.Dockerfile) (push) Canceled after 0s
Gedankenstriche durch Bindestriche ersetzt
375 Vorkommen in 210 Dateien. Betrifft Kommentare, Oberflaechentexte und die
README; an keiner Stelle Bedeutung, nur Zeichensetzung.
2026-09-04 08:54:52 +02:00

114 lines
4.0 KiB
TypeScript

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 }
}