ForcePilot/backend/package/yuxi/channels/adapters/mattermost/accounts.py
Kris 002d601d1b feat(mattermost): 实现完整的 Mattermost 适配器模块
新增 Mattermost 渠道完整实现,包含适配器核心、消息处理、交互回调、命令支持、安全校验、多账号管理等功能,支持机器人消息发送、交互按钮、命令注册、投票功能以及配置动态修改等特性。
2026-05-12 00:46:12 +08:00

110 lines
3.9 KiB
Python

from __future__ import annotations
from dataclasses import dataclass, field
@dataclass
class MattermostAccount:
account_id: str
server_url: str = ""
bot_token: str = ""
nick: str = "ForcePilot"
username: str = ""
realname: str = ""
channels: list[str] = field(default_factory=list)
nickserv_password: str = ""
nickserv_register_email: str = ""
enabled: bool = True
@property
def configured(self) -> bool:
return bool(self.server_url and self.bot_token)
@classmethod
def from_config_entry(cls, account_id: str, entry: dict) -> MattermostAccount:
return cls(
account_id=account_id,
server_url=entry.get("server_url", "") or entry.get("host", ""),
bot_token=entry.get("bot_token", "") or entry.get("token", ""),
nick=entry.get("nick", "ForcePilot"),
username=entry.get("username", ""),
realname=entry.get("realname", ""),
channels=entry.get("channels", []),
nickserv_password=entry.get("nickserv_password", ""),
nickserv_register_email=entry.get("nickserv_register_email", ""),
enabled=entry.get("enabled", True),
)
DEFAULT_ACCOUNT_ID = "default"
@dataclass
class MultiAccountConfig:
accounts: dict[str, MattermostAccount] = field(default_factory=dict)
default_account_id: str = DEFAULT_ACCOUNT_ID
@classmethod
def from_config(cls, config: dict) -> MultiAccountConfig:
accounts_data = config.get("accounts", {})
if not accounts_data:
account = MattermostAccount.from_config_entry(
DEFAULT_ACCOUNT_ID,
{
"server_url": config.get("server_url", ""),
"bot_token": config.get("bot_token", ""),
"nick": config.get("nick", "ForcePilot"),
"username": config.get("username", ""),
"realname": config.get("realname", ""),
"channels": config.get("channels", []),
"nickserv_password": config.get("nickserv_password", ""),
"nickserv_register_email": config.get("nickserv_register_email", ""),
"enabled": True,
},
)
return cls(accounts={DEFAULT_ACCOUNT_ID: account}, default_account_id=DEFAULT_ACCOUNT_ID)
accounts = {}
for aid, entry in accounts_data.items():
accounts[aid] = MattermostAccount.from_config_entry(aid, entry)
default_id = config.get("default_account_id", DEFAULT_ACCOUNT_ID)
if default_id not in accounts and accounts:
default_id = next(iter(accounts))
return cls(accounts=accounts, default_account_id=default_id)
def resolve_account(self, account_id: str | None = None) -> MattermostAccount | None:
if account_id and account_id in self.accounts:
return self.accounts[account_id]
if self.default_account_id in self.accounts:
return self.accounts[self.default_account_id]
return None
def list_account_ids(self) -> list[str]:
return list(self.accounts.keys())
def list_configured_accounts(self) -> list[MattermostAccount]:
return [a for a in self.accounts.values() if a.configured and a.enabled]
def merge_config(
top_level: dict,
account_config: dict,
) -> dict:
merged = {**top_level, **account_config}
top_commands = top_level.get("commands", {})
account_commands = account_config.get("commands", {})
if top_commands or account_commands:
merged["commands"] = {**top_commands, **account_commands}
top_interactions = top_level.get("interactions", {})
account_interactions = account_config.get("interactions", {})
if top_interactions or account_interactions:
merged["interactions"] = {**top_interactions, **account_interactions}
return merged