Files
MABEA/backend/app/models/dokument.py
T
patrickandClaude Sonnet 5 654d448e7b
CI / backend-tests (push) Failing after 2m17s
CI / frontend-build (push) Successful in 28s
feat(dokumente): DOC-005 Zugriffsrechte je Dokumenttyp (Rechnungen eingeschränkt)
Rechnungen sind finanziell sensibel - nur Materialverantwortliche/
Leitungsverantwortliche/Administration dürfen sie in der Liste sehen und
herunterladen (403 bei direktem Downloadversuch), Mitarbeiter nicht.
Hochladen bleibt für alle offen (z.B. Wareneingang direkt scannen). Andere
Dokumenttypen bleiben unverändert für jeden mit Aktenzugriff sichtbar - die
werden im Feldeinsatz gebraucht. EINGESCHRAENKTE_DOKUMENTTYPEN als zentrale
Stelle für künftige weitere Einschränkungen.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01CVgbozhYmuEhiEJHffRXCV
2026-09-08 10:39:42 +02:00

64 lines
3.0 KiB
Python

import enum
import uuid
from datetime import datetime
from sqlalchemy import ForeignKey, Integer, String
from sqlalchemy.dialects.postgresql import ENUM as PgEnum, TIMESTAMP, UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.db.base import Base
class DokumentTyp(str, enum.Enum):
"""DOC-002: feste Kategorie statt Freitext - macht Dokumente filter-/
wiederfindbar (Nutzer-Vorgabe Modul 10: Prüfprotokolle/Wartungsberichte/
Bedienungsanleitungen/Rechnungen/Zulassungsdokumente)."""
pruefprotokoll = "pruefprotokoll"
wartungsbericht = "wartungsbericht"
bedienungsanleitung = "bedienungsanleitung"
rechnung = "rechnung"
zulassungsdokument = "zulassungsdokument"
sonstiges = "sonstiges"
dokument_typ_pg = PgEnum(DokumentTyp, name="dokument_typ", create_type=False)
# DOC-005: Rechnungen sind finanziell sensibel - nur Materialverantwortliche/
# Leitungsverantwortliche/Administration dürfen sie sehen/herunterladen,
# Mitarbeiter nicht (dürfen sie aber weiterhin hochladen, z.B. direkt beim
# Wareneingang scannen). Andere Dokumenttypen (Prüfprotokolle, Anleitungen,
# ...) bleiben für alle mit Zugriff auf die Akte sichtbar - die werden im
# Feld gebraucht.
EINGESCHRAENKTE_DOKUMENTTYPEN = {DokumentTyp.rechnung}
class Dokument(Base):
"""Roadmap Phase 5 (Modul Dokumente): polymorpher Datei-Anhang an beliebige
Ressource (Objekt, Objektposition, Geräteinstanz, Mangel, Fahrzeugdetails,
Benutzer, ...) - gleiches entitaet_typ/entitaet_id-Muster wie Historie/
Mangel. Datei liegt lokal auf Platte (self-hosted, kein Cloud-Zwang),
speicherpfad ist relativ zu settings.upload_dir."""
__tablename__ = "dokument"
id: Mapped[uuid.UUID] = mapped_column(UUID(as_uuid=True), primary_key=True, default=uuid.uuid4)
entitaet_typ: Mapped[str] = mapped_column(String, nullable=False)
entitaet_id: Mapped[str] = mapped_column(String, nullable=False)
dateiname: Mapped[str] = mapped_column(String, nullable=False)
speicherpfad: Mapped[str] = mapped_column(String, nullable=False)
mime_type: Mapped[str] = mapped_column(String, nullable=False)
groesse_bytes: Mapped[int] = mapped_column(Integer, nullable=False)
# SHA-256 des Dateiinhalts (DOC-001: Duplikat-Erkennung) - hex-codiert, 64
# Zeichen. Vergleich nur innerhalb derselben entitaet_typ/entitaet_id, nicht
# global (gleiche Datei an zwei verschiedenen Objekten ist kein Duplikat).
# Nullable wegen Altbestand vor dieser Migration (Hash nachträglich ohne
# Dateizugriff nicht sinnvoll befüllbar); jeder neue Upload setzt ihn.
dateihash: Mapped[str | None] = mapped_column(String(64))
dokumenttyp: Mapped[DokumentTyp] = mapped_column(
dokument_typ_pg, nullable=False, default=DokumentTyp.sonstiges
)
beschreibung: Mapped[str | None] = mapped_column(String)
hochgeladen_von: Mapped[int] = mapped_column(ForeignKey("benutzer.id"), nullable=False)
hochgeladen_am: Mapped[datetime] = mapped_column(TIMESTAMP(timezone=True), nullable=False)