152 lines
5.2 KiB
Go
152 lines
5.2 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
applogger "github.com/gochat/gochat/pkg/logger"
|
|
)
|
|
|
|
// LabelService implements business logic for conversation-label associations
|
|
// and batch label management.
|
|
type LabelService struct {
|
|
convLabelRepo *repository.ConversationLabelRepo
|
|
tagRepo *repository.TagRepo
|
|
}
|
|
|
|
func NewLabelService(convLabelRepo *repository.ConversationLabelRepo, tagRepo *repository.TagRepo) *LabelService {
|
|
return &LabelService{convLabelRepo: convLabelRepo, tagRepo: tagRepo}
|
|
}
|
|
|
|
// AddLabelToConversation attaches a label/tag to a conversation.
|
|
func (s *LabelService) AddLabelToConversation(ctx context.Context, accountID, conversationID, tagID uint) (*model.ConversationLabel, error) {
|
|
// Verify tag exists and belongs to the account
|
|
tag, err := s.tagRepo.GetByID(ctx, tagID)
|
|
if err != nil {
|
|
return nil, errors.New("tag not found")
|
|
}
|
|
if tag.AccountID != accountID {
|
|
return nil, errors.New("tag does not belong to this account")
|
|
}
|
|
|
|
// Check for duplicate
|
|
exists, err := s.convLabelRepo.Exists(ctx, conversationID, tagID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if exists {
|
|
return nil, errors.New("label already attached to this conversation")
|
|
}
|
|
|
|
cl := &model.ConversationLabel{
|
|
ConversationID: conversationID,
|
|
TagID: tagID,
|
|
AccountID: accountID,
|
|
}
|
|
if err := s.convLabelRepo.AddLabel(ctx, cl); err != nil {
|
|
applogger.L().Errorf("Add label to conversation: %v", err)
|
|
return nil, err
|
|
}
|
|
return cl, nil
|
|
}
|
|
|
|
// RemoveLabelFromConversation detaches a label/tag from a conversation.
|
|
func (s *LabelService) RemoveLabelFromConversation(ctx context.Context, conversationID, tagID uint) error {
|
|
if err := s.convLabelRepo.RemoveLabel(ctx, conversationID, tagID); err != nil {
|
|
applogger.L().Errorf("Remove label from conversation: %v", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetConversationLabels returns all labels attached to a conversation.
|
|
func (s *LabelService) GetConversationLabels(ctx context.Context, conversationID uint) ([]model.ConversationLabel, error) {
|
|
labels, err := s.convLabelRepo.FindByConversationID(ctx, conversationID)
|
|
if err != nil {
|
|
applogger.L().Errorf("Get conversation labels: %v", err)
|
|
return nil, err
|
|
}
|
|
return labels, nil
|
|
}
|
|
|
|
// ReplaceConversationLabels replaces all labels on a conversation with a new set.
|
|
func (s *LabelService) ReplaceConversationLabels(ctx context.Context, accountID, conversationID uint, tagIDs []uint) ([]model.ConversationLabel, error) {
|
|
// Validate all tagIDs belong to the account
|
|
for _, tagID := range tagIDs {
|
|
tag, err := s.tagRepo.GetByID(ctx, tagID)
|
|
if err != nil {
|
|
return nil, errors.New("tag not found: " + tag.Name)
|
|
}
|
|
if tag.AccountID != accountID {
|
|
return nil, errors.New("tag does not belong to this account")
|
|
}
|
|
}
|
|
|
|
if err := s.convLabelRepo.ReplaceLabels(ctx, conversationID, accountID, tagIDs); err != nil {
|
|
applogger.L().Errorf("Replace conversation labels: %v", err)
|
|
return nil, err
|
|
}
|
|
|
|
return s.convLabelRepo.FindByConversationID(ctx, conversationID)
|
|
}
|
|
|
|
// BatchAddLabelRequest is the DTO for batch adding a label to conversations.
|
|
type BatchAddLabelRequest struct {
|
|
TagID uint `json:"tag_id" validate:"required"`
|
|
ConversationIDs []uint `json:"conversation_ids" validate:"required,min=1"`
|
|
}
|
|
|
|
// BatchRemoveLabelRequest is the DTO for batch removing a label from conversations.
|
|
type BatchRemoveLabelRequest struct {
|
|
TagID uint `json:"tag_id" validate:"required"`
|
|
ConversationIDs []uint `json:"conversation_ids" validate:"required,min=1"`
|
|
}
|
|
|
|
// BatchAddLabel attaches a label to multiple conversations at once.
|
|
func (s *LabelService) BatchAddLabel(ctx context.Context, accountID uint, req *BatchAddLabelRequest) error {
|
|
// Verify tag belongs to account
|
|
tag, err := s.tagRepo.GetByID(ctx, req.TagID)
|
|
if err != nil {
|
|
return errors.New("tag not found")
|
|
}
|
|
if tag.AccountID != accountID {
|
|
return errors.New("tag does not belong to this account")
|
|
}
|
|
|
|
if err := s.convLabelRepo.BatchAddLabels(ctx, req.ConversationIDs, req.TagID, accountID); err != nil {
|
|
applogger.L().Errorf("Batch add label: %v", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// BatchRemoveLabel detaches a label from multiple conversations at once.
|
|
func (s *LabelService) BatchRemoveLabel(ctx context.Context, accountID uint, req *BatchRemoveLabelRequest) error {
|
|
// Verify tag belongs to account
|
|
tag, err := s.tagRepo.GetByID(ctx, req.TagID)
|
|
if err != nil {
|
|
return errors.New("tag not found")
|
|
}
|
|
if tag.AccountID != accountID {
|
|
return errors.New("tag does not belong to this account")
|
|
}
|
|
|
|
if err := s.convLabelRepo.BatchRemoveLabels(ctx, req.ConversationIDs, req.TagID); err != nil {
|
|
applogger.L().Errorf("Batch remove label: %v", err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// GetConversationsByTag returns all conversations that have a specific tag.
|
|
func (s *LabelService) GetConversationsByTag(ctx context.Context, accountID, tagID uint, page, perPage int) ([]model.ConversationLabel, int64, error) {
|
|
offset := (page - 1) * perPage
|
|
labels, count, err := s.convLabelRepo.FindByTagID(ctx, accountID, tagID, offset, perPage)
|
|
if err != nil {
|
|
applogger.L().Errorf("Get conversations by tag: %v", err)
|
|
return nil, 0, err
|
|
}
|
|
return labels, count, nil
|
|
} |