ForcePilot/backend/server/routers/channels/doctor_router.py
Kris bba1775220 refactor(channel-router): 清理冗余空行并优化代码结构
本次提交包含多类优化:
1.  移除多个路由文件中多余的空导入行,统一代码格式
2.  重构Query参数定义,将长参数拆分为多行提升可读性
3.  新增多个业务端点:
    - 渠道能力画像矩阵查询CAP-03
    - 配对审批计数接口用于待办角标
    - 批量查询对端目录资料接口
    - 向导扫码登录相关端点
    - 会话实时事件SSE推送端点
    - 工作台待办统计接口
4.  完善异常处理逻辑,补充OperationTimeoutError导入并优化NotImplementedError的细节返回
5.  调整路由导入顺序,修复动态路由路径冲突隐患
6.  更新文档注释与接口清单,修正部分接口描述细节
2026-07-06 20:50:03 +08:00

240 lines
9.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

"""配置诊断 Router。
路由分一类:
- 诊断端点GET /checks / GET /checks/{check_id} / POST /checks/run-all /
POST /checks/{check_id}/run / POST /checks/{check_id}/repair/preview /
POST /checks/{check_id}/repair控制面操作通过 DoctorPort 走
控制面管道,统一执行认证 / 权限 / 限流 / 分派 / 审计五阶段(模板 A
失败时通过 ``raiseOnControlFailure`` 反向重构异常交由全局 handler 映射。
端口装配:
- ``use_cases.doctor`` 字段绑定到 ``ChannelControlService`` 同一实例
(窄端口依赖,由 ``infrastructure/channel_use_cases.py`` 装配)
鉴权策略:
- 全部端点使用 ``get_admin_user`` 依赖(管理员角色校验)
- 无 Webhook 入站端点,无匿名访问
``check_id`` 校验策略:
- 路径参数声明为 ``str``(无 Pydantic 注解),格式校验
``^[A-Za-z0-9_-]+$``)统一在 ``DoctorHandler.match_pattern``
入口经模块级 ``_validateCheckId`` 函数执行,确保非法格式也经
控制面管道五阶段AC-32 失败审计),避免 Router 层
``StringConstraints`` 注解返回 422 与管道内 ``ValidationError``
返回 400 的错误码不一致P2 修正)。
"""
from __future__ import annotations
from typing import Any
from fastapi import APIRouter, Depends, Request
from yuxi.channels.contract.dtos.channel import ChannelType
from yuxi.storage.postgres.models_business import User
from server.routers.channels import (
build_operator,
get_channel_use_cases,
raiseOnControlFailure,
serialize_control_data,
)
from server.utils.auth_middleware import get_admin_user
doctor_router = APIRouter(tags=["channels-doctor"])
@doctor_router.get(
"/{channel_type}/{account_id}/doctor/checks",
response_model=dict,
)
async def list_doctor_checks(
channel_type: ChannelType,
account_id: str,
request: Request,
use_cases=Depends(get_channel_use_cases),
current_user: User = Depends(get_admin_user),
) -> dict[str, Any]:
"""查询诊断检查项列表DOC-CHECK-01FR-17
对应控制面操作 ``doctor/checks``(由 ``ChannelControlService.getDoctorChecks``
内部构造 ``ControlCmd`` 并委托 ``_executeControl`` 执行控制面管道)。
返回指定渠道账户的诊断检查项列表,包括插件声明的检查项与框架级
默认检查项。渠道未注册诊断适配器时返回 501。
"""
operator = build_operator(current_user, request)
result = await use_cases.doctor.getDoctorChecks(
channel_type=channel_type,
account_id=account_id,
operator=operator,
)
raiseOnControlFailure(result)
return {"success": True, "data": serialize_control_data(result.data)}
@doctor_router.post(
"/{channel_type}/{account_id}/doctor/checks/run-all",
response_model=dict,
)
async def run_all_doctor_checks(
channel_type: ChannelType,
account_id: str,
request: Request,
use_cases=Depends(get_channel_use_cases),
current_user: User = Depends(get_admin_user),
) -> dict[str, Any]:
"""运行全部诊断检查DOC-CHECK-03FR-17AC-19 / AC-64
对应控制面操作 ``doctor/run``(由 ``ChannelControlService.runDoctorChecks``
内部构造 ``ControlCmd`` 并委托 ``_executeControl`` 执行控制面管道)。
执行 6 项框架级默认检查credential_validity / required_permissions /
webhook_registered / webhook_reachable / rate_limit_status /
whitelist_status+ 适配器自定义检查项,聚合为诊断报告(含整体健康度、
检查项结果列表、已应用迁移列表)。单项检查异常不中断整体流程
_safeRunItem 捕获非 DependencyError 降级为"未通过 + ERROR")。
"""
operator = build_operator(current_user, request)
result = await use_cases.doctor.runDoctorChecks(
channel_type=channel_type,
account_id=account_id,
operator=operator,
)
raiseOnControlFailure(result)
return {"success": True, "data": serialize_control_data(result.data)}
@doctor_router.get(
"/{channel_type}/{account_id}/doctor/checks/{check_id}",
response_model=dict,
)
async def get_doctor_check(
channel_type: ChannelType,
account_id: str,
check_id: str,
request: Request,
use_cases=Depends(get_channel_use_cases),
current_user: User = Depends(get_admin_user),
) -> dict[str, Any]:
"""查询单项检查项元信息DOC-CHECK-02FR-17
对应控制面操作 ``doctor/checks/{check_id}``(由
``ChannelControlService.getDoctorCheck`` 内部构造 ``ControlCmd`` 并
委托 ``_executeControl`` 执行控制面管道)。返回检查项元信息
``check_id`` / ``name`` / ``severity`` / ``description`` /
``auto_repairable``)。检查项不存在返回 404由 ``DoctorService.getCheck``
经 ``_getCheckItem`` 抛 ``NotFoundError``,携带 ``trace_id``
``check_id`` 格式非法返回 400由 ``doctor_handler._validateCheckId``
在管道内抛 ``ValidationError``);渠道未注册诊断适配器返回 501。
本端点走标准模板 A控制面端口路由不复用 ``getDoctorChecks`` 全量
查询后过滤GAP-06 修正):单项查询直接走 ``DoctorService.getCheck``
端口方法,避免 router 层业务判断与 ``trace_id`` 丢失。
"""
operator = build_operator(current_user, request)
result = await use_cases.doctor.getDoctorCheck(
channel_type=channel_type,
account_id=account_id,
check_id=check_id,
operator=operator,
)
raiseOnControlFailure(result)
return {"success": True, "data": serialize_control_data(result.data)}
@doctor_router.post(
"/{channel_type}/{account_id}/doctor/checks/{check_id}/run",
response_model=dict,
)
async def run_doctor_check(
channel_type: ChannelType,
account_id: str,
check_id: str,
request: Request,
use_cases=Depends(get_channel_use_cases),
current_user: User = Depends(get_admin_user),
) -> dict[str, Any]:
"""运行单项诊断检查DOC-CHECK-04FR-17
对应控制面操作 ``doctor/checks/{check_id}/run``(由
``ChannelControlService.runDoctorCheck`` 内部构造 ``ControlCmd`` 并
委托 ``_executeControl`` 执行控制面管道)。``check_id`` 格式由
``doctor_handler._validateCheckId`` 在管道内校验(正则
``^[A-Za-z0-9_-]+$``),格式非法返回 400经审计五阶段AC-32
检查项不存在返回 404渠道未注册诊断适配器返回 501。
"""
operator = build_operator(current_user, request)
result = await use_cases.doctor.runDoctorCheck(
channel_type=channel_type,
account_id=account_id,
check_id=check_id,
operator=operator,
)
raiseOnControlFailure(result)
return {"success": True, "data": serialize_control_data(result.data)}
@doctor_router.post(
"/{channel_type}/{account_id}/doctor/checks/{check_id}/repair/preview",
response_model=dict,
)
async def preview_doctor_repair(
channel_type: ChannelType,
account_id: str,
check_id: str,
request: Request,
use_cases=Depends(get_channel_use_cases),
current_user: User = Depends(get_admin_user),
) -> dict[str, Any]:
"""修复方案预览DOC-REP-02FR-17 / AC-40dry-run 只读)。
对应控制面操作 ``doctor/checks/{check_id}/repair/preview``(由
``ChannelControlService.repairDoctorCheck`` 在 ``confirmed=False`` 时
内部构造 ``ControlCmd`` 并委托 ``_executeControl`` 执行控制面管道)。
返回含修复方案repair_plan的检查结果不执行修复。preview 与 execute
使用独立 operation确保只读预览审计为 ``doctor_repair_previewed`` 而非
写操作 ``doctor_repair``。检查项不支持自动修复时返回 400检查项不存在
返回 404渠道未注册诊断适配器返回 501。
"""
operator = build_operator(current_user, request)
result = await use_cases.doctor.repairDoctorCheck(
channel_type=channel_type,
account_id=account_id,
check_id=check_id,
confirmed=False,
operator=operator,
)
raiseOnControlFailure(result)
return {"success": True, "data": serialize_control_data(result.data)}
@doctor_router.post(
"/{channel_type}/{account_id}/doctor/checks/{check_id}/repair",
response_model=dict,
)
async def execute_doctor_repair(
channel_type: ChannelType,
account_id: str,
check_id: str,
request: Request,
use_cases=Depends(get_channel_use_cases),
current_user: User = Depends(get_admin_user),
) -> dict[str, Any]:
"""执行修复DOC-REP-01FR-17 / AC-40写操作
对应控制面操作 ``doctor/checks/{check_id}/repair``(由
``ChannelControlService.repairDoctorCheck`` 在 ``confirmed=True`` 时
内部构造 ``ControlCmd`` 并委托 ``_executeControl`` 执行控制面管道)。
执行 ``adapter.autoFix`` 修复后复检返回结果;修复失败时返回原检查结果
"未通过"不修改渠道配置AC-40。检查项不支持自动修复时返回 400
检查项不存在返回 404渠道未注册诊断适配器返回 501。
"""
operator = build_operator(current_user, request)
result = await use_cases.doctor.repairDoctorCheck(
channel_type=channel_type,
account_id=account_id,
check_id=check_id,
confirmed=True,
operator=operator,
)
raiseOnControlFailure(result)
return {"success": True, "data": serialize_control_data(result.data)}