feat: add governed Scheduling DSAR coverage
This commit is contained in:
@@ -6,8 +6,10 @@ from govoplan_core.core.access import CAPABILITY_AUTH_PERMISSION_EVALUATOR, CAPA
|
||||
from govoplan_core.core.calendar import CAPABILITY_CALENDAR_SCHEDULING
|
||||
from govoplan_core.core.module_guards import drop_table_retirement_provider, persistent_table_uninstall_guard
|
||||
from govoplan_core.core.modules import (
|
||||
CapabilityDocumentation,
|
||||
DocumentationTopic,
|
||||
DocumentationCondition,
|
||||
DocumentationLink,
|
||||
FrontendModule,
|
||||
FrontendRoute,
|
||||
MigrationSpec,
|
||||
@@ -36,10 +38,11 @@ from govoplan_core.core.policy import CAPABILITY_POLICY_SCHEDULING_PARTICIPANT_P
|
||||
from govoplan_core.core.views import ViewSurface
|
||||
from govoplan_core.db.base import Base
|
||||
from govoplan_scheduling.backend.db import models as scheduling_models # noqa: F401 - populate Scheduling ORM metadata
|
||||
from govoplan_scheduling.backend.dsar_provider import SCHEDULING_DSAR_CAPABILITY
|
||||
|
||||
MODULE_ID = "scheduling"
|
||||
MODULE_NAME = "Scheduling"
|
||||
MODULE_VERSION = "0.1.18"
|
||||
MODULE_VERSION = "0.1.19"
|
||||
READ_SCOPE = "scheduling:schedule:read"
|
||||
WRITE_SCOPE = "scheduling:schedule:write"
|
||||
ADMIN_SCOPE = "scheduling:schedule:admin"
|
||||
@@ -102,6 +105,63 @@ DOCUMENTATION = (
|
||||
related_modules=("poll", "evaluation", "calendar", "appointments", "mail", "notifications", "portal"),
|
||||
metadata={"seed": True},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="scheduling.privacy.data-subject-requests",
|
||||
title="Review Scheduling data in a data-subject request",
|
||||
summary="Collect tenant-scoped participation and coordination metadata while leaving Poll responses and Calendar effects with their owners.",
|
||||
body=(
|
||||
"Scheduling's DSAR provider searches the effective tenant by normalized participant email, membership, identity or bound-account references, and namespaced Scheduling request or participant references. "
|
||||
"It isolates the matching participant, request and candidate-slot context, and matching notification envelopes. It does not export Poll or invitation identifiers, participation-gateway state, reusable enrollment links or proof hashes, anonymous-password hashes, Calendar event or hold identifiers, free/busy conflict detail, notification payloads or errors, token material, opaque metadata, or unrelated participants. Poll remains authoritative for actual availability choices and response-retirement evidence; Calendar remains authoritative for event, hold, and synchronization state. "
|
||||
"Decided, handed-off, cancelled, archived, responded, notified, or removed state is retained with a reason. Active shared scheduling content requires coordinated manual review. The provider can anonymize and retire only a participant who has no invitation, response, enrollment, notification, or terminal decision evidence, and revalidates all of those conditions under tenant-bound row locks before acting."
|
||||
),
|
||||
layer="configured",
|
||||
documentation_types=("admin",),
|
||||
audience=("privacy_officer", "scheduling_manager", "records_manager", "operator"),
|
||||
order=5,
|
||||
conditions=(
|
||||
DocumentationCondition(
|
||||
required_modules=("scheduling", "access"),
|
||||
any_scopes=(
|
||||
"access:privacy:read",
|
||||
"access:privacy:manage",
|
||||
"access:privacy:erase",
|
||||
),
|
||||
),
|
||||
),
|
||||
links=(
|
||||
DocumentationLink(
|
||||
label="Data-subject requests",
|
||||
href="/admin?section=tenant-data-subject-requests",
|
||||
kind="runtime",
|
||||
),
|
||||
DocumentationLink(
|
||||
label="Scheduling module guide",
|
||||
href="govoplan-scheduling/README.md",
|
||||
kind="repository",
|
||||
),
|
||||
),
|
||||
related_modules=("access", "audit", "poll", "calendar", "notifications"),
|
||||
metadata={
|
||||
"kind": "workflow",
|
||||
"route": "/admin?section=tenant-data-subject-requests",
|
||||
"screen": "Data-subject requests",
|
||||
"help_contexts": ["admin.privacy.data-subject-requests"],
|
||||
"prerequisites": [
|
||||
"The privacy request and Scheduling selectors have been independently authorized and corroborated.",
|
||||
"The reviewer can coordinate with Poll and Calendar owners when a response or event is involved.",
|
||||
],
|
||||
"steps": [
|
||||
"Run the Scheduling provider search and review participant, request, slot, and notification dispositions.",
|
||||
"Run the Poll provider for actual availability choices and the Calendar provider for event or hold state.",
|
||||
"Retain terminal decision and delivery evidence with its reason.",
|
||||
"Execute anonymization only for an approved participant classified as unengaged after revalidation.",
|
||||
],
|
||||
"limitations": [
|
||||
"Poll choices and invitation evidence are not copied into Scheduling's export.",
|
||||
"Participant erasure remains manual whenever shared responses, delivery, self-enrollment, Calendar effects, or terminal decisions exist.",
|
||||
],
|
||||
},
|
||||
),
|
||||
DocumentationTopic(
|
||||
id="scheduling.find-and-decide-meeting-time",
|
||||
title="Find and decide a meeting time",
|
||||
@@ -265,6 +325,13 @@ def _scheduling_router(context: ModuleContext):
|
||||
return router
|
||||
|
||||
|
||||
def _scheduling_dsar_provider(context: ModuleContext) -> object:
|
||||
del context
|
||||
from govoplan_scheduling.backend.dsar_provider import SchedulingDsarProvider
|
||||
|
||||
return SchedulingDsarProvider()
|
||||
|
||||
|
||||
def _public_tenant_resolver(request: object, session: object) -> str | None:
|
||||
path_params = getattr(request, "path_params", {})
|
||||
request_id = str(path_params.get("request_id") or "").strip()
|
||||
@@ -344,6 +411,7 @@ manifest = ModuleManifest(
|
||||
provides_interfaces=(
|
||||
ModuleInterfaceProvider(name="scheduling.candidate_slots", version=MODULE_VERSION),
|
||||
ModuleInterfaceProvider(name="scheduling.decision_handoff", version=MODULE_VERSION),
|
||||
ModuleInterfaceProvider(name=SCHEDULING_DSAR_CAPABILITY, version="0.1.0"),
|
||||
),
|
||||
requires_interfaces=(
|
||||
ModuleInterfaceRequirement(name="poll.option_ordering", version_min="0.1.11", version_max_exclusive="0.2.0"),
|
||||
@@ -434,6 +502,18 @@ manifest = ModuleManifest(
|
||||
),
|
||||
),
|
||||
documentation=DOCUMENTATION,
|
||||
capability_factories={
|
||||
SCHEDULING_DSAR_CAPABILITY: _scheduling_dsar_provider,
|
||||
},
|
||||
capability_documentation={
|
||||
SCHEDULING_DSAR_CAPABILITY: CapabilityDocumentation(
|
||||
label="Scheduling data-subject request provider",
|
||||
summary="Finds isolated Scheduling participation and coordination metadata and classifies governed erasure actions.",
|
||||
contract_version="0.1.0",
|
||||
documentation_types=("admin",),
|
||||
audience=("privacy_officer", "scheduling_manager", "records_manager"),
|
||||
),
|
||||
},
|
||||
architecture=declared_module_architecture(
|
||||
layer="communication_participation",
|
||||
kind="domain",
|
||||
|
||||
Reference in New Issue
Block a user