feat(campaigns): add accountable work assignments
Module Package Release / publish-packages (push) Successful in 14s
Module Package Release / publish-packages (push) Successful in 14s
This commit is contained in:
@@ -4,7 +4,7 @@ from collections import Counter
|
||||
from collections.abc import Mapping, Sequence
|
||||
from datetime import datetime, timezone
|
||||
|
||||
from sqlalchemy import Text, cast, func, or_
|
||||
from sqlalchemy import Text, and_, cast, func, or_
|
||||
from sqlalchemy.orm import Session
|
||||
|
||||
from govoplan_campaign.backend.db.models import (
|
||||
@@ -18,6 +18,8 @@ from govoplan_campaign.backend.db.models import (
|
||||
CampaignSchedule,
|
||||
CampaignShare,
|
||||
CampaignVersion,
|
||||
CampaignWorkAssignment,
|
||||
CampaignWorkAssignmentEvent,
|
||||
ImapAppendAttempt,
|
||||
PostboxDeliveryAttempt,
|
||||
PrintOutputAttempt,
|
||||
@@ -279,6 +281,7 @@ class CampaignDsarProvider:
|
||||
append=append,
|
||||
tenant_id=tenant_id,
|
||||
subject_user_id=subject_user_id,
|
||||
subject_account_id=subject.account_id,
|
||||
campaign_ids=evidence_campaign_ids,
|
||||
version_ids=version_ids,
|
||||
)
|
||||
@@ -643,9 +646,124 @@ class CampaignDsarProvider:
|
||||
append: object,
|
||||
tenant_id: str,
|
||||
subject_user_id: str | None,
|
||||
subject_account_id: str | None,
|
||||
campaign_ids: set[str],
|
||||
version_ids: set[str],
|
||||
) -> None:
|
||||
assignment_filters = []
|
||||
if subject_user_id is not None:
|
||||
assignment_filters.append(
|
||||
CampaignWorkAssignment.assigned_by_user_id == subject_user_id
|
||||
)
|
||||
if subject_account_id is not None:
|
||||
assignment_filters.append(
|
||||
and_(
|
||||
CampaignWorkAssignment.assignee_type == "account",
|
||||
CampaignWorkAssignment.assignee_id == subject_account_id,
|
||||
)
|
||||
)
|
||||
assignment_ids: set[str] = set()
|
||||
if assignment_filters:
|
||||
assignment_rows = _bounded_rows(
|
||||
db.query(CampaignWorkAssignment)
|
||||
.filter(
|
||||
CampaignWorkAssignment.tenant_id == tenant_id,
|
||||
or_(*assignment_filters),
|
||||
)
|
||||
.order_by(CampaignWorkAssignment.id)
|
||||
)
|
||||
assignment_ids = {item.id for item in assignment_rows}
|
||||
for assignment in assignment_rows:
|
||||
match_fields = []
|
||||
if assignment.assigned_by_user_id == subject_user_id:
|
||||
match_fields.append("assigned_by_user_id")
|
||||
if (
|
||||
assignment.assignee_type == "account"
|
||||
and assignment.assignee_id == subject_account_id
|
||||
):
|
||||
match_fields.append("assignee_id")
|
||||
append( # type: ignore[operator]
|
||||
_record(
|
||||
"campaign_work_assignment",
|
||||
assignment.id,
|
||||
"campaign_work_accountability",
|
||||
"Campaign work assignment",
|
||||
{
|
||||
"match_fields": match_fields,
|
||||
"campaign_id": assignment.campaign_id,
|
||||
"campaign_version_id": assignment.campaign_version_id,
|
||||
"purpose": assignment.purpose,
|
||||
"status": assignment.status,
|
||||
"due_at": _iso(assignment.due_at),
|
||||
"assignee_type": assignment.assignee_type,
|
||||
"assignee_id": assignment.assignee_id,
|
||||
"assignee_label_snapshot": assignment.assignee_label_snapshot,
|
||||
"assignee_resolution_state": assignment.assignee_resolution_state,
|
||||
"reference_kind": assignment.reference_kind,
|
||||
"reference_id": assignment.reference_id,
|
||||
"completed_at": _iso(assignment.completed_at),
|
||||
"cancelled_at": _iso(assignment.cancelled_at),
|
||||
},
|
||||
observed_at=assignment.updated_at,
|
||||
source_path=f"/campaigns/{assignment.campaign_id}/work",
|
||||
)
|
||||
)
|
||||
|
||||
event_filters = []
|
||||
if subject_user_id is not None:
|
||||
event_filters.append(
|
||||
CampaignWorkAssignmentEvent.actor_user_id == subject_user_id
|
||||
)
|
||||
if assignment_ids:
|
||||
event_filters.append(
|
||||
CampaignWorkAssignmentEvent.assignment_id.in_(assignment_ids)
|
||||
)
|
||||
if subject_account_id is not None:
|
||||
event_filters.extend(
|
||||
(
|
||||
and_(
|
||||
CampaignWorkAssignmentEvent.assignee_type_snapshot == "account",
|
||||
CampaignWorkAssignmentEvent.assignee_id_snapshot
|
||||
== subject_account_id,
|
||||
),
|
||||
cast(CampaignWorkAssignmentEvent.details, Text).contains(
|
||||
subject_account_id
|
||||
),
|
||||
)
|
||||
)
|
||||
if event_filters:
|
||||
event_rows = _bounded_rows(
|
||||
db.query(CampaignWorkAssignmentEvent)
|
||||
.filter(
|
||||
CampaignWorkAssignmentEvent.tenant_id == tenant_id,
|
||||
or_(*event_filters),
|
||||
)
|
||||
.order_by(CampaignWorkAssignmentEvent.id)
|
||||
)
|
||||
for event in event_rows:
|
||||
append( # type: ignore[operator]
|
||||
_record(
|
||||
"campaign_work_assignment_event",
|
||||
event.id,
|
||||
"campaign_work_accountability_evidence",
|
||||
"Campaign work assignment event",
|
||||
{
|
||||
"campaign_id": event.campaign_id,
|
||||
"assignment_id": event.assignment_id,
|
||||
"event_kind": event.event_kind,
|
||||
"status": event.status_snapshot,
|
||||
"assignee_type": event.assignee_type_snapshot,
|
||||
"assignee_id": event.assignee_id_snapshot,
|
||||
"assignee_label_snapshot": event.assignee_label_snapshot,
|
||||
"resolution_state": event.resolution_state_snapshot,
|
||||
},
|
||||
observed_at=event.created_at,
|
||||
immutable=True,
|
||||
retention_reason="Assignment lifecycle events retain accountable institutional work history.",
|
||||
source_path=f"/campaigns/{event.campaign_id}/work",
|
||||
)
|
||||
)
|
||||
|
||||
if subject_user_id is not None:
|
||||
collaboration_rows = _bounded_rows(
|
||||
db.query(CampaignCollaborationEntry)
|
||||
|
||||
Reference in New Issue
Block a user