feat(crm): align nested conversation payloads
This commit is contained in:
@@ -265,16 +265,13 @@ func (h *CompanyHandler) ListConversations(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
pg := pagination.Parse(c)
|
||||
|
||||
conversations, total, svcErr := h.svc.ListConversations(c.Request.Context(), uint(companyID), accountID, pg.Offset, pg.PerPage)
|
||||
conversations, _, svcErr := h.svc.ListConversations(c.Request.Context(), uint(companyID), accountID, 0, 20)
|
||||
if svcErr != nil {
|
||||
handleServiceError(c, svcErr)
|
||||
return
|
||||
}
|
||||
|
||||
_ = total
|
||||
c.JSON(http.StatusOK, gin.H{"payload": conversations})
|
||||
c.JSON(http.StatusOK, gin.H{"payload": serializeConversationPayloads(c.Request.Context(), h.svc.DB(), conversations)})
|
||||
}
|
||||
|
||||
func (h *CompanyHandler) SearchContacts(c *gin.Context) {
|
||||
|
||||
@@ -8,6 +8,7 @@ import (
|
||||
"net/http"
|
||||
"net/http/httptest"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"github.com/stretchr/testify/assert"
|
||||
@@ -60,6 +61,8 @@ func (s *CompanyHandlerTestSuite) SetupSuite() {
|
||||
&model.Contact{},
|
||||
&model.Inbox{},
|
||||
&model.Conversation{},
|
||||
&model.Message{},
|
||||
&model.Attachment{},
|
||||
))
|
||||
s.db = db
|
||||
|
||||
@@ -129,6 +132,10 @@ func (s *CompanyHandlerTestSuite) TearDownSuite() {
|
||||
|
||||
func (s *CompanyHandlerTestSuite) SetupTest() {
|
||||
// Clean company-related tables between tests
|
||||
s.db.Exec("DELETE FROM attachments")
|
||||
s.db.Exec("DELETE FROM messages")
|
||||
s.db.Exec("DELETE FROM conversations")
|
||||
s.db.Exec("DELETE FROM contacts")
|
||||
s.db.Exec("DELETE FROM company_notes")
|
||||
s.db.Exec("DELETE FROM company_contacts")
|
||||
s.db.Exec("DELETE FROM companies")
|
||||
@@ -379,9 +386,38 @@ func (s *CompanyHandlerTestSuite) TestListConversations_Success() {
|
||||
companyRepo := repository.NewCompanyRepo(s.db)
|
||||
company := &model.Company{AccountID: s.accountID, Name: "ConvsCorp"}
|
||||
s.Require().NoError(companyRepo.Create(context.Background(), company))
|
||||
contact := &model.Contact{AccountID: s.accountID, CompanyID: &company.ID, Name: "Company Contact", Email: "company-contact@example.com"}
|
||||
s.Require().NoError(s.db.Create(contact).Error)
|
||||
inbox := &model.Inbox{AccountID: s.accountID, Name: "Company Inbox", ChannelType: "web_widget", ChannelID: 1}
|
||||
s.Require().NoError(s.db.Create(inbox).Error)
|
||||
|
||||
now := time.Now().Unix()
|
||||
conversation := &model.Conversation{AccountID: s.accountID, InboxID: inbox.ID, ContactID: contact.ID, Status: "open", Priority: "urgent", ChannelType: "web_widget", Channel: "web_widget", LastActivityAt: &now}
|
||||
s.Require().NoError(s.db.Create(conversation).Error)
|
||||
senderID := contact.ID
|
||||
s.Require().NoError(s.db.Create(&model.Message{AccountID: s.accountID, InboxID: inbox.ID, ConversationID: conversation.ID, SenderID: &senderID, SenderType: "contact", MessageType: "incoming", ContentType: "text", Status: "sent", Content: "Company scoped message"}).Error)
|
||||
|
||||
w := s.makeRequest("GET", fmt.Sprintf("/api/v1/accounts/%d/companies/%d/conversations", s.accountID, company.ID), nil)
|
||||
assert.Equal(s.T(), http.StatusOK, w.Code)
|
||||
|
||||
var resp map[string]interface{}
|
||||
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
|
||||
payload := resp["payload"].([]interface{})
|
||||
s.Require().Len(payload, 1)
|
||||
first := payload[0].(map[string]interface{})
|
||||
assert.Equal(s.T(), "urgent", first["priority"])
|
||||
assert.Equal(s.T(), float64(conversation.ID), first["id"])
|
||||
assert.Equal(s.T(), float64(s.accountID), first["account_id"])
|
||||
assert.NotContains(s.T(), first, "contact_id")
|
||||
|
||||
meta := first["meta"].(map[string]interface{})
|
||||
assert.Equal(s.T(), "web_widget", meta["channel"])
|
||||
assert.Equal(s.T(), float64(contact.ID), meta["sender"].(map[string]interface{})["id"])
|
||||
messages := first["messages"].([]interface{})
|
||||
s.Require().Len(messages, 1)
|
||||
message := messages[0].(map[string]interface{})
|
||||
assert.Equal(s.T(), "Company scoped message", message["content"])
|
||||
assert.Equal(s.T(), float64(0), message["message_type"])
|
||||
}
|
||||
|
||||
// ========== ListNotes ==========
|
||||
|
||||
@@ -416,7 +416,7 @@ func (h *ContactHandler) ListConversations(c *gin.Context) {
|
||||
return
|
||||
}
|
||||
|
||||
c.JSON(http.StatusOK, gin.H{"payload": conversations})
|
||||
c.JSON(http.StatusOK, gin.H{"payload": serializeConversationPayloads(c.Request.Context(), h.svc.DB(), conversations)})
|
||||
}
|
||||
|
||||
// ListNotes retrieves notes for a contact.
|
||||
|
||||
@@ -57,6 +57,7 @@ func (s *ContactHandlerCRUDTestSuite) SetupSuite() {
|
||||
&model.Notification{},
|
||||
&model.Conversation{},
|
||||
&model.Message{},
|
||||
&model.Attachment{},
|
||||
&model.ContactInbox{},
|
||||
&model.InboxMember{},
|
||||
&model.ContactNote{},
|
||||
@@ -134,6 +135,7 @@ func (s *ContactHandlerCRUDTestSuite) SetupTest() {
|
||||
s.db.Exec("DELETE FROM contact_exports")
|
||||
s.db.Exec("DELETE FROM data_imports")
|
||||
s.db.Exec("DELETE FROM notifications")
|
||||
s.db.Exec("DELETE FROM attachments")
|
||||
s.db.Exec("DELETE FROM messages")
|
||||
s.db.Exec("DELETE FROM notes")
|
||||
s.db.Exec("DELETE FROM contact_inboxes")
|
||||
@@ -852,8 +854,12 @@ func (s *ContactHandlerCRUDTestSuite) TestListConversations_Success() {
|
||||
|
||||
now := time.Now().Unix()
|
||||
older := now - 60
|
||||
s.Require().NoError(s.db.Create(&model.Conversation{AccountID: s.account.ID, InboxID: inbox.ID, ContactID: s.contact.ID, Status: "open", Priority: "low", ChannelType: "web_widget", Channel: "web_widget", LastActivityAt: &older}).Error)
|
||||
s.Require().NoError(s.db.Create(&model.Conversation{AccountID: s.account.ID, InboxID: inbox.ID, ContactID: s.contact.ID, Status: "open", Priority: "high", ChannelType: "web_widget", Channel: "web_widget", LastActivityAt: &now}).Error)
|
||||
olderConversation := &model.Conversation{AccountID: s.account.ID, InboxID: inbox.ID, ContactID: s.contact.ID, Status: "open", Priority: "low", ChannelType: "web_widget", Channel: "web_widget", LastActivityAt: &older}
|
||||
recentConversation := &model.Conversation{AccountID: s.account.ID, InboxID: inbox.ID, ContactID: s.contact.ID, Status: "open", Priority: "high", ChannelType: "web_widget", Channel: "web_widget", LastActivityAt: &now}
|
||||
s.Require().NoError(s.db.Create(olderConversation).Error)
|
||||
s.Require().NoError(s.db.Create(recentConversation).Error)
|
||||
senderID := s.contact.ID
|
||||
s.Require().NoError(s.db.Create(&model.Message{AccountID: s.account.ID, InboxID: inbox.ID, ConversationID: recentConversation.ID, SenderID: &senderID, SenderType: "contact", MessageType: "incoming", ContentType: "text", Status: "sent", Content: "Latest contact message"}).Error)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req, _ := http.NewRequest("GET", fmt.Sprintf("/api/v1/accounts/%d/contacts/%d/conversations", s.account.ID, s.contact.ID), nil)
|
||||
@@ -867,6 +873,24 @@ func (s *ContactHandlerCRUDTestSuite) TestListConversations_Success() {
|
||||
s.Len(payload, 2)
|
||||
first := payload[0].(map[string]interface{})
|
||||
s.Equal("high", first["priority"])
|
||||
s.Contains(first, "meta")
|
||||
s.Contains(first, "messages")
|
||||
s.Contains(first, "last_non_activity_message")
|
||||
s.Equal(float64(recentConversation.ID), first["id"])
|
||||
s.Equal(float64(s.account.ID), first["account_id"])
|
||||
s.Equal(float64(inbox.ID), first["inbox_id"])
|
||||
s.NotContains(first, "contact_id")
|
||||
|
||||
meta := first["meta"].(map[string]interface{})
|
||||
s.Equal("web_widget", meta["channel"])
|
||||
s.Equal(float64(s.contact.ID), meta["sender"].(map[string]interface{})["id"])
|
||||
|
||||
messages := first["messages"].([]interface{})
|
||||
s.Len(messages, 1)
|
||||
message := messages[0].(map[string]interface{})
|
||||
s.Equal("Latest contact message", message["content"])
|
||||
s.Equal(float64(0), message["message_type"])
|
||||
s.Equal(float64(recentConversation.ID), message["conversation_id"])
|
||||
}
|
||||
|
||||
func (s *ContactHandlerCRUDTestSuite) TestListConversations_InvalidContactID() {
|
||||
|
||||
@@ -108,6 +108,14 @@ func serializeConversationList(ctx context.Context, db *gorm.DB, conversations [
|
||||
}}
|
||||
}
|
||||
|
||||
func serializeConversationPayloads(ctx context.Context, db *gorm.DB, conversations []model.Conversation) []chatwootConversationPayload {
|
||||
payload := make([]chatwootConversationPayload, 0, len(conversations))
|
||||
for i := range conversations {
|
||||
payload = append(payload, serializeConversation(ctx, db, &conversations[i]))
|
||||
}
|
||||
return payload
|
||||
}
|
||||
|
||||
func serializeConversation(ctx context.Context, db *gorm.DB, conversation *model.Conversation) chatwootConversationPayload {
|
||||
var lastMessage *model.Message
|
||||
if db != nil {
|
||||
|
||||
Reference in New Issue
Block a user