新增 Mattermost 渠道完整实现,包含适配器核心、消息处理、交互回调、命令支持、安全校验、多账号管理等功能,支持机器人消息发送、交互按钮、命令注册、投票功能以及配置动态修改等特性。
111 lines
3.1 KiB
Python
111 lines
3.1 KiB
Python
from __future__ import annotations
|
||
|
||
from typing import Any
|
||
|
||
_POLL_EMOJI_MAP = {
|
||
"A": ("1️⃣", "one"),
|
||
"B": ("2️⃣", "two"),
|
||
"C": ("3️⃣", "three"),
|
||
"D": ("4️⃣", "four"),
|
||
"E": ("5️⃣", "five"),
|
||
}
|
||
|
||
YES_NO_EMOJIS = [("✅", "yes"), ("❌", "no")]
|
||
|
||
|
||
def build_poll_props(
|
||
question: str,
|
||
options: list[str],
|
||
poll_id: str = "",
|
||
) -> dict[str, Any]:
|
||
"""构建 Mattermost poll attachments props。"""
|
||
if len(options) < 2:
|
||
options = list(options) + ["—"]
|
||
|
||
action_options = []
|
||
for i, opt in enumerate(options[:5]):
|
||
key_letter = chr(65 + i)
|
||
emoji, label = _POLL_EMOJI_MAP.get(key_letter, ("❓", f"option_{i}"))
|
||
action_options.append(
|
||
{
|
||
"text": f"{emoji} {opt}",
|
||
"value": f"poll_{poll_id}_opt_{key_letter}",
|
||
}
|
||
)
|
||
|
||
attachment = {
|
||
"fallback": f"Poll: {question}",
|
||
"title": f"📊 {question}",
|
||
"text": "\n".join(
|
||
f"{_POLL_EMOJI_MAP.get(chr(65 + i), ('❓', ''))[0]} {opt}" for i, opt in enumerate(options[:5])
|
||
),
|
||
"actions": [
|
||
{
|
||
"name": f"poll_{poll_id}",
|
||
"integration": {
|
||
"url": "", # 由回调端点填充
|
||
"context": {
|
||
"action": "poll_vote",
|
||
"poll_id": poll_id,
|
||
},
|
||
},
|
||
"type": "select",
|
||
"options": action_options,
|
||
},
|
||
],
|
||
}
|
||
|
||
return {
|
||
"attachments": [attachment],
|
||
"props": {"poll_id": poll_id, "type": "poll"},
|
||
}
|
||
|
||
|
||
def build_yes_no_poll_props(question: str, poll_id: str = "") -> dict[str, Any]:
|
||
"""构建是/否投票。"""
|
||
attachment = {
|
||
"fallback": f"Poll: {question}",
|
||
"title": f"📊 {question}",
|
||
"text": "选择你的答案:",
|
||
"actions": [
|
||
{
|
||
"name": f"poll_{poll_id}_yes",
|
||
"integration": {
|
||
"url": "", # 由回调端点填充
|
||
"context": {
|
||
"action": "poll_vote",
|
||
"poll_id": poll_id,
|
||
"vote": "yes",
|
||
},
|
||
},
|
||
"type": "button",
|
||
"text": "✅ 是",
|
||
"value": "yes",
|
||
},
|
||
{
|
||
"name": f"poll_{poll_id}_no",
|
||
"integration": {
|
||
"url": "", # 由回调端点填充
|
||
"context": {"action": "poll_vote", "poll_id": poll_id, "vote": "no"},
|
||
},
|
||
"type": "button",
|
||
"text": "❌ 否",
|
||
"value": "no",
|
||
},
|
||
],
|
||
}
|
||
|
||
return {
|
||
"attachments": [attachment],
|
||
"props": {"poll_id": poll_id, "type": "yes_no_poll"},
|
||
}
|
||
|
||
|
||
def parse_poll_action(context: dict) -> dict:
|
||
"""解析 poll action context。"""
|
||
return {
|
||
"action": context.get("action", ""),
|
||
"poll_id": context.get("poll_id", ""),
|
||
"vote": context.get("vote", ""),
|
||
}
|