intermittent commit

This commit is contained in:
2026-07-14 13:22:11 +02:00
parent 3444a4920f
commit 6163c8f733
24 changed files with 2367 additions and 0 deletions

View File

@@ -0,0 +1,116 @@
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 MigrationSpec, ModuleContext, ModuleInterfaceProvider, ModuleManifest, PermissionDefinition, RoleTemplate
from govoplan_core.core.notifications import CAPABILITY_NOTIFICATIONS_DISPATCH
from govoplan_core.db.base import Base
from govoplan_notifications.backend.db import models as notification_models # noqa: F401 - populate Notifications ORM metadata
MODULE_ID = "notifications"
MODULE_NAME = "Notifications"
MODULE_VERSION = "0.1.8"
READ_SCOPE = "notifications:notification:read"
WRITE_SCOPE = "notifications:notification:write"
DISPATCH_SCOPE = "notifications:delivery:dispatch"
ADMIN_SCOPE = "notifications:notification:admin"
def _permission(scope: str, label: str, description: str) -> PermissionDefinition:
module_id, resource, action = scope.split(":", 2)
return PermissionDefinition(
scope=scope,
label=label,
description=description,
category="Notifications",
level="tenant",
module_id=module_id,
resource=resource,
action=action,
)
PERMISSIONS = (
_permission(READ_SCOPE, "View notifications", "Read notification inbox, outbox, and delivery state."),
_permission(WRITE_SCOPE, "Manage notifications", "Create, update, cancel, read, and acknowledge notifications."),
_permission(DISPATCH_SCOPE, "Dispatch notifications", "Run notification delivery attempts and delivery workers."),
_permission(ADMIN_SCOPE, "Administer notifications", "Manage tenant-wide notification delivery state."),
)
ROLE_TEMPLATES = (
RoleTemplate(
slug="notification_manager",
name="Notification manager",
description="Manage and dispatch tenant notifications.",
permissions=(READ_SCOPE, WRITE_SCOPE, DISPATCH_SCOPE),
),
RoleTemplate(
slug="notification_viewer",
name="Notification viewer",
description="Read notification state.",
permissions=(READ_SCOPE,),
),
)
def _tenant_summary(session, tenant_id: str) -> dict[str, int]:
from govoplan_notifications.backend.db.models import NotificationMessage
return {
"notifications": session.query(NotificationMessage).filter(NotificationMessage.tenant_id == tenant_id, NotificationMessage.deleted_at.is_(None)).count(),
"pending_notifications": session.query(NotificationMessage).filter(NotificationMessage.tenant_id == tenant_id, NotificationMessage.status.in_(("pending", "queued", "failed")), NotificationMessage.deleted_at.is_(None)).count(),
}
def _notifications_router(_context: ModuleContext):
from govoplan_notifications.backend.router import router
return router
manifest = ModuleManifest(
id=MODULE_ID,
name=MODULE_NAME,
version=MODULE_VERSION,
required_capabilities=(CAPABILITY_AUTH_PRINCIPAL_RESOLVER, CAPABILITY_AUTH_PERMISSION_EVALUATOR),
optional_dependencies=("mail", "tasks", "portal", "workflow", "calendar", "scheduling"),
provides_interfaces=(ModuleInterfaceProvider(name="notifications.dispatch", version="0.1.8"),),
permissions=PERMISSIONS,
role_templates=ROLE_TEMPLATES,
route_factory=_notifications_router,
tenant_summary_providers=(_tenant_summary,),
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(
notification_models.NotificationMessage,
notification_models.NotificationDeliveryAttempt,
notification_models.NotificationPreference,
label="Notifications",
),
retirement_notes="Destructive retirement drops notification-owned database tables after the installer captures a database snapshot.",
),
uninstall_guard_providers=(
persistent_table_uninstall_guard(
notification_models.NotificationMessage,
notification_models.NotificationDeliveryAttempt,
notification_models.NotificationPreference,
label="Notifications",
),
),
capability_factories={
CAPABILITY_NOTIFICATIONS_DISPATCH: lambda context: __import__(
"govoplan_notifications.backend.capabilities",
fromlist=["dispatch_capability"],
).dispatch_capability(context),
},
)
def get_manifest() -> ModuleManifest:
return manifest