feat(sdk): API-Referenz Frontend + Backend-Konsolidierung (Shared Utilities, CRUD Factory)
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 32s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 21s
CI / test-python-dsms-gateway (push) Successful in 18s
All checks were successful
CI / go-lint (push) Has been skipped
CI / python-lint (push) Has been skipped
CI / nodejs-lint (push) Has been skipped
CI / test-go-ai-compliance (push) Successful in 32s
CI / test-python-backend-compliance (push) Successful in 30s
CI / test-python-document-crawler (push) Successful in 21s
CI / test-python-dsms-gateway (push) Successful in 18s
- API-Referenz Seite (/sdk/api-docs) mit ~690 Endpoints, Suche, Filter, Modul-Index - Shared db_utils.py (row_to_dict) + tenant_utils Integration in 6 Route-Dateien - CRUD Factory (crud_factory.py) fuer zukuenftige Module - Version-Route Auto-Registration in versioning_utils.py - 1338 Tests bestanden, -232 Zeilen Duplikat-Code Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -18,19 +18,18 @@ import logging
|
||||
from datetime import datetime
|
||||
from typing import Optional, List, Any, Dict
|
||||
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query, Header
|
||||
from fastapi import APIRouter, Depends, HTTPException, Query
|
||||
from pydantic import BaseModel
|
||||
from sqlalchemy import text
|
||||
from sqlalchemy.orm import Session
|
||||
from uuid import UUID
|
||||
|
||||
from classroom_engine.database import get_db
|
||||
from .tenant_utils import get_tenant_id as _get_tenant_id
|
||||
from .db_utils import row_to_dict as _row_to_dict
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
router = APIRouter(prefix="/legal-templates", tags=["legal-templates"])
|
||||
|
||||
DEFAULT_TENANT_ID = "9282a473-5c95-4b3a-bf78-0ecc0ec71d3e"
|
||||
|
||||
VALID_DOCUMENT_TYPES = {
|
||||
# Original types
|
||||
"privacy_policy",
|
||||
@@ -105,30 +104,6 @@ class LegalTemplateUpdate(BaseModel):
|
||||
inspiration_sources: Optional[List[Any]] = None
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Helpers
|
||||
# =============================================================================
|
||||
|
||||
def _row_to_dict(row) -> Dict[str, Any]:
|
||||
result = dict(row._mapping)
|
||||
for key, val in result.items():
|
||||
if isinstance(val, datetime):
|
||||
result[key] = val.isoformat()
|
||||
elif hasattr(val, '__str__') and not isinstance(val, (str, int, float, bool, list, dict, type(None))):
|
||||
result[key] = str(val)
|
||||
return result
|
||||
|
||||
|
||||
def _get_tenant_id(x_tenant_id: Optional[str] = Header(None)) -> str:
|
||||
if x_tenant_id:
|
||||
try:
|
||||
UUID(x_tenant_id)
|
||||
return x_tenant_id
|
||||
except ValueError:
|
||||
pass
|
||||
return DEFAULT_TENANT_ID
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Routes
|
||||
# =============================================================================
|
||||
@@ -142,10 +117,9 @@ async def list_legal_templates(
|
||||
limit: int = Query(50, ge=1, le=200),
|
||||
offset: int = Query(0, ge=0),
|
||||
db: Session = Depends(get_db),
|
||||
x_tenant_id: Optional[str] = Header(None),
|
||||
tenant_id: str = Depends(_get_tenant_id),
|
||||
):
|
||||
"""List legal templates with optional filters."""
|
||||
tenant_id = _get_tenant_id(x_tenant_id)
|
||||
|
||||
where_clauses = ["tenant_id = :tenant_id"]
|
||||
params: Dict[str, Any] = {"tenant_id": tenant_id, "limit": limit, "offset": offset}
|
||||
@@ -192,10 +166,9 @@ async def list_legal_templates(
|
||||
@router.get("/status")
|
||||
async def get_templates_status(
|
||||
db: Session = Depends(get_db),
|
||||
x_tenant_id: Optional[str] = Header(None),
|
||||
tenant_id: str = Depends(_get_tenant_id),
|
||||
):
|
||||
"""Return template counts by document_type."""
|
||||
tenant_id = _get_tenant_id(x_tenant_id)
|
||||
|
||||
total_row = db.execute(
|
||||
text("SELECT COUNT(*) FROM compliance_legal_templates WHERE tenant_id = :tenant_id"),
|
||||
@@ -234,10 +207,9 @@ async def get_templates_status(
|
||||
@router.get("/sources")
|
||||
async def get_template_sources(
|
||||
db: Session = Depends(get_db),
|
||||
x_tenant_id: Optional[str] = Header(None),
|
||||
tenant_id: str = Depends(_get_tenant_id),
|
||||
):
|
||||
"""Return distinct source_name values."""
|
||||
tenant_id = _get_tenant_id(x_tenant_id)
|
||||
|
||||
rows = db.execute(
|
||||
text("SELECT DISTINCT source_name FROM compliance_legal_templates WHERE tenant_id = :tenant_id ORDER BY source_name"),
|
||||
@@ -251,10 +223,9 @@ async def get_template_sources(
|
||||
async def get_legal_template(
|
||||
template_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
x_tenant_id: Optional[str] = Header(None),
|
||||
tenant_id: str = Depends(_get_tenant_id),
|
||||
):
|
||||
"""Fetch a single template by ID."""
|
||||
tenant_id = _get_tenant_id(x_tenant_id)
|
||||
row = db.execute(
|
||||
text("SELECT * FROM compliance_legal_templates WHERE id = :id AND tenant_id = :tenant_id"),
|
||||
{"id": template_id, "tenant_id": tenant_id},
|
||||
@@ -268,10 +239,9 @@ async def get_legal_template(
|
||||
async def create_legal_template(
|
||||
payload: LegalTemplateCreate,
|
||||
db: Session = Depends(get_db),
|
||||
x_tenant_id: Optional[str] = Header(None),
|
||||
tenant_id: str = Depends(_get_tenant_id),
|
||||
):
|
||||
"""Create a new legal template."""
|
||||
tenant_id = _get_tenant_id(x_tenant_id)
|
||||
|
||||
if payload.document_type not in VALID_DOCUMENT_TYPES:
|
||||
raise HTTPException(
|
||||
@@ -335,10 +305,9 @@ async def update_legal_template(
|
||||
template_id: str,
|
||||
payload: LegalTemplateUpdate,
|
||||
db: Session = Depends(get_db),
|
||||
x_tenant_id: Optional[str] = Header(None),
|
||||
tenant_id: str = Depends(_get_tenant_id),
|
||||
):
|
||||
"""Update an existing legal template."""
|
||||
tenant_id = _get_tenant_id(x_tenant_id)
|
||||
|
||||
updates = payload.model_dump(exclude_unset=True)
|
||||
if not updates:
|
||||
@@ -385,10 +354,9 @@ async def update_legal_template(
|
||||
async def delete_legal_template(
|
||||
template_id: str,
|
||||
db: Session = Depends(get_db),
|
||||
x_tenant_id: Optional[str] = Header(None),
|
||||
tenant_id: str = Depends(_get_tenant_id),
|
||||
):
|
||||
"""Delete a legal template."""
|
||||
tenant_id = _get_tenant_id(x_tenant_id)
|
||||
result = db.execute(
|
||||
text("DELETE FROM compliance_legal_templates WHERE id = :id AND tenant_id = :tenant_id"),
|
||||
{"id": template_id, "tenant_id": tenant_id},
|
||||
|
||||
Reference in New Issue
Block a user