from __future__ import annotations from io import BytesIO from fastapi import APIRouter, Depends, File, HTTPException, Query, UploadFile from fastapi.responses import Response from PIL import Image, UnidentifiedImageError from app.core.auth_dependencies import require_permission from app.modules.website_content.backend.schemas import ( CompleteOperation, CustomerReferenceCreate, CustomerReferenceUpdate, IncidentCreate, IncidentUpdate, OperationCreate, OperationUpdate, ) from app.modules.website_content.backend.service import NotFoundError, WebsiteContentAPIError, website_content_service router = APIRouter() ALLOWED_LOGOS = {"image/png", "image/jpeg", "image/webp", "image/gif"} MAX_LOGO_BYTES = 5 * 1024 * 1024 def call_service(method, *args, **kwargs): try: return method(*args, **kwargs) except NotFoundError: raise HTTPException(status_code=404, detail="Indholdet blev ikke fundet") except WebsiteContentAPIError as exc: raise HTTPException(status_code=503, detail=str(exc)) @router.get("/customers") async def list_customers( include_hidden: bool = Query(True), _user: dict = Depends(require_permission("website_content.view")), ): return call_service(website_content_service.list, "customers", include_hidden) @router.post("/customers", status_code=201) async def create_customer( payload: CustomerReferenceCreate, _user: dict = Depends(require_permission("website_content.edit")), ): return call_service(website_content_service.create, "customers", payload.model_dump()) @router.patch("/customers/{item_id}") async def update_customer( item_id: int, payload: CustomerReferenceUpdate, _user: dict = Depends(require_permission("website_content.edit")), ): return call_service( website_content_service.update, "customers", item_id, payload.model_dump(exclude_unset=True) ) @router.post("/customers/{item_id}/logo") async def upload_customer_logo( item_id: int, logo: UploadFile = File(...), _user: dict = Depends(require_permission("website_content.edit")), ): if logo.content_type not in ALLOWED_LOGOS: raise HTTPException(status_code=415, detail="Logo skal være PNG, JPEG, WebP eller GIF") content = await logo.read(MAX_LOGO_BYTES + 1) if not content or len(content) > MAX_LOGO_BYTES: raise HTTPException(status_code=413, detail="Logo må højst fylde 5 MB") try: image = Image.open(BytesIO(content)) image.verify() except (UnidentifiedImageError, OSError): raise HTTPException(status_code=422, detail="Filen er ikke et gyldigt billede") return call_service(website_content_service.upload_logo, item_id, content, logo.content_type) @router.get("/customers/{item_id}/logo") async def preview_customer_logo( item_id: int, _user: dict = Depends(require_permission("website_content.view")), ): content, mime_type = call_service(website_content_service.logo, item_id) return Response(content=content, media_type=mime_type, headers={"Cache-Control": "private, max-age=60"}) @router.get("/operations") async def list_operations( include_hidden: bool = Query(True), _user: dict = Depends(require_permission("website_content.view")), ): return call_service(website_content_service.list, "operations", include_hidden) @router.post("/operations", status_code=201) async def create_operation( payload: OperationCreate, _user: dict = Depends(require_permission("website_content.edit")), ): return call_service(website_content_service.create, "operations", payload.model_dump()) @router.patch("/operations/{item_id}") async def update_operation( item_id: int, payload: OperationUpdate, _user: dict = Depends(require_permission("website_content.edit")), ): return call_service( website_content_service.update, "operations", item_id, payload.model_dump(exclude_unset=True) ) @router.post("/operations/{item_id}/complete", status_code=201) async def complete_operation( item_id: int, payload: CompleteOperation, _user: dict = Depends(require_permission("website_content.edit")), ): return call_service( website_content_service.complete_operation, item_id, payload.ends_at, payload.is_public ) @router.get("/incidents") async def list_incidents( include_hidden: bool = Query(True), _user: dict = Depends(require_permission("website_content.view")), ): return call_service(website_content_service.list, "incidents", include_hidden) @router.post("/incidents", status_code=201) async def create_incident( payload: IncidentCreate, _user: dict = Depends(require_permission("website_content.edit")), ): return call_service(website_content_service.create, "incidents", payload.model_dump()) @router.patch("/incidents/{item_id}") async def update_incident( item_id: int, payload: IncidentUpdate, _user: dict = Depends(require_permission("website_content.edit")), ): return call_service( website_content_service.update, "incidents", item_id, payload.model_dump(exclude_unset=True) )