174 lines
6.0 KiB
Go
174 lines
6.0 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
|
|
"github.com/gochat/gochat/internal/model"
|
|
"github.com/gochat/gochat/internal/repository"
|
|
pkgvalidator "github.com/gochat/gochat/pkg/validator"
|
|
applogger "github.com/gochat/gochat/pkg/logger"
|
|
)
|
|
|
|
// CaptainPreferenceService implements business logic for CaptainPreference operations.
|
|
// Reference: Chatwoot enterprise/app/controllers/api/v1/captain/preferences_controller.rb
|
|
type CaptainPreferenceService struct {
|
|
repo *repository.CaptainPreferenceRepo
|
|
}
|
|
|
|
func NewCaptainPreferenceService(repo *repository.CaptainPreferenceRepo) *CaptainPreferenceService {
|
|
return &CaptainPreferenceService{repo: repo}
|
|
}
|
|
|
|
// --- Request DTOs ---
|
|
|
|
// CreatePreferenceRequest is the DTO for creating a preference.
|
|
// Reference: Chatwoot enterprise/app/models/captain/preference.rb
|
|
type CreatePreferenceRequest struct {
|
|
Tone string `json:"tone" validate:"omitempty,oneof=professional casual friendly formal"`
|
|
Language string `json:"language" validate:"omitempty,min=1,max=10"`
|
|
ResponseGuidelines string `json:"response_guidelines" validate:"omitempty,max=2000"`
|
|
AutoLabelEnabled bool `json:"auto_label_enabled"`
|
|
AutoFollowUpEnabled bool `json:"auto_follow_up_enabled"`
|
|
AutoReplyEnabled bool `json:"auto_reply_enabled"`
|
|
MaxResponseLength int `json:"max_response_length" validate:"omitempty,min=50,max=5000"`
|
|
CustomPromptSuffix string `json:"custom_prompt_suffix" validate:"omitempty,max=1000"`
|
|
}
|
|
|
|
// UpdatePreferenceRequest is the DTO for updating a preference.
|
|
// Reference: Chatwoot enterprise/app/models/captain/preference.rb
|
|
type UpdatePreferenceRequest struct {
|
|
Tone string `json:"tone,omitempty" validate:"omitempty,oneof=professional casual friendly formal"`
|
|
Language string `json:"language,omitempty" validate:"omitempty,min=1,max=10"`
|
|
ResponseGuidelines string `json:"response_guidelines,omitempty" validate:"omitempty,max=2000"`
|
|
AutoLabelEnabled *bool `json:"auto_label_enabled,omitempty"`
|
|
AutoFollowUpEnabled *bool `json:"auto_follow_up_enabled,omitempty"`
|
|
AutoReplyEnabled *bool `json:"auto_reply_enabled,omitempty"`
|
|
MaxResponseLength *int `json:"max_response_length,omitempty" validate:"omitempty,min=50,max=5000"`
|
|
CustomPromptSuffix string `json:"custom_prompt_suffix,omitempty" validate:"omitempty,max=1000"`
|
|
}
|
|
|
|
// --- Business logic ---
|
|
|
|
// validTones are the allowed tone values for captain preferences.
|
|
// Reference: Chatwoot enterprise/app/models/captain/preference.rb TONES
|
|
var validTones = []string{"professional", "casual", "friendly", "formal"}
|
|
|
|
// isValidTone checks if a tone value is valid.
|
|
func isValidTone(tone string) bool {
|
|
for _, t := range validTones {
|
|
if t == tone {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Create creates a new preference for an account.
|
|
func (s *CaptainPreferenceService) Create(ctx context.Context, accountID uint, req *CreatePreferenceRequest) (*model.CaptainPreference, error) {
|
|
// Validate request
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, fmt.Errorf("validation error: %w", err)
|
|
}
|
|
|
|
// Check if preference already exists for this account
|
|
existing, err := s.repo.GetByAccountID(ctx, accountID)
|
|
if err == nil && existing != nil {
|
|
return nil, fmt.Errorf("preference already exists for account %d", accountID)
|
|
}
|
|
|
|
pref := &model.CaptainPreference{
|
|
AccountID: accountID,
|
|
Tone: req.Tone,
|
|
Language: req.Language,
|
|
ResponseGuidelines: req.ResponseGuidelines,
|
|
AutoLabelEnabled: req.AutoLabelEnabled,
|
|
AutoFollowUpEnabled: req.AutoFollowUpEnabled,
|
|
AutoReplyEnabled: req.AutoReplyEnabled,
|
|
MaxResponseLength: req.MaxResponseLength,
|
|
CustomPromptSuffix: req.CustomPromptSuffix,
|
|
}
|
|
|
|
// Apply defaults
|
|
if pref.Tone == "" {
|
|
pref.Tone = "professional"
|
|
}
|
|
if pref.Language == "" {
|
|
pref.Language = "en"
|
|
}
|
|
if pref.MaxResponseLength == 0 {
|
|
pref.MaxResponseLength = 500
|
|
}
|
|
|
|
if err := s.repo.Create(ctx, pref); err != nil {
|
|
applogger.L().Errorf("Create captain preference: %v", err)
|
|
return nil, fmt.Errorf("create preference: %w", err)
|
|
}
|
|
|
|
return pref, nil
|
|
}
|
|
|
|
// Get retrieves the preference for an account.
|
|
func (s *CaptainPreferenceService) Get(ctx context.Context, accountID uint) (*model.CaptainPreference, error) {
|
|
pref, err := s.repo.GetByAccountID(ctx, accountID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("preference not found for account %d: %w", accountID, err)
|
|
}
|
|
return pref, nil
|
|
}
|
|
|
|
// Update updates the preference for an account.
|
|
func (s *CaptainPreferenceService) Update(ctx context.Context, accountID uint, req *UpdatePreferenceRequest) (*model.CaptainPreference, error) {
|
|
// Validate request
|
|
if err := pkgvalidator.ValidateStruct(req); err != nil {
|
|
return nil, fmt.Errorf("validation error: %w", err)
|
|
}
|
|
|
|
pref, err := s.repo.GetByAccountID(ctx, accountID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("preference not found for account %d: %w", accountID, err)
|
|
}
|
|
|
|
// Apply partial updates
|
|
if req.Tone != "" {
|
|
pref.Tone = req.Tone
|
|
}
|
|
if req.Language != "" {
|
|
pref.Language = req.Language
|
|
}
|
|
if req.ResponseGuidelines != "" {
|
|
pref.ResponseGuidelines = req.ResponseGuidelines
|
|
}
|
|
if req.AutoLabelEnabled != nil {
|
|
pref.AutoLabelEnabled = *req.AutoLabelEnabled
|
|
}
|
|
if req.AutoFollowUpEnabled != nil {
|
|
pref.AutoFollowUpEnabled = *req.AutoFollowUpEnabled
|
|
}
|
|
if req.AutoReplyEnabled != nil {
|
|
pref.AutoReplyEnabled = *req.AutoReplyEnabled
|
|
}
|
|
if req.MaxResponseLength != nil {
|
|
pref.MaxResponseLength = *req.MaxResponseLength
|
|
}
|
|
if req.CustomPromptSuffix != "" {
|
|
pref.CustomPromptSuffix = req.CustomPromptSuffix
|
|
}
|
|
|
|
if err := s.repo.Update(ctx, pref); err != nil {
|
|
applogger.L().Errorf("Update captain preference: %v", err)
|
|
return nil, fmt.Errorf("update preference: %w", err)
|
|
}
|
|
|
|
return pref, nil
|
|
}
|
|
|
|
// Delete removes the preference for an account.
|
|
func (s *CaptainPreferenceService) Delete(ctx context.Context, accountID uint) error {
|
|
if err := s.repo.Delete(ctx, accountID); err != nil {
|
|
applogger.L().Errorf("Delete captain preference: %v", err)
|
|
return fmt.Errorf("delete preference: %w", err)
|
|
}
|
|
return nil
|
|
}
|