import os import logging logger = logging.getLogger(__name__) ENV_PREFIX = "WORKPLACE" class WorkplaceConfigAdapter: def list_account_ids(self, config: dict | None = None) -> list[str]: ids: list[str] = [] if config and "accounts" in config: ids.extend(config["accounts"].keys()) token = os.environ.get(f"{ENV_PREFIX}_ACCESS_TOKEN") if token: ids.append("default") return list(dict.fromkeys(ids)) or ["default"] async def resolve_account(self, account_id: str = "default", config: dict | None = None) -> dict: raw = {} if config and "accounts" in config: raw = config["accounts"].get(account_id, {}) return self._build_account(account_id, raw) def _build_account(self, account_id: str, raw: dict) -> dict: suffix = f"_{account_id.upper()}" if account_id != "default" else "" return { "account_id": account_id, "community_id": raw.get("community_id", os.environ.get(f"{ENV_PREFIX}_COMMUNITY_ID{suffix}", "")), "page_id": raw.get("page_id", os.environ.get(f"{ENV_PREFIX}_PAGE_ID{suffix}", "")), "access_token": raw.get("access_token", os.environ.get(f"{ENV_PREFIX}_ACCESS_TOKEN{suffix}", "")), "app_id": raw.get("app_id", os.environ.get(f"{ENV_PREFIX}_APP_ID{suffix}", "")), "app_secret": raw.get("app_secret", os.environ.get(f"{ENV_PREFIX}_APP_SECRET{suffix}", "")), "verify_token": raw.get("verify_token", os.environ.get(f"{ENV_PREFIX}_VERIFY_TOKEN{suffix}", "")), "dm_policy": raw.get("dm_policy", os.environ.get(f"{ENV_PREFIX}_DM_POLICY{suffix}", "pairing")), "allow_from": raw.get("allow_from", []), "graph_api_version": raw.get( "graph_api_version", os.environ.get(f"{ENV_PREFIX}_GRAPH_API_VERSION{suffix}", "v24.0") ), "group_chat_enabled": raw.get( "group_chat_enabled", os.environ.get(f"{ENV_PREFIX}_GROUP_CHAT_ENABLED{suffix}", "false").lower() == "true", ), "group_post_enabled": raw.get( "group_post_enabled", os.environ.get(f"{ENV_PREFIX}_GROUP_POST_ENABLED{suffix}", "false").lower() == "true", ), } @staticmethod def is_configured(account: dict) -> bool: return bool(account.get("access_token") and account.get("app_secret")) @staticmethod def is_enabled(account: dict) -> bool: return account.get("enabled", True) @staticmethod def disabled_reason(account: dict) -> str: if not account.get("access_token"): return "缺少 access_token" if not account.get("app_secret"): return "缺少 app_secret" return "" def config_schema(self) -> dict | None: return { "type": "object", "properties": { "access_token": { "type": "string", "title": "Access Token", "description": "Workplace Custom Integration 永不过期 Access Token", }, "app_id": { "type": "string", "title": "App ID", "description": "Workplace Custom Integration App ID", }, "app_secret": { "type": "string", "title": "App Secret", "description": "App Secret,用于 Webhook 签名验证", }, "verify_token": { "type": "string", "title": "Verify Token", "description": "Webhook 订阅验证 Token", }, "community_id": { "type": "string", "title": "Community ID", "description": "Workplace 社区 ID(可选,从 API 自动获取)", }, "dm_policy": { "type": "string", "enum": ["open", "pairing", "allowlist", "disabled"], "title": "DM 策略", "default": "pairing", }, }, "required": ["access_token", "app_secret", "verify_token"], } @staticmethod def describe_account(account: dict) -> dict: return { "account_id": account.get("account_id", ""), "name": account.get("community_id", "") or "Workplace Bot", } @staticmethod def default_account_id(config: dict | None = None) -> str: if config and "accounts" in config: return next(iter(config["accounts"]), "default") return "default"