H-337: fix Web Channel availability and realtime delivery (#60)
* H-337: fix Web Channel availability and realtime delivery * fix(widget): preserve realtime sender and activity contracts * fix(widget): keep realtime sender payloads consistent * fix(widget): make public message persistence atomic * fix(inbox): keep availability projection out of schema --------- Co-authored-by: Rogee <rogee@ipao.vip>
This commit is contained in:
@@ -43,13 +43,6 @@ func (n *noopTypingIndicatorWidget) SetTypingOff(_ context.Context, _ uint, _ ui
|
||||
return nil
|
||||
}
|
||||
|
||||
type recordingWidgetEventPublisher struct {
|
||||
accountID uint
|
||||
pubsubToken string
|
||||
eventType string
|
||||
payload interface{}
|
||||
}
|
||||
|
||||
func TestPublicMessagePayloadSanitizesIdentity(t *testing.T) {
|
||||
senderID := uint(9)
|
||||
message := model.Message{
|
||||
@@ -73,13 +66,6 @@ func TestPublicMessagePayloadSanitizesIdentity(t *testing.T) {
|
||||
assert.Empty(t, publicMessagePayload(message, model.Conversation{})["content_attributes"])
|
||||
}
|
||||
|
||||
func (p *recordingWidgetEventPublisher) PublishWidgetEvent(accountID uint, pubsubToken string, eventType string, payload interface{}) {
|
||||
p.accountID = accountID
|
||||
p.pubsubToken = pubsubToken
|
||||
p.eventType = eventType
|
||||
p.payload = payload
|
||||
}
|
||||
|
||||
type recordingWidgetTranscriptDeliverer struct {
|
||||
requests []automation.AutomationTranscriptRequest
|
||||
err error
|
||||
@@ -779,42 +765,6 @@ func TestWidgetHandler_ChatwootMessages_AuthTokenAndNestedPayload(t *testing.T)
|
||||
assertWidgetContactFixtureShape(t, contactResp)
|
||||
}
|
||||
|
||||
func TestWidgetHandler_ChatwootMessagePublishesWidgetRealtimePayload(t *testing.T) {
|
||||
db, router, handler := setupWidgetHandlerTest(t)
|
||||
_, _ = seedWidgetHandlerData(t, db)
|
||||
publisher := &recordingWidgetEventPublisher{}
|
||||
handler.WithEventPublisher(publisher)
|
||||
|
||||
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)
|
||||
|
||||
body, _ := json.Marshal(map[string]interface{}{
|
||||
"message": map[string]interface{}{"content": "Realtime widget message"},
|
||||
})
|
||||
wMessage := httptest.NewRecorder()
|
||||
reqMessage, _ := http.NewRequest("POST", "/api/v1/widget/messages", bytes.NewReader(body))
|
||||
reqMessage.Header.Set("Content-Type", "application/json")
|
||||
reqMessage.Header.Set("X-Auth-Token", authToken)
|
||||
router.ServeHTTP(wMessage, reqMessage)
|
||||
require.Equal(t, http.StatusOK, wMessage.Code)
|
||||
|
||||
assert.Equal(t, uint(1), publisher.accountID)
|
||||
assert.Equal(t, authToken, publisher.pubsubToken)
|
||||
assert.Equal(t, ws.EventMessageCreated, publisher.eventType)
|
||||
payload, ok := publisher.payload.(gin.H)
|
||||
require.True(t, ok, "expected widget realtime payload to use Chatwoot widget message shape")
|
||||
assert.Equal(t, "Realtime widget message", payload["content"])
|
||||
assert.Equal(t, uint(1), payload["account_id"])
|
||||
assert.NotEmpty(t, payload["conversation_id"])
|
||||
assertWidgetMessageFixtureShape(t, payload)
|
||||
}
|
||||
|
||||
func TestWidgetHandler_ChatwootMessagesIndexFiltersInternalMessages(t *testing.T) {
|
||||
db, router, _ := setupWidgetHandlerTest(t)
|
||||
_, inbox := seedWidgetHandlerData(t, db)
|
||||
@@ -1656,21 +1606,26 @@ func TestWidgetHandler_ChatwootInboxMembers_Success(t *testing.T) {
|
||||
db, router, _ := setupWidgetHandlerTest(t)
|
||||
_, inbox := seedWidgetHandlerData(t, db)
|
||||
|
||||
user := &model.User{
|
||||
userA := &model.User{
|
||||
AccountID: inbox.AccountID,
|
||||
Name: "Ada Agent",
|
||||
Name: "Agent A",
|
||||
Email: "ada@handler.test",
|
||||
Password: "secret",
|
||||
AvatarURL: "https://example.test/ada.png",
|
||||
Active: true,
|
||||
}
|
||||
require.NoError(t, db.Create(user).Error)
|
||||
userB := &model.User{AccountID: inbox.AccountID, Name: "Agent B", Email: "b@handler.test", Password: "secret", Active: true}
|
||||
require.NoError(t, db.Create(userA).Error)
|
||||
require.NoError(t, db.Create(userB).Error)
|
||||
require.NoError(t, db.Create(&model.AccountUser{AccountID: inbox.AccountID, UserID: userA.ID, Role: "agent", Availability: "online"}).Error)
|
||||
require.NoError(t, db.Create(&model.AccountUser{AccountID: inbox.AccountID, UserID: userB.ID, Role: "agent", Availability: "online"}).Error)
|
||||
require.NoError(t, db.Create(&model.InboxMember{
|
||||
InboxID: inbox.ID,
|
||||
UserID: user.ID,
|
||||
UserID: userA.ID,
|
||||
Role: "agent",
|
||||
AvailabilityStatus: "online",
|
||||
AvailabilityStatus: "offline",
|
||||
}).Error)
|
||||
require.NoError(t, db.Create(&model.InboxMember{InboxID: inbox.ID, UserID: userB.ID, Role: "agent", AvailabilityStatus: "offline"}).Error)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", "/api/v1/widget/inbox_members?website_token=handler_ws_token_123", nil)
|
||||
@@ -1680,10 +1635,11 @@ func TestWidgetHandler_ChatwootInboxMembers_Success(t *testing.T) {
|
||||
var resp map[string]interface{}
|
||||
require.NoError(t, json.Unmarshal(w.Body.Bytes(), &resp))
|
||||
payload := resp["payload"].([]interface{})
|
||||
require.Len(t, payload, 1)
|
||||
member := payload[0].(map[string]interface{})
|
||||
assert.Equal(t, "Ada Agent", member["name"])
|
||||
assert.Equal(t, "online", member["availability_status"])
|
||||
require.Len(t, payload, 2)
|
||||
assert.Equal(t, "Agent A", payload[0].(map[string]interface{})["name"])
|
||||
assert.Equal(t, "online", payload[0].(map[string]interface{})["availability_status"])
|
||||
assert.Equal(t, "Agent B", payload[1].(map[string]interface{})["name"])
|
||||
assert.Equal(t, "online", payload[1].(map[string]interface{})["availability_status"])
|
||||
}
|
||||
|
||||
func TestWidgetHandler_ChatwootInboxMembers_InvalidWebsiteTokenReturnsNotFound(t *testing.T) {
|
||||
|
||||
Reference in New Issue
Block a user