Backend: - PdfTemplate model with locale field + UNIQUE(name, locale) constraint - Migration 007: pdf_templates table + template_id FK on generated_pdfs - Template service: CRUD, Jinja2 validation, render preview with sample data - Admin endpoints: CRUD /admin/pdf-templates + POST preview - User endpoint: GET /pdf/templates (active templates list) - pdf_service: resolves template from DB by ID or falls back to default for the appropriate locale - AI generate_pdf tool accepts optional template_id - Seed script + 4 HTML template files: - Basic Report (en/ru) — general-purpose report - Medical Report (en/ru) — health-focused with disclaimers Frontend: - Admin PDF templates page with editor, locale selector, live preview (iframe), template variables reference panel - PDF page: template selector dropdown in generation form - API clients for admin CRUD + user template listing - Sidebar: admin templates link - English + Russian translations Also added Phase 9 (OAuth) and Phase 10 (Rate Limits) placeholders to GeneralPlan. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
52 lines
1.9 KiB
Python
52 lines
1.9 KiB
Python
"""Seed default PDF templates (basic + medical, en + ru)."""
|
||
import asyncio
|
||
from pathlib import Path
|
||
|
||
from sqlalchemy import select
|
||
|
||
from app.database import async_session_factory
|
||
from app.models.pdf_template import PdfTemplate
|
||
|
||
TEMPLATES_DIR = Path(__file__).parent.parent / "app" / "templates" / "pdf" / "seeds"
|
||
|
||
|
||
async def seed_templates() -> None:
|
||
templates = [
|
||
("Basic Report", "en", "Standard report with key information and documents", "basic_en.html", True),
|
||
("Basic Report", "ru", "Стандартный отчёт с ключевой информацией и документами", "basic_ru.html", True),
|
||
("Medical Report", "en", "Medical-styled report with health profile and disclaimers", "medical_en.html", False),
|
||
("Medical Report", "ru", "Медицинский отчёт с профилем здоровья и дисклеймером", "medical_ru.html", False),
|
||
]
|
||
|
||
async with async_session_factory() as db:
|
||
for name, locale, desc, filename, is_default in templates:
|
||
result = await db.execute(
|
||
select(PdfTemplate).where(PdfTemplate.name == name, PdfTemplate.locale == locale)
|
||
)
|
||
if result.scalar_one_or_none():
|
||
print(f" Exists: {name} ({locale})")
|
||
continue
|
||
|
||
html_path = TEMPLATES_DIR / filename
|
||
if not html_path.exists():
|
||
print(f" Missing: {html_path}")
|
||
continue
|
||
|
||
html_content = html_path.read_text(encoding="utf-8")
|
||
template = PdfTemplate(
|
||
name=name,
|
||
locale=locale,
|
||
description=desc,
|
||
html_content=html_content,
|
||
is_default=is_default,
|
||
)
|
||
db.add(template)
|
||
print(f" Created: {name} ({locale})")
|
||
|
||
await db.commit()
|
||
print("Template seeding complete.")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
asyncio.run(seed_templates())
|