from __future__ import annotations import os from .types import SmsScene, SmsTemplateConfig, TemplateType, TencentSmsAccount class TencentSmsConfigAdapter: ENV_MAP = { "secret_id": "TENCENT_SMS_SECRET_ID", "secret_key": "TENCENT_SMS_SECRET_KEY", "sms_sdk_app_id": "TENCENT_SMS_SDK_APP_ID", "sign_name": "TENCENT_SMS_SIGN_NAME", "region": "TENCENT_SMS_REGION", } def __init__(self): self._config: dict | None = None def set_config(self, config: dict) -> None: self._config = config def list_account_ids(self, config: dict) -> list[str]: accounts = config.get("accounts", []) if not accounts: sid = os.environ.get("TENCENT_SMS_SECRET_ID", "") if sid: return ["default"] return [] return [a.get("account_id", str(i)) for i, a in enumerate(accounts)] async def resolve_account(self, account_id: str) -> dict: if self._config is None: return {} accounts = self._config.get("accounts", []) if not accounts: sid = os.environ.get("TENCENT_SMS_SECRET_ID", "") if sid and account_id in ("default", "0", ""): return { "account_id": "default", "secret_id": sid, "secret_key": os.environ.get("TENCENT_SMS_SECRET_KEY", ""), "sms_sdk_app_id": os.environ.get("TENCENT_SMS_SDK_APP_ID", ""), "sign_name": os.environ.get("TENCENT_SMS_SIGN_NAME", ""), "region": os.environ.get("TENCENT_SMS_REGION", "ap-guangzhou"), } return {} for a in accounts: if a.get("account_id", str(accounts.index(a))) == account_id: return a return {} def _parse_account(self, account: dict) -> TencentSmsAccount: secret_id = account.get("secret_id") or os.environ.get("TENCENT_SMS_SECRET_ID", "") secret_key = account.get("secret_key") or os.environ.get("TENCENT_SMS_SECRET_KEY", "") sms_sdk_app_id = account.get("sms_sdk_app_id") or os.environ.get("TENCENT_SMS_SDK_APP_ID", "") sign_name = account.get("sign_name") or os.environ.get("TENCENT_SMS_SIGN_NAME", "") region = account.get("region") or os.environ.get("TENCENT_SMS_REGION", "ap-guangzhou") templates = [] for tpl in account.get("templates", []): templates.append( SmsTemplateConfig( scene=SmsScene(tpl.get("scene", "notification")), template_id=tpl.get("template_id", ""), sign_name=tpl.get("sign_name", sign_name), template_type=TemplateType(tpl.get("template_type", "0")), param_count=tpl.get("param_count", 1), max_daily=tpl.get("max_daily", 1000), description=tpl.get("description", ""), template_format=tpl.get("template_format", ""), ) ) return TencentSmsAccount( account_id=account.get("account_id", "default"), secret_id=secret_id, secret_key=secret_key, sms_sdk_app_id=sms_sdk_app_id, sign_name=sign_name, region=region, endpoint=account.get("endpoint", "sms.tencentcloudapi.com"), callback_url=account.get("callback_url", "/webhook/tencent-sms/callback"), reply_callback_url=account.get("reply_callback_url", "/webhook/tencent-sms/reply-callback"), templates=templates, dm_policy=account.get("dm_policy", "open"), allow_from=account.get("allow_from", []), daily_limit=account.get("daily_limit", 1000), interval_seconds=account.get("interval_seconds", 30), phone_daily_limit=account.get("phone_daily_limit", 10), poll_interval_seconds=account.get("poll_interval_seconds", 120), enabled=account.get("enabled", True), extend_code=account.get("extend_code", ""), sender_id=account.get("sender_id", ""), allowed_callback_ips=account.get("allowed_callback_ips", []), ) def is_configured(self, account: dict) -> bool: ta = self._parse_account(account) return ta.is_configured def is_enabled(self, account: dict) -> bool: ta = self._parse_account(account) return ta.enabled and ta.is_configured def disabled_reason(self, account: dict) -> str: ta = self._parse_account(account) if not ta.secret_id: return "\u7f3a\u5c11 SecretId" if not ta.secret_key: return "\u7f3a\u5c11 SecretKey" if not ta.sms_sdk_app_id: return "\u7f3a\u5c11 SmsSdkAppId" if not ta.sign_name: return "\u672a\u914d\u7f6e\u77ed\u4fe1\u7b7e\u540d (SignName)" if not ta.templates: return "\u672a\u914d\u7f6e\u77ed\u4fe1\u6a21\u677f" if not ta.enabled: return "\u6e20\u9053\u5df2\u7981\u7528" return "" def describe_account(self, account: dict) -> dict: ta = self._parse_account(account) return { "account_id": ta.account_id, "sms_sdk_app_id": ta.sms_sdk_app_id, "sign_name": ta.sign_name, "region": ta.region, "dm_policy": ta.dm_policy, "template_count": len(ta.templates), "template_scenes": [t.scene.value for t in ta.templates], } def config_schema(self) -> dict: return { "type": "object", "properties": { "secret_id": { "type": "string", "description": "\u817e\u8baf\u4e91 API SecretId\uff08CAM \u63a7\u5236\u53f0\u83b7\u53d6\uff09", }, "secret_key": { "type": "string", "description": "\u817e\u8baf\u4e91 API SecretKey", "format": "password", }, "sms_sdk_app_id": { "type": "string", "description": "\u77ed\u4fe1\u5e94\u7528 ID\uff08\u63a7\u5236\u53f0\u5e94\u7528\u7ba1\u7406 -> SDK AppID\uff09", }, "sign_name": { "type": "string", "description": "\u77ed\u4fe1\u7b7e\u540d\uff08\u5df2\u5ba1\u6838\u901a\u8fc7\uff0c\u4e0d\u542b\u3010\u3011\uff09", }, "region": { "type": "string", "default": "ap-guangzhou", "description": "API \u5730\u57df", }, "templates": { "type": "array", "items": { "type": "object", "properties": { "scene": { "type": "string", "enum": ["verification", "notification", "alert", "marketing"], }, "template_id": {"type": "string"}, "sign_name": {"type": "string"}, "param_count": {"type": "integer", "minimum": 1, "maximum": 12}, "description": {"type": "string"}, "template_format": {"type": "string"}, }, "required": ["scene", "template_id", "param_count"], }, }, "dm_policy": { "type": "string", "enum": ["open", "pairing", "allowlist", "disabled"], "default": "open", }, "allow_from": { "type": "array", "items": {"type": "string"}, "description": "\u5141\u8bb8\u63a5\u6536\u77ed\u4fe1\u7684\u624b\u673a\u53f7\u767d\u540d\u5355\uff08E.164 \u683c\u5f0f\uff09", }, "daily_limit": { "type": "integer", "minimum": 1, "maximum": 100000, "default": 1000, }, "phone_daily_limit": { "type": "integer", "minimum": 1, "maximum": 50, "default": 10, }, "extend_code": { "type": "string", "description": "\u77ed\u4fe1\u7801\u53f7\u6269\u5c55\u53f7\uff08\u56fd\u9645/\u6e2f\u6fb3\u53f0\u77ed\u4fe1\u7528\uff09", }, "sender_id": { "type": "string", "description": "\u56fd\u9645/\u6e2f\u6fb3\u53f0 Sender ID", }, "allowed_callback_ips": { "type": "array", "items": {"type": "string"}, "description": "\u5141\u8bb8\u7684 Webhook \u56de\u8c03 IP \u767d\u540d\u5355", }, "enabled": {"type": "boolean", "default": True}, }, "required": ["secret_id", "secret_key", "sms_sdk_app_id", "sign_name"], } def default_account_id(self, config: dict) -> str: ids = self.list_account_ids(config) return ids[0] if ids else "default"