fix(qq): preserve filenames in file uploads (#1913)
This commit is contained in:
parent
2c48cd3461
commit
f06173a5e0
2 changed files with 82 additions and 0 deletions
|
|
@ -357,6 +357,7 @@ type qqMediaUpload struct {
|
||||||
FileType uint64 `json:"file_type"`
|
FileType uint64 `json:"file_type"`
|
||||||
URL string `json:"url,omitempty"`
|
URL string `json:"url,omitempty"`
|
||||||
FileData string `json:"file_data,omitempty"`
|
FileData string `json:"file_data,omitempty"`
|
||||||
|
FileName string `json:"file_name,omitempty"`
|
||||||
SrvSendMsg bool `json:"srv_send_msg,omitempty"`
|
SrvSendMsg bool `json:"srv_send_msg,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -393,6 +394,7 @@ func (c *QQChannel) buildMediaUpload(part bus.MediaPart) (*qqMediaUpload, error)
|
||||||
if isHTTPURL(mediaRef) {
|
if isHTTPURL(mediaRef) {
|
||||||
payload.FileType = qqFileType(c.outboundMediaType(part, ""))
|
payload.FileType = qqFileType(c.outboundMediaType(part, ""))
|
||||||
payload.URL = mediaRef
|
payload.URL = mediaRef
|
||||||
|
payload.FileName = qqUploadFilename(part, mediaRef, payload.FileType)
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -415,9 +417,11 @@ func (c *QQChannel) buildMediaUpload(part bus.MediaPart) (*qqMediaUpload, error)
|
||||||
if isHTTPURL(resolved) {
|
if isHTTPURL(resolved) {
|
||||||
payload.FileType = qqFileType(c.outboundMediaType(part, ""))
|
payload.FileType = qqFileType(c.outboundMediaType(part, ""))
|
||||||
payload.URL = resolved
|
payload.URL = resolved
|
||||||
|
payload.FileName = qqUploadFilename(part, resolved, payload.FileType)
|
||||||
return payload, nil
|
return payload, nil
|
||||||
}
|
}
|
||||||
payload.FileType = qqFileType(c.outboundMediaType(part, resolved))
|
payload.FileType = qqFileType(c.outboundMediaType(part, resolved))
|
||||||
|
payload.FileName = qqUploadFilename(part, resolved, payload.FileType)
|
||||||
|
|
||||||
if limitBytes := c.maxBase64FileSizeBytes(); limitBytes > 0 {
|
if limitBytes := c.maxBase64FileSizeBytes(); limitBytes > 0 {
|
||||||
info, statErr := os.Stat(resolved)
|
info, statErr := os.Stat(resolved)
|
||||||
|
|
@ -444,6 +448,28 @@ func (c *QQChannel) buildMediaUpload(part bus.MediaPart) (*qqMediaUpload, error)
|
||||||
return payload, nil
|
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 {
|
func (c *QQChannel) outboundMediaType(part bus.MediaPart, localPath string) string {
|
||||||
if part.Type != "audio" {
|
if part.Type != "audio" {
|
||||||
return part.Type
|
return part.Type
|
||||||
|
|
|
||||||
|
|
@ -444,6 +444,9 @@ func TestSendMedia_UsesRemoteURLUploadForC2C(t *testing.T) {
|
||||||
if upload.body.FileType != 4 {
|
if upload.body.FileType != 4 {
|
||||||
t.Fatalf("upload file_type = %d, want 4", upload.body.FileType)
|
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 {
|
if len(api.c2cMessages) != 1 {
|
||||||
t.Fatalf("c2cMessages = %d, want 1", len(api.c2cMessages))
|
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) {
|
func TestSendMedia_ReturnsSendFailedWithoutMediaStore(t *testing.T) {
|
||||||
messageBus := bus.NewMessageBus()
|
messageBus := bus.NewMessageBus()
|
||||||
ch := &QQChannel{
|
ch := &QQChannel{
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue