新增 Zalo OA、Zoom Chat、Zulip 三个渠道扩展。 Zalo OA 渠道扩展主要模块:sidecar_client, config, gateway, outbound, streaming, pairing, security, auth, dedupe, directory, monitor, status, session, reactions, tools Zoom Chat 渠道扩展主要模块:config, gateway, webhook, outbound, streaming, pairing, security, crypto, dedupe, actions, media, mentions, monitor, status, session, reactions, threading Zulip 渠道扩展主要模块:client, config, gateway, outbound, streaming, pairing, security, monitor, status
108 lines
3.7 KiB
Python
108 lines
3.7 KiB
Python
import base64
|
|
import logging
|
|
|
|
import httpx
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class ZoomStatus:
|
|
async def probe(self, account: dict | None = None) -> dict:
|
|
"""
|
|
健康探测:
|
|
|
|
1. Token 有效性: POST /oauth/token → GET /v2/users/me
|
|
2. API 连通性: GET /v2/users/me
|
|
3. Webhook 连通性: (无法直接探测 Zoom → 本地,仅检查配置)
|
|
|
|
Returns:
|
|
dict with keys: ok, token_valid, api_accessible, bot_user_id, errors
|
|
"""
|
|
if not account:
|
|
return {
|
|
"ok": False,
|
|
"token_valid": False,
|
|
"api_accessible": False,
|
|
"bot_user_id": "",
|
|
"errors": ["No account provided"],
|
|
}
|
|
|
|
client_id = account.get("client_id", "")
|
|
client_secret = account.get("client_secret", "")
|
|
account_id_zoom = account.get("account_id", "")
|
|
|
|
if not client_id or not client_secret or not account_id_zoom:
|
|
return {
|
|
"ok": False,
|
|
"token_valid": False,
|
|
"api_accessible": False,
|
|
"bot_user_id": "",
|
|
"errors": ["Missing Zoom OAuth credentials"],
|
|
}
|
|
|
|
result: dict = {
|
|
"ok": True,
|
|
"token_valid": False,
|
|
"api_accessible": False,
|
|
"bot_user_id": "",
|
|
"errors": [],
|
|
}
|
|
|
|
try:
|
|
raw_auth = f"{client_id}:{client_secret}"
|
|
auth_header = base64.b64encode(raw_auth.encode()).decode()
|
|
|
|
async with httpx.AsyncClient(timeout=httpx.Timeout(15.0)) as client:
|
|
token_resp = await client.post(
|
|
"https://zoom.us/oauth/token",
|
|
params={"grant_type": "account_credentials", "account_id": account_id_zoom},
|
|
headers={
|
|
"Authorization": f"Basic {auth_header}",
|
|
"Content-Type": "application/x-www-form-urlencoded",
|
|
},
|
|
)
|
|
if token_resp.status_code == 200:
|
|
result["token_valid"] = True
|
|
token = token_resp.json().get("access_token", "")
|
|
|
|
user_resp = await client.get(
|
|
"https://api.zoom.us/v2/users/me",
|
|
headers={"Authorization": f"Bearer {token}"},
|
|
)
|
|
if user_resp.status_code == 200:
|
|
result["api_accessible"] = True
|
|
result["bot_user_id"] = user_resp.json().get("id", "")
|
|
else:
|
|
result["errors"].append(f"API probe failed: {user_resp.status_code}")
|
|
else:
|
|
result["errors"].append(f"Token probe failed: {token_resp.status_code}")
|
|
result["ok"] = False
|
|
except Exception as e:
|
|
result["errors"].append(str(e))
|
|
result["ok"] = False
|
|
|
|
return result
|
|
|
|
def build_summary(self, snapshot: dict) -> dict:
|
|
"""构建账户状态摘要"""
|
|
if not isinstance(snapshot, dict):
|
|
return {"channel": "zoomchat", "status": "unknown"}
|
|
|
|
token_valid = snapshot.get("token_valid", False)
|
|
api_accessible = snapshot.get("api_accessible", False)
|
|
|
|
if token_valid and api_accessible:
|
|
status = "ok"
|
|
elif token_valid:
|
|
status = "degraded"
|
|
else:
|
|
status = "error"
|
|
|
|
return {
|
|
"channel": "zoomchat",
|
|
"status": status,
|
|
"token_valid": token_valid,
|
|
"api_accessible": api_accessible,
|
|
"bot_user_id": snapshot.get("bot_user_id", ""),
|
|
}
|