Files
govoplan-views/src/govoplan_views/backend/manifest.py
T
zemion 17a808a3ba
Module Package Release / publish-packages (push) Successful in 12s
Release v0.1.16
2026-08-05 19:52:17 +02:00

436 lines
16 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 (
DocumentationLink,
DocumentationTopic,
FrontendModule,
MigrationSpec,
ModuleContext,
ModuleInterfaceProvider,
ModuleManifest,
PermissionDefinition,
RoleTemplate,
)
from govoplan_core.core.provider_governance import declared_module_architecture
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.16"
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. The titlebar eye "
"opens the selector and is accented while a specialized View is "
"active. 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"),
links=(
DocumentationLink(
label="Views administration",
href="/admin?section=system-views",
kind="runtime",
),
DocumentationLink(
label="Views API",
href="/api/v1/views/definitions",
kind="api",
),
),
metadata={
"kind": "guide",
"help_contexts": [
"views.selector",
"views.admin.system",
"views.admin.tenant",
"views.settings.personal",
"views.admin.blocked",
],
},
order=18,
),
DocumentationTopic(
id="views.reference.fields-and-consequences",
title="View fields, assignments, and consequences",
summary=(
"Understand immutable revisions, assignment precedence, required "
"View safeguards, and the difference between visibility and access."
),
body=(
"A View definition owns immutable revisions of visible surface IDs. "
"Publishing makes the latest revision assignable. Available assignments "
"let users opt in, defaults apply until changed, and required assignments "
"cannot be left. User and group assignments take precedence over tenant "
"and system assignments. Pinning preserves one published revision; an "
"unpinned assignment follows later publications. Required Views must keep "
"the selector and administration escape surfaces. Hiding a surface never "
"grants or revokes authorization. The surface catalogue is constrained by "
"the active tenant's module entitlement, so a View cannot expose a module "
"that system policy made unavailable or the tenant disabled. Saved references "
"to such surfaces remain in immutable revisions and are reported as stale. "
"Inherited definitions or assignments must be changed in their owning scope."
),
documentation_types=("admin",),
audience=("administrator", "power_user", "workflow_designer"),
related_modules=("access", "admin", "policy", "workflow_engine"),
links=(
DocumentationLink(
label="Views administration",
href="/admin?section=system-views",
kind="runtime",
),
DocumentationLink(
label="View assignments API",
href="/api/v1/views/assignments",
kind="api",
),
),
metadata={
"kind": "reference",
"help_contexts": [
"views.field.name",
"views.field.description",
"views.field.surfaces",
"views.field.assignment-target",
"views.field.assignment-mode",
"views.field.assignment-priority",
"views.action.publish",
"views.action.archive",
],
"consequence_classes": {
"publish": "Creates the assignable immutable revision used by unpinned assignments.",
"required": "Constrains affected users while retaining selector and administration escape surfaces.",
"archive": "Deactivates optional assignments; required assignments must be removed first.",
"remove_assignment": "Stops the target from inheriting this assignment without deleting the View.",
},
},
order=19,
),
),
architecture=declared_module_architecture(
layer="governance_accountability",
kind="presentation",
maturity="vertical_slice",
documentation_ref="README.md",
test_ref="tests/test_views.py",
known_limits=("A View filters presentation only; modules still vary in the granularity of announced surfaces.",),
owned_concepts=("view definition", "view revision", "view assignment", "view selection"),
non_owned_concepts=("authorization", "module navigation", "workflow definition", "dashboard layout"),
recovery_docs=("README.md",),
security_docs=("README.md",),
),
)
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",
]