diff --git a/src/channels/feishu.rs b/src/channels/feishu.rs index 9f68f9e..351d25c 100644 --- a/src/channels/feishu.rs +++ b/src/channels/feishu.rs @@ -1384,7 +1384,16 @@ fn parse_post_content(content: &str) -> String { } "code_block" => { let lang = el.get("language").and_then(|l| l.as_str()).unwrap_or(""); - let code_text = el.get("text").and_then(|t| t.as_str()).unwrap_or(""); + let code_text = if let Some(content_arr) = el.get("content").and_then(|c| c.as_array()) { + content_arr + .iter() + .filter_map(|item| item.get("text").and_then(|t| t.as_str())) + .collect::>() + .join("") + } else { + // Fallback to text field for backwards compatibility + el.get("text").and_then(|t| t.as_str()).unwrap_or("").to_string() + }; out.push(format!("\n```{}\n{}\n```\n", lang, code_text)); } _ => { @@ -2190,7 +2199,7 @@ fn sanitize_download_file_name(file_name: &str) -> String { mod tests { use super::{ FeishuChannel, MsgFormat, extract_file_name_from_content_disposition, - infer_download_filename, sanitize_download_file_name, + infer_download_filename, parse_post_content, sanitize_download_file_name, }; #[test] @@ -2279,6 +2288,42 @@ mod tests { let file_name = extract_file_name_from_content_disposition(&headers); assert_eq!(file_name.as_deref(), Some("archive.zip")); } + + #[test] + fn parse_post_content_handles_code_block_with_content_array() { + // Test parsing code_block with content array (standard Feishu format) + let post_json = r#"{"post":{"zh_cn":{"content":[[{"tag":"code_block","language":"python","content":[{"tag":"text","text":"def hello():"},{"tag":"text","text":" print('world')"}]}]]}}}"#; + let result = parse_post_content(post_json); + assert!(result.contains("```python")); + assert!(result.contains("def hello():")); + assert!(result.contains("print('world')")); + } + + #[test] + fn parse_post_content_handles_code_block_with_fallback_text() { + // Backwards compatibility: some formats might use text field directly + let post_json = r#"{"post":{"zh_cn":{"content":[[{"tag":"code_block","language":"rust","text":"fn main() {}"}]]}}}"#; + let result = parse_post_content(post_json); + assert!(result.contains("```rust")); + assert!(result.contains("fn main() {}")); + } + + #[test] + fn parse_post_content_handles_code_block_without_language() { + // Test code_block without language field + let post_json = r#"{"post":{"zh_cn":{"content":[[{"tag":"code_block","content":[{"tag":"text","text":"plain text"}]}]]}}}"#; + let result = parse_post_content(post_json); + assert!(result.contains("```")); + assert!(result.contains("plain text")); + } + + #[test] + fn parse_post_content_handles_empty_code_block() { + // Test code_block with empty content + let post_json = r#"{"post":{"zh_cn":{"content":[[{"tag":"code_block","language":"go"}]]}}}"#; + let result = parse_post_content(post_json); + assert!(result.contains("```go")); + } } #[async_trait]