ForcePilot/backend/package/yuxi/external_systems/integrations/zendesk/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.1 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.

"""Zendesk 厂商集成元数据。
定义 ``IntegrationMetadata(key="zendesk", ...)``,由 ``__init__.py`` 自注册到
``IntegrationRegistry``。元数据为内存态,不持久化到数据库。
同时提供:
- ``ZendeskConnectionConfig``Zendesk 连接配置 Schema含 ``subdomain`` / ``base_url``
供前端动态表单与校验。
- ``resolve_oauth_endpoints``:根据 ``base_url`` 拼接 Zendesk 实例级 OAuth 端点,
供 handler 在 OAuth2 模式下注入到 ``auth_config``。
认证设计(见设计文档 §3
- ``oauth2_authorization_code``复用框架级插件handler 内通过
``resolve_oauth_endpoints`` 注入 ``token_url``。
- ``basic``API Token 模式):复用框架级 ``BasicAuthPlugin``
``username="{email}/token"````password=api_token``。
"""
from __future__ import annotations
from pydantic import BaseModel, Field, model_validator
from yuxi.external_systems.integrations.schemas import IntegrationMetadata
ZENDESK_METADATA = IntegrationMetadata(
key="zendesk",
display_name="Zendesk",
description="客服 / 工单平台,基于 Support REST API 集成",
adapter_type="http",
source_types=["zendesk"],
supported_auth_types=[
"oauth2_authorization_code", # 标准 OAuth2
"basic", # API Token 模式username="{email}/token", password=api_token
],
tags=["customer_support", "ticketing", "crm"],
icon="zendesk",
docs_url="https://developer.zendesk.com/api-reference/",
connection_extra_schema={
"type": "object",
"properties": {
"subdomain": {"type": "string", "description": "Zendesk 子域名,如 acme"},
"base_url": {
"type": "string",
"description": "完整 base_url优先级高于 subdomain",
},
},
},
example_config={
"connection_config": {
"subdomain": "acme",
},
"auth_config": {
"auth_type": "basic",
"username": "agent@acme.com/token",
"password": "ref://zendesk/acme/api_token",
},
},
dependency_note=(
"1. 调用账号需对 tickets / users / organizations / ticket_fields / "
"user_fields / organization_fields / search 具备 READ 权限;"
"2. OAuth2 应用需在 Zendesk 后台注册并配置回调地址;"
"3. API Token 在 Zendesk 后台 Admin > Channels > API 中生成,"
"auth_type=basicusername='{email}/token'password=api_token"
"4. api_token 建议使用 ref:// 密钥引用;"
"5. 通用 API 限流 OAuth2 700/min、basic 200/min搜索 API 30/min。"
),
)
class ZendeskConnectionConfig(BaseModel):
"""Zendesk 连接配置 Schema供前端动态表单与校验
``base_url`` 优先级高于 ``subdomain``,支持自定义域名场景。两者至少填写一项,
仅填写 ``subdomain`` 时自动拼接为 ``https://{subdomain}.zendesk.com``。
"""
subdomain: str | None = Field(
default=None,
description="Zendesk 子域名,如 acme对应 https://acme.zendesk.com",
)
base_url: str | None = Field(
default=None,
description="完整 base_url优先级高于 subdomain用于自定义域名或私有部署",
)
@model_validator(mode="after")
def _ensure_url(self) -> ZendeskConnectionConfig:
if not self.base_url and not self.subdomain:
raise ValueError("subdomain 与 base_url 至少填写一项")
if not self.base_url:
self.base_url = f"https://{self.subdomain}.zendesk.com"
return self
def resolve_oauth_endpoints(base_url: str) -> dict[str, str]:
"""根据 base_url 拼接 Zendesk 实例级 OAuth 端点。
Args:
base_url: Zendesk 实例 base_url如 ``https://acme.zendesk.com``)。
Returns:
含 ``authorize_url`` / ``token_url`` 的字典,供 handler 注入到
``auth_config`` 后传给框架级 OAuth2 插件消费。
"""
return {
"authorize_url": f"{base_url}/oauth/authorizations/new",
"token_url": f"{base_url}/oauth/tokens",
}