feat(public-gallery): add public templates gallery API (Tasks 2 & 3)

Implements a no-auth read-only API for the public templates gallery page:
- Schemas in schemas/public_templates.py (PublicFlowTemplate, PublicScriptTemplate, PublicGalleryResponse, PublicFlowDetail, PublicScriptDetail)
- Five endpoints under /api/v1/public/templates: listing, flow detail, script detail, categories with counts, full-text search
- Tree preview truncated to 3 levels max; script_body never exposed
- Rate limited at 30/minute; paginated with category/type/sort filters
- 25 passing integration tests covering feature flags, truncation, script body protection, search, categories, and 404 behavior

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-19 19:12:34 +00:00
parent 836a014a0f
commit bacdb9d466
4 changed files with 906 additions and 0 deletions

View File

@@ -0,0 +1,83 @@
"""Schemas for the public templates gallery. No auth required."""
from datetime import datetime
from typing import Any
from uuid import UUID
from pydantic import BaseModel
class PublicFlowTemplate(BaseModel):
id: UUID
name: str
description: str | None = None
category: str | None = None
tree_type: str
step_count: int
usage_count: int
success_rate: float | None = None
tags: list[str] = []
preview_structure: dict[str, Any] | None = None
created_at: datetime
model_config = {"from_attributes": True}
class PublicScriptTemplate(BaseModel):
id: UUID
name: str
description: str | None = None
category_name: str | None = None
category_icon: str | None = None
complexity: str | None = None
tags: list[str] = []
parameter_count: int = 0
requires_elevation: bool = False
requires_modules: list[str] = []
usage_count: int = 0
is_verified: bool = False
created_at: datetime
model_config = {"from_attributes": True}
class PublicGalleryResponse(BaseModel):
flow_templates: list[PublicFlowTemplate]
script_templates: list[PublicScriptTemplate]
total_flows: int
total_scripts: int
categories: list[str]
domains: list[str]
class PublicFlowDetail(BaseModel):
id: UUID
name: str
description: str | None = None
category: str | None = None
tree_type: str
step_count: int
usage_count: int
success_rate: float | None = None
tags: list[str] = []
preview_structure: dict[str, Any] | None = None
created_at: datetime
model_config = {"from_attributes": True}
class PublicScriptDetail(BaseModel):
id: UUID
name: str
description: str | None = None
category_name: str | None = None
complexity: str | None = None
tags: list[str] = []
parameters: list[dict[str, Any]] = []
requires_elevation: bool = False
requires_modules: list[str] = []
usage_count: int = 0
is_verified: bool = False
created_at: datetime
model_config = {"from_attributes": True}