package service import ( "context" "fmt" "github.com/gochat/gochat/internal/model" "github.com/gochat/gochat/internal/repository" applogger "github.com/gochat/gochat/pkg/logger" ) // CustomRoleService implements business logic for CustomRole operations. // Reference: Chatwoot enterprise/app/models/custom_role.rb type CustomRoleService struct { repo *repository.CustomRoleRepo } // NewCustomRoleService creates a new CustomRole service. func NewCustomRoleService(repo *repository.CustomRoleRepo) *CustomRoleService { return &CustomRoleService{repo: repo} } // CreateCustomRoleRequest is the DTO for creating a custom role. type CreateCustomRoleRequest struct { Name string `json:"name" validate:"required,min=2"` Permissions map[model.PermissionDimension]model.PermissionLevel `json:"permissions"` Description string `json:"description,omitempty"` } // UpdateCustomRoleRequest is the DTO for updating a custom role. type UpdateCustomRoleRequest struct { Name string `json:"name,omitempty" validate:"omitempty,min=2"` Permissions map[model.PermissionDimension]model.PermissionLevel `json:"permissions,omitempty"` Description string `json:"description,omitempty"` } // List retrieves all custom roles for an account with pagination. func (s *CustomRoleService) List(ctx context.Context, accountID uint, page, pageSize int) ([]model.CustomRole, int64, error) { if page < 1 { page = 1 } if pageSize < 1 { pageSize = 25 } offset := (page - 1) * pageSize roles, total, err := s.repo.FindByAccount(ctx, accountID, offset, pageSize) if err != nil { applogger.L().Errorf("List custom roles for account %d: %v", accountID, err) return nil, 0, fmt.Errorf("failed to list custom roles: %w", err) } return roles, total, nil } // Create creates a new custom role within an account. func (s *CustomRoleService) Create(ctx context.Context, accountID uint, req CreateCustomRoleRequest) (*model.CustomRole, error) { role := &model.CustomRole{ AccountID: accountID, Name: req.Name, Description: req.Description, } // Serialize permissions via SetPermissionMap if req.Permissions != nil { if err := role.SetPermissionMap(req.Permissions); err != nil { return nil, fmt.Errorf("invalid permissions: %w", err) } } else { role.Permissions = "{}" } // Validate the role before persisting if err := role.Validate(); err != nil { return nil, err } if err := s.repo.Create(ctx, role); err != nil { applogger.L().Errorf("failed to create custom role: %v", err) return nil, fmt.Errorf("failed to create custom role: %w", err) } return role, nil } // Update updates an existing custom role scoped to an account. func (s *CustomRoleService) Update(ctx context.Context, id, accountID uint, req UpdateCustomRoleRequest) (*model.CustomRole, error) { role, err := s.repo.FindByIDAndAccount(ctx, id, accountID) if err != nil { return nil, fmt.Errorf("custom role not found: %w", err) } // Merge fields: only update non-empty values if req.Name != "" { role.Name = req.Name } if req.Description != "" { role.Description = req.Description } // Merge permissions: if provided, replace entirely if req.Permissions != nil { if err := role.SetPermissionMap(req.Permissions); err != nil { return nil, fmt.Errorf("invalid permissions: %w", err) } } // Validate the updated role before persisting if err := role.Validate(); err != nil { return nil, err } if err := s.repo.Update(ctx, role); err != nil { applogger.L().Errorf("failed to update custom role: %v", err) return nil, fmt.Errorf("failed to update custom role: %w", err) } return role, nil } // Delete soft-deletes a custom role scoped to an account. func (s *CustomRoleService) Delete(ctx context.Context, id, accountID uint) error { if err := s.repo.Delete(ctx, id, accountID); err != nil { applogger.L().Errorf("failed to delete custom role %d for account %d: %v", id, accountID, err) return fmt.Errorf("failed to delete custom role: %w", err) } return nil } // GetByID retrieves a single custom role scoped to an account. func (s *CustomRoleService) GetByID(ctx context.Context, id, accountID uint) (*model.CustomRole, error) { role, err := s.repo.FindByIDAndAccount(ctx, id, accountID) if err != nil { return nil, fmt.Errorf("custom role not found: %w", err) } return role, nil }