from __future__ import annotations import logging import os from yuxi.channel.extensions.ringcentral.types import ResolvedRingCentralAccount logger = logging.getLogger(__name__) _DEFAULT_WEBHOOK_PATH = "/api/webhook/ringcentral" class RingCentralConfigAdapter: DEFAULT_ACCOUNT_ID = "default" def list_account_ids(self, config: dict) -> list[str]: raw = config.get("channels", {}).get("ringcentral", {}) accounts = raw.get("accounts", {}) if accounts: return list(accounts.keys()) if raw.get("client_id"): return [self.DEFAULT_ACCOUNT_ID] return [] async def resolve_account(self, account_id: str) -> dict: from yuxi.channel.runtime.manager import gateway config = gateway.global_config if gateway is not None else {} rc_config = config.get("channels", {}).get("ringcentral", {}) if config else {} defaults = rc_config.get("accounts", {}).get("default", {}) account_cfg = rc_config.get("accounts", {}).get(account_id, {}) merged = {**rc_config, **defaults, **account_cfg} resolved = self._build_resolved(account_id, merged) return { "account_id": account_id, "name": resolved.name, "client_id": resolved.client_id, "client_secret": resolved.client_secret, "server_url": resolved.server_url, "jwt_token": resolved.jwt_token, "webhook_path": resolved.webhook_path, "webhook_validation_token": resolved.webhook_validation_token, "bot_person_id": resolved.bot_person_id, "subscription_id": resolved.subscription_id, "dm_policy": resolved.dm_policy, "dm_enabled": resolved.dm_enabled, "dm_allow_from": resolved.dm_allow_from, "group_policy": resolved.group_policy, "require_mention": resolved.require_mention, "text_chunk_limit": resolved.text_chunk_limit, "media_max_mb": resolved.media_max_mb, "enabled": resolved.enabled, "config": resolved.config, "resolved": resolved, } def _build_resolved(self, account_id: str, merged: dict) -> ResolvedRingCentralAccount: client_id = merged.get("client_id", "") or os.getenv("RINGCENTRAL_CLIENT_ID", "") client_secret = merged.get("client_secret", "") or os.getenv("RINGCENTRAL_CLIENT_SECRET", "") jwt_token = merged.get("jwt_token", "") or os.getenv("RINGCENTRAL_JWT_TOKEN", "") return ResolvedRingCentralAccount( account_id=account_id, name=merged.get("name", account_id), client_id=client_id, client_secret=client_secret, server_url=merged.get("server_url", "https://platform.ringcentral.com"), jwt_token=jwt_token, webhook_path=merged.get("webhook_path", _DEFAULT_WEBHOOK_PATH), webhook_validation_token=merged.get("webhook_validation_token", ""), bot_person_id=merged.get("bot_person_id", ""), subscription_id=merged.get("subscription_id", ""), dm_policy=merged.get("dm_policy", "pairing"), dm_enabled=merged.get("dm_enabled", True), dm_allow_from=merged.get("dm_allow_from", []), group_policy=merged.get("group_policy", "allowlist"), require_mention=merged.get("require_mention", True), text_chunk_limit=merged.get("text_chunk_limit", 1000), media_max_mb=merged.get("media_max_mb", 20), enabled=merged.get("enabled", True), config=merged, ) def is_configured(self, account: dict) -> bool: resolved = account.get("resolved") if isinstance(resolved, ResolvedRingCentralAccount): return resolved.is_configured return bool(account.get("client_id") and account.get("jwt_token")) def is_enabled(self, account: dict) -> bool: return bool(account.get("enabled", True)) def disabled_reason(self, account: dict) -> str: if not self.is_configured(account): return "RingCentral client_id, client_secret and jwt_token are required" return "" async def resolve_allow_from(self, config: dict, account_id: str) -> list[str] | None: account = await self.resolve_account(account_id) return account.get("dm_allow_from", []) def describe_account(self, account: dict) -> dict: return { "account_id": account.get("account_id", ""), "name": account.get("name", ""), "configured": self.is_configured(account), } def config_schema(self) -> dict: return { "type": "object", "properties": { "enabled": {"type": "boolean", "default": True}, "name": {"type": "string"}, "clientId": {"type": "string"}, "clientSecret": {"type": "string"}, "serverUrl": { "type": "string", "default": "https://platform.ringcentral.com", }, "jwtToken": {"type": "string"}, "webhookPath": {"type": "string", "default": _DEFAULT_WEBHOOK_PATH}, "webhookValidationToken": {"type": "string"}, "botPersonId": {"type": "string"}, "subscriptionId": {"type": "string"}, "dmPolicy": { "type": "string", "enum": ["open", "pairing", "allowlist", "disabled"], "default": "pairing", }, "dmEnabled": {"type": "boolean", "default": True}, "dmAllowFrom": {"type": "array", "items": {"type": "string"}}, "groupPolicy": { "type": "string", "enum": ["open", "allowlist", "disabled"], "default": "allowlist", }, "requireMention": {"type": "boolean", "default": True}, "textChunkLimit": {"type": "integer", "default": 1000}, "mediaMaxMb": {"type": "integer", "default": 20}, "accounts": { "type": "object", "additionalProperties": { "type": "object", "properties": { "name": {"type": "string"}, "clientId": {"type": "string"}, "clientSecret": {"type": "string"}, "serverUrl": {"type": "string"}, "jwtToken": {"type": "string"}, "webhookPath": {"type": "string"}, "webhookValidationToken": {"type": "string"}, "botPersonId": {"type": "string"}, "subscriptionId": {"type": "string"}, "dmPolicy": {"type": "string"}, "dmEnabled": {"type": "boolean"}, "dmAllowFrom": {"type": "array", "items": {"type": "string"}}, "groupPolicy": {"type": "string"}, "requireMention": {"type": "boolean"}, }, }, }, }, }