ForcePilot/backend/package/yuxi/channels/adapters/dingding/config_schema.py
Kris 9c01d480cc feat(dingding): 完整实现钉钉适配器功能模块
- 新增钉钉工具调用审计日志功能
- 新增参数校验装饰器与基础工具集(文档、审批、多维表格)
- 完善事件类型映射与会话ID生成逻辑
- 新增消息去重、访问策略匹配、配置校验与UI提示
- 新增酷应用卡片、目录管理、表情反应支持
- 优化消息发送逻辑,添加401重试机制
- 新增配置化的权限控制与流式输出支持
2026-05-13 16:06:10 +08:00

105 lines
4.6 KiB
Python

from __future__ import annotations
from typing import Any
from yuxi.utils.logging_config import logger
VALID_MODES = {"stream", "webhook"}
VALID_DM_POLICIES = {"open", "pairing", "allowlist"}
VALID_GROUP_POLICIES = {"open", "allowlist", "disabled"}
VALID_STREAMING_MODES = {"off", "block", "partial"}
def refine_dingding_config(config: dict[str, Any]) -> dict[str, Any]:
refined = dict(config)
mode = refined.get("mode", "stream")
if mode not in VALID_MODES:
logger.warning("[DingDingConfig] Invalid mode '%s', falling back to 'stream'", mode)
refined["mode"] = "stream"
group_policy = refined.get("group_policy", refined.get("groupPolicy", "allowlist"))
if group_policy not in VALID_GROUP_POLICIES:
logger.warning("[DingDingConfig] Invalid groupPolicy '%s', falling back to 'allowlist'", group_policy)
refined["groupPolicy"] = "allowlist"
refined["group_policy"] = "allowlist"
dm_policy = refined.get("dm_policy", refined.get("dmPolicy", "pairing"))
if dm_policy not in VALID_DM_POLICIES:
logger.warning("[DingDingConfig] Invalid dmPolicy '%s', falling back to 'pairing'", dm_policy)
refined["dmPolicy"] = "pairing"
refined["dm_policy"] = "pairing"
streaming = refined.get("streaming", {})
if isinstance(streaming, dict):
stream_mode = streaming.get("mode", "block")
if stream_mode not in VALID_STREAMING_MODES:
logger.warning("[DingDingConfig] Invalid streaming mode '%s', falling back to 'block'", stream_mode)
streaming["mode"] = "block"
accounts = refined.get("accounts", {})
if isinstance(accounts, dict):
default_account = accounts.get("default", {})
if not isinstance(default_account, dict):
accounts["default"] = {}
default_account = accounts["default"]
if "robot_code" not in default_account:
logger.info("[DingDingConfig] No robot_code in default account, reactions and cards may not work")
return refined
def validate_dingding_config(config: dict[str, Any]) -> list[str]:
errors: list[str] = []
accounts = config.get("accounts", {})
if not isinstance(accounts, dict) or not accounts:
errors.append("accounts 为必填项,至少需要配置 default 账户")
else:
default_account = accounts.get("default", {})
if not isinstance(default_account, dict):
errors.append("accounts.default 必须为字典类型")
else:
app_key = default_account.get("app_key", default_account.get("appKey", ""))
app_secret = default_account.get("app_secret", default_account.get("appSecret", ""))
if not app_key:
errors.append("accounts.default.app_key 为必填项")
if not app_secret:
errors.append("accounts.default.app_secret 为必填项")
mode = config.get("mode", "stream")
if mode not in VALID_MODES:
errors.append(f"mode 值无效: '{mode}',有效值为: {VALID_MODES}")
group_policy = config.get("group_policy", config.get("groupPolicy", "allowlist"))
if group_policy not in VALID_GROUP_POLICIES:
errors.append(f"groupPolicy 值无效: '{group_policy}',有效值为: {VALID_GROUP_POLICIES}")
dm_policy = config.get("dm_policy", config.get("dmPolicy", "pairing"))
if dm_policy not in VALID_DM_POLICIES:
errors.append(f"dmPolicy 值无效: '{dm_policy}',有效值为: {VALID_DM_POLICIES}")
max_media = config.get("max_media_size_mb", config.get("mediaMaxMb", 10))
if not isinstance(max_media, (int, float)) or max_media <= 0 or max_media > 200:
errors.append(f"max_media_size_mb 值无效: {max_media},有效范围: 1-200")
text_limit = config.get("text_chunk_limit", config.get("textChunkLimit", 4096))
if not isinstance(text_limit, int) or text_limit < 100 or text_limit > 20000:
errors.append(f"text_chunk_limit 值无效: {text_limit},有效范围: 100-20000")
allowlist = config.get("allowFrom", config.get("allowlist", []))
if isinstance(allowlist, list):
for item in allowlist:
if isinstance(item, str) and not item.strip():
errors.append("allowlist 包含空白条目")
groups_config = config.get("groups", {})
if isinstance(groups_config, dict):
for group_id, group_cfg in groups_config.items():
if isinstance(group_cfg, dict):
require_mention = group_cfg.get("requireMention")
if require_mention is not None and not isinstance(require_mention, bool):
errors.append(f"groups.{group_id}.requireMention 必须为布尔值")
return errors