from __future__ import annotations from datetime import datetime from typing import Protocol from sqlalchemy.orm import Session from govoplan_core.core.events import ( EventActorRef, EventObjectRef, EventTenantRef, PlatformEvent, emit_platform_event, ) class AssignmentEventSource(Protocol): id: str tenant_id: str identity_id: str account_id: str | None function_id: str organization_unit_id: str applies_to_subunits: bool source: str delegated_from_assignment_id: str | None acting_for_account_id: str | None valid_from: datetime | None valid_until: datetime | None is_active: bool def emit_assignment_event( session: Session, item: AssignmentEventSource, *, event_type: str, actor_type: str, actor_id: str | None = None, occurred_at: datetime | None = None, ) -> None: event_options = {"occurred_at": occurred_at} if occurred_at else {} emit_platform_event( session, PlatformEvent( type=event_type, module_id="idm", payload={ "identity_id": item.identity_id, "account_id": item.account_id, "function_id": item.function_id, "organization_unit_id": item.organization_unit_id, "applies_to_subunits": item.applies_to_subunits, "source": item.source, "delegated_from_assignment_id": ( item.delegated_from_assignment_id ), "acting_for_account_id": item.acting_for_account_id, "valid_from": ( item.valid_from.isoformat() if item.valid_from is not None else None ), "valid_until": ( item.valid_until.isoformat() if item.valid_until is not None else None ), "is_active": item.is_active, }, actor=EventActorRef(type=actor_type, id=actor_id), tenant=EventTenantRef(id=item.tenant_id), subject=EventObjectRef( type="organization_function", id=item.function_id, ), resource=EventObjectRef( type="organization_function_assignment", id=item.id, ), classification="internal", **event_options, ), ) __all__ = ["emit_assignment_event"]