ForcePilot/backend/package/yuxi/external_systems/integrations/servicenow/metadata.py
Kris 55188ff7fa refactor: 整理代码结构并修复多处细节问题
1. 调整导入顺序与格式,修复重复导入
2. 替换通用异常捕获为更精准的ValueError
3. 重构持久层仓库的get_deleted/list_deleted方法,添加ORM转领域模型逻辑
4. 完善配置校验与参数合法性检查,新增缺失字段校验
5. 优化多行字符串与函数调用的换行格式
6. 修复通知服务状态判定逻辑与文档描述
7. 简化无用的TYPE_CHECKING代码块
8. 重构ServiceNow元数据发现逻辑,增加字段合法性校验
9. 修复数据库查询验证器的子查询处理逻辑
10. 完善领域模型的初始化校验与属性语义
2026-07-11 07:34:48 +08:00

112 lines
4.3 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.

"""ServiceNow 厂商集成元数据。
定义 ``IntegrationMetadata(key="servicenow", ...)``,由 ``__init__.py`` 自注册到
``IntegrationRegistry``。元数据为内存态,不持久化到数据库。
同时定义 ``ServiceNowConnectionConfig`` 连接配置 Schema 与
``resolve_oauth_endpoints`` OAuth 端点拼接函数,供 use_cases 层 / 前端在系统创建
与配置阶段调用(见设计文档 §3.2 / §3.3)。
"""
from __future__ import annotations
from pydantic import BaseModel, ConfigDict, Field, model_validator
from yuxi.external_systems.integrations.schemas import IntegrationMetadata
class ServiceNowConnectionConfig(BaseModel):
"""ServiceNow 连接配置 Schema。
``base_url`` 优先级高于 ``instance``支持私有部署场景。OAuth 端点由
``resolve_oauth_endpoints`` 在 handler 外动态拼接,注入到 ``auth_config``
后传给框架级 OAuth2 插件。
"""
model_config = ConfigDict(populate_by_name=True, extra="ignore")
instance: str | None = Field(
default=None,
description="ServiceNow 实例名,如 acme对应 https://acme.service-now.com",
)
base_url: str | None = Field(
default=None,
description="完整 base_url优先级高于 instance用于私有部署或自定义域名",
)
api_version: str | None = Field(
default=None,
description="Table API 版本,如 v1 / v2None 表示非版本化路径 /api/now/table/...",
)
@model_validator(mode="after")
def _ensure_url(self) -> ServiceNowConnectionConfig:
if not self.base_url and not self.instance:
raise ValueError("instance 与 base_url 至少填写一项")
if not self.base_url:
self.base_url = f"https://{self.instance}.service-now.com"
return self
def resolve_oauth_endpoints(base_url: str) -> dict[str, str]:
"""根据 base_url 拼接 ServiceNow 实例级 OAuth 端点。
由 use_cases 层 / 前端在系统创建与配置阶段调用,根据
``connection_config.base_url`` 拼接 ``token_url`` / ``authorize_url``
写入 ``auth_config`` 后持久化。handler 执行时 token 已由 use_cases 层通过
``token_manager.get_token`` 预解析并注入到 ``system_config["_resolved_token"]``
handler 不再调用本函数(与 dynamics365 一致)。
"""
return {
"authorize_url": f"{base_url}/oauth_auth.do",
"token_url": f"{base_url}/oauth_token.do",
}
SERVICENOW_METADATA = IntegrationMetadata(
key="servicenow",
display_name="ServiceNow",
description="ITSM / 工作流平台,基于 Table REST API 集成",
adapter_type="http",
source_types=["servicenow"],
supported_auth_types=[
"oauth2_authorization_code",
"oauth2_password",
"oauth2_client_credentials",
"basic",
],
tags=["itsm", "workflow", "ticketing"],
icon="servicenow",
docs_url="https://developer.servicenow.com/dev.do#!/learn/learning-plans/yokohama/rest_api",
connection_extra_schema={
"instance": {
"type": "string",
"description": "ServiceNow 实例名,如 acme对应 https://acme.service-now.com",
},
"base_url": {
"type": "string",
"description": "完整 base_url优先级高于 instance用于私有部署或自定义域名",
},
"api_version": {
"type": "string",
"enum": ["v1", "v2"],
"description": "Table API 版本None 表示非版本化路径 /api/now/table/...",
},
},
example_config={
"instance": "acme",
"api_version": None,
"auth_type": "oauth2_client_credentials",
"token_url": "https://acme.service-now.com/oauth_token.do",
"client_id": "example-client-id",
"client_secret": "ref://servicenow/acme/client_secret",
"scope": None,
},
dependency_note=(
"1. 调用账号需对 sys_db_object / sys_dictionary / "
"sys_documentation / sys_choice / sys_glide_object 具备 READ 权限;"
"2. OAuth2 应用需在目标实例中注册并配置回调地址;"
"3. oauth2_client_credentials 需 Washington DC 及以上版本;"
"4. client_secret 建议使用 ref:// 密钥引用。"
),
)