import uuid from fastapi import APIRouter, Depends, File, Form, HTTPException, UploadFile, status from fastapi.responses import FileResponse from sqlalchemy.ext.asyncio import AsyncSession from app.api.deps import get_current_user, require_roles from app.db.session import get_db from app.models.auth import RolleTyp from app.models.dokument import Dokument from app.schemas.dokument import DokumentRead, EntitaetTyp from app.services.dokument import ( DateityperlaubtError, DateizugrossError, dateipfad, liste_fuer_entitaet, loesche_dokument, speichere_dokument, ) router = APIRouter() _mitarbeiter_plus = require_roles( RolleTyp.mitarbeiter, RolleTyp.materialverantwortlicher, RolleTyp.leitungsverantwortlicher, RolleTyp.administration, ) _materialverantwortliche = require_roles( RolleTyp.administration, RolleTyp.materialverantwortlicher, RolleTyp.leitungsverantwortlicher ) @router.get("/dokumente", response_model=list[DokumentRead]) async def liste_dokumente( entitaet_typ: EntitaetTyp, entitaet_id: str, db: AsyncSession = Depends(get_db), _=Depends(get_current_user), ) -> list[Dokument]: return await liste_fuer_entitaet(db, entitaet_typ=entitaet_typ, entitaet_id=entitaet_id) @router.post("/dokumente", response_model=DokumentRead, status_code=status.HTTP_201_CREATED) async def lade_dokument_hoch( entitaet_typ: EntitaetTyp = Form(...), entitaet_id: str = Form(...), beschreibung: str | None = Form(None), datei: UploadFile = File(...), db: AsyncSession = Depends(get_db), current_user=Depends(_mitarbeiter_plus), ) -> Dokument: inhalt = await datei.read() try: return await speichere_dokument( db, entitaet_typ=entitaet_typ, entitaet_id=entitaet_id, dateiname=datei.filename or "unbenannt", mime_type=datei.content_type or "application/octet-stream", inhalt=inhalt, beschreibung=beschreibung, hochgeladen_von=current_user.id, ) except DateityperlaubtError as exc: raise HTTPException( status_code=status.HTTP_415_UNSUPPORTED_MEDIA_TYPE, detail=f"Dateityp nicht erlaubt: {exc}" ) from exc except DateizugrossError as exc: raise HTTPException( status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE, detail="Datei zu groß" ) from exc @router.get("/dokumente/{dokument_id}/download") async def lade_dokument_herunter( dokument_id: uuid.UUID, db: AsyncSession = Depends(get_db), _=Depends(get_current_user) ) -> FileResponse: dokument = await db.get(Dokument, dokument_id) if dokument is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Dokument nicht gefunden") pfad = dateipfad(dokument) if not pfad.exists(): raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Datei nicht mehr vorhanden") return FileResponse(pfad, media_type=dokument.mime_type, filename=dokument.dateiname) @router.delete("/dokumente/{dokument_id}", status_code=status.HTTP_204_NO_CONTENT) async def entferne_dokument( dokument_id: uuid.UUID, db: AsyncSession = Depends(get_db), _=Depends(_materialverantwortliche) ) -> None: dokument = await db.get(Dokument, dokument_id) if dokument is None: raise HTTPException(status_code=status.HTTP_404_NOT_FOUND, detail="Dokument nicht gefunden") await loesche_dokument(db, dokument=dokument)