Files
govoplan-views/src/govoplan_views/backend/manifest.py
T

341 lines
11 KiB
Python

from __future__ import annotations
from pathlib import Path
from govoplan_core.core.access import (
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
)
from govoplan_core.core.module_guards import (
drop_table_retirement_provider,
persistent_table_uninstall_guard,
)
from govoplan_core.core.modules import (
DocumentationTopic,
FrontendModule,
MigrationSpec,
ModuleContext,
ModuleInterfaceProvider,
ModuleManifest,
PermissionDefinition,
RoleTemplate,
)
from govoplan_core.core.views import CAPABILITY_VIEWS_RESOLVER, ViewSurface
from govoplan_core.db.base import Base
from govoplan_views.backend.db import models as view_models
MODULE_ID = "views"
MODULE_NAME = "Views"
MODULE_VERSION = "0.1.0"
DEFINITION_READ_SCOPE = "views:definition:read"
DEFINITION_WRITE_SCOPE = "views:definition:write"
GROUP_DEFINITION_READ_SCOPE = "views:group_definition:read"
GROUP_DEFINITION_WRITE_SCOPE = "views:group_definition:write"
PERSONAL_DEFINITION_READ_SCOPE = "views:personal_definition:read"
PERSONAL_DEFINITION_WRITE_SCOPE = "views:personal_definition:write"
ASSIGNMENT_READ_SCOPE = "views:assignment:read"
ASSIGNMENT_WRITE_SCOPE = "views:assignment:write"
SELECTION_READ_SCOPE = "views:selection:read"
SELECTION_WRITE_SCOPE = "views:selection:write"
SYSTEM_DEFINITION_READ_SCOPE = "views:system_definition:read"
SYSTEM_DEFINITION_WRITE_SCOPE = "views:system_definition:write"
SYSTEM_ASSIGNMENT_READ_SCOPE = "views:system_assignment:read"
SYSTEM_ASSIGNMENT_WRITE_SCOPE = "views:system_assignment:write"
def _permission(
scope: str,
label: str,
description: str,
*,
level: str = "tenant",
) -> PermissionDefinition:
module_id, resource, action = scope.split(":", 2)
return PermissionDefinition(
scope=scope,
label=label,
description=description,
category="Views",
level=level,
module_id=module_id,
resource=resource,
action=action,
)
PERMISSIONS = (
_permission(
DEFINITION_READ_SCOPE,
"View tenant Views",
"Read tenant and inherited View definitions and immutable revisions.",
),
_permission(
DEFINITION_WRITE_SCOPE,
"Manage tenant Views",
"Create, revise, publish, and archive tenant View definitions.",
),
_permission(
GROUP_DEFINITION_READ_SCOPE,
"View group Views",
"Read View definitions owned by groups the account belongs to.",
),
_permission(
GROUP_DEFINITION_WRITE_SCOPE,
"Manage group Views",
"Create, revise, publish, and archive Views owned by the account's groups.",
),
_permission(
PERSONAL_DEFINITION_READ_SCOPE,
"View personal Views",
"Read View definitions owned by the current account.",
),
_permission(
PERSONAL_DEFINITION_WRITE_SCOPE,
"Manage personal Views",
"Create, revise, publish, and archive Views owned by the current account.",
),
_permission(
ASSIGNMENT_READ_SCOPE,
"View tenant View assignments",
"Read tenant, group, and user View assignments.",
),
_permission(
ASSIGNMENT_WRITE_SCOPE,
"Manage tenant View assignments",
"Assign available, default, and required Views within a tenant.",
),
_permission(
SELECTION_READ_SCOPE,
"View effective View",
"Read the effective View projection for the current account.",
),
_permission(
SELECTION_WRITE_SCOPE,
"Select available Views",
"Select or leave an available View unless an administrator requires it.",
),
_permission(
SYSTEM_DEFINITION_READ_SCOPE,
"View system Views",
"Read system-wide View definitions and immutable revisions.",
level="system",
),
_permission(
SYSTEM_DEFINITION_WRITE_SCOPE,
"Manage system Views",
"Create, revise, publish, and archive system-wide View definitions.",
level="system",
),
_permission(
SYSTEM_ASSIGNMENT_READ_SCOPE,
"View system View assignments",
"Read system-wide View assignments.",
level="system",
),
_permission(
SYSTEM_ASSIGNMENT_WRITE_SCOPE,
"Manage system View assignments",
"Assign available, default, and required Views system-wide.",
level="system",
),
)
ROLE_TEMPLATES = (
RoleTemplate(
slug="view_manager",
name="View manager",
description="Design tenant Views and manage their assignments.",
permissions=(
DEFINITION_READ_SCOPE,
DEFINITION_WRITE_SCOPE,
GROUP_DEFINITION_READ_SCOPE,
GROUP_DEFINITION_WRITE_SCOPE,
PERSONAL_DEFINITION_READ_SCOPE,
PERSONAL_DEFINITION_WRITE_SCOPE,
ASSIGNMENT_READ_SCOPE,
ASSIGNMENT_WRITE_SCOPE,
SELECTION_READ_SCOPE,
SELECTION_WRITE_SCOPE,
),
),
RoleTemplate(
slug="view_designer",
name="View designer",
description="Design personal Views and reusable Views for assigned groups.",
permissions=(
GROUP_DEFINITION_READ_SCOPE,
GROUP_DEFINITION_WRITE_SCOPE,
PERSONAL_DEFINITION_READ_SCOPE,
PERSONAL_DEFINITION_WRITE_SCOPE,
SELECTION_READ_SCOPE,
SELECTION_WRITE_SCOPE,
),
),
RoleTemplate(
slug="view_user",
name="View user",
description="Use available Views and design Views for the current account.",
permissions=(
PERSONAL_DEFINITION_READ_SCOPE,
PERSONAL_DEFINITION_WRITE_SCOPE,
SELECTION_READ_SCOPE,
SELECTION_WRITE_SCOPE,
),
default_authenticated=True,
),
)
def _router(context: ModuleContext):
from govoplan_views.backend.runtime import configure_runtime
configure_runtime(registry=context.registry)
from govoplan_views.backend.router import router
return router
def _resolver(context: ModuleContext):
from govoplan_views.backend.capabilities import resolver_capability
from govoplan_views.backend.runtime import configure_runtime
configure_runtime(registry=context.registry)
return resolver_capability(context)
manifest = ModuleManifest(
id=MODULE_ID,
name=MODULE_NAME,
version=MODULE_VERSION,
optional_dependencies=("access", "admin", "policy", "workflow_engine"),
required_capabilities=(
CAPABILITY_AUTH_PRINCIPAL_RESOLVER,
CAPABILITY_AUTH_PERMISSION_EVALUATOR,
),
provides_interfaces=(
ModuleInterfaceProvider(name="views.surface_contract", version="1.0.0"),
ModuleInterfaceProvider(name="views.resolver", version="0.1.0"),
),
permissions=PERMISSIONS,
role_templates=ROLE_TEMPLATES,
frontend=FrontendModule(
module_id=MODULE_ID,
package_name="@govoplan/views-webui",
view_surfaces=(
ViewSurface(
id="views.selector",
module_id=MODULE_ID,
kind="selector",
label="View selector",
description="Always-available selector for leaving optional Views.",
order=1,
required=True,
),
ViewSurface(
id="views.admin.system",
module_id=MODULE_ID,
kind="section",
label="System Views administration",
description="Edit system-wide Views and assignments.",
order=20,
),
ViewSurface(
id="views.admin.tenant",
module_id=MODULE_ID,
kind="section",
label="Tenant Views administration",
description="Edit tenant, group, and user Views and assignments.",
order=30,
),
ViewSurface(
id="views.settings.personal",
module_id=MODULE_ID,
kind="section",
label="Personal and group Views",
description="Design reusable Views owned by the account or its groups.",
order=40,
),
),
),
route_factory=_router,
migration_spec=MigrationSpec(
module_id=MODULE_ID,
metadata=Base.metadata,
script_location=str(Path(__file__).with_name("migrations") / "versions"),
retirement_supported=True,
retirement_provider=drop_table_retirement_provider(
view_models.ViewPreference,
view_models.ViewAssignment,
view_models.ViewRevision,
view_models.ViewDefinition,
label="Views",
),
retirement_notes=(
"Destructive retirement removes View definitions, revisions, "
"assignments, and user selections after a database snapshot."
),
),
uninstall_guard_providers=(
persistent_table_uninstall_guard(
view_models.ViewDefinition,
view_models.ViewAssignment,
label="Views",
),
),
capability_factories={
CAPABILITY_VIEWS_RESOLVER: _resolver,
},
documentation=(
DocumentationTopic(
id="views.interface-projections",
title="Task-focused Views",
summary=(
"Reduce the visible interface to the modules and functions needed "
"for a task without changing authorization."
),
body=(
"Views are versioned presentation projections. Modules announce "
"their selectable surfaces through the platform contract. System "
"and tenant administrators can publish Views and make them "
"available, default, or required at system, tenant, group, and "
"user scope. Required Views retain administration escape surfaces "
"so they can always be inspected and changed. Hidden functions "
"remain protected by their normal permission checks."
),
layer="available",
documentation_types=("admin", "user"),
audience=("administrator", "power_user", "workflow_designer"),
related_modules=("access", "admin", "policy", "workflow_engine"),
order=18,
),
),
)
def get_manifest() -> ModuleManifest:
return manifest
__all__ = [
"ASSIGNMENT_READ_SCOPE",
"ASSIGNMENT_WRITE_SCOPE",
"DEFINITION_READ_SCOPE",
"DEFINITION_WRITE_SCOPE",
"GROUP_DEFINITION_READ_SCOPE",
"GROUP_DEFINITION_WRITE_SCOPE",
"PERSONAL_DEFINITION_READ_SCOPE",
"PERSONAL_DEFINITION_WRITE_SCOPE",
"MODULE_ID",
"MODULE_VERSION",
"SELECTION_READ_SCOPE",
"SELECTION_WRITE_SCOPE",
"SYSTEM_ASSIGNMENT_READ_SCOPE",
"SYSTEM_ASSIGNMENT_WRITE_SCOPE",
"SYSTEM_DEFINITION_READ_SCOPE",
"SYSTEM_DEFINITION_WRITE_SCOPE",
"get_manifest",
"manifest",
]