fix(search): align search filters
This commit is contained in:
@@ -85,7 +85,7 @@ func (h *SearchHandler) GlobalSearch(c *gin.Context) {
|
||||
}
|
||||
|
||||
query := c.Query("q")
|
||||
filter := parseChatwootSearchFilter(c)
|
||||
filter := parseChatwootSearchFilter(c, "global")
|
||||
filter.Types = append([]search.SearchResultType(nil), chatwootGlobalSearchTypes...)
|
||||
|
||||
result, svcErr := h.svc.GlobalSearch(c.Request.Context(), accountID, query, &filter)
|
||||
@@ -135,7 +135,7 @@ func (h *SearchHandler) SearchConversations(c *gin.Context) {
|
||||
}
|
||||
|
||||
query := c.Query("q")
|
||||
filter := parseChatwootSearchFilter(c)
|
||||
filter := parseChatwootSearchFilter(c, "conversation")
|
||||
// Force type to conversations only
|
||||
filter.Types = []search.SearchResultType{search.ResultTypeConversation}
|
||||
|
||||
@@ -186,7 +186,7 @@ func (h *SearchHandler) SearchMessages(c *gin.Context) {
|
||||
}
|
||||
|
||||
query := c.Query("q")
|
||||
filter := parseChatwootSearchFilter(c)
|
||||
filter := parseChatwootSearchFilter(c, "message")
|
||||
// Force type to messages only
|
||||
filter.Types = []search.SearchResultType{search.ResultTypeMessage}
|
||||
|
||||
@@ -231,7 +231,7 @@ func (h *SearchHandler) SearchContacts(c *gin.Context) {
|
||||
}
|
||||
|
||||
query := c.Query("q")
|
||||
filter := parseChatwootSearchFilter(c)
|
||||
filter := parseChatwootSearchFilter(c, "contact")
|
||||
// Force type to contacts only
|
||||
filter.Types = []search.SearchResultType{search.ResultTypeContact}
|
||||
|
||||
@@ -279,7 +279,7 @@ func (h *SearchHandler) SearchArticles(c *gin.Context) {
|
||||
}
|
||||
|
||||
query := c.Query("q")
|
||||
filter := parseChatwootSearchFilter(c)
|
||||
filter := parseChatwootSearchFilter(c, "article")
|
||||
// Force type to articles only
|
||||
filter.Types = []search.SearchResultType{search.ResultTypeArticle}
|
||||
|
||||
@@ -302,12 +302,34 @@ func serializeSearchPayload(ctx context.Context, db *gorm.DB, results []search.S
|
||||
}
|
||||
}
|
||||
|
||||
func parseChatwootSearchFilter(c *gin.Context) search.SearchFilter {
|
||||
func parseChatwootSearchFilter(c *gin.Context, scope string) search.SearchFilter {
|
||||
filter := search.ParseSearchFilter(c)
|
||||
if userID := getUserID(c); userID != 0 {
|
||||
filter.CurrentUserID = &userID
|
||||
}
|
||||
filter.PerPage = chatwootSearchPerPage
|
||||
filter = sanitizeChatwootSearchFilter(filter, scope)
|
||||
return filter
|
||||
}
|
||||
|
||||
func sanitizeChatwootSearchFilter(filter search.SearchFilter, scope string) search.SearchFilter {
|
||||
filter.Status = nil
|
||||
filter.Priority = nil
|
||||
filter.AssigneeID = nil
|
||||
filter.TeamID = nil
|
||||
filter.Labels = nil
|
||||
filter.ContactSource = ""
|
||||
filter.MessageType = ""
|
||||
filter.ContentType = ""
|
||||
filter.Private = nil
|
||||
filter.PortalID = nil
|
||||
filter.ArticleStatus = ""
|
||||
filter.ArticleLocale = ""
|
||||
if scope != "message" && scope != "global" {
|
||||
filter.SenderType = ""
|
||||
filter.SenderID = nil
|
||||
filter.InboxID = nil
|
||||
}
|
||||
return filter
|
||||
}
|
||||
|
||||
|
||||
@@ -25,27 +25,31 @@ type mockSearchRepo struct {
|
||||
conversations []model.Conversation
|
||||
convTotal int64
|
||||
convErr error
|
||||
convFilter *search.SearchFilter
|
||||
|
||||
messages []model.Message
|
||||
msgTotal int64
|
||||
msgErr error
|
||||
msgFilter *search.SearchFilter
|
||||
|
||||
contacts []model.Contact
|
||||
contactTotal int64
|
||||
contactErr error
|
||||
contacts []model.Contact
|
||||
contactTotal int64
|
||||
contactErr error
|
||||
contactFilter *search.SearchFilter
|
||||
|
||||
companies []model.Company
|
||||
companyTotal int64
|
||||
companyErr error
|
||||
companyCalled bool
|
||||
|
||||
articles []model.Article
|
||||
articleTotal int64
|
||||
articleErr error
|
||||
articles []model.Article
|
||||
articleTotal int64
|
||||
articleErr error
|
||||
articleFilter *search.SearchFilter
|
||||
}
|
||||
|
||||
func (m *mockSearchRepo) SearchConversations(ctx context.Context, accountID uint, query string, filter *search.SearchFilter) ([]model.Conversation, int64, error) {
|
||||
m.convFilter = filter
|
||||
return m.conversations, m.convTotal, m.convErr
|
||||
}
|
||||
|
||||
@@ -55,6 +59,7 @@ func (m *mockSearchRepo) SearchMessages(ctx context.Context, accountID uint, que
|
||||
}
|
||||
|
||||
func (m *mockSearchRepo) SearchContacts(ctx context.Context, accountID uint, query string, filter *search.SearchFilter) ([]model.Contact, int64, error) {
|
||||
m.contactFilter = filter
|
||||
return m.contacts, m.contactTotal, m.contactErr
|
||||
}
|
||||
|
||||
@@ -64,6 +69,7 @@ func (m *mockSearchRepo) SearchCompanies(ctx context.Context, accountID uint, qu
|
||||
}
|
||||
|
||||
func (m *mockSearchRepo) SearchArticles(ctx context.Context, accountID uint, query string, filter *search.SearchFilter) ([]model.Article, int64, error) {
|
||||
m.articleFilter = filter
|
||||
return m.articles, m.articleTotal, m.articleErr
|
||||
}
|
||||
|
||||
@@ -287,6 +293,34 @@ func TestSearchHandler_SearchConversations_ChatwootPayloadShape(t *testing.T) {
|
||||
assert.Equal(t, float64(0), item["message"].(map[string]any)["message_type"])
|
||||
}
|
||||
|
||||
func TestSearchHandler_SearchConversations_IgnoresUnsupportedSearchFilters(t *testing.T) {
|
||||
repo := &mockSearchRepo{
|
||||
conversations: []model.Conversation{makeConversation(1, "open")},
|
||||
convTotal: 1,
|
||||
}
|
||||
svc := search.NewSearchService(repo)
|
||||
handler := NewSearchHandler(svc)
|
||||
router := setupSearchHandlerRouter(handler)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/api/v1/accounts/1/search/conversations?q=billing&status=resolved&priority=urgent&labels=vip&inbox_id=5&from=agent:7&message_type=outgoing&contact_source=email&portal_id=2&article_status=draft&locale=fr", nil)
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
require.NotNil(t, repo.convFilter)
|
||||
assert.Empty(t, repo.convFilter.Status)
|
||||
assert.Empty(t, repo.convFilter.Priority)
|
||||
assert.Empty(t, repo.convFilter.Labels)
|
||||
assert.Nil(t, repo.convFilter.InboxID)
|
||||
assert.Empty(t, repo.convFilter.SenderType)
|
||||
assert.Nil(t, repo.convFilter.SenderID)
|
||||
assert.Empty(t, repo.convFilter.MessageType)
|
||||
assert.Empty(t, repo.convFilter.ContactSource)
|
||||
assert.Nil(t, repo.convFilter.PortalID)
|
||||
assert.Empty(t, repo.convFilter.ArticleStatus)
|
||||
assert.Empty(t, repo.convFilter.ArticleLocale)
|
||||
}
|
||||
|
||||
func TestSearchHandler_SearchConversations_InvalidAccountID(t *testing.T) {
|
||||
repo := &mockSearchRepo{}
|
||||
svc := search.NewSearchService(repo)
|
||||
@@ -363,6 +397,35 @@ func TestSearchHandler_SearchMessages_AddsCurrentUserToFilter(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestSearchHandler_SearchMessages_KeepsOnlyReferenceAdvancedFilters(t *testing.T) {
|
||||
repo := &mockSearchRepo{
|
||||
messages: []model.Message{makeMessage(1, 1, "hello world")},
|
||||
msgTotal: 1,
|
||||
}
|
||||
svc := search.NewSearchService(repo)
|
||||
handler := NewSearchHandler(svc)
|
||||
router := setupSearchHandlerRouter(handler)
|
||||
|
||||
w := httptest.NewRecorder()
|
||||
req := httptest.NewRequest("GET", "/api/v1/accounts/1/search/messages?q=hello&from=agent:7&inbox_id=5&message_type=outgoing&content_type=text&private=true&status=resolved&contact_source=email&portal_id=2&article_status=draft", nil)
|
||||
router.ServeHTTP(w, req)
|
||||
|
||||
require.Equal(t, http.StatusOK, w.Code)
|
||||
require.NotNil(t, repo.msgFilter)
|
||||
require.NotNil(t, repo.msgFilter.SenderID)
|
||||
assert.Equal(t, "agent", repo.msgFilter.SenderType)
|
||||
assert.Equal(t, uint(7), *repo.msgFilter.SenderID)
|
||||
require.NotNil(t, repo.msgFilter.InboxID)
|
||||
assert.Equal(t, uint(5), *repo.msgFilter.InboxID)
|
||||
assert.Empty(t, repo.msgFilter.MessageType)
|
||||
assert.Empty(t, repo.msgFilter.ContentType)
|
||||
assert.Nil(t, repo.msgFilter.Private)
|
||||
assert.Empty(t, repo.msgFilter.Status)
|
||||
assert.Empty(t, repo.msgFilter.ContactSource)
|
||||
assert.Nil(t, repo.msgFilter.PortalID)
|
||||
assert.Empty(t, repo.msgFilter.ArticleStatus)
|
||||
}
|
||||
|
||||
func TestSearchHandler_SearchMessages_MeiliHitPayloadShape(t *testing.T) {
|
||||
svc := search.NewSearchServiceWithEngine(&stubSearchEngine{
|
||||
resp: &search.SearchResponse{
|
||||
|
||||
Reference in New Issue
Block a user