package feishu import ( "encoding/json" "regexp" "strings" larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1" ) // stringValue safely dereferences a *string pointer. func stringValue(v *string) string { if v == nil { return "" } return *v } // buildMarkdownCard builds a Feishu Interactive Card JSON 2.0 string with markdown content. // JSON 2.0 cards support full CommonMark standard markdown syntax. func buildMarkdownCard(content string) (string, error) { card := map[string]any{ "schema": "2.0", "body": map[string]any{ "elements": []map[string]any{ { "tag": "markdown", "content": content, }, }, }, } data, err := json.Marshal(card) if err != nil { return "", err } return string(data), nil } // extractImageKey extracts the image_key from a Feishu image message content JSON. // Format: {"image_key": "img_xxx"} func extractImageKey(content string) string { var payload struct { ImageKey string `json:"image_key"` } if err := json.Unmarshal([]byte(content), &payload); err != nil { return "" } return payload.ImageKey } // extractFileKey extracts the file_key from a Feishu file/audio message content JSON. // Format: {"file_key": "file_xxx", "file_name": "...", ...} func extractFileKey(content string) string { var payload struct { FileKey string `json:"file_key"` } if err := json.Unmarshal([]byte(content), &payload); err != nil { return "" } return payload.FileKey } // extractFileName extracts the file_name from a Feishu file message content JSON. func extractFileName(content string) string { var payload struct { FileName string `json:"file_name"` } if err := json.Unmarshal([]byte(content), &payload); err != nil { return "" } return payload.FileName } // mentionPlaceholderRegex matches @_user_N placeholders inserted by Feishu for mentions. var mentionPlaceholderRegex = regexp.MustCompile(`@_user_\d+`) // stripMentionPlaceholders removes @_user_N placeholders from the text content. // These are inserted by Feishu when users @mention someone in a message. func stripMentionPlaceholders(content string, mentions []*larkim.MentionEvent) string { if len(mentions) == 0 { return content } for _, m := range mentions { if m.Key != nil && *m.Key != "" { content = strings.ReplaceAll(content, *m.Key, "") } } // Also clean up any remaining @_user_N patterns content = mentionPlaceholderRegex.ReplaceAllString(content, "") return strings.TrimSpace(content) }