bmc_hub/app/modules/website_content/backend/router.py

153 lines
5.0 KiB
Python
Raw Permalink Normal View History

2026-08-28 20:49:55 +02:00
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)
)