- Brand-enforced export pipeline (PPTX/PDF with auto brand fonts/colors/logo) - Client library dashboard with two-level navigation (client grid → detail tabs) - Data retention service with ARQ cron jobs (daily cleanup + weekly purge) - Brand-adaptive UI theme via CSS custom properties (dynamic per client) - Analytics dashboard with overview, usage, quality, and performance metrics Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
58 lines
1.8 KiB
Python
58 lines
1.8 KiB
Python
"""Presentation export endpoints with brand enforcement."""
|
|
import uuid
|
|
from typing import Literal, Optional
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException
|
|
from pydantic import BaseModel
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from models.sql.presentation import PresentationModel
|
|
from models.sql.user import UserModel
|
|
from services import audit_service
|
|
from services.database import get_async_session
|
|
from utils.auth_dependencies import get_current_user
|
|
from utils.export_utils import export_presentation
|
|
|
|
EXPORT_ROUTER = APIRouter(prefix="/api/v1/ppt", tags=["Export"])
|
|
|
|
|
|
class ExportRequest(BaseModel):
|
|
format: Literal["pptx", "pdf"] = "pptx"
|
|
|
|
|
|
@EXPORT_ROUTER.post("/presentation/{presentation_id}/export")
|
|
async def export_with_brand(
|
|
presentation_id: uuid.UUID,
|
|
body: ExportRequest,
|
|
current_user: UserModel = Depends(get_current_user),
|
|
session: AsyncSession = Depends(get_async_session),
|
|
):
|
|
"""Export presentation with automatic brand enforcement.
|
|
|
|
- Loads brand config from the presentation's client
|
|
- Applies brand fonts, colors, logo, and contrast fixes
|
|
- Returns file path for download
|
|
"""
|
|
presentation = await session.get(PresentationModel, presentation_id)
|
|
if not presentation:
|
|
raise HTTPException(status_code=404, detail="Presentation not found")
|
|
|
|
result = await export_presentation(
|
|
presentation_id=presentation.id,
|
|
title=presentation.title or str(presentation.id),
|
|
export_as=body.format,
|
|
client_id=presentation.client_id,
|
|
session=session,
|
|
)
|
|
|
|
# Audit log
|
|
audit_service.log(
|
|
user_id=current_user.id,
|
|
action="export",
|
|
resource_type="presentation",
|
|
resource_id=presentation.id,
|
|
client_id=presentation.client_id,
|
|
details={"format": body.format},
|
|
)
|
|
|
|
return {"path": result.path}
|