实现完整的Freshdesk和Freshchat集成支持,包含会话守卫、错误定义、消息去重、配置管理、webhook处理、出站消息发送、状态监控、安全校验、配对功能和流式回复支持
122 lines
4.9 KiB
Python
122 lines
4.9 KiB
Python
import os
|
|
|
|
from yuxi.channel.extensions.freshdesk.types import FreshdeskAccount, FreshdeskMode
|
|
|
|
|
|
class FreshdeskConfigAdapter:
|
|
def list_account_ids(self, config: dict | None = None) -> list[str]:
|
|
if config is None:
|
|
config = {}
|
|
accounts = config.get("channels", {}).get("freshdesk", {}).get("accounts", {})
|
|
if accounts:
|
|
return list(accounts.keys())
|
|
return ["default"]
|
|
|
|
def resolve_account(self, account_id: str = "default", config: dict | None = None) -> FreshdeskAccount:
|
|
if config is None:
|
|
config = {}
|
|
channel_cfg = config.get("channels", {}).get("freshdesk", {})
|
|
accounts = channel_cfg.get("accounts", {})
|
|
account_cfg = accounts.get(account_id, {}) if accounts else channel_cfg
|
|
|
|
mode = account_cfg.get("mode", "both")
|
|
|
|
freshdesk_domain = account_cfg.get("freshdeskDomain") or os.getenv("FRESHDESK_DOMAIN", "")
|
|
freshdesk_api_key = account_cfg.get("freshdeskApiKey") or os.getenv("FRESHDESK_API_KEY", "")
|
|
|
|
freshchat_domain = account_cfg.get("freshchatDomain") or freshdesk_domain
|
|
freshchat_api_key = (
|
|
account_cfg.get("freshchatApiKey") or os.getenv("FRESHCHAT_API_KEY", "") or freshdesk_api_key
|
|
)
|
|
|
|
webhook_secret = account_cfg.get("webhookSecret") or os.getenv("FRESHDESK_WEBHOOK_SECRET", "")
|
|
|
|
return FreshdeskAccount(
|
|
account_id=account_id,
|
|
mode=FreshdeskMode(mode),
|
|
freshdesk_domain=freshdesk_domain,
|
|
freshdesk_api_key=freshdesk_api_key,
|
|
freshchat_domain=freshchat_domain,
|
|
freshchat_api_key=freshchat_api_key,
|
|
webhook_secret=webhook_secret,
|
|
agent_id=account_cfg.get("agentId", ""),
|
|
dm_policy=account_cfg.get("dmPolicy", "open"),
|
|
allow_from=account_cfg.get("allowFrom", []),
|
|
auto_skip_closed=account_cfg.get("autoSkipClosed", True),
|
|
auto_skip_resolved=account_cfg.get("autoSkipResolved", True),
|
|
handoff_policy=account_cfg.get("handoffPolicy", "ignore"),
|
|
default_priority=account_cfg.get("defaultPriority", 2),
|
|
)
|
|
|
|
def is_configured(self, account: FreshdeskAccount) -> bool:
|
|
if account.mode in (FreshdeskMode.FRESHCHAT, FreshdeskMode.BOTH):
|
|
return bool(account.freshchat_api_key and account.freshchat_domain)
|
|
return bool(account.freshdesk_api_key and account.freshdesk_domain)
|
|
|
|
def config_schema(self) -> dict:
|
|
return {
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"type": "object",
|
|
"properties": {
|
|
"mode": {
|
|
"type": "string",
|
|
"enum": ["freshdesk", "freshchat", "both"],
|
|
"default": "both",
|
|
"title": "集成模式",
|
|
},
|
|
"freshdeskDomain": {
|
|
"type": "string",
|
|
"title": "Freshdesk 域名",
|
|
},
|
|
"freshdeskApiKey": {
|
|
"type": "string",
|
|
"title": "Freshdesk API Key",
|
|
"writeOnly": True,
|
|
},
|
|
"freshchatDomain": {
|
|
"type": "string",
|
|
"title": "Freshchat 域名",
|
|
},
|
|
"freshchatApiKey": {
|
|
"type": "string",
|
|
"title": "Freshchat API Key",
|
|
"writeOnly": True,
|
|
},
|
|
"webhookSecret": {
|
|
"type": "string",
|
|
"title": "Webhook Secret",
|
|
"writeOnly": True,
|
|
},
|
|
"agentId": {
|
|
"type": "string",
|
|
"title": "Agent ID",
|
|
},
|
|
"dmPolicy": {
|
|
"type": "string",
|
|
"enum": ["open", "pairing", "allowlist", "disabled"],
|
|
"default": "open",
|
|
"title": "DM 安全策略",
|
|
},
|
|
"allowFrom": {
|
|
"type": "array",
|
|
"items": {"type": "string"},
|
|
"title": "白名单",
|
|
},
|
|
"autoSkipClosed": {"type": "boolean", "default": True, "title": "跳过已关闭会话"},
|
|
"autoSkipResolved": {"type": "boolean", "default": True, "title": "跳过已解决工单"},
|
|
"handoffPolicy": {
|
|
"type": "string",
|
|
"enum": ["ignore", "note_only", "continue"],
|
|
"default": "ignore",
|
|
"title": "人工接管策略",
|
|
},
|
|
"defaultPriority": {
|
|
"type": "integer",
|
|
"enum": [1, 2, 3, 4],
|
|
"default": 2,
|
|
"title": "默认优先级",
|
|
},
|
|
},
|
|
"required": ["freshdeskDomain"],
|
|
}
|