143 lines
3.4 KiB
Go
143 lines
3.4 KiB
Go
package isphere
|
|
|
|
import (
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"strings"
|
|
)
|
|
|
|
type File struct {
|
|
FileID string
|
|
MessageID string
|
|
ConversationID string
|
|
FileName string
|
|
SizeBytes *int64
|
|
MimeType string
|
|
CreatedAt string
|
|
DownloadRef string
|
|
SavedPath string
|
|
SHA256 string
|
|
Source string
|
|
RawRef string
|
|
}
|
|
|
|
type ListFilesQuery struct {
|
|
ConversationID string
|
|
MessageID string
|
|
FileID string
|
|
NameContains string
|
|
Limit int
|
|
}
|
|
|
|
type ListFilesResult struct {
|
|
Files []File
|
|
}
|
|
|
|
var fileNamePattern = regexp.MustCompile(`(?i)[^\s<>:"|?*]+\.(?:docx?|xlsx?|pptx?|pdf|zip|rar|png|jpe?g|txt|csv)\b`)
|
|
|
|
func ListFilesFromMessages(messages []Message, query ListFilesQuery) ListFilesResult {
|
|
files := make([]File, 0)
|
|
for _, message := range messages {
|
|
if !messageLooksFileBacked(message) {
|
|
continue
|
|
}
|
|
fileName := extractMessageFileName(message.Text)
|
|
if fileName == "" {
|
|
continue
|
|
}
|
|
file := File{
|
|
FileID: fileID(message.ID, fileName),
|
|
MessageID: message.ID,
|
|
ConversationID: message.ConversationID,
|
|
FileName: fileName,
|
|
MimeType: mimeTypeForFileName(fileName),
|
|
CreatedAt: message.Timestamp,
|
|
Source: "local_readonly",
|
|
RawRef: "packetlog_file_transfer",
|
|
}
|
|
if fileMatchesQuery(file, query) {
|
|
files = append(files, file)
|
|
}
|
|
}
|
|
|
|
sort.Slice(files, func(i, j int) bool {
|
|
if files[i].FileID == files[j].FileID {
|
|
return files[i].MessageID < files[j].MessageID
|
|
}
|
|
return files[i].FileID < files[j].FileID
|
|
})
|
|
|
|
limit := query.Limit
|
|
if limit <= 0 || limit > len(files) {
|
|
limit = len(files)
|
|
}
|
|
return ListFilesResult{Files: files[:limit]}
|
|
}
|
|
|
|
func messageLooksFileBacked(message Message) bool {
|
|
return strings.Contains(strings.ToUpper(message.Subject), "FILE_TRANSFER") || extractMessageFileName(message.Text) != ""
|
|
}
|
|
|
|
func extractMessageFileName(text string) string {
|
|
match := fileNamePattern.FindString(strings.TrimSpace(text))
|
|
return strings.Trim(match, " .,;,。;")
|
|
}
|
|
|
|
func fileID(messageID string, fileName string) string {
|
|
if messageID == "" {
|
|
return fileName
|
|
}
|
|
return messageID + ":" + fileName
|
|
}
|
|
|
|
func fileMatchesQuery(file File, query ListFilesQuery) bool {
|
|
if query.ConversationID != "" && file.ConversationID != query.ConversationID {
|
|
return false
|
|
}
|
|
if query.MessageID != "" && file.MessageID != query.MessageID {
|
|
return false
|
|
}
|
|
if query.FileID != "" && file.FileID != query.FileID {
|
|
return false
|
|
}
|
|
nameQuery := strings.ToLower(strings.TrimSpace(query.NameContains))
|
|
if nameQuery != "" && !strings.Contains(strings.ToLower(file.FileName), nameQuery) {
|
|
return false
|
|
}
|
|
return true
|
|
}
|
|
|
|
func mimeTypeForFileName(name string) string {
|
|
switch strings.ToLower(filepath.Ext(name)) {
|
|
case ".doc":
|
|
return "application/msword"
|
|
case ".docx":
|
|
return "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
|
|
case ".xls":
|
|
return "application/vnd.ms-excel"
|
|
case ".xlsx":
|
|
return "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet"
|
|
case ".ppt":
|
|
return "application/vnd.ms-powerpoint"
|
|
case ".pptx":
|
|
return "application/vnd.openxmlformats-officedocument.presentationml.presentation"
|
|
case ".pdf":
|
|
return "application/pdf"
|
|
case ".zip":
|
|
return "application/zip"
|
|
case ".rar":
|
|
return "application/vnd.rar"
|
|
case ".png":
|
|
return "image/png"
|
|
case ".jpg", ".jpeg":
|
|
return "image/jpeg"
|
|
case ".txt":
|
|
return "text/plain"
|
|
case ".csv":
|
|
return "text/csv"
|
|
default:
|
|
return ""
|
|
}
|
|
}
|