Files
MABEA/backend/app/models/dokument.py
T
patrickandClaude Sonnet 5 707701d897
CI / backend-tests (push) Failing after 2m11s
CI / frontend-build (push) Successful in 20s
feat(dokumente): DOC-001 Duplikat-Erkennung + Fix Online-Ansicht (Popup-Blocker)
Duplikat-Erkennung: SHA-256-Hash je Dokument (Migration 0024), Upload wird
mit 409 abgelehnt, wenn dieselbe Datei bereits an derselben Entität liegt
(Vergleich bewusst pro Entität, nicht global - gleiche Datei an zwei
Objekten ist kein Duplikat). Frontend zeigt die Backend-Fehlermeldung
(Dateiname/Datum des bestehenden Dokuments) statt generischem Text.

Nebenbei gefunden+gefixt: "Ansehen" (PDF/JPG/PNG online statt Download)
funktionierte nicht zuverlässig, weil window.open() erst nach einem await
fetch() aufgerufen wurde - Popup-Blocker werten das nicht mehr als direkte
Nutzeraktion. Jetzt öffnet der Tab sofort synchron, die Blob-URL wird
nachgeladen.

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

36 lines
1.8 KiB
Python

import uuid
from datetime import datetime
from sqlalchemy import ForeignKey, Integer, String
from sqlalchemy.dialects.postgresql import TIMESTAMP, UUID
from sqlalchemy.orm import Mapped, mapped_column
from app.db.base import Base
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))
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)