- 新增钉钉工具调用审计日志功能 - 新增参数校验装饰器与基础工具集(文档、审批、多维表格) - 完善事件类型映射与会话ID生成逻辑 - 新增消息去重、访问策略匹配、配置校验与UI提示 - 新增酷应用卡片、目录管理、表情反应支持 - 优化消息发送逻辑,添加401重试机制 - 新增配置化的权限控制与流式输出支持
180 lines
4.7 KiB
Python
180 lines
4.7 KiB
Python
from __future__ import annotations
|
|
|
|
import uuid
|
|
from typing import Any
|
|
|
|
TEXT_CHUNK_LIMIT = 4096
|
|
|
|
|
|
def generate_card_biz_id(prefix: str = "fp") -> str:
|
|
suffix = uuid.uuid4().hex[:12]
|
|
return f"{prefix}_{suffix}"
|
|
|
|
|
|
def build_dingding_text_payload(content: str) -> dict[str, Any]:
|
|
return {"content": str(content)[:TEXT_CHUNK_LIMIT]}
|
|
|
|
|
|
def build_dingding_markdown_payload(title: str, text: str) -> dict[str, Any]:
|
|
return {
|
|
"title": str(title),
|
|
"text": str(text),
|
|
}
|
|
|
|
|
|
def build_dingding_action_card(
|
|
title: str,
|
|
text: str,
|
|
*,
|
|
single_title: str | None = None,
|
|
single_url: str | None = None,
|
|
buttons: list[dict[str, str]] | None = None,
|
|
btn_orientation: str = "0",
|
|
) -> dict[str, Any]:
|
|
msg_key = "sampleActionCard1" if single_title else "sampleActionCard2"
|
|
params: dict[str, Any] = {
|
|
"title": str(title),
|
|
"text": str(text),
|
|
}
|
|
if single_title and single_url:
|
|
params["singleTitle"] = single_title
|
|
params["singleURL"] = single_url
|
|
if buttons:
|
|
params["btns"] = buttons
|
|
params["btnOrientation"] = btn_orientation
|
|
|
|
return {"msg_key": msg_key, "msg_param": params}
|
|
|
|
|
|
def build_dingding_feed_card(links: list[dict[str, str]]) -> dict[str, Any]:
|
|
return {
|
|
"msg_key": "sampleFeedCard",
|
|
"msg_param": {"links": links},
|
|
}
|
|
|
|
|
|
def build_standard_card(
|
|
*,
|
|
card_biz_id: str | None = None,
|
|
title: str = "",
|
|
markdown_content: str = "",
|
|
buttons: list[dict[str, Any]] | None = None,
|
|
status: str = "",
|
|
private_data: dict[str, Any] | None = None,
|
|
pc_slide_open: str = "0",
|
|
) -> dict[str, Any]:
|
|
biz_id = card_biz_id or generate_card_biz_id()
|
|
|
|
card_data: dict[str, Any] = {
|
|
"cardBizId": biz_id,
|
|
}
|
|
|
|
if title:
|
|
card_data["header"] = {
|
|
"title": {"type": "text", "text": title},
|
|
}
|
|
|
|
components: list[dict[str, Any]] = []
|
|
if markdown_content:
|
|
components.append({
|
|
"componentType": "markdown",
|
|
"text": markdown_content,
|
|
})
|
|
|
|
if status:
|
|
components.append({
|
|
"componentType": "status",
|
|
"status": status,
|
|
})
|
|
|
|
if buttons:
|
|
button_list: list[dict[str, Any]] = []
|
|
for btn in buttons:
|
|
button_item: dict[str, Any] = {
|
|
"actionType": btn.get("action_type", "CALLBACK"),
|
|
"title": btn.get("title", ""),
|
|
}
|
|
if "url" in btn:
|
|
button_item["url"] = btn["url"]
|
|
if "callback_key" in btn:
|
|
button_item["callbackKey"] = btn["callback_key"]
|
|
if "params" in btn:
|
|
button_item["params"] = btn["params"]
|
|
btn_color = btn.get("color", "")
|
|
if btn_color:
|
|
button_item["buttonStyle"] = {"color": btn_color}
|
|
button_list.append(button_item)
|
|
|
|
if button_list:
|
|
components.append({
|
|
"componentType": "actionGroup",
|
|
"actions": button_list,
|
|
})
|
|
|
|
if components:
|
|
card_data["body"] = components
|
|
|
|
card_data["pcSlideOpen"] = pc_slide_open
|
|
|
|
payload: dict[str, Any] = {
|
|
"cardData": card_data,
|
|
"cardBizId": biz_id,
|
|
}
|
|
|
|
if private_data:
|
|
payload["privateData"] = private_data
|
|
|
|
send_options: dict[str, Any] = {
|
|
"atAll": False,
|
|
"atUserListJson": "[]",
|
|
}
|
|
payload["sendOptions"] = send_options
|
|
|
|
return payload
|
|
|
|
|
|
def build_card_template(
|
|
template_id: str,
|
|
*,
|
|
card_biz_id: str | None = None,
|
|
variables: dict[str, Any] | None = None,
|
|
private_data: dict[str, Any] | None = None,
|
|
) -> dict[str, Any]:
|
|
biz_id = card_biz_id or generate_card_biz_id("tmpl")
|
|
|
|
payload: dict[str, Any] = {
|
|
"cardData": {
|
|
"cardBizId": biz_id,
|
|
"templateId": template_id,
|
|
"cardTemplateVariableParams": variables or {},
|
|
},
|
|
"cardBizId": biz_id,
|
|
}
|
|
|
|
if private_data:
|
|
payload["privateData"] = private_data
|
|
|
|
return payload
|
|
|
|
|
|
def build_approved_card_params(
|
|
card_data: dict[str, Any],
|
|
*,
|
|
card_instance_id: str = "",
|
|
) -> dict[str, Any]:
|
|
params: dict[str, Any] = {
|
|
"msgKey": "actionCard",
|
|
"msgParam": card_data,
|
|
}
|
|
if card_instance_id:
|
|
params["cardInstanceId"] = card_instance_id
|
|
return params
|
|
|
|
|
|
def parse_card_private_data(card_callback_data: dict[str, Any]) -> dict[str, Any]:
|
|
return card_callback_data.get("cardPrivateData", card_callback_data.get("privateData", {}))
|
|
|
|
|
|
def parse_card_callback_params(card_callback_data: dict[str, Any]) -> dict[str, Any]:
|
|
return card_callback_data.get("actionParameter", card_callback_data.get("params", {}))
|