新增 Mattermost 渠道完整实现,包含适配器核心、消息处理、交互回调、命令支持、安全校验、多账号管理等功能,支持机器人消息发送、交互按钮、命令注册、投票功能以及配置动态修改等特性。
97 lines
3.6 KiB
Python
97 lines
3.6 KiB
Python
from __future__ import annotations
|
|
|
|
import os
|
|
from typing import Any
|
|
|
|
|
|
async def diagnose(adapter: Any) -> dict[str, Any]:
|
|
issues: list[str] = []
|
|
warnings: list[str] = []
|
|
checks: dict[str, bool] = {}
|
|
|
|
config = (adapter.config or {}) if adapter else {}
|
|
|
|
server_url = (
|
|
config.get("server_url", "") or os.getenv("MATTERMOST_SERVER_URL", "") or os.getenv("MATTERMOST_URL", "")
|
|
)
|
|
bot_token = config.get("bot_token", "") or os.getenv("MATTERMOST_BOT_TOKEN", "")
|
|
|
|
checks["server_url_configured"] = bool(server_url)
|
|
checks["bot_token_configured"] = bool(bot_token)
|
|
|
|
if not server_url:
|
|
issues.append("server_url not configured (config.server_url or MATTERMOST_SERVER_URL)")
|
|
if not bot_token:
|
|
issues.append("bot_token not configured (config.bot_token or MATTERMOST_BOT_TOKEN)")
|
|
|
|
if checks["server_url_configured"] and checks["bot_token_configured"]:
|
|
from .adapter import probe_mattermost
|
|
|
|
try:
|
|
probe_result = await probe_mattermost(server_url, bot_token, timeout_s=30.0)
|
|
if probe_result.get("status") == "ok":
|
|
checks["connection_ok"] = True
|
|
checks["bot_verified"] = True
|
|
else:
|
|
checks["connection_ok"] = False
|
|
issues.append(f"Connection probe failed: {probe_result.get('message', 'unknown')}")
|
|
except Exception as e:
|
|
checks["connection_ok"] = False
|
|
issues.append(f"Connection probe exception: {e}")
|
|
|
|
signing_secret = os.getenv("MATTERMOST_SIGNING_SECRET", "")
|
|
checks["signing_secret_configured"] = bool(signing_secret)
|
|
if not signing_secret:
|
|
warnings.append("MATTERMOST_SIGNING_SECRET not set — interactive messages may fail")
|
|
|
|
dm_policy = config.get("dm_policy", "open")
|
|
group_policy = config.get("group_policy", "open")
|
|
|
|
if dm_policy == "disabled" and group_policy == "disabled":
|
|
warnings.append("Both DM and group policies are disabled — bot will not respond")
|
|
|
|
result = {
|
|
"channel": "mattermost",
|
|
"status": "error" if issues else ("warning" if warnings else "ok"),
|
|
"checks": checks,
|
|
"issues": issues,
|
|
"warnings": warnings,
|
|
"server_url": server_url,
|
|
"configured": checks["server_url_configured"] and checks["bot_token_configured"],
|
|
}
|
|
|
|
if adapter:
|
|
snapshot = adapter.snapshot() if hasattr(adapter, "snapshot") else {}
|
|
result["connected"] = adapter._is_connected() if hasattr(adapter, "_is_connected") else False
|
|
result["snapshot"] = snapshot
|
|
|
|
return result
|
|
|
|
|
|
async def migrate_config(adapter: Any) -> dict[str, Any]:
|
|
config = (adapter.config or {}) if adapter else {}
|
|
changes: list[str] = []
|
|
|
|
if not config.get("silence_send"):
|
|
changes.append("Added silence_send default")
|
|
|
|
if "commands" not in config or not isinstance(config.get("commands"), dict):
|
|
from .slash import SlashCommandConfig
|
|
|
|
slash_cfg = SlashCommandConfig.from_config(config.get("slash_commands", {}))
|
|
config["commands"] = {
|
|
"native": slash_cfg.auto_register,
|
|
"callback_url": slash_cfg.callback_url,
|
|
}
|
|
changes.append("Migrated slash_commands to commands config")
|
|
|
|
if "interactions" not in config:
|
|
config["interactions"] = {"allowedSourceIps": []}
|
|
changes.append("Added default interactions config")
|
|
|
|
if "blockStreamingCoalesce" not in config:
|
|
config["blockStreamingCoalesce"] = {"minChars": 1500, "idleMs": 1000}
|
|
changes.append("Added default block streaming coalesce config")
|
|
|
|
return {"migrated": bool(changes), "changes": changes, "config": config}
|