193 lines
8.5 KiB
Python
193 lines
8.5 KiB
Python
|
|
import os
|
|||
|
|
import logging
|
|||
|
|
|
|||
|
|
from yuxi.channel.extensions.intercom.types import IntercomAccount
|
|||
|
|
|
|||
|
|
logger = logging.getLogger(__name__)
|
|||
|
|
|
|||
|
|
|
|||
|
|
class IntercomConfigAdapter:
|
|||
|
|
def list_account_ids(self, config: dict) -> list[str]:
|
|||
|
|
accounts = config.get("channels", {}).get("intercom", {}).get("accounts", {})
|
|||
|
|
if accounts:
|
|||
|
|
return list(accounts.keys())
|
|||
|
|
if os.getenv("INTERCOM_ACCESS_TOKEN"):
|
|||
|
|
return ["default"]
|
|||
|
|
return []
|
|||
|
|
|
|||
|
|
async def resolve_account(self, account_id: str, config: dict | None = None) -> dict:
|
|||
|
|
account = self._resolve_account_dataclass(account_id, config or {})
|
|||
|
|
return {
|
|||
|
|
"account_id": account.account_id,
|
|||
|
|
"access_token": account.access_token,
|
|||
|
|
"webhook_secret": account.webhook_secret,
|
|||
|
|
"admin_id": account.admin_id,
|
|||
|
|
"dm_policy": account.dm_policy,
|
|||
|
|
"allow_from": account.allow_from,
|
|||
|
|
"auto_skip_closed": account.auto_skip_closed,
|
|||
|
|
"auto_skip_snoozed": account.auto_skip_snoozed,
|
|||
|
|
"handoff_policy": account.handoff_policy,
|
|||
|
|
"datacenter": account.datacenter,
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def _resolve_account_dataclass(self, account_id: str, config: dict) -> IntercomAccount:
|
|||
|
|
channel_cfg = config.get("channels", {}).get("intercom", {})
|
|||
|
|
accounts = channel_cfg.get("accounts", {})
|
|||
|
|
account_cfg = accounts.get(account_id, {}) if accounts else channel_cfg
|
|||
|
|
|
|||
|
|
access_token = self._resolve_token(account_cfg.get("accessToken"), "INTERCOM_ACCESS_TOKEN")
|
|||
|
|
webhook_secret = self._resolve_token(account_cfg.get("webhookSecret"), "INTERCOM_WEBHOOK_SECRET")
|
|||
|
|
admin_id = account_cfg.get("adminId") or os.getenv("INTERCOM_ADMIN_ID", "")
|
|||
|
|
|
|||
|
|
return IntercomAccount(
|
|||
|
|
account_id=account_id,
|
|||
|
|
access_token=access_token,
|
|||
|
|
webhook_secret=webhook_secret,
|
|||
|
|
admin_id=admin_id,
|
|||
|
|
dm_policy=account_cfg.get("dmPolicy", "open"),
|
|||
|
|
allow_from=account_cfg.get("allowFrom", []),
|
|||
|
|
auto_skip_closed=account_cfg.get("autoSkipClosed", True),
|
|||
|
|
auto_skip_snoozed=account_cfg.get("autoSkipSnoozed", True),
|
|||
|
|
handoff_policy=account_cfg.get("handoffPolicy", "ignore"),
|
|||
|
|
datacenter=account_cfg.get("datacenter", "us"),
|
|||
|
|
)
|
|||
|
|
|
|||
|
|
@staticmethod
|
|||
|
|
def _resolve_token(account_value: str | None, env_key: str) -> str:
|
|||
|
|
if account_value is not None:
|
|||
|
|
if account_value == "none":
|
|||
|
|
return ""
|
|||
|
|
if account_value.startswith("$"):
|
|||
|
|
env_val = os.environ.get(account_value.strip("${}"), "")
|
|||
|
|
return env_val
|
|||
|
|
return account_value
|
|||
|
|
return os.environ.get(env_key, "")
|
|||
|
|
|
|||
|
|
def is_configured(self, account: dict) -> bool:
|
|||
|
|
return bool(account.get("access_token"))
|
|||
|
|
|
|||
|
|
def is_enabled(self, account: dict, config: dict) -> bool:
|
|||
|
|
return True
|
|||
|
|
|
|||
|
|
def disabled_reason(self, account: dict, config: dict) -> str:
|
|||
|
|
return ""
|
|||
|
|
|
|||
|
|
def unconfigured_reason(self, account: dict, config: dict) -> str:
|
|||
|
|
if self.is_configured(account):
|
|||
|
|
return ""
|
|||
|
|
return "Missing required credential: accessToken"
|
|||
|
|
|
|||
|
|
def describe_account(self, account: dict, config: dict) -> dict:
|
|||
|
|
return {
|
|||
|
|
"account_id": account.get("account_id", ""),
|
|||
|
|
"dm_policy": account.get("dm_policy", "open"),
|
|||
|
|
"handoff_policy": account.get("handoff_policy", "ignore"),
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
def default_account_id(self, config: dict) -> str:
|
|||
|
|
return config.get("channels", {}).get("intercom", {}).get("default_account", "default")
|
|||
|
|
|
|||
|
|
def resolve_allow_from(self, config: dict, account_id: str | None = None) -> list[str] | None:
|
|||
|
|
channel_cfg = config.get("channels", {}).get("intercom", {})
|
|||
|
|
accounts = channel_cfg.get("accounts", {})
|
|||
|
|
if account_id and account_id in accounts:
|
|||
|
|
return accounts[account_id].get("allowFrom")
|
|||
|
|
return channel_cfg.get("allowFrom")
|
|||
|
|
|
|||
|
|
def format_allow_from(self, config: dict, account_id: str | None, allow_from: list[str | int]) -> list[str]:
|
|||
|
|
return [str(entry) for entry in allow_from]
|
|||
|
|
|
|||
|
|
def has_configured_state(self, config: dict) -> bool:
|
|||
|
|
accounts = config.get("channels", {}).get("intercom", {}).get("accounts", {})
|
|||
|
|
if accounts:
|
|||
|
|
for account_cfg in accounts.values():
|
|||
|
|
if account_cfg.get("accessToken") or account_cfg.get("accessToken") is None:
|
|||
|
|
return True
|
|||
|
|
return bool(os.getenv("INTERCOM_ACCESS_TOKEN"))
|
|||
|
|
|
|||
|
|
def has_persisted_auth_state(self, config: dict) -> bool:
|
|||
|
|
accounts = config.get("channels", {}).get("intercom", {}).get("accounts", {})
|
|||
|
|
if accounts:
|
|||
|
|
for account_cfg in accounts.values():
|
|||
|
|
if account_cfg.get("accessToken"):
|
|||
|
|
return True
|
|||
|
|
return False
|
|||
|
|
|
|||
|
|
def config_schema(self) -> dict:
|
|||
|
|
return {
|
|||
|
|
"$schema": "https://json-schema.org/draft-07/schema#",
|
|||
|
|
"type": "object",
|
|||
|
|
"title": "Intercom 渠道配置",
|
|||
|
|
"properties": {
|
|||
|
|
"accounts": {
|
|||
|
|
"type": "object",
|
|||
|
|
"title": "账户列表",
|
|||
|
|
"description": "Intercom 账户配置,key 为账户 ID",
|
|||
|
|
"additionalProperties": {
|
|||
|
|
"type": "object",
|
|||
|
|
"properties": {
|
|||
|
|
"accessToken": {
|
|||
|
|
"type": "string",
|
|||
|
|
"title": "Access Token",
|
|||
|
|
"description": "Intercom Access Token (Settings > Developer Hub > Access Tokens)",
|
|||
|
|
"x-ui-password": True,
|
|||
|
|
},
|
|||
|
|
"webhookSecret": {
|
|||
|
|
"type": "string",
|
|||
|
|
"title": "Webhook Secret",
|
|||
|
|
"description": "用于验证 Webhook 请求的 HMAC 密钥",
|
|||
|
|
"x-ui-password": True,
|
|||
|
|
},
|
|||
|
|
"adminId": {
|
|||
|
|
"type": "string",
|
|||
|
|
"title": "Admin ID",
|
|||
|
|
"description": "Bot 的管理员 ID(留空则自动从 API 获取)",
|
|||
|
|
},
|
|||
|
|
"dmPolicy": {
|
|||
|
|
"type": "string",
|
|||
|
|
"title": "DM 安全策略",
|
|||
|
|
"enum": ["open", "pairing", "allowlist", "disabled"],
|
|||
|
|
"default": "open",
|
|||
|
|
},
|
|||
|
|
"allowFrom": {
|
|||
|
|
"type": "array",
|
|||
|
|
"title": "白名单 Contact ID",
|
|||
|
|
"items": {"type": "string"},
|
|||
|
|
"description": "仅 dmPolicy=allowlist 时生效,格式: contact_xxx 或 lead_xxx",
|
|||
|
|
},
|
|||
|
|
"autoSkipClosed": {
|
|||
|
|
"type": "boolean",
|
|||
|
|
"title": "跳过已关闭会话",
|
|||
|
|
"default": True,
|
|||
|
|
},
|
|||
|
|
"autoSkipSnoozed": {
|
|||
|
|
"type": "boolean",
|
|||
|
|
"title": "跳过已暂停会话",
|
|||
|
|
"default": True,
|
|||
|
|
},
|
|||
|
|
"handoffPolicy": {
|
|||
|
|
"type": "string",
|
|||
|
|
"title": "人工接管策略",
|
|||
|
|
"enum": ["ignore", "note_only", "continue"],
|
|||
|
|
"default": "ignore",
|
|||
|
|
"description": "检测到人工接管后的行为",
|
|||
|
|
},
|
|||
|
|
"datacenter": {
|
|||
|
|
"type": "string",
|
|||
|
|
"title": "数据中心",
|
|||
|
|
"enum": ["us", "eu", "au"],
|
|||
|
|
"default": "us",
|
|||
|
|
"description": "Intercom 数据中心区域",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
"required": ["accessToken"],
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
"default_account": {
|
|||
|
|
"type": "string",
|
|||
|
|
"title": "默认账户",
|
|||
|
|
"default": "default",
|
|||
|
|
},
|
|||
|
|
},
|
|||
|
|
}
|