from __future__ import annotations import os from yuxi.channel.extensions.lazada.types import LazadaAccount LAZADA_SITE_ENDPOINTS = { "SG": "https://api.lazada.sg/rest", "MY": "https://api.lazada.com.my/rest", "TH": "https://api.lazada.co.th/rest", "VN": "https://api.lazada.vn/rest", "ID": "https://api.lazada.co.id/rest", "PH": "https://api.lazada.com.ph/rest", } LAZADA_AUTH_ENDPOINT = "https://auth.lazada.com/rest" COMMON_CONFIG_SCHEMA = { "$schema": "https://json-schema.org/draft-07/schema#", "type": "object", "title": "Lazada 渠道配置", "properties": { "appKey": { "type": "string", "title": "App Key", "description": "Lazada 开放平台应用 Key (ISV Console 获取)", }, "appSecret": { "type": "string", "title": "App Secret", "x-ui-password": True, "description": "Lazada 开放平台应用密钥", }, "accessToken": { "type": "string", "title": "Access Token", "x-ui-password": True, "description": "OAuth 2.0 授权获得的 access_token", }, "refreshToken": { "type": "string", "title": "Refresh Token", "x-ui-password": True, "description": "OAuth 2.0 授权获得的 refresh_token", }, "sellerId": { "type": "string", "title": "Seller ID", "description": "Lazada 卖家 ID", }, "siteCode": { "type": "string", "title": "站点代码", "enum": ["SG", "MY", "TH", "VN", "ID", "PH"], "default": "SG", "description": "六国站点代码", }, "webhookPath": { "type": "string", "title": "Webhook 回调路径", "default": "/webhook/lazada/callback", }, "webhookSecret": { "type": "string", "title": "Webhook 签名密钥", "x-ui-password": True, "description": "用于验证 LPM 推送签名", }, "dmPolicy": { "type": "string", "title": "DM 安全策略", "enum": ["open", "pairing", "allowlist", "disabled"], "default": "open", }, "maxTextLength": { "type": "integer", "title": "单条消息最大字符数", "default": 2000, "maximum": 2000, }, "httpTimeoutMs": { "type": "integer", "title": "HTTP 请求超时(毫秒)", "default": 15000, }, "pollingIntervalMs": { "type": "integer", "title": "长轮询间隔(毫秒)", "default": 5000, "minimum": 1000, }, "enabled": { "type": "boolean", "title": "启用", "default": False, "description": "⚠️ 启用前请确保已完成 IM API 权限申请", }, }, "required": ["appKey", "appSecret"], } class LazadaConfig: ENV_MAP = { "app_key": "LAZADA_APP_KEY", "app_secret": "LAZADA_APP_SECRET", "seller_id": "LAZADA_SELLER_ID", "site_code": "LAZADA_SITE_CODE", "dm_policy": "LAZADA_DM_POLICY", } def list_account_ids(self, config: dict | None = None) -> list[str]: channels = (config or {}).get("channels", {}) lazada_config = channels.get("lazada", {}) accounts = lazada_config.get("accounts", {}) if accounts: return list(accounts.keys()) if self._env_or_config("app_key"): return ["default"] return [] async def resolve_account(self, account_id: str = "default", config: dict | None = None) -> LazadaAccount: channels = (config or {}).get("channels", {}) lazada_config = channels.get("lazada", {}) accounts = lazada_config.get("accounts", {}) account_data = accounts.get(account_id, {}) return LazadaAccount( account_id=account_id, app_key=account_data.get("app_key") or self._env_or_config("app_key") or "", app_secret=account_data.get("app_secret") or self._env_or_config("app_secret") or "", access_token=account_data.get("access_token", ""), refresh_token=account_data.get("refresh_token", ""), token_expires_at=account_data.get("token_expires_at", 0), refresh_expires_at=account_data.get("refresh_expires_at", 0), seller_id=account_data.get("seller_id") or self._env_or_config("seller_id") or "", site_code=account_data.get("site_code") or self._env_or_config("site_code") or "SG", webhook_path=account_data.get("webhook_path", "/webhook/lazada/callback"), webhook_secret=account_data.get("webhook_secret", ""), dm_policy=account_data.get("dm_policy") or self._env_or_config("dm_policy") or "open", allow_from=account_data.get("allow_from", []), max_text_length=account_data.get("max_text_length", 2000), http_timeout_ms=account_data.get("http_timeout_ms", 15000), polling_interval_ms=account_data.get("polling_interval_ms", 5000), enabled=account_data.get("enabled", False), ) def is_configured(self, account: dict | None = None) -> bool: if account: return bool(account.get("app_key") and account.get("app_secret")) return bool(self._env_or_config("app_key") and self._env_or_config("app_secret")) def _env_or_config(self, key: str, config: dict | None = None) -> str | None: env_key = self.ENV_MAP.get(key, "") if env_key: val = os.getenv(env_key) if val: return val return None def config_schema(self) -> dict: return COMMON_CONFIG_SCHEMA