PMFlow/backend/app/services/signal/signal_source_repair/mixin_persist.py

106 lines
3.2 KiB
Python

"""Persistence and visibility logging helpers for repair workflow."""
from __future__ import annotations
from .shared import (
NotificationService,
SignalSourceRegistry,
get_audit_context,
log_operation,
now_cn_naive,
)
class SignalSourceRepairPersistMixin:
"""Persist repaired links and emit visibility records."""
async def _emit_visibility_records(
self,
*,
tenant_id: int,
project_id: int,
row: SignalSourceRegistry,
signal_id: int,
capture_status: str,
) -> None:
dedupe_key = f"signal-source-repair:{int(tenant_id)}:{int(row.id)}:{int(signal_id)}"
await NotificationService(self.db).create_notifications(
tenant_id=int(tenant_id),
user_ids=await self._active_user_ids(tenant_id=tenant_id),
category="system",
title="AI 已修复历史信号源关联",
content=(
f"项目ID: {int(project_id)}\n"
f"信号源ID: {int(row.id)}\n"
f"signal_id: {int(signal_id)}\n"
f"status: {capture_status or 'relinked'}"
),
source="ai_steward_repair",
entity_type="signal_source_registry",
entity_id=int(row.id),
kind="info",
priority="medium",
status="notified",
recommended_action="view_result",
dedupe_key=dedupe_key,
payload={
"project_id": int(project_id),
"registry_id": int(row.id),
"signal_id": int(signal_id),
"capture_status": capture_status or "relinked",
},
commit=False,
)
context = get_audit_context()
await log_operation(
self.db,
tenant_id=int(tenant_id),
user_id=int(context.user_id or 1),
project_id=int(project_id),
entity_type="signal_source_registry",
entity_id=str(int(row.id)),
action="signal_source_registry.repair_link",
after_data={
"signal_id": int(signal_id),
"capture_status": capture_status or "relinked",
},
remark="repair dirty signal source registry link",
)
async def _persist_registry_link(
self,
*,
tenant_id: int,
project_id: int,
row: SignalSourceRegistry,
signal_id: int,
capture_status: str,
) -> None:
row.signal_id = int(signal_id)
row.last_signal_at = now_cn_naive()
await self._emit_visibility_records(
tenant_id=tenant_id,
project_id=project_id,
row=row,
signal_id=signal_id,
capture_status=capture_status,
)
await self.db.flush()
def _build_item_result(
self,
*,
row: SignalSourceRegistry,
signal_id: int | None,
capture_status: str,
work_item_id: int | None,
route_status: str,
) -> dict[str, object]:
return {
"registry_id": int(row.id),
"signal_id": signal_id,
"capture_status": capture_status,
"work_item_id": work_item_id,
"route_status": route_status,
}