fix(qq): preserve filenames in file uploads (#1913)

This commit is contained in:
美電球
2026-03-24 05:00:15 +08:00
committed by GitHub
parent 2c48cd3461
commit f06173a5e0
2 changed files with 82 additions and 0 deletions
+26
View File
@@ -357,6 +357,7 @@ type qqMediaUpload struct {
FileType uint64 `json:"file_type"`
URL string `json:"url,omitempty"`
FileData string `json:"file_data,omitempty"`
FileName string `json:"file_name,omitempty"`
SrvSendMsg bool `json:"srv_send_msg,omitempty"`
}
@@ -393,6 +394,7 @@ func (c *QQChannel) buildMediaUpload(part bus.MediaPart) (*qqMediaUpload, error)
if isHTTPURL(mediaRef) {
payload.FileType = qqFileType(c.outboundMediaType(part, ""))
payload.URL = mediaRef
payload.FileName = qqUploadFilename(part, mediaRef, payload.FileType)
return payload, nil
}
@@ -415,9 +417,11 @@ func (c *QQChannel) buildMediaUpload(part bus.MediaPart) (*qqMediaUpload, error)
if isHTTPURL(resolved) {
payload.FileType = qqFileType(c.outboundMediaType(part, ""))
payload.URL = resolved
payload.FileName = qqUploadFilename(part, resolved, payload.FileType)
return payload, nil
}
payload.FileType = qqFileType(c.outboundMediaType(part, resolved))
payload.FileName = qqUploadFilename(part, resolved, payload.FileType)
if limitBytes := c.maxBase64FileSizeBytes(); limitBytes > 0 {
info, statErr := os.Stat(resolved)
@@ -444,6 +448,28 @@ func (c *QQChannel) buildMediaUpload(part bus.MediaPart) (*qqMediaUpload, error)
return payload, nil
}
func qqUploadFilename(part bus.MediaPart, resolved string, fileType uint64) string {
if fileType != qqFileType("file") {
return ""
}
if part.Filename != "" {
return part.Filename
}
if isHTTPURL(resolved) {
if parsed, err := url.Parse(resolved); err == nil {
if base := path.Base(parsed.Path); base != "" && base != "." && base != "/" {
return base
}
}
return ""
}
if base := filepath.Base(resolved); base != "" && base != "." {
return base
}
return ""
}
func (c *QQChannel) outboundMediaType(part bus.MediaPart, localPath string) string {
if part.Type != "audio" {
return part.Type
+56
View File
@@ -444,6 +444,9 @@ func TestSendMedia_UsesRemoteURLUploadForC2C(t *testing.T) {
if upload.body.FileType != 4 {
t.Fatalf("upload file_type = %d, want 4", upload.body.FileType)
}
if upload.body.FileName != "report.pdf" {
t.Fatalf("upload file_name = %q, want report.pdf", upload.body.FileName)
}
if len(api.c2cMessages) != 1 {
t.Fatalf("c2cMessages = %d, want 1", len(api.c2cMessages))
@@ -460,6 +463,59 @@ func TestSendMedia_UsesRemoteURLUploadForC2C(t *testing.T) {
}
}
func TestSendMedia_LocalFileUploadIncludesStoredFilename(t *testing.T) {
messageBus := bus.NewMessageBus()
store := media.NewFileMediaStore()
localPath := writeTempFile(t, t.TempDir(), "report.pdf", []byte("fake-pdf"))
ref, err := store.Store(localPath, media.MediaMeta{
Filename: "report.pdf",
ContentType: "application/pdf",
}, "qq:test")
if err != nil {
t.Fatalf("Store() error = %v", err)
}
api := &fakeQQAPI{
transportResp: mustJSON(t, dto.Message{FileInfo: []byte("local-file-info")}),
}
ch := &QQChannel{
BaseChannel: channels.NewBaseChannel("qq", nil, messageBus, nil),
api: api,
dedup: make(map[string]time.Time),
done: make(chan struct{}),
ctx: context.Background(),
}
ch.SetRunning(true)
ch.SetMediaStore(store)
ch.chatType.Store("user-1", "direct")
err = ch.SendMedia(context.Background(), bus.OutboundMediaMessage{
ChatID: "user-1",
Parts: []bus.MediaPart{{
Type: "file",
Ref: ref,
}},
})
if err != nil {
t.Fatalf("SendMedia() error = %v", err)
}
if len(api.transportCalls) != 1 {
t.Fatalf("transportCalls = %d, want 1", len(api.transportCalls))
}
upload := api.transportCalls[0]
if upload.body.FileType != 4 {
t.Fatalf("upload file_type = %d, want 4", upload.body.FileType)
}
if upload.body.FileName != "report.pdf" {
t.Fatalf("upload file_name = %q, want report.pdf", upload.body.FileName)
}
if upload.body.FileData == "" {
t.Fatal("upload file_data = empty, want base64 payload")
}
}
func TestSendMedia_ReturnsSendFailedWithoutMediaStore(t *testing.T) {
messageBus := bus.NewMessageBus()
ch := &QQChannel{