141 lines
4.4 KiB
Python
141 lines
4.4 KiB
Python
import logging
|
|
import uuid
|
|
from typing import Any
|
|
|
|
import aiohttp
|
|
from fastapi import HTTPException
|
|
from sqlalchemy import select
|
|
|
|
from models.sql.presentation_layout_code import PresentationLayoutCodeModel
|
|
from models.sql.template import TemplateModel
|
|
from services.database import async_session_maker
|
|
from templates.presentation_layout import PresentationLayoutModel
|
|
from utils.internal_http import internal_request_headers
|
|
|
|
LOGGER = logging.getLogger(__name__)
|
|
|
|
_CUSTOM_COMPILE_URL = "http://localhost/api/template/custom"
|
|
|
|
|
|
async def load_custom_presentation_layout(layout_name: str) -> PresentationLayoutModel:
|
|
"""Load a custom template from the DB and compile layouts via Next.js (no Puppeteer)."""
|
|
if not layout_name.startswith("custom-"):
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail=f"Invalid custom template id: {layout_name}",
|
|
)
|
|
|
|
try:
|
|
template_uuid = uuid.UUID(layout_name.replace("custom-", "", 1))
|
|
except ValueError as exc:
|
|
raise HTTPException(
|
|
status_code=400,
|
|
detail="Invalid custom template ID",
|
|
) from exc
|
|
|
|
LOGGER.info(
|
|
"[template_layout] loading custom template via server compile template=%r",
|
|
layout_name,
|
|
)
|
|
|
|
async with async_session_maker() as session:
|
|
template_meta = await session.get(TemplateModel, template_uuid)
|
|
result = await session.execute(
|
|
select(PresentationLayoutCodeModel).where(
|
|
PresentationLayoutCodeModel.presentation == template_uuid
|
|
)
|
|
)
|
|
layouts_db = result.scalars().all()
|
|
|
|
if not template_meta:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Template '{layout_name}' not found",
|
|
)
|
|
|
|
if not layouts_db:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"No layouts found for template '{layout_name}'",
|
|
)
|
|
|
|
payload = await _compile_custom_layouts_on_nextjs(
|
|
layout_name=layout_name,
|
|
layouts_db=layouts_db,
|
|
)
|
|
|
|
slides = payload.get("slides") or []
|
|
if not slides:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Template '{layout_name}' not found",
|
|
)
|
|
|
|
LOGGER.info(
|
|
"[template_layout] custom server compile OK template=%r slides=%d",
|
|
layout_name,
|
|
len(slides),
|
|
)
|
|
return PresentationLayoutModel(**payload)
|
|
|
|
|
|
async def _compile_custom_layouts_on_nextjs(
|
|
layout_name: str,
|
|
layouts_db: list[PresentationLayoutCodeModel],
|
|
) -> dict[str, Any]:
|
|
body = {
|
|
"group": layout_name,
|
|
"layouts": [
|
|
{
|
|
"layout_id": layout.layout_id,
|
|
"layout_name": layout.layout_name,
|
|
"layout_code": layout.layout_code,
|
|
}
|
|
for layout in layouts_db
|
|
],
|
|
}
|
|
|
|
headers = internal_request_headers()
|
|
|
|
try:
|
|
async with aiohttp.ClientSession() as session:
|
|
async with session.post(
|
|
_CUSTOM_COMPILE_URL, json=body, headers=headers
|
|
) as response:
|
|
if response.status == 200:
|
|
payload = await response.json()
|
|
if isinstance(payload, dict):
|
|
return payload
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail="Custom template compile returned invalid payload",
|
|
)
|
|
|
|
error = await response.text()
|
|
LOGGER.error(
|
|
"[template_layout] custom server compile HTTP %s template=%r body=%s",
|
|
response.status,
|
|
layout_name,
|
|
(error or "")[:600],
|
|
)
|
|
if response.status == 404:
|
|
raise HTTPException(
|
|
status_code=404,
|
|
detail=f"Template '{layout_name}' not found",
|
|
)
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail=f"Failed to compile custom template layouts: {error or response.status}",
|
|
)
|
|
except HTTPException:
|
|
raise
|
|
except aiohttp.ClientError as exc:
|
|
LOGGER.exception(
|
|
"[template_layout] custom server compile request failed template=%r",
|
|
layout_name,
|
|
)
|
|
raise HTTPException(
|
|
status_code=500,
|
|
detail=f"Failed to reach template compile service: {exc}",
|
|
) from exc
|