- 新增钉钉工具调用审计日志功能 - 新增参数校验装饰器与基础工具集(文档、审批、多维表格) - 完善事件类型映射与会话ID生成逻辑 - 新增消息去重、访问策略匹配、配置校验与UI提示 - 新增酷应用卡片、目录管理、表情反应支持 - 优化消息发送逻辑,添加401重试机制 - 新增配置化的权限控制与流式输出支持
105 lines
4.6 KiB
Python
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
|