feat(conversations): align meta counts
This commit is contained in:
@@ -921,10 +921,53 @@ func (s *ConversationService) UpdatePriority(ctx context.Context, accountID, id
|
||||
return conversation, nil
|
||||
}
|
||||
|
||||
// GetMeta retrieves aggregated conversation metadata (status counts, label counts) for an account.
|
||||
// Reference: Chatwoot app/controllers/api/v1/conversations_controller.rb#meta
|
||||
func (s *ConversationService) GetMeta(ctx context.Context, accountID uint) (*repository.ConversationMeta, error) {
|
||||
return s.repo.GetMeta(ctx, accountID)
|
||||
// GetMeta retrieves Chatwoot conversation sidebar counts for an account.
|
||||
// Reference: ConversationFinder#perform_meta_only and conversations/meta.json.jbuilder.
|
||||
func (s *ConversationService) GetMeta(ctx context.Context, accountID, userID uint, params FilterParams) (*repository.ConversationMeta, error) {
|
||||
metaParams := repository.ConversationMetaParams{
|
||||
Status: params.Status,
|
||||
InboxID: params.InboxID,
|
||||
TeamID: params.TeamID,
|
||||
Labels: splitConversationMetaLabels(params.Labels),
|
||||
ConversationType: params.ConversationType,
|
||||
}
|
||||
|
||||
if userID != 0 {
|
||||
var accountUser model.AccountUser
|
||||
err := s.repo.DB().WithContext(ctx).Where("account_id = ? AND user_id = ?", accountID, userID).First(&accountUser).Error
|
||||
if errors.Is(err, gorm.ErrRecordNotFound) {
|
||||
metaParams.RestrictToInboxes = true
|
||||
return s.repo.GetMeta(ctx, accountID, userID, metaParams)
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !accountUser.IsAdministrator() {
|
||||
ids, err := s.visibleUnreadCountInboxIDs(ctx, accountID, userID)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
metaParams.RestrictToInboxes = true
|
||||
metaParams.RestrictedInboxIDs = ids
|
||||
}
|
||||
}
|
||||
|
||||
return s.repo.GetMeta(ctx, accountID, userID, metaParams)
|
||||
}
|
||||
|
||||
func splitConversationMetaLabels(labels string) []string {
|
||||
if strings.TrimSpace(labels) == "" {
|
||||
return nil
|
||||
}
|
||||
parts := strings.Split(labels, ",")
|
||||
out := make([]string, 0, len(parts))
|
||||
for _, part := range parts {
|
||||
part = strings.TrimSpace(part)
|
||||
if part != "" {
|
||||
out = append(out, part)
|
||||
}
|
||||
}
|
||||
return out
|
||||
}
|
||||
|
||||
// MarkUnread marks a conversation as unread by setting agent_last_seen_at to
|
||||
|
||||
@@ -277,20 +277,25 @@ func TestConversationService_GetMeta(t *testing.T) {
|
||||
account := createConversationServiceTestAccount(t, db)
|
||||
inbox := createConversationServiceTestInbox(t, db, account.ID)
|
||||
contact := createConversationServiceTestContact(t, db, account.ID)
|
||||
user := &model.User{Name: "Meta Agent", Email: "meta-agent@example.com"}
|
||||
require.NoError(t, db.Create(user).Error)
|
||||
require.NoError(t, db.Create(&model.AccountUser{AccountID: account.ID, UserID: user.ID, Role: "administrator"}).Error)
|
||||
|
||||
// Create conversations with different statuses
|
||||
createConversationServiceTestConversation(t, db, account.ID, inbox.ID, contact.ID, "open")
|
||||
// Chatwoot meta defaults to open conversations and reports assignee buckets.
|
||||
openUnassigned := createConversationServiceTestConversation(t, db, account.ID, inbox.ID, contact.ID, "open")
|
||||
assert.NotZero(t, openUnassigned.ID)
|
||||
openAssigned := createConversationServiceTestConversation(t, db, account.ID, inbox.ID, contact.ID, "open")
|
||||
require.NoError(t, db.Model(openAssigned).Update("assignee_id", user.ID).Error)
|
||||
conv2 := createConversationServiceTestConversation(t, db, account.ID, inbox.ID, contact.ID, "resolved")
|
||||
require.NoError(t, db.Model(conv2).Update("labels", "support").Error)
|
||||
createConversationServiceTestConversation(t, db, account.ID, inbox.ID, contact.ID, "pending")
|
||||
|
||||
meta, err := svc.GetMeta(context.Background(), account.ID)
|
||||
meta, err := svc.GetMeta(context.Background(), account.ID, user.ID, FilterParams{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(3), meta.TotalCount)
|
||||
assert.Equal(t, int64(1), meta.StatusCounts["open"])
|
||||
assert.Equal(t, int64(1), meta.StatusCounts["resolved"])
|
||||
assert.Equal(t, int64(1), meta.StatusCounts["pending"])
|
||||
assert.Equal(t, int64(1), meta.LabelCounts["support"])
|
||||
assert.Equal(t, int64(2), meta.AllCount)
|
||||
assert.Equal(t, int64(1), meta.MineCount)
|
||||
assert.Equal(t, int64(1), meta.AssignedCount)
|
||||
assert.Equal(t, int64(1), meta.UnassignedCount)
|
||||
}
|
||||
|
||||
func TestConversationService_GetMeta_EmptyAccount(t *testing.T) {
|
||||
@@ -298,10 +303,33 @@ func TestConversationService_GetMeta_EmptyAccount(t *testing.T) {
|
||||
|
||||
account := createConversationServiceTestAccount(t, db)
|
||||
|
||||
meta, err := svc.GetMeta(context.Background(), account.ID)
|
||||
meta, err := svc.GetMeta(context.Background(), account.ID, 0, FilterParams{})
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, int64(0), meta.TotalCount)
|
||||
assert.Empty(t, meta.StatusCounts)
|
||||
assert.Equal(t, int64(0), meta.AllCount)
|
||||
assert.Equal(t, int64(0), meta.UnassignedCount)
|
||||
}
|
||||
|
||||
func TestConversationService_GetMeta_FiltersByLabelAndVisibility(t *testing.T) {
|
||||
svc, db := setupConversationService(t)
|
||||
|
||||
account := createConversationServiceTestAccount(t, db)
|
||||
inbox := createConversationServiceTestInbox(t, db, account.ID)
|
||||
hiddenInbox := createConversationServiceTestInbox(t, db, account.ID)
|
||||
contact := createConversationServiceTestContact(t, db, account.ID)
|
||||
user := &model.User{Name: "Scoped Meta Agent", Email: "scoped-meta@example.com"}
|
||||
require.NoError(t, db.Create(user).Error)
|
||||
require.NoError(t, db.Create(&model.AccountUser{AccountID: account.ID, UserID: user.ID, Role: "agent"}).Error)
|
||||
require.NoError(t, db.Create(&model.InboxMember{InboxID: inbox.ID, UserID: user.ID}).Error)
|
||||
|
||||
visible := createConversationServiceTestConversation(t, db, account.ID, inbox.ID, contact.ID, "open")
|
||||
require.NoError(t, db.Model(visible).Updates(map[string]any{"labels": "vip", "assignee_id": user.ID}).Error)
|
||||
hidden := createConversationServiceTestConversation(t, db, account.ID, hiddenInbox.ID, contact.ID, "open")
|
||||
require.NoError(t, db.Model(hidden).Update("labels", "vip").Error)
|
||||
|
||||
meta, err := svc.GetMeta(context.Background(), account.ID, user.ID, FilterParams{Labels: "vip"})
|
||||
require.NoError(t, err)
|
||||
assert.Equal(t, int64(1), meta.AllCount)
|
||||
assert.Equal(t, int64(1), meta.MineCount)
|
||||
}
|
||||
|
||||
// ========== MarkUnread Tests ==========
|
||||
|
||||
Reference in New Issue
Block a user