"""匿名接口,统一放在 /api/public 下,一眼能看出哪些不鉴权""" from typing import Any from fastapi import APIRouter from fastapi.responses import FileResponse from app.api.screens import Service from app.common.response import ApiResponse, success_response from app.core.exceptions import BizException from app.schemas.saved_screen import PublicScreen from app.services.screens import public_page router = APIRouter(prefix="/public", tags=["Public"]) @router.get("/screens/{share_id}") async def get_public_screen( share_id: str, service: Service ) -> ApiResponse[PublicScreen]: """线上版本:返回发布快照,不是草稿;已下线、已删除、不存在都是 404""" summary, snapshot = await service.get_live(share_id) return success_response( PublicScreen( name=summary.name, page=public_page(snapshot.page), version=snapshot.version, published_at=snapshot.published_at, ) ) @router.get("/screens/{share_id}/datasources/{datasource_id}") async def fetch_public_datasource( share_id: str, datasource_id: str, service: Service ) -> ApiResponse[dict[str, Any] | list[Any]]: """线上取数:地址取自已发布快照里的数据源配置,前端只传 ID""" return success_response( await service.fetch_live_datasource(share_id, datasource_id) ) @router.get("/thumbnails/{thumbnail_id}") async def get_thumbnail(thumbnail_id: str, service: Service) -> FileResponse: opened = service.open_thumbnail(thumbnail_id) if opened is None: raise BizException(404, "封面不存在") path, media_type = opened # 每次上传都换新 ID,内容永远不变,可以放心长期缓存 return FileResponse( path, media_type=media_type, headers={"Cache-Control": "public, max-age=31536000, immutable"}, )