"""Compatibility facade for privacy retention policy. Policy-owned behavior is provided by ``govoplan-policy`` through the ``policy.privacyRetention`` capability. This module keeps legacy imports stable without importing policy implementation code from core. """ from __future__ import annotations from dataclasses import dataclass from typing import Any, Mapping from govoplan_core.core.policy import CAPABILITY_POLICY_PRIVACY_RETENTION, PrivacyRetentionService from govoplan_core.core.runtime import get_registry from govoplan_core.privacy.schemas import ( RETENTION_DAY_KEYS as RETENTION_DAY_KEYS, RETENTION_POLICY_FIELD_KEYS, default_allow_lower_level_limits as default_allow_lower_level_limits, normalize_allow_lower_level_limits, ) PRIVACY_POLICY_SETTINGS_KEY = "privacy_retention_policy" _DEFAULT_POLICY = { "store_raw_campaign_json": True, "raw_campaign_json_retention_days": None, "generated_eml_retention_days": None, "stored_report_detail_retention_days": None, "mock_mailbox_retention_days": None, "audit_detail_retention_days": None, "audit_detail_level": "full", } _EXPORTS = ( "PRIVACY_POLICY_SETTINGS_KEY", "RETENTION_DAY_KEYS", "RETENTION_POLICY_FIELD_KEYS", "PrivacyRetentionPolicy", "PrivacyRetentionPolicyPatch", "PrivacyPolicyError", "default_allow_lower_level_limits", "privacy_policy_from_settings", "privacy_policy_from_session", "set_privacy_policy", "effective_privacy_policy", "parent_privacy_policy", "effective_privacy_policy_sources", "parent_privacy_policy_sources", "get_privacy_policy_for_scope", "set_privacy_policy_for_scope", "sanitize_audit_details_for_policy", "apply_retention_policy", ) class PrivacyPolicyError(RuntimeError): pass class _UnavailablePolicyModel: def __init__(self, *args: Any, **kwargs: Any) -> None: del args, kwargs _raise_unavailable() @classmethod def model_validate(cls, value: Any) -> Any: del value _raise_unavailable() PrivacyRetentionPolicy = _UnavailablePolicyModel PrivacyRetentionPolicyPatch = _UnavailablePolicyModel @dataclass(frozen=True, slots=True) class _SystemPrivacyPolicy: payload: Mapping[str, Any] def model_dump(self, *args: Any, **kwargs: Any) -> dict[str, Any]: del args, kwargs return dict(self.payload) def _raise_unavailable() -> None: raise PrivacyPolicyError("Privacy retention policy requires the active govoplan-policy module.") def _runtime_service() -> PrivacyRetentionService | None: registry = get_registry() if registry is None or not hasattr(registry, "has_capability") or not registry.has_capability(CAPABILITY_POLICY_PRIVACY_RETENTION): return None capability = registry.require_capability(CAPABILITY_POLICY_PRIVACY_RETENTION) if not isinstance(capability, PrivacyRetentionService): raise PrivacyPolicyError("Privacy retention policy capability is invalid") return capability def _service() -> PrivacyRetentionService: service = _runtime_service() if service is None: _raise_unavailable() return service def _settings_payload(item: object) -> dict[str, Any]: settings = getattr(item, "settings", None) return dict(settings or {}) if isinstance(settings, Mapping) else {} def _policy_data(settings_payload: Mapping[str, Any] | None) -> dict[str, Any]: raw = settings_payload.get(PRIVACY_POLICY_SETTINGS_KEY) if isinstance(settings_payload, Mapping) else None if not isinstance(raw, Mapping): raw = {} payload = dict(_DEFAULT_POLICY) for key in RETENTION_POLICY_FIELD_KEYS: if key in raw: payload[key] = raw[key] payload["allow_lower_level_limits"] = normalize_allow_lower_level_limits(raw.get("allow_lower_level_limits"), fill_defaults=True) return payload def privacy_policy_from_settings(item: object) -> Any: service = _runtime_service() if service is not None: return service.privacy_policy_from_settings(item) return _SystemPrivacyPolicy(_policy_data(_settings_payload(item))) def privacy_policy_from_session(*args: Any, **kwargs: Any) -> Any: return _service().privacy_policy_from_session(*args, **kwargs) def set_privacy_policy(item: object, policy: Any) -> Any: service = _runtime_service() if service is not None: return service.set_privacy_policy(item, policy) value = policy.model_dump(mode="json") if hasattr(policy, "model_dump") else dict(policy or {}) next_settings = _settings_payload(item) next_settings[PRIVACY_POLICY_SETTINGS_KEY] = _policy_data({PRIVACY_POLICY_SETTINGS_KEY: value}) setattr(item, "settings", next_settings) return _SystemPrivacyPolicy(next_settings[PRIVACY_POLICY_SETTINGS_KEY]) def effective_privacy_policy(*args: Any, **kwargs: Any) -> Any: return _service().effective_privacy_policy(*args, **kwargs) def parent_privacy_policy(*args: Any, **kwargs: Any) -> Any: return _service().parent_privacy_policy(*args, **kwargs) def effective_privacy_policy_sources(*args: Any, **kwargs: Any) -> Any: return _service().effective_privacy_policy_sources(*args, **kwargs) def parent_privacy_policy_sources(*args: Any, **kwargs: Any) -> Any: return _service().parent_privacy_policy_sources(*args, **kwargs) def get_privacy_policy_for_scope(*args: Any, **kwargs: Any) -> Any: return _service().get_privacy_policy_for_scope(*args, **kwargs) def set_privacy_policy_for_scope(*args: Any, **kwargs: Any) -> Any: return _service().set_privacy_policy_for_scope(*args, **kwargs) def sanitize_audit_details_for_policy(*args: Any, **kwargs: Any) -> dict[str, Any]: service = _runtime_service() if service is not None: return dict(service.sanitize_audit_details_for_policy(*args, **kwargs)) details = args[1] if len(args) > 1 else kwargs.get("details") return dict(details or {}) def apply_retention_policy(*args: Any, **kwargs: Any) -> Any: return _service().apply_retention_policy(*args, **kwargs) __all__ = list(_EXPORTS)