forked from erp-dev/erp
feat: message-api for mission via wecomm agent
This commit is contained in:
132
notifier/message_api.py
Normal file
132
notifier/message_api.py
Normal file
@@ -0,0 +1,132 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
from dataclasses import dataclass
|
||||
from urllib.parse import urljoin
|
||||
from urllib.error import HTTPError, URLError
|
||||
from urllib.request import Request, urlopen
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
@dataclass(frozen=True)
|
||||
class MessageAPIResponse:
|
||||
errcode: int
|
||||
errmsg: str
|
||||
raw: dict
|
||||
|
||||
@property
|
||||
def ok(self) -> bool:
|
||||
return int(self.errcode) == 0
|
||||
|
||||
|
||||
def _request_json(
|
||||
*,
|
||||
url: str,
|
||||
method: str = "GET",
|
||||
payload: dict | None = None,
|
||||
timeout_seconds: float = 10.0,
|
||||
headers: dict | None = None,
|
||||
) -> dict:
|
||||
data = None
|
||||
request_headers = dict(headers or {})
|
||||
if payload is not None:
|
||||
data = json.dumps(payload, ensure_ascii=False).encode("utf-8")
|
||||
request_headers.setdefault("Content-Type", "application/json")
|
||||
|
||||
req = Request(url=url, data=data, headers=request_headers, method=method)
|
||||
try:
|
||||
with urlopen(req, timeout=float(timeout_seconds)) as resp:
|
||||
body = resp.read().decode("utf-8", errors="replace")
|
||||
except HTTPError as exc:
|
||||
body = ""
|
||||
try:
|
||||
body = exc.read().decode("utf-8", errors="replace")
|
||||
except Exception:
|
||||
pass
|
||||
raise RuntimeError(f"Message API HTTPError: status={exc.code}, body={body}") from exc
|
||||
except URLError as exc:
|
||||
raise RuntimeError(f"Message API URLError: {exc}") from exc
|
||||
|
||||
try:
|
||||
return json.loads(body) if body else {}
|
||||
except Exception as exc:
|
||||
raise RuntimeError(f"Message API 响应不是合法 JSON: {body}") from exc
|
||||
|
||||
|
||||
def _get_message_api_base_url() -> str:
|
||||
base_url = str(getattr(settings, "MESSAGE_API_BASE_URL", "") or "").strip().rstrip("/")
|
||||
if not base_url:
|
||||
raise ValueError("MESSAGE_API_BASE_URL 未配置")
|
||||
return base_url
|
||||
|
||||
|
||||
def _get_message_api_authorization() -> str:
|
||||
authorization = str(getattr(settings, "MESSAGE_API_AUTHORIZATION", "") or "").strip()
|
||||
if not authorization:
|
||||
raise ValueError("MESSAGE_API_AUTHORIZATION 未配置")
|
||||
return authorization
|
||||
|
||||
|
||||
def _build_url(path: str) -> str:
|
||||
return urljoin(f"{_get_message_api_base_url()}/", path.lstrip("/"))
|
||||
|
||||
|
||||
def _post_message_api(*, path: str, payload: dict, timeout_seconds: float) -> dict:
|
||||
raw = _request_json(
|
||||
url=_build_url(path),
|
||||
method="POST",
|
||||
payload=payload,
|
||||
timeout_seconds=timeout_seconds,
|
||||
headers={
|
||||
"Authorization": _get_message_api_authorization(),
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
)
|
||||
return raw
|
||||
|
||||
|
||||
def send_message_api_text_message(
|
||||
*,
|
||||
agent_id: int,
|
||||
content: str,
|
||||
user_ids: list[str] | None = None,
|
||||
timeout_seconds: float = 10.0,
|
||||
) -> MessageAPIResponse:
|
||||
payload = {
|
||||
"agent_id": int(agent_id),
|
||||
"content": str(content or "").strip(),
|
||||
}
|
||||
if user_ids:
|
||||
payload["user_ids"] = user_ids
|
||||
|
||||
raw = _post_message_api(path="/api/message/send", payload=payload, timeout_seconds=timeout_seconds)
|
||||
return MessageAPIResponse(
|
||||
errcode=int(raw.get("errcode") or 0),
|
||||
errmsg=str(raw.get("errmsg") or ""),
|
||||
raw=raw,
|
||||
)
|
||||
|
||||
|
||||
def send_message_api_news_to_agents(
|
||||
*,
|
||||
agent_ids: list[int],
|
||||
title: str,
|
||||
description: str,
|
||||
url: str,
|
||||
image_url: str,
|
||||
user_ids: list[str] | None = None,
|
||||
timeout_seconds: float = 10.0,
|
||||
) -> list[dict]:
|
||||
payload = {
|
||||
"agent_ids": [int(agent_id) for agent_id in agent_ids],
|
||||
"title": title,
|
||||
"description": description,
|
||||
"url": url,
|
||||
"image_url": image_url,
|
||||
}
|
||||
if user_ids:
|
||||
payload["user_ids"] = user_ids
|
||||
|
||||
raw = _post_message_api(path="/api/message/send/news", payload=payload, timeout_seconds=timeout_seconds)
|
||||
return raw.get("results") or []
|
||||
Reference in New Issue
Block a user