111 lines
4.1 KiB
Python
111 lines
4.1 KiB
Python
|
|
"""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=basic,username='{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",
|
|||
|
|
}
|