106 lines
3.2 KiB
Python
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,
|
|
}
|