ForcePilot/backend/package/yuxi/external_systems/integrations/servicenow/metadata.py
Kris 74709ba2d3 feat: 完成外部系统限界上下文核心代码实现
新增六边形架构核心代码包,包含:
1. 协议适配器层:HTTP/SMTP/IMAP/SSH/GRPC等多协议适配器实现
2. 认证插件体系:基础认证、API密钥、HMAC等多类型认证插件
3. 执行编排框架:工具执行器、上下文构建、运行时治理组件
4. 用例端口与DTO:定义领域服务端口与数据传输对象
5. 厂商集成包框架:支持第三方系统集成扩展
6. 基础设施装配层:实现依赖注入与服务装配

所有代码遵循六边形架构设计原则,实现端口与适配器解耦,支持动态扩展与自动发现。
2026-06-20 22:12:42 +08:00

111 lines
4.2 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:// 密钥引用。"
),
)