<message> - Introduce Feishu and DingTalk adapters in the robot lifecycle for enhanced integration capabilities. - Update the integration dispatcher to include new adapters for handling events from Feishu and DingTalk. - Modify the configuration structure to support settings for both Feishu and DingTalk integrations. - Enhance the integration parsing logic to recognize and process configurations for Feishu and DingTalk.
154 lines
4.5 KiB
Go
154 lines
4.5 KiB
Go
package feishu
|
|
|
|
import (
|
|
"encoding/json"
|
|
)
|
|
|
|
// ConvertedMessage is the unified output after parsing a Feishu event message.
|
|
type ConvertedMessage struct {
|
|
MessageID string `json:"message_id"`
|
|
ChatID string `json:"chat_id"`
|
|
ChatType string `json:"chat_type"` // p2p, group
|
|
SenderID string `json:"sender_id"`
|
|
SenderName string `json:"sender_name,omitempty"`
|
|
Text string `json:"text,omitempty"`
|
|
MediaItems []MediaItem `json:"media,omitempty"`
|
|
MentionBot bool `json:"mention_bot,omitempty"`
|
|
EventID string `json:"event_id,omitempty"`
|
|
LanguageCode string `json:"language_code,omitempty"`
|
|
}
|
|
|
|
// MediaItem describes a single media attachment from the message.
|
|
type MediaItem struct {
|
|
Type MediaType `json:"type"`
|
|
Key string `json:"key"`
|
|
MimeType string `json:"mime_type,omitempty"`
|
|
FileName string `json:"file_name,omitempty"`
|
|
FileSize int64 `json:"file_size,omitempty"`
|
|
Wrapper string `json:"wrapper,omitempty"`
|
|
}
|
|
|
|
// MediaType indicates the attachment type.
|
|
type MediaType string
|
|
|
|
const (
|
|
MediaImage MediaType = "image"
|
|
MediaFile MediaType = "file"
|
|
MediaAudio MediaType = "audio"
|
|
MediaVideo MediaType = "video"
|
|
MediaMedia MediaType = "media"
|
|
)
|
|
|
|
// HasMedia returns true if the message contains any media.
|
|
func (cm *ConvertedMessage) HasMedia() bool { return len(cm.MediaItems) > 0 }
|
|
|
|
// HasText returns true if the message contains text.
|
|
func (cm *ConvertedMessage) HasText() bool { return cm.Text != "" }
|
|
|
|
// feishuTextContent is the JSON structure of a text-type message body.
|
|
type feishuTextContent struct {
|
|
Text string `json:"text"`
|
|
}
|
|
|
|
// feishuImageContent is the JSON structure of an image-type message body.
|
|
type feishuImageContent struct {
|
|
ImageKey string `json:"image_key"`
|
|
}
|
|
|
|
// feishuFileContent is the JSON structure of a file-type message body.
|
|
type feishuFileContent struct {
|
|
FileKey string `json:"file_key"`
|
|
FileName string `json:"file_name"`
|
|
}
|
|
|
|
// feishuAudioContent is the JSON structure of an audio-type message body.
|
|
type feishuAudioContent struct {
|
|
FileKey string `json:"file_key"`
|
|
Duration int `json:"duration"`
|
|
}
|
|
|
|
// feishuMediaContent is the JSON structure of a media-type message body.
|
|
type feishuMediaContent struct {
|
|
FileKey string `json:"file_key"`
|
|
FileName string `json:"file_name"`
|
|
ImageKey string `json:"image_key"`
|
|
}
|
|
|
|
// ParseMessageContent parses a Feishu message body (JSON string) based on its type.
|
|
func ParseMessageContent(msgType, content string) (text string, media []MediaItem) {
|
|
switch msgType {
|
|
case "text":
|
|
var tc feishuTextContent
|
|
if err := json.Unmarshal([]byte(content), &tc); err == nil {
|
|
text = tc.Text
|
|
}
|
|
case "image":
|
|
var ic feishuImageContent
|
|
if err := json.Unmarshal([]byte(content), &ic); err == nil && ic.ImageKey != "" {
|
|
media = append(media, MediaItem{Type: MediaImage, Key: ic.ImageKey, MimeType: "image/jpeg"})
|
|
}
|
|
case "file":
|
|
var fc feishuFileContent
|
|
if err := json.Unmarshal([]byte(content), &fc); err == nil && fc.FileKey != "" {
|
|
media = append(media, MediaItem{Type: MediaFile, Key: fc.FileKey, FileName: fc.FileName})
|
|
}
|
|
case "audio":
|
|
var ac feishuAudioContent
|
|
if err := json.Unmarshal([]byte(content), &ac); err == nil && ac.FileKey != "" {
|
|
media = append(media, MediaItem{Type: MediaAudio, Key: ac.FileKey, MimeType: "audio/ogg"})
|
|
}
|
|
case "media":
|
|
var mc feishuMediaContent
|
|
if err := json.Unmarshal([]byte(content), &mc); err == nil && mc.FileKey != "" {
|
|
media = append(media, MediaItem{Type: MediaVideo, Key: mc.FileKey, FileName: mc.FileName})
|
|
}
|
|
case "post":
|
|
var post map[string]interface{}
|
|
if err := json.Unmarshal([]byte(content), &post); err == nil {
|
|
text = extractPostText(post)
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
// extractPostText extracts plain text from a rich-text (post) message.
|
|
func extractPostText(post map[string]interface{}) string {
|
|
for _, langContent := range post {
|
|
lc, ok := langContent.(map[string]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
contentArr, ok := lc["content"].([]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
var result string
|
|
for _, para := range contentArr {
|
|
paraArr, ok := para.([]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
for _, elem := range paraArr {
|
|
elemMap, ok := elem.(map[string]interface{})
|
|
if !ok {
|
|
continue
|
|
}
|
|
tag, _ := elemMap["tag"].(string)
|
|
if tag == "text" {
|
|
if t, ok := elemMap["text"].(string); ok {
|
|
result += t
|
|
}
|
|
} else if tag == "a" {
|
|
if t, ok := elemMap["text"].(string); ok {
|
|
result += t
|
|
}
|
|
}
|
|
}
|
|
result += "\n"
|
|
}
|
|
if result != "" {
|
|
return result
|
|
}
|
|
}
|
|
return ""
|
|
}
|