- Create FastAPI application with async I/O - Implement Redis session storage (fixes session loss on restart) - Add JWT authentication with refresh tokens - Add Microsoft SSO support via MSAL - Copy all processors from src/ (100% reused, no changes) - Create file upload/download endpoints - Create metadata update endpoints - Create template CRUD endpoints - Add SQLAlchemy async database models - Add Docker Compose configuration with Redis Solves critical issues: - Session management: Redis replaces in-memory dicts - Scalability: Async FastAPI + microservices architecture - File handling: Persistent storage with auto-cleanup Key files: - backend/app/main.py - FastAPI entry point - backend/app/core/redis_client.py - Session store - backend/app/core/auth.py - JWT authentication - backend/app/api/* - All REST endpoints - backend/app/processors/ - Reused from src/ Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
124 lines
3.7 KiB
Python
124 lines
3.7 KiB
Python
"""
|
|
Templates API Endpoints
|
|
Handles template CRUD operations and application.
|
|
"""
|
|
|
|
from fastapi import APIRouter, Depends, HTTPException, Request, status
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
from typing import List
|
|
|
|
from app.core.auth import get_current_user_id
|
|
from app.core.database import get_db, AuditLogRepository
|
|
from app.services.metadata_service import get_metadata_service, MetadataService
|
|
from app.models.file import (
|
|
TemplateCreate,
|
|
TemplateResponse,
|
|
TemplateApply,
|
|
TemplatePreview
|
|
)
|
|
|
|
|
|
router = APIRouter()
|
|
|
|
|
|
@router.get("/", response_model=List[TemplateResponse])
|
|
async def list_templates(
|
|
metadata_service: MetadataService = Depends(get_metadata_service),
|
|
user_id: int = Depends(get_current_user_id)
|
|
):
|
|
"""List all available templates."""
|
|
templates = metadata_service.template_manager.list_templates()
|
|
return [TemplateResponse(**template) for template in templates]
|
|
|
|
|
|
@router.post("/", status_code=status.HTTP_201_CREATED)
|
|
async def create_template(
|
|
template_data: TemplateCreate,
|
|
db: AsyncSession = Depends(get_db),
|
|
metadata_service: MetadataService = Depends(get_metadata_service),
|
|
user_id: int = Depends(get_current_user_id)
|
|
):
|
|
"""Create a new template."""
|
|
template = {
|
|
"name": template_data.name,
|
|
"title": template_data.title,
|
|
"subject": template_data.subject,
|
|
"keywords": template_data.keywords,
|
|
"description": template_data.description
|
|
}
|
|
|
|
metadata_service.template_manager.save_template(template)
|
|
|
|
await AuditLogRepository.log_action(
|
|
db,
|
|
user_id=user_id,
|
|
action="template_create",
|
|
details=f"Created template: {template_data.name}"
|
|
)
|
|
|
|
return {"success": True, "message": "Template created", "template": template}
|
|
|
|
|
|
@router.get("/{template_name}", response_model=TemplateResponse)
|
|
async def get_template(
|
|
template_name: str,
|
|
metadata_service: MetadataService = Depends(get_metadata_service),
|
|
user_id: int = Depends(get_current_user_id)
|
|
):
|
|
"""Get template by name."""
|
|
template = metadata_service.template_manager.load_template(template_name)
|
|
if not template:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Template '{template_name}' not found"
|
|
)
|
|
return TemplateResponse(**template)
|
|
|
|
|
|
@router.delete("/{template_name}")
|
|
async def delete_template(
|
|
template_name: str,
|
|
db: AsyncSession = Depends(get_db),
|
|
metadata_service: MetadataService = Depends(get_metadata_service),
|
|
user_id: int = Depends(get_current_user_id)
|
|
):
|
|
"""Delete template."""
|
|
success = metadata_service.template_manager.delete_template(template_name)
|
|
|
|
if not success:
|
|
raise HTTPException(
|
|
status_code=status.HTTP_404_NOT_FOUND,
|
|
detail=f"Template '{template_name}' not found"
|
|
)
|
|
|
|
await AuditLogRepository.log_action(
|
|
db,
|
|
user_id=user_id,
|
|
action="template_delete",
|
|
details=f"Deleted template: {template_name}"
|
|
)
|
|
|
|
return {"success": True, "message": "Template deleted"}
|
|
|
|
|
|
@router.post("/preview")
|
|
async def preview_template(
|
|
preview_data: TemplatePreview,
|
|
metadata_service: MetadataService = Depends(get_metadata_service),
|
|
user_id: int = Depends(get_current_user_id)
|
|
):
|
|
"""Preview template output."""
|
|
template = {
|
|
"title": preview_data.title,
|
|
"subject": preview_data.subject,
|
|
"keywords": preview_data.keywords
|
|
}
|
|
|
|
result = metadata_service.template_manager.apply_template(
|
|
template=template,
|
|
filename=preview_data.sample_filename,
|
|
user="user",
|
|
custom_vars=preview_data.custom_vars or {}
|
|
)
|
|
|
|
return {"preview": result}
|