251 lines
8.6 KiB
Go
251 lines
8.6 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
applogger "github.com/gochat/gochat/pkg/logger"
|
|
pkgvalidator "github.com/gochat/gochat/pkg/validator"
|
|
)
|
|
|
|
// AssignmentPolicyV2Service implements business logic for AssignmentPolicy V2 operations.
|
|
// Reference: Chatwoot app/controllers/api/v1/assignment_policies_controller.rb
|
|
type AssignmentPolicyV2Service struct {
|
|
policyRepo *repository.AssignmentPolicyV2Repo
|
|
apInboxRepo *repository.AssignmentPolicyInboxRepo
|
|
}
|
|
|
|
// NewAssignmentPolicyV2Service creates a new AssignmentPolicyV2 service.
|
|
func NewAssignmentPolicyV2Service(
|
|
policyRepo *repository.AssignmentPolicyV2Repo,
|
|
apInboxRepo *repository.AssignmentPolicyInboxRepo,
|
|
) *AssignmentPolicyV2Service {
|
|
return &AssignmentPolicyV2Service{policyRepo: policyRepo, apInboxRepo: apInboxRepo}
|
|
}
|
|
|
|
// CreatePolicyV2Request is the DTO for creating a V2 assignment policy.
|
|
type CreatePolicyV2Request struct {
|
|
Name string `json:"name" validate:"required"`
|
|
Description string `json:"description,omitempty"`
|
|
Type model.AssignmentPolicyV2Type `json:"type" validate:"required,oneof=round_robin fair best_skill_match"`
|
|
}
|
|
|
|
// UpdatePolicyV2Request is the DTO for updating a V2 assignment policy.
|
|
type UpdatePolicyV2Request struct {
|
|
Name string `json:"name,omitempty"`
|
|
Description string `json:"description,omitempty"`
|
|
Type model.AssignmentPolicyV2Type `json:"type,omitempty" validate:"omitempty,oneof=round_robin fair best_skill_match"`
|
|
}
|
|
|
|
// AddInboxRequestV2 is the DTO for adding an inbox to a V2 policy.
|
|
type AddInboxRequestV2 struct {
|
|
InboxID uint `json:"inbox_id" validate:"required"`
|
|
}
|
|
|
|
// Create creates a new assignment policy V2.
|
|
func (s *AssignmentPolicyV2Service) Create(ctx context.Context, accountID uint, req *CreatePolicyV2Request) (*model.AssignmentPolicyV2, error) {
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, fmt.Errorf("validation error: %w", err)
|
|
}
|
|
|
|
policy := &model.AssignmentPolicyV2{
|
|
AccountID: accountID,
|
|
Name: req.Name,
|
|
Description: req.Description,
|
|
Type: req.Type,
|
|
}
|
|
|
|
if err := s.policyRepo.Create(ctx, policy); err != nil {
|
|
return nil, fmt.Errorf("create assignment policy v2: %w", err)
|
|
}
|
|
|
|
applogger.L().Infof("Assignment policy V2 %d created for account %d (type=%s)", policy.ID, accountID, policy.Type)
|
|
return policy, nil
|
|
}
|
|
|
|
// Get retrieves an assignment policy V2 by ID.
|
|
func (s *AssignmentPolicyV2Service) Get(ctx context.Context, accountID, policyID uint) (*model.AssignmentPolicyV2, error) {
|
|
policy, err := s.policyRepo.FindByID(ctx, policyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("assignment policy v2 not found: %w", err)
|
|
}
|
|
if policy.AccountID != accountID {
|
|
return nil, fmt.Errorf("assignment policy v2 %d does not belong to account %d", policyID, accountID)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// List retrieves all assignment policies V2 for an account.
|
|
func (s *AssignmentPolicyV2Service) List(ctx context.Context, accountID uint) ([]model.AssignmentPolicyV2, error) {
|
|
return s.policyRepo.FindByAccount(ctx, accountID)
|
|
}
|
|
|
|
// Update updates an assignment policy V2.
|
|
func (s *AssignmentPolicyV2Service) Update(ctx context.Context, accountID, policyID uint, req *UpdatePolicyV2Request) (*model.AssignmentPolicyV2, error) {
|
|
policy, err := s.Get(ctx, accountID, policyID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if req.Name != "" {
|
|
policy.Name = req.Name
|
|
}
|
|
if req.Description != "" {
|
|
policy.Description = req.Description
|
|
}
|
|
if req.Type != "" {
|
|
policy.Type = req.Type
|
|
}
|
|
|
|
if err := s.policyRepo.Update(ctx, policy); err != nil {
|
|
return nil, fmt.Errorf("update assignment policy v2: %w", err)
|
|
}
|
|
|
|
applogger.L().Infof("Assignment policy V2 %d updated for account %d", policyID, accountID)
|
|
return policy, nil
|
|
}
|
|
|
|
// Delete deletes an assignment policy V2 (and its inbox associations).
|
|
func (s *AssignmentPolicyV2Service) Delete(ctx context.Context, accountID, policyID uint) error {
|
|
policy, err := s.Get(ctx, accountID, policyID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
// Remove all inbox associations first
|
|
if err := s.apInboxRepo.DeleteByAssignmentPolicy(ctx, policy.ID); err != nil {
|
|
return fmt.Errorf("delete inbox associations: %w", err)
|
|
}
|
|
|
|
if err := s.policyRepo.Delete(ctx, policy.ID); err != nil {
|
|
return fmt.Errorf("delete assignment policy v2: %w", err)
|
|
}
|
|
|
|
applogger.L().Infof("Assignment policy V2 %d deleted for account %d", policyID, accountID)
|
|
return nil
|
|
}
|
|
|
|
// ListInboxes retrieves all inboxes associated with a policy.
|
|
func (s *AssignmentPolicyV2Service) ListInboxes(ctx context.Context, accountID, policyID uint) ([]model.AssignmentPolicyInbox, error) {
|
|
policy, err := s.Get(ctx, accountID, policyID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return s.apInboxRepo.FindByAssignmentPolicy(ctx, policy.ID)
|
|
}
|
|
|
|
// AddInbox associates an inbox with a policy.
|
|
func (s *AssignmentPolicyV2Service) AddInbox(ctx context.Context, accountID, policyID uint, req *AddInboxRequestV2) (*model.AssignmentPolicyInbox, error) {
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, fmt.Errorf("validation error: %w", err)
|
|
}
|
|
|
|
policy, err := s.Get(ctx, accountID, policyID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Check if inbox already has a policy association
|
|
existing, findErr := s.apInboxRepo.FindByInbox(ctx, req.InboxID)
|
|
if findErr == nil && existing != nil {
|
|
// Inbox already has a policy — update it to the new policy
|
|
existing.AssignmentPolicyID = policy.ID
|
|
if err := s.apInboxRepo.Create(ctx, existing); err != nil {
|
|
return nil, fmt.Errorf("inbox already has a policy association: %w", err)
|
|
}
|
|
return existing, nil
|
|
}
|
|
|
|
apInbox := &model.AssignmentPolicyInbox{
|
|
AssignmentPolicyID: policy.ID,
|
|
InboxID: req.InboxID,
|
|
AccountID: accountID,
|
|
}
|
|
|
|
if err := s.apInboxRepo.Create(ctx, apInbox); err != nil {
|
|
return nil, fmt.Errorf("add inbox to policy: %w", err)
|
|
}
|
|
|
|
applogger.L().Infof("Inbox %d added to assignment policy V2 %d", req.InboxID, policyID)
|
|
return apInbox, nil
|
|
}
|
|
|
|
// RemoveInbox removes an inbox association from a policy.
|
|
func (s *AssignmentPolicyV2Service) RemoveInbox(ctx context.Context, accountID, policyID, inboxID uint) error {
|
|
policy, err := s.Get(ctx, accountID, policyID)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
apInboxes, err := s.apInboxRepo.FindByAssignmentPolicy(ctx, policy.ID)
|
|
if err != nil {
|
|
return fmt.Errorf("find inbox associations: %w", err)
|
|
}
|
|
|
|
for _, apInbox := range apInboxes {
|
|
if apInbox.InboxID == inboxID {
|
|
if err := s.apInboxRepo.Delete(ctx, apInbox.ID); err != nil {
|
|
return fmt.Errorf("remove inbox from policy: %w", err)
|
|
}
|
|
applogger.L().Infof("Inbox %d removed from assignment policy V2 %d", inboxID, policyID)
|
|
return nil
|
|
}
|
|
}
|
|
|
|
return fmt.Errorf("inbox %d not associated with policy %d", inboxID, policyID)
|
|
}
|
|
|
|
// GetInboxPolicy retrieves the assignment policy for a specific inbox.
|
|
func (s *AssignmentPolicyV2Service) GetInboxPolicy(ctx context.Context, accountID, inboxID uint) (*model.AssignmentPolicyV2, error) {
|
|
apInbox, err := s.apInboxRepo.FindByInbox(ctx, inboxID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("inbox %d has no assignment policy v2: %w", inboxID, err)
|
|
}
|
|
if apInbox.AccountID != accountID {
|
|
return nil, fmt.Errorf("inbox policy does not belong to account %d", accountID)
|
|
}
|
|
|
|
policy, err := s.policyRepo.FindByID(ctx, apInbox.AssignmentPolicyID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("assignment policy v2 not found: %w", err)
|
|
}
|
|
return policy, nil
|
|
}
|
|
|
|
// SetInboxPolicy sets the assignment policy for a specific inbox.
|
|
func (s *AssignmentPolicyV2Service) SetInboxPolicy(ctx context.Context, accountID, inboxID, policyID uint) (*model.AssignmentPolicyInbox, error) {
|
|
policy, err := s.Get(ctx, accountID, policyID)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// Check if inbox already has a policy — remove it first
|
|
s.apInboxRepo.DeleteByInbox(ctx, inboxID) // ignore error (may not exist)
|
|
|
|
apInbox := &model.AssignmentPolicyInbox{
|
|
AssignmentPolicyID: policy.ID,
|
|
InboxID: inboxID,
|
|
AccountID: accountID,
|
|
}
|
|
|
|
if err := s.apInboxRepo.Create(ctx, apInbox); err != nil {
|
|
return nil, fmt.Errorf("set inbox policy: %w", err)
|
|
}
|
|
|
|
applogger.L().Infof("Inbox %d set to assignment policy V2 %d", inboxID, policyID)
|
|
return apInbox, nil
|
|
}
|
|
|
|
// DeleteInboxPolicy removes the assignment policy association from an inbox.
|
|
func (s *AssignmentPolicyV2Service) DeleteInboxPolicy(ctx context.Context, accountID, inboxID uint) error {
|
|
if err := s.apInboxRepo.DeleteByInbox(ctx, inboxID); err != nil {
|
|
return fmt.Errorf("delete inbox policy: %w", err)
|
|
}
|
|
|
|
applogger.L().Infof("Assignment policy V2 removed from inbox %d", inboxID)
|
|
return nil
|
|
}
|