Add conditional localized form definitions

This commit is contained in:
2026-08-01 20:57:26 +02:00
parent 343a208894
commit e2033640a1
11 changed files with 1346 additions and 33 deletions
+102 -3
View File
@@ -1,5 +1,7 @@
from __future__ import annotations
from datetime import UTC, datetime
from fastapi import APIRouter, Depends, HTTPException, Query, status
from sqlalchemy.orm import Session
@@ -11,13 +13,19 @@ from govoplan_forms.backend.schemas import (
FormDefinitionHistoryResponse,
FormDefinitionListResponse,
FormDefinitionWriteRequest,
FormPackageImportRequest,
FormPackageRequest,
)
from govoplan_forms.backend.service import (
FormDefinitionStoreError,
definition_from_mapping,
assess_form_definition_fragment,
export_form_definition_fragment,
form_definition_diagnostics,
form_definition_history,
get_form_definition,
list_form_definitions,
import_form_definition_fragment,
record_form_definition,
)
@@ -32,9 +40,11 @@ def _require(principal: ApiPrincipal, scope: str) -> None:
def _error(exc: Exception) -> HTTPException:
message = str(exc)
code = 409 if any(
word in message.casefold() for word in ("conflict", "already", "stale")
) else 400
code = (
409
if any(word in message.casefold() for word in ("conflict", "already", "stale"))
else 400
)
return HTTPException(status_code=code, detail=message)
@@ -117,6 +127,95 @@ def api_get_form_definition(
return item.to_dict()
@router.get("/definitions/{form_id}/diagnostics", response_model=dict[str, object])
def api_form_definition_diagnostics(
form_id: str,
revision: str | None = Query(default=None, max_length=255),
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> dict[str, object]:
_require(principal, READ_SCOPE)
item = get_form_definition(session, principal, form_id=form_id, revision=revision)
if item is None:
raise HTTPException(status_code=404, detail="Form definition not found")
diagnostics = form_definition_diagnostics(item)
return {
"diagnostics": [dict(value) for value in diagnostics],
"error_count": sum(value.get("severity") == "error" for value in diagnostics),
"warning_count": sum(
value.get("severity") == "warning" for value in diagnostics
),
}
@router.get("/definitions/{form_id}/package", response_model=dict[str, object])
def api_export_form_definition_package(
form_id: str,
revision: str | None = Query(default=None, max_length=255),
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> dict[str, object]:
_require(principal, READ_SCOPE)
item = get_form_definition(session, principal, form_id=form_id, revision=revision)
if item is None:
raise HTTPException(status_code=404, detail="Form definition not found")
actor_id = next(
(
str(getattr(principal, name))
for name in ("account_id", "identity_id", "membership_id")
if getattr(principal, name, None)
),
None,
)
return export_form_definition_fragment(
item,
exported_at=datetime.now(UTC),
exported_by=actor_id,
)
@router.post("/packages/assess", response_model=dict[str, object])
def api_assess_form_definition_package(
payload: FormPackageRequest,
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> dict[str, object]:
_require(principal, WRITE_SCOPE)
try:
return assess_form_definition_fragment(
session,
principal,
fragment=payload.fragment,
)
except (FormDefinitionStoreError, InstitutionalContextError) as exc:
raise _error(exc) from exc
@router.post("/packages/import", response_model=dict[str, object])
def api_import_form_definition_package(
payload: FormPackageImportRequest,
session: Session = Depends(get_session),
principal: ApiPrincipal = Depends(get_api_principal),
) -> dict[str, object]:
_require(principal, WRITE_SCOPE)
try:
item = import_form_definition_fragment(
session,
principal,
fragment=payload.fragment,
target_form_id=payload.target_form_id,
target_key=payload.target_key,
expected_revision=payload.expected_revision,
change_reason=payload.change_reason,
recorded_at=payload.recorded_at,
)
session.commit()
except (FormDefinitionStoreError, InstitutionalContextError) as exc:
session.rollback()
raise _error(exc) from exc
return item.to_dict()
@router.get(
"/definitions/{form_id}/history",
response_model=FormDefinitionHistoryResponse,