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

100 lines
3.0 KiB
Python

from __future__ import annotations
import secrets
import time
from dataclasses import dataclass, field
PAIRING_CODE_LENGTH = 6
PAIRING_REQUEST_TTL_S = 300
@dataclass
class PairingRequest:
user_id: str
code: str
created_at: float = field(default_factory=time.monotonic)
approved: bool = False
denied: bool = False
@property
def expired(self) -> bool:
return time.monotonic() - self.created_at > PAIRING_REQUEST_TTL_S
@dataclass
class PairingResult:
needs_pairing: bool
code: str = ""
reason: str = ""
class MattermostPairingManager:
def __init__(self):
self._pending: dict[str, PairingRequest] = {}
def check_or_request(self, user_id: str) -> PairingResult:
existing = self._pending.get(user_id)
if existing and not existing.expired:
if existing.approved:
return PairingResult(needs_pairing=False, reason="already approved")
return PairingResult(
needs_pairing=True,
code=existing.code,
reason="pairing pending",
)
code = self._generate_code()
self._pending[user_id] = PairingRequest(user_id=user_id, code=code)
self._cleanup_expired()
return PairingResult(needs_pairing=True, code=code, reason="new pairing request")
def approve(self, user_id: str, code: str) -> bool:
req = self._pending.get(user_id)
if req is None or req.expired:
return False
if req.code != code:
return False
req.approved = True
return True
def deny(self, user_id: str) -> bool:
req = self._pending.get(user_id)
if req is None or req.expired:
return False
req.denied = True
return True
def is_approved(self, user_id: str) -> bool:
req = self._pending.get(user_id)
if req is None:
return False
if req.expired:
del self._pending[user_id]
return False
return req.approved
def list_pending(self) -> list[PairingRequest]:
self._cleanup_expired()
return [r for r in self._pending.values() if not r.approved and not r.denied]
def list_approved(self) -> list[PairingRequest]:
self._cleanup_expired()
return [r for r in self._pending.values() if r.approved]
@staticmethod
def _generate_code() -> str:
return secrets.token_hex(PAIRING_CODE_LENGTH // 2)[:PAIRING_CODE_LENGTH].upper()
def _cleanup_expired(self) -> None:
self._pending = {uid: r for uid, r in self._pending.items() if not r.expired}
def build_pairing_notification(user_id: str, pairing_code: str) -> str:
return (
f"**ForcePilot DM 配对请求**\n\n"
f"检测到来自 `{user_id}` 的私聊消息,但该用户未在您的允许列表中。\n\n"
f"配对码:**`{pairing_code}`**\n\n"
f"请管理员确认此配对请求以允许该用户与 Bot 对话。\n"
f"配对码有效期:{PAIRING_REQUEST_TTL_S // 60} 分钟。"
)