170 lines
6.6 KiB
Python
170 lines
6.6 KiB
Python
import os
|
||
|
||
from yuxi.channel.extensions.alipay.types import AlipayAccount, AlipayDmPolicy, AlipayMode
|
||
|
||
|
||
class AlipayConfig:
|
||
ENV_MAP = {
|
||
"app_id": "ALIPAY_APP_ID",
|
||
"app_private_key": "ALIPAY_PRIVATE_KEY",
|
||
"alipay_public_key": "ALIPAY_PUBLIC_KEY",
|
||
"aes_key": "ALIPAY_AES_KEY",
|
||
"mode": "ALIPAY_MODE",
|
||
"dm_policy": "ALIPAY_DM_POLICY",
|
||
"subscribe_msg": "ALIPAY_SUBSCRIBE_MSG",
|
||
"remove_markdown": "ALIPAY_REMOVE_MD",
|
||
}
|
||
|
||
def list_account_ids(self, config: dict | None = None) -> list[str]:
|
||
if self._resolve_app_id():
|
||
return ["default"]
|
||
return []
|
||
|
||
def resolve_account(self, account_id: str = "default") -> AlipayAccount:
|
||
app_id = self._resolve_app_id()
|
||
return AlipayAccount(
|
||
account_id=account_id,
|
||
app_id=app_id or "",
|
||
app_private_key=self._env_or_config("app_private_key") or "",
|
||
alipay_public_key=self._env_or_config("alipay_public_key") or "",
|
||
aes_key=self._env_or_config("aes_key"),
|
||
mode=AlipayMode(self._env_or_config("mode") or "production"),
|
||
gateway_url=(
|
||
"https://openapi.alipaydev.com/gateway.do"
|
||
if self._env_or_config("mode") == "sandbox"
|
||
else "https://openapi.alipay.com/gateway.do"
|
||
),
|
||
name=self._env_or_config("name") or "",
|
||
enabled=self._env_or_config("enabled") != "false",
|
||
dm_policy=AlipayDmPolicy(self._env_or_config("dm_policy") or "open"),
|
||
allow_from=[],
|
||
remove_markdown=self._env_or_config("remove_markdown") != "false",
|
||
subscribe_msg=self._env_or_config("subscribe_msg") or "",
|
||
)
|
||
|
||
def is_configured(self, account: dict | None = None) -> bool:
|
||
return bool(
|
||
self._resolve_app_id()
|
||
and self._env_or_config("app_private_key")
|
||
and self._env_or_config("alipay_public_key")
|
||
)
|
||
|
||
def _resolve_app_id(self) -> str | None:
|
||
return self._env_or_config("app_id")
|
||
|
||
@staticmethod
|
||
def _env_or_config(key: str) -> str | None:
|
||
env_key = AlipayConfig.ENV_MAP.get(key, "")
|
||
if env_key:
|
||
val = os.getenv(env_key)
|
||
if val:
|
||
return val
|
||
return None
|
||
|
||
def config_schema(self) -> dict:
|
||
return {
|
||
"$schema": "https://json-schema.org/draft-07/schema#",
|
||
"type": "object",
|
||
"title": "支付宝渠道配置",
|
||
"properties": {
|
||
"app_id": {
|
||
"type": "string",
|
||
"title": "AppID",
|
||
"description": "支付宝开放平台应用 AppID",
|
||
},
|
||
"app_private_key": {
|
||
"type": "string",
|
||
"title": "应用私钥",
|
||
"x-ui-password": True,
|
||
"description": "RSA2 应用私钥 (PEM 格式)",
|
||
},
|
||
"alipay_public_key": {
|
||
"type": "string",
|
||
"title": "支付宝公钥",
|
||
"description": "支付宝公钥 (PEM 格式)",
|
||
},
|
||
"aes_key": {
|
||
"type": "string",
|
||
"title": "AES 解密密钥",
|
||
"x-ui-password": True,
|
||
"description": "AES 密钥(可选,16 字符)",
|
||
},
|
||
"mode": {
|
||
"type": "string",
|
||
"enum": ["production", "sandbox"],
|
||
"default": "production",
|
||
"title": "运行模式",
|
||
},
|
||
"dm_policy": {
|
||
"type": "string",
|
||
"enum": ["open", "pairing", "allowlist", "disabled"],
|
||
"default": "open",
|
||
"title": "DM 策略",
|
||
},
|
||
"subscribe_msg": {
|
||
"type": "string",
|
||
"title": "关注欢迎语",
|
||
"description": "用户关注生活号后自动回复的文本",
|
||
},
|
||
"remove_markdown": {
|
||
"type": "boolean",
|
||
"default": True,
|
||
"title": "移除 Markdown 格式",
|
||
"description": "自动移除 AI 回复中的 Markdown 符号",
|
||
},
|
||
},
|
||
"required": ["app_id", "app_private_key", "alipay_public_key"],
|
||
}
|
||
|
||
def is_enabled(self, account: dict | None = None, config: dict | None = None) -> bool:
|
||
if account is None:
|
||
return self._env_or_config("enabled") != "false"
|
||
return account.get("enabled", True)
|
||
|
||
def disabled_reason(self, account: dict | None = None, config: dict | None = None) -> str:
|
||
if not account:
|
||
return "未配置账户"
|
||
if not account.get("enabled", True):
|
||
return "账户已被禁用"
|
||
return ""
|
||
|
||
def unconfigured_reason(self, account: dict | None = None, config: dict | None = None) -> str:
|
||
if not account:
|
||
return "未配置账户"
|
||
missing = []
|
||
if not account.get("app_id"):
|
||
missing.append("AppId")
|
||
if not account.get("app_private_key"):
|
||
missing.append("应用私钥")
|
||
if not account.get("alipay_public_key"):
|
||
missing.append("支付宝公钥")
|
||
return f"缺少: {', '.join(missing)}" if missing else ""
|
||
|
||
def describe_account(self, account: dict | None = None, config: dict | None = None) -> dict:
|
||
if not account:
|
||
return {"account_id": ""}
|
||
return {
|
||
"account_id": account.get("account_id", "default"),
|
||
"app_id": account.get("app_id", ""),
|
||
"name": account.get("name", ""),
|
||
"mode": account.get("mode", "production"),
|
||
"dm_policy": account.get("dm_policy", "open"),
|
||
"enabled": account.get("enabled", True),
|
||
}
|
||
|
||
def resolve_allow_from(self, config: dict, account_id: str | None = None) -> list[str] | None:
|
||
account = self.resolve_account(account_id or "default")
|
||
return account.allow_from or None
|
||
|
||
def format_allow_from(self, config: dict, account_id: str | None, allow_from: list) -> list[str]:
|
||
return [str(item) for item in allow_from]
|
||
|
||
def has_configured_state(self, config: dict | None = None) -> bool:
|
||
return self.is_configured()
|
||
|
||
def has_persisted_auth_state(self, config: dict | None = None) -> bool:
|
||
return bool(self._resolve_app_id() and self._env_or_config("app_private_key"))
|
||
|
||
def default_account_id(self, config: dict | None = None) -> str:
|
||
return "default"
|