Complete effective assignment expiry lifecycle

This commit is contained in:
2026-07-31 18:07:36 +02:00
parent d1c5738ca8
commit f025b0c25b
13 changed files with 619 additions and 59 deletions
+27 -50
View File
@@ -16,13 +16,6 @@ from govoplan_core.core.configuration_control import (
ensure_configuration_change_allowed,
record_configuration_change_applied,
)
from govoplan_core.core.events import (
EventActorRef,
EventObjectRef,
EventTenantRef,
PlatformEvent,
emit_platform_event,
)
from govoplan_core.core.principal_cache import invalidate_auth_principals
from govoplan_core.core.identity import (
CAPABILITY_IDENTITY_DIRECTORY,
@@ -42,11 +35,13 @@ from govoplan_core.security.time import utc_now
from govoplan_idm.backend.assignment_transitions import (
AssignmentMutationPlan,
AssignmentTransitionError,
assignment_is_expired,
lifecycle_event_types,
plan_assignment_update,
validate_assignment_shape,
validate_assignment_source_rules,
)
from govoplan_idm.backend.assignment_events import emit_assignment_event
from govoplan_idm.backend.db.models import IdmOrganizationFunctionAssignment, IdmTenantSettings
from .schemas import (
@@ -436,45 +431,12 @@ def _publish_assignment_event(
*,
event_type: str,
) -> None:
emit_platform_event(
emit_assignment_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,
"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="account", id=principal.account_id),
tenant=EventTenantRef(id=principal.tenant_id),
subject=EventObjectRef(
type="organization_function",
id=item.function_id,
),
resource=EventObjectRef(
type="organization_function_assignment",
id=item.id,
),
classification="internal",
)
item,
event_type=event_type,
actor_type="account",
actor_id=principal.account_id,
)
@@ -621,6 +583,15 @@ def create_organization_function_assignment(
result,
event_type="idm.function_assignment.created.v1",
)
now = utc_now()
if assignment_is_expired(item, now=now):
item.expired_event_at = now
_publish_assignment_event(
session,
principal,
_assignment_item(item),
event_type="idm.function_assignment.expired.v1",
)
_commit_assignment_transaction(session, item)
return _assignment_item(item)
@@ -643,6 +614,16 @@ def update_organization_function_assignment(
tenant_id=tenant_id,
)
plan.apply(item)
now = utc_now()
event_types = lifecycle_event_types(
plan.before,
plan.after,
now=now,
)
if "idm.function_assignment.expired.v1" in event_types:
item.expired_event_at = now
elif not assignment_is_expired(item, now=now):
item.expired_event_at = None
_flush_assignment(session, item)
result = _assignment_item(item)
after = result.model_dump(mode="json")
@@ -656,11 +637,7 @@ def update_organization_function_assignment(
before=before,
after=after,
)
for event_type in lifecycle_event_types(
plan.before,
plan.after,
now=utc_now(),
):
for event_type in event_types:
_publish_assignment_event(
session,
principal,
@@ -37,6 +37,7 @@ class OrganizationFunctionAssignmentItem(BaseModel):
acting_for_account_id: str | None = None
valid_from: datetime | None = None
valid_until: datetime | None = None
expired_event_at: datetime | None = None
is_active: bool
settings: dict[str, Any]
created_at: datetime