153 lines
4.5 KiB
Python
153 lines
4.5 KiB
Python
from __future__ import annotations
|
|
|
|
from collections.abc import Mapping, Sequence
|
|
|
|
from sqlalchemy.orm import Session
|
|
|
|
from govoplan_core.auth import ApiPrincipal
|
|
from govoplan_core.core.modules import ModuleContext
|
|
from govoplan_core.core.templates import (
|
|
TemplateCatalogProvider,
|
|
TemplateCompatibility,
|
|
TemplateRef,
|
|
)
|
|
from govoplan_templates.backend.rendering import SqlTemplateRenderer
|
|
from govoplan_templates.backend.service import (
|
|
READ_SCOPE,
|
|
compatibility,
|
|
get_template,
|
|
get_template_revision,
|
|
list_templates,
|
|
template_ref,
|
|
)
|
|
|
|
|
|
class SqlTemplateCatalog(TemplateCatalogProvider):
|
|
def list_templates(
|
|
self,
|
|
session: object,
|
|
principal: object,
|
|
*,
|
|
query: str = "",
|
|
usage: str | None = None,
|
|
template_type: str | None = None,
|
|
locale: str | None = None,
|
|
limit: int = 100,
|
|
) -> Sequence[TemplateRef]:
|
|
sql_session, api_principal = _context(session, principal)
|
|
_require_read(api_principal)
|
|
rows = list_templates(
|
|
sql_session,
|
|
api_principal,
|
|
query=query,
|
|
usage=usage,
|
|
template_type=template_type,
|
|
locale=locale,
|
|
limit=limit,
|
|
)
|
|
return tuple(
|
|
template_ref(
|
|
row,
|
|
get_template_revision(sql_session, row, published_preferred=True),
|
|
read_only=_read_only(api_principal, row.scope_type, row.scope_id),
|
|
)
|
|
for row in rows
|
|
)
|
|
|
|
def get_template(
|
|
self,
|
|
session: object,
|
|
principal: object,
|
|
*,
|
|
template_id: str,
|
|
revision: int | None = None,
|
|
) -> TemplateRef | None:
|
|
sql_session, api_principal = _context(session, principal)
|
|
_require_read(api_principal)
|
|
try:
|
|
row = get_template(sql_session, api_principal, template_id)
|
|
item_revision = get_template_revision(
|
|
sql_session,
|
|
row,
|
|
revision=revision,
|
|
published_preferred=revision is None,
|
|
)
|
|
except ValueError:
|
|
return None
|
|
return template_ref(
|
|
row,
|
|
item_revision,
|
|
read_only=_read_only(api_principal, row.scope_type, row.scope_id),
|
|
)
|
|
|
|
def check_compatibility(
|
|
self,
|
|
session: object,
|
|
principal: object,
|
|
*,
|
|
template_id: str,
|
|
revision: int | None = None,
|
|
usage: str | None = None,
|
|
output_format: str | None = None,
|
|
available_fields: Mapping[str, str] | Sequence[str] = (),
|
|
) -> TemplateCompatibility:
|
|
sql_session, api_principal = _context(session, principal)
|
|
_require_read(api_principal)
|
|
row = get_template(sql_session, api_principal, template_id)
|
|
item_revision = get_template_revision(
|
|
sql_session,
|
|
row,
|
|
revision=revision,
|
|
published_preferred=revision is None,
|
|
)
|
|
return compatibility(
|
|
item_revision,
|
|
usage=usage,
|
|
output_format=output_format,
|
|
available_fields=available_fields,
|
|
)
|
|
|
|
|
|
def catalog_capability(_context: ModuleContext) -> SqlTemplateCatalog:
|
|
return SqlTemplateCatalog()
|
|
|
|
|
|
def renderer_capability(context: ModuleContext) -> SqlTemplateRenderer:
|
|
return SqlTemplateRenderer(context.registry)
|
|
|
|
|
|
def _context(session: object, principal: object) -> tuple[Session, ApiPrincipal]:
|
|
if not isinstance(session, Session):
|
|
raise TypeError("Template catalogue access requires a SQLAlchemy session.")
|
|
if not isinstance(principal, ApiPrincipal):
|
|
raise TypeError("Template catalogue access requires an API principal.")
|
|
return session, principal
|
|
|
|
|
|
def _require_read(principal: ApiPrincipal) -> None:
|
|
if not any(
|
|
principal.has(scope)
|
|
for scope in (
|
|
READ_SCOPE,
|
|
"templates:template:write",
|
|
"templates:template:publish",
|
|
"templates:template:admin",
|
|
)
|
|
):
|
|
raise PermissionError(f"Template catalogue access requires {READ_SCOPE}.")
|
|
|
|
|
|
def _read_only(principal: ApiPrincipal, scope_type: str, scope_id: str | None) -> bool:
|
|
if principal.has("templates:template:admin") or scope_type == "tenant":
|
|
return False
|
|
if scope_type == "user":
|
|
return scope_id != principal.account_id
|
|
return scope_id not in principal.group_ids
|
|
|
|
|
|
__all__ = [
|
|
"SqlTemplateCatalog",
|
|
"catalog_capability",
|
|
"renderer_capability",
|
|
]
|