feat(widget): support chatwoot direct upload attachments

This commit is contained in:
2026-06-04 22:43:35 +08:00
parent 8dce39f85f
commit 8cd564e1da
10 changed files with 617 additions and 44 deletions
@@ -7,10 +7,12 @@ import (
"crypto/sha256"
"encoding/hex"
"encoding/json"
"mime/multipart"
"net/http"
"net/http/httptest"
"strconv"
"testing"
"time"
"github.com/gin-gonic/gin"
"github.com/stretchr/testify/assert"
@@ -55,6 +57,8 @@ func setupWidgetHandlerTest(t *testing.T) (*gorm.DB, *gin.Engine, *WidgetHandler
&model.ContactInbox{},
&model.Conversation{},
&model.Message{},
&model.Attachment{},
&model.DirectUpload{},
&model.WidgetThemeConfig{},
&model.PreChatForm{},
&model.WidgetFileUpload{},
@@ -353,6 +357,77 @@ func TestWidgetHandler_ChatwootMessages_AuthTokenAndNestedPayload(t *testing.T)
require.Equal(t, http.StatusOK, wContact.Code)
}
func TestWidgetHandler_ChatwootMessageDirectUploadAttachment(t *testing.T) {
db, router, _ := setupWidgetHandlerTest(t)
account, _ := seedWidgetHandlerData(t, db)
wConfig := httptest.NewRecorder()
reqConfig, _ := http.NewRequest("POST", "/api/v1/widget/config?website_token=handler_ws_token_123", nil)
router.ServeHTTP(wConfig, reqConfig)
require.Equal(t, http.StatusOK, wConfig.Code)
var configResp map[string]interface{}
require.NoError(t, json.Unmarshal(wConfig.Body.Bytes(), &configResp))
authToken := configResp["contact"].(map[string]interface{})["pubsub_token"].(string)
upload := &model.DirectUpload{
UploadUUID: "signed-widget-upload-1",
AccountID: account.ID,
Status: model.DirectUploadStatusPending,
Source: model.DirectUploadSourceWidget,
OriginalName: "screenshot.png",
FileType: "image",
MimeType: "image/png",
FileSize: 12,
FileURL: "/uploads/widget_direct/signed-widget-upload-1.png",
ThumbURL: "/uploads/widget_direct/signed-widget-upload-1.png",
ExpiresAt: time.Now().Add(time.Hour),
}
require.NoError(t, db.Create(upload).Error)
body := &bytes.Buffer{}
writer := multipart.NewWriter(body)
require.NoError(t, writer.WriteField("message[attachments][]", upload.UploadUUID))
require.NoError(t, writer.Close())
wMessage := httptest.NewRecorder()
reqMessage, _ := http.NewRequest("POST", "/api/v1/widget/messages", body)
reqMessage.Header.Set("Content-Type", writer.FormDataContentType())
reqMessage.Header.Set("X-Auth-Token", authToken)
router.ServeHTTP(wMessage, reqMessage)
require.Equal(t, http.StatusOK, wMessage.Code)
var messageResp map[string]interface{}
require.NoError(t, json.Unmarshal(wMessage.Body.Bytes(), &messageResp))
assert.Empty(t, messageResp["content"])
attachments := messageResp["attachments"].([]interface{})
require.Len(t, attachments, 1)
attachmentPayload := attachments[0].(map[string]interface{})
assert.Equal(t, "/uploads/widget_direct/signed-widget-upload-1.png", attachmentPayload["data_url"])
assert.Equal(t, "image", attachmentPayload["file_type"])
var attachment model.Attachment
require.NoError(t, db.Where("file_name = ?", "screenshot.png").First(&attachment).Error)
assert.Equal(t, upload.FileURL, attachment.FileURL)
require.NoError(t, db.First(upload, upload.ID).Error)
assert.Equal(t, model.DirectUploadStatusCompleted, upload.Status)
wIndex := httptest.NewRecorder()
reqIndex, _ := http.NewRequest("GET", "/api/v1/widget/messages", nil)
reqIndex.Header.Set("X-Auth-Token", authToken)
router.ServeHTTP(wIndex, reqIndex)
require.Equal(t, http.StatusOK, wIndex.Code)
var indexResp map[string]interface{}
require.NoError(t, json.Unmarshal(wIndex.Body.Bytes(), &indexResp))
payload := indexResp["payload"].([]interface{})
require.Len(t, payload, 1)
indexedMessage := payload[0].(map[string]interface{})
indexedAttachments := indexedMessage["attachments"].([]interface{})
require.Len(t, indexedAttachments, 1)
assert.Equal(t, "/uploads/widget_direct/signed-widget-upload-1.png", indexedAttachments[0].(map[string]interface{})["data_url"])
}
func TestWidgetHandler_ChatwootMessageUpdate_SubmitsEmail(t *testing.T) {
db, router, _ := setupWidgetHandlerTest(t)
_, inbox := seedWidgetHandlerData(t, db)