feat(conversations): filter meta query source

This commit is contained in:
2026-06-07 03:04:15 +08:00
parent cdc0978476
commit a518a0de7e
5 changed files with 80 additions and 4 deletions
@@ -236,6 +236,31 @@ func (s *ConversationHandlerTestSuite) TestMeta_FiltersStatusAndIgnoresAssigneeT
assert.Equal(s.T(), int64(2), resp.Meta.AllCount)
}
func (s *ConversationHandlerTestSuite) TestMeta_QueryAndSourceIDFilters() {
contactInbox := &model.ContactInbox{ContactID: s.testConv.ContactID, InboxID: s.testConv.InboxID, SourceID: "widget-source"}
s.Require().NoError(s.db.Create(contactInbox).Error)
s.Require().NoError(s.db.Model(s.testConv).Updates(map[string]any{"contact_inbox_id": contactInbox.ID, "assignee_id": s.testUser.ID}).Error)
other := &model.Conversation{AccountID: s.testAccount.ID, InboxID: s.testConv.InboxID, ContactID: s.testConv.ContactID, Status: "open", ChannelType: "web_widget", Channel: "web_widget"}
s.Require().NoError(s.db.Create(other).Error)
s.Require().NoError(s.db.Create(&model.Message{AccountID: s.testAccount.ID, InboxID: s.testConv.InboxID, ConversationID: s.testConv.ID, Content: "needle from widget", MessageType: string(model.MessageTypeIncoming)}).Error)
s.Require().NoError(s.db.Create(&model.Message{AccountID: s.testAccount.ID, InboxID: s.testConv.InboxID, ConversationID: other.ID, Content: "needle from other", MessageType: string(model.MessageTypeIncoming)}).Error)
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", s.accountURL()+"/conversations/meta?q=needle&source_id=widget-source", nil)
s.router.ServeHTTP(w, req)
assert.Equal(s.T(), http.StatusOK, w.Code)
var resp struct {
Meta struct {
MineCount int64 `json:"mine_count"`
AllCount int64 `json:"all_count"`
} `json:"meta"`
}
s.Require().NoError(json.Unmarshal(w.Body.Bytes(), &resp))
assert.Equal(s.T(), int64(1), resp.Meta.AllCount)
assert.Equal(s.T(), int64(1), resp.Meta.MineCount)
}
func (s *ConversationHandlerTestSuite) TestMeta_InvalidAccountID() {
w := httptest.NewRecorder()
req, _ := http.NewRequest("GET", "/api/v1/accounts/invalid/conversations/meta", nil)
+12
View File
@@ -397,6 +397,8 @@ type ConversationMetaParams struct {
TeamID *uint
Labels []string
ConversationType string
Query string
SourceID string
RestrictedInboxIDs []uint
RestrictToInboxes bool
}
@@ -446,6 +448,16 @@ func (r *ConversationRepo) conversationMetaBaseQuery(ctx context.Context, accoun
query = query.Where(r.db.Where(strings.Join(conditions, " OR "), args...).Or("conversations.id IN (?)", tagSubquery))
}
}
if strings.TrimSpace(params.Query) != "" {
searchTerm := "%" + strings.TrimSpace(params.Query) + "%"
query = query.Joins("JOIN messages ON messages.conversation_id = conversations.id").
Where("messages.content LIKE ?", searchTerm).
Where("messages.message_type IN ?", []string{string(model.MessageTypeIncoming), string(model.MessageTypeOutgoing)})
}
if strings.TrimSpace(params.SourceID) != "" {
query = query.Joins("JOIN contact_inboxes ON contact_inboxes.id = conversations.contact_inbox_id").
Where("contact_inboxes.source_id = ?", strings.TrimSpace(params.SourceID))
}
switch params.ConversationType {
case "mention":
@@ -523,6 +523,39 @@ func TestConversationRepo_GetMeta_FiltersStatusLabelsAndConversationType(t *test
assert.Equal(t, int64(1), meta.UnassignedCount)
}
func TestConversationRepo_GetMeta_FiltersQueryAndSourceID(t *testing.T) {
db := setupTestDB(t)
repo := NewConversationRepo(db)
userID := uint(88)
account := &model.Account{Name: "MetaQueryOrg", Locale: "en", Active: true}
require.NoError(t, db.Create(account).Error)
inbox := &model.Inbox{AccountID: account.ID, Name: "MetaQueryInbox", ChannelType: "web_widget", ChannelID: 1}
require.NoError(t, db.Create(inbox).Error)
contact := &model.Contact{AccountID: account.ID, Name: "MetaQueryContact"}
require.NoError(t, db.Create(contact).Error)
contactInbox := &model.ContactInbox{ContactID: contact.ID, InboxID: inbox.ID, SourceID: "source-a"}
require.NoError(t, db.Create(contactInbox).Error)
otherContactInbox := &model.ContactInbox{ContactID: contact.ID, InboxID: inbox.ID, SourceID: "source-b"}
require.NoError(t, db.Create(otherContactInbox).Error)
match := createTestConversation(t, db, account.ID, inbox.ID, contact.ID, "open")
require.NoError(t, db.Model(match).Updates(map[string]any{"contact_inbox_id": contactInbox.ID, "assignee_id": userID}).Error)
otherSource := createTestConversation(t, db, account.ID, inbox.ID, contact.ID, "open")
require.NoError(t, db.Model(otherSource).Update("contact_inbox_id", otherContactInbox.ID).Error)
activityOnly := createTestConversation(t, db, account.ID, inbox.ID, contact.ID, "open")
require.NoError(t, db.Model(activityOnly).Update("contact_inbox_id", contactInbox.ID).Error)
require.NoError(t, db.Create(&model.Message{AccountID: account.ID, InboxID: inbox.ID, ConversationID: match.ID, Content: "needle visible", MessageType: string(model.MessageTypeIncoming)}).Error)
require.NoError(t, db.Create(&model.Message{AccountID: account.ID, InboxID: inbox.ID, ConversationID: otherSource.ID, Content: "needle wrong source", MessageType: string(model.MessageTypeOutgoing)}).Error)
require.NoError(t, db.Create(&model.Message{AccountID: account.ID, InboxID: inbox.ID, ConversationID: activityOnly.ID, Content: "needle activity", MessageType: string(model.MessageTypeActivity)}).Error)
meta, err := repo.GetMeta(context.Background(), account.ID, userID, ConversationMetaParams{Query: "needle", SourceID: "source-a"})
require.NoError(t, err)
assert.Equal(t, int64(1), meta.AllCount)
assert.Equal(t, int64(1), meta.MineCount)
}
// ========== MarkUnread Tests ==========
func TestConversationRepo_MarkUnread(t *testing.T) {
+2
View File
@@ -930,6 +930,8 @@ func (s *ConversationService) GetMeta(ctx context.Context, accountID, userID uin
TeamID: params.TeamID,
Labels: splitConversationMetaLabels(params.Labels),
ConversationType: params.ConversationType,
Query: params.Query,
SourceID: params.SourceID,
}
if userID != 0 {