DM-Agent / src /dingtalk.py
unknown
refactor: consolidate repo structure, remove upload_to_github duplication
3291500
Raw History Blame Contribute Delete
1.89 kB
"""
钉钉自定义机器人:加签并 POST 发送 Markdown 消息。
"""
import base64
import hashlib
import hmac
import os
import time
import urllib.parse
from pathlib import Path
import requests
from dotenv import load_dotenv
# 从项目根目录加载 .env
_project_root = Path(__file__).resolve().parent.parent
load_dotenv(_project_root / ".env")
def _sign(secret: str) -> tuple[str, str]:
timestamp = str(round(time.time() * 1000))
string_to_sign = f"{timestamp}\n{secret}"
hmac_code = hmac.new(
secret.encode("utf-8"),
string_to_sign.encode("utf-8"),
digestmod=hashlib.sha256,
).digest()
sign = urllib.parse.quote(base64.b64encode(hmac_code))
return timestamp, sign
def build_signed_url(webhook: str, secret: str) -> str:
"""在 Webhook URL 后追加 timestamp 与 sign 参数。"""
timestamp, sign = _sign(secret)
sep = "&" if "?" in webhook else "?"
return f"{webhook}{sep}timestamp={timestamp}&sign={sign}"
def send_markdown(title: str, text: str) -> tuple[bool, str]:
"""
发送钉钉 Markdown 消息。
返回 (成功与否, 错误信息)。
"""
webhook = os.environ.get("DINGTALK_WEBHOOK", "").strip()
secret = os.environ.get("DINGTALK_SECRET", "").strip()
if not webhook:
return False, "未配置 DINGTALK_WEBHOOK"
url = build_signed_url(webhook, secret) if secret else webhook
body = {
"msgtype": "markdown",
"markdown": {
"title": title,
"text": text,
},
}
try:
r = requests.post(url, json=body, headers={"Content-Type": "application/json"}, timeout=10)
data = r.json()
if r.status_code != 200 or data.get("errcode") != 0:
return False, data.get("errmsg", r.text) or str(r.status_code)
return True, ""
except Exception as e:
return False, str(e)