153 lines
5.0 KiB
Python
153 lines
5.0 KiB
Python
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)
|
|
)
|