feat: add governed DSAR workflow

This commit is contained in:
2026-08-07 14:53:07 +02:00
parent eb0c01c5d2
commit e6457b3f6b
19 changed files with 2239 additions and 2 deletions
+66
View File
@@ -18,7 +18,9 @@ from celery.signals import (
from govoplan_core.core.campaigns import (
CAPABILITY_CAMPAIGNS_DELIVERY_TASKS,
CAPABILITY_CAMPAIGNS_SCHEDULES,
CampaignDeliveryTaskProvider,
CampaignScheduleProvider,
)
from govoplan_core.core.calendar import (
CAPABILITY_CALENDAR_OUTBOX,
@@ -100,6 +102,7 @@ celery.conf.update(
task_routes={
"govoplan.campaigns.send_email": {"queue": "send_email"},
"govoplan.campaigns.append_sent": {"queue": "append_sent"},
"govoplan.campaigns.dispatch_schedules": {"queue": "default"},
"govoplan.notifications.deliver": {"queue": "notifications"},
"govoplan.notifications.deliver_pending": {"queue": "notifications"},
"govoplan.mail.dispatch_outbox": {"queue": "mail"},
@@ -132,6 +135,11 @@ celery.conf.update(
"schedule": 60.0,
"args": (None, 100),
},
"campaign-schedules-every-minute": {
"task": "govoplan.campaigns.dispatch_schedules",
"schedule": 60.0,
"args": (None, 50),
},
"mail-outbox-every-five-seconds": {
"task": "govoplan.mail.dispatch_outbox",
"schedule": 5.0,
@@ -555,6 +563,18 @@ def _campaign_delivery_tasks(
return capability
def _campaign_schedules(
registry: PlatformRegistry | None = None,
) -> CampaignScheduleProvider | None:
registry = registry or _platform_registry()
if not registry.has_capability(CAPABILITY_CAMPAIGNS_SCHEDULES):
return None
capability = registry.require_capability(CAPABILITY_CAMPAIGNS_SCHEDULES)
if not isinstance(capability, CampaignScheduleProvider):
raise RuntimeError("Campaign schedule capability is invalid")
return capability
def _notification_dispatch(
registry: PlatformRegistry | None = None,
) -> NotificationDispatchProvider:
@@ -699,6 +719,52 @@ def _idm_assignment_lifecycle(
return capability
@celery.task(
name="govoplan.campaigns.dispatch_schedules",
bind=True,
max_retries=0,
)
def dispatch_campaign_schedules(
self,
tenant_id: str | None = None,
limit: int = 50,
):
"""Prepare due campaign drafts; delivery always remains a separate action."""
from govoplan_core.db.session import get_database
with get_database().SessionLocal() as session:
registry = _platform_registry()
defaults = {
"selected": 0,
"prepared": 0,
"failed": 0,
"completed": 0,
"coalesced": 0,
"campaign_ids": [],
"operator_actions": [],
}
if not registry.has_capability(CAPABILITY_CAMPAIGNS_SCHEDULES):
return defaults
result = _run_tenant_worker_batches(
registry,
session,
capability_name=CAPABILITY_CAMPAIGNS_SCHEDULES,
tenant_id=tenant_id,
operation=lambda effective_tenant_id: _campaign_schedules(
registry
).dispatch_due( # type: ignore[union-attr]
session,
tenant_id=effective_tenant_id,
limit=limit,
),
defaults=defaults,
work_state="new",
)
session.commit()
return result
@celery.task(name="govoplan.campaigns.send_email", bind=True, max_retries=0)
def send_email(self, job_id: str):
"""Send one explicitly queued campaign job.