Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 6 additions & 3 deletions src/dingtalk_channel_sdk/normalize/converters/richtext.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,14 @@ def convert_rich_text(content: Dict[str, Any]) -> Tuple[str, List[Dict[str, Any]
resources: List[Dict[str, Any]] = []
seen: set = set()
parts: List[str] = []
for item in (content or {}).get("richText", []):
rich_list = (content or {}).get("richText")
if not isinstance(rich_list, list):
return "", mentions, resources
for item in rich_list:
if not isinstance(item, dict):
continue
item_type = item.get("type", "")
if item_type == "text":
item_type = item.get("type") or ""
if item_type in ("", "text"):
text = item.get("text", "")
if isinstance(text, str):
parts.append(text)
Expand Down
65 changes: 65 additions & 0 deletions tests/test_message.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,71 @@ def test_normalize_richtext():
assert any(m.get("userId") == "staff-2" for m in msg.mentions)


def test_normalize_richtext_with_attachment_without_text_type():
"""钉钉带附件的 richText 消息:顶层无 text 字段,且 richText 文本段无 type 字段。"""
# 群聊:@机器人 + 文本 + 图片
data_group = json.dumps({
"conversationId": "cid-1",
"conversationType": "2",
"msgId": "rt-2",
"senderStaffId": "staff-1",
"senderNick": "John",
"sessionWebhook": "",
"isInAtList": True,
"msgtype": "richText",
"content": {
"richText": [
{"text": "@机器人 请帮我看看这张图"},
{"downloadCode": "dc-pic-1", "type": "picture", "pictureDownloadCode": "pdc-1"},
]
},
})
msg_group = normalize_incoming(data_group)
assert msg_group.text == "请帮我看看这张图"
assert msg_group.resources == [{"type": "image", "downloadCode": "dc-pic-1"}]

# 单聊真实样本:图片段在前 + {"text": "\n"} + {"text": "请解释下"}(均无 type 字段)
data_dm = json.dumps({
"senderPlatform": "Win",
"conversationId": "cidXxxxxx=",
"chatbotCorpId": "dingxxxxxx",
"chatbotUserId": "$:LWCP_v1:$xXxxxx",
"openThreadId": "cidXxxxxx=",
"msgId": "msgsXxxxxxx",
"senderNick": "Xxxxx",
"isAdmin": True,
"senderStaffId": "0000000000-1234334534",
"sessionWebhookExpiredTime": 1792294060566,
"createAt": 1792288660182,
"content": {
"richText": [
{
"pictureDownloadCode": "EJiwxxxxx",
"downloadCode": "mIoxxxxx",
"type": "picture",
},
{
"text": "\n",
},
{
"text": "请解释下",
},
]
},
"senderCorpId": "dingxxxxxx",
"conversationType": "1",
"senderId": "$:LWCP_v1:$Xxxxxx",
"sessionWebhook": "https://oapi.dingtalk.com/robot/sendBySession?session=xxxx",
"robotCode": "dingjgxxxxxxxxxxxxxxx",
"msgtype": "richText",
})
msg_dm = normalize_incoming(data_dm)
assert msg_dm.text == "请解释下"
assert msg_dm.resources == [{"type": "image", "downloadCode": "mIoxxxxx"}]




def test_normalize_picture():
data = json.dumps({
"conversationId": "cid-1",
Expand Down
19 changes: 19 additions & 0 deletions tests/test_normalize_converters.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,3 +178,22 @@ def test_convert_rich_text_resources_dirty_data():
text, resources, _ = parse_content("richText", content, [])
assert text == "ok"
assert resources == []


def test_convert_rich_text_without_type_field():
"""钉钉真实 richText 回调中文本段通常不带 type 字段(仅有 {"text": "..."})。"""
content = {
"richText": [
{"text": "请帮我看看"},
{"downloadCode": "dc-img-1", "type": "picture", "pictureDownloadCode": "pdc-1"},
{"text": "和这份文档"},
{"downloadCode": "dc-file-1", "type": "file", "fileName": "spec.pdf"},
]
}
text, resources, _ = parse_content("richText", content, [])
assert text == "请帮我看看和这份文档"
assert resources == [
{"type": "image", "downloadCode": "dc-img-1"},
{"type": "file", "downloadCode": "dc-file-1", "fileName": "spec.pdf"},
]