ForcePilot/backend/package/yuxi/channel/extensions/msteams/config.py
Kris 94444ced96 feat(channel): 添加 Microsoft Teams 渠道扩展
新增 Microsoft Teams 渠道扩展,支持在 Yuxi 平台中集成 Microsoft Teams 协作平台。

包含以下功能模块:
- sdk: Bot Framework SDK 封装
- config: 渠道配置管理
- gateway: SSE/WebSocket 网关接入
- webhook: Webhook 事件处理
- outbound: 外发消息管理
- streaming: 流式消息处理
- pairing: 用户配对与绑定
- security: 安全校验
- auth: JWT 认证
- jwks: JWKS 密钥管理
- dedupe: 消息去重
- monitor: 渠道状态监控
- status: 会话状态管理
- session: 会话管理
- state: 状态管理
- runtime: 运行时管理
- actions: 动作处理
- adaptive_card: 自适应卡片
- task_modules: 任务模块
- message_extension: 消息扩展
- proactive: Proactive Messaging
- graph: Microsoft Graph API 集成
- graph_teams: Teams 操作
- graph_members: 成员管理
- graph_messages: 消息获取
- graph_thread: 线程管理
- graph_users: 用户管理
- graph_upload: 文件上传
- files: 文件处理
- file_consent: 文件授权
- conversations: 会话存储
- mentions: @提及处理
- threading: 线程管理
- reactions: 表情反应
- polls: 投票功能
- meetings: 会议集成
- feedback: 反馈处理
- sso: 单点登录
- deep_links: 深层链接
- incoming_webhook: 入站 Webhook
- localization: 本地化
- user_agent: 用户代理
- sent_message_cache: 消息缓存
- types: 类型定义
2026-05-21 11:28:42 +08:00

96 lines
3.5 KiB
Python

from __future__ import annotations
import logging
import os
from .types import MSTeamsAuthType
logger = logging.getLogger(__name__)
class MSTeamsConfigAdapter:
def __init__(self): ...
def list_account_ids(self, config: dict) -> list[str]:
accounts = config.get("channels", {}).get("msteams", {}).get("accounts", {})
if accounts:
return list(accounts.keys())
return ["default"]
def _resolve_channel_config(self, config: dict) -> dict:
return config.get("channels", {}).get("msteams", {}) or {}
async def resolve_account(self, account_id: str) -> dict:
raw = self._load_raw(account_id)
app_id = raw.get("appId") or os.environ.get("MSTEAMS_APP_ID", "")
app_password = raw.get("appPassword") or os.environ.get("MSTEAMS_APP_PASSWORD", "")
tenant_id = raw.get("tenantId") or os.environ.get("MSTEAMS_TENANT_ID", "")
auth_type = MSTeamsAuthType.SECRET
certificate_path = raw.get("certificatePath")
use_managed_identity = raw.get("useManagedIdentity")
if certificate_path or use_managed_identity:
auth_type = MSTeamsAuthType.FEDERATED
return {
"account_id": account_id,
"app_id": app_id,
"app_password": app_password,
"tenant_id": tenant_id,
"auth_type": auth_type,
"config": raw,
}
def _load_raw(self, account_id: str) -> dict:
try:
from yuxi.channel.config.snapshot import get_latest_snapshot
snapshot = get_latest_snapshot()
if snapshot and hasattr(snapshot, "config"):
channel_cfg = snapshot.config.get("channels", {}).get("msteams", {}) or {}
accounts = channel_cfg.get("accounts", {}) or {}
if account_id in accounts:
return accounts[account_id]
if "default" in accounts:
return accounts["default"]
return channel_cfg
except Exception:
pass
return {}
def is_configured(self, account: dict) -> bool:
return bool(account.get("app_id") and account.get("app_password"))
def is_enabled(self, account: dict, config: dict) -> bool:
channel_cfg = self._resolve_channel_config(config)
return channel_cfg.get("enabled", True)
def disabled_reason(self, account: dict, config: dict) -> str:
if not self.is_configured(account):
return "App ID 或 App Password 未配置"
return ""
def describe_account(self, account: dict, config: dict) -> dict:
return {
"account_id": account.get("account_id", "default"),
"app_id": account.get("app_id", ""),
"tenant_id": account.get("tenant_id", ""),
"configured": self.is_configured(account),
}
def default_account_id(self, config: dict) -> str:
accounts = self._resolve_channel_config(config).get("accounts", {})
if accounts:
return next(iter(accounts.keys()))
return "default"
def resolve_allow_from(self, config: dict, account_id: str | None = None) -> list[str | int] | None:
channel_cfg = self._resolve_channel_config(config)
allow_from = channel_cfg.get("allowFrom", [])
return allow_from if allow_from else None
def has_configured_state(self, config: dict) -> bool:
channel_cfg = self._resolve_channel_config(config)
return bool(channel_cfg.get("appId") or channel_cfg.get("accounts"))