fix(feishu): tolerate null multi_url and list fields in card extract
This commit is contained in:
@@ -269,7 +269,7 @@ def _extract_element_content(element: dict) -> list[str]:
|
|||||||
parts.append(text_content)
|
parts.append(text_content)
|
||||||
elif isinstance(text, str):
|
elif isinstance(text, str):
|
||||||
parts.append(text)
|
parts.append(text)
|
||||||
for field in element.get("fields", []):
|
for field in element.get("fields") or []:
|
||||||
if isinstance(field, dict):
|
if isinstance(field, dict):
|
||||||
field_text = field.get("text", {})
|
field_text = field.get("text", {})
|
||||||
if isinstance(field_text, dict):
|
if isinstance(field_text, dict):
|
||||||
@@ -291,7 +291,10 @@ def _extract_element_content(element: dict) -> list[str]:
|
|||||||
c = text.get("content", "")
|
c = text.get("content", "")
|
||||||
if c:
|
if c:
|
||||||
parts.append(c)
|
parts.append(c)
|
||||||
url = element.get("url", "") or element.get("multi_url", {}).get("url", "")
|
multi_url = element.get("multi_url") or {}
|
||||||
|
url = element.get("url", "") or (
|
||||||
|
multi_url.get("url", "") if isinstance(multi_url, dict) else ""
|
||||||
|
)
|
||||||
if url:
|
if url:
|
||||||
parts.append(f"link: {url}")
|
parts.append(f"link: {url}")
|
||||||
|
|
||||||
@@ -300,12 +303,14 @@ def _extract_element_content(element: dict) -> list[str]:
|
|||||||
parts.append(alt.get("content", "[image]") if isinstance(alt, dict) else "[image]")
|
parts.append(alt.get("content", "[image]") if isinstance(alt, dict) else "[image]")
|
||||||
|
|
||||||
elif tag == "note":
|
elif tag == "note":
|
||||||
for ne in element.get("elements", []):
|
for ne in element.get("elements") or []:
|
||||||
parts.extend(_extract_element_content(ne))
|
parts.extend(_extract_element_content(ne))
|
||||||
|
|
||||||
elif tag == "column_set":
|
elif tag == "column_set":
|
||||||
for col in element.get("columns", []):
|
for col in element.get("columns") or []:
|
||||||
for ce in col.get("elements", []):
|
if not isinstance(col, dict):
|
||||||
|
continue
|
||||||
|
for ce in col.get("elements") or []:
|
||||||
parts.extend(_extract_element_content(ce))
|
parts.extend(_extract_element_content(ce))
|
||||||
|
|
||||||
elif tag == "plain_text":
|
elif tag == "plain_text":
|
||||||
@@ -319,7 +324,7 @@ def _extract_element_content(element: dict) -> list[str]:
|
|||||||
for column in (element.get("columns") or [])
|
for column in (element.get("columns") or [])
|
||||||
if isinstance(column, dict) and column.get("name")
|
if isinstance(column, dict) and column.get("name")
|
||||||
]
|
]
|
||||||
rows = element.get("rows", [])
|
rows = element.get("rows") or []
|
||||||
if columns:
|
if columns:
|
||||||
parts.append(" | ".join(header for _, header in columns))
|
parts.append(" | ".join(header for _, header in columns))
|
||||||
if isinstance(rows, list):
|
if isinstance(rows, list):
|
||||||
@@ -337,7 +342,7 @@ def _extract_element_content(element: dict) -> list[str]:
|
|||||||
parts.append(row_text)
|
parts.append(row_text)
|
||||||
|
|
||||||
else:
|
else:
|
||||||
for ne in element.get("elements", []):
|
for ne in element.get("elements") or []:
|
||||||
parts.extend(_extract_element_content(ne))
|
parts.extend(_extract_element_content(ne))
|
||||||
|
|
||||||
return parts
|
return parts
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import json
|
import json
|
||||||
|
|
||||||
from nanobot.channels.feishu.runtime import (
|
from nanobot.channels.feishu.runtime import (
|
||||||
|
_extract_element_content,
|
||||||
_extract_post_content,
|
_extract_post_content,
|
||||||
_extract_share_card_content,
|
_extract_share_card_content,
|
||||||
)
|
)
|
||||||
@@ -60,3 +61,28 @@ def test_extract_post_content_tolerates_null_fields() -> None:
|
|||||||
assert "@user" in text
|
assert "@user" in text
|
||||||
assert "ok" in text
|
assert "ok" in text
|
||||||
assert images == []
|
assert images == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_button_tolerates_null_multi_url() -> None:
|
||||||
|
element = {"tag": "button", "text": {"content": "Go"}, "multi_url": None}
|
||||||
|
assert _extract_element_content(element) == ["Go"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_column_set_tolerates_null_columns_and_elements() -> None:
|
||||||
|
assert _extract_element_content({"tag": "column_set", "columns": None}) == []
|
||||||
|
assert _extract_element_content(
|
||||||
|
{"tag": "column_set", "columns": [{"elements": None}]}
|
||||||
|
) == []
|
||||||
|
|
||||||
|
|
||||||
|
def test_extract_div_tolerates_null_fields() -> None:
|
||||||
|
assert _extract_element_content(
|
||||||
|
{"tag": "div", "text": {"content": "hi"}, "fields": None}
|
||||||
|
) == ["hi"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_interactive_card_button_null_multi_url() -> None:
|
||||||
|
content = {
|
||||||
|
"elements": [{"tag": "button", "text": {"content": "Go"}, "multi_url": None}]
|
||||||
|
}
|
||||||
|
assert _extract_share_card_content(content, "interactive") == "Go"
|
||||||
|
|||||||
Reference in New Issue
Block a user