package feetback import ( "context" "errors" "fmt" "strings" "api_yal/internal/models" "api_yal/internal/repository" "gorm.io/gorm" ) type FeedbackService interface { Create(ctx context.Context, feedback *models.Feedback) error GetByID(ctx context.Context, id uint) (*models.Feedback, error) Update(ctx context.Context, feedback *models.Feedback) error Delete(ctx context.Context, id uint) error List(ctx context.Context, page, pageSize int) ([]models.Feedback, int64, error) ListByOwner(ctx context.Context, ownerID uint, page, pageSize int) ([]models.Feedback, error) ListByObject(ctx context.Context, objectID uint, page, pageSize int) ([]models.Feedback, error) ListByPlatform(ctx context.Context, platform models.PlatformType, page, pageSize int) ([]models.Feedback, error) Search(ctx context.Context, query string, page, pageSize int) ([]models.Feedback, error) // Comment methods AddComment(ctx context.Context, feedbackID uint, comment *models.Comment) error GetComments(ctx context.Context, feedbackID uint, page, pageSize int) ([]models.Comment, error) UpdateComment(ctx context.Context, commentID uint, text string) error DeleteComment(ctx context.Context, commentID uint) error } type feedbackServiceImpl struct { feedbackRepository repository.FeedbackRepository } func NewFeedbackServiceImpl(feedbackRepository repository.FeedbackRepository) FeedbackService { return &feedbackServiceImpl{ feedbackRepository: feedbackRepository, } } // Create создает новый отзыв func (s *feedbackServiceImpl) Create(ctx context.Context, feedback *models.Feedback) error { // Валидация входных данных if err := s.validateFeedback(feedback); err != nil { return fmt.Errorf("validation failed: %w", err) } // Устанавливаем начальное значение счетчика комментариев feedback.CommentCount = 0 // Создаем отзыв if err := s.feedbackRepository.Create(feedback); err != nil { return fmt.Errorf("failed to create feedback: %w", err) } return nil } // GetByID возвращает отзыв по ID func (s *feedbackServiceImpl) GetByID(ctx context.Context, id uint) (*models.Feedback, error) { if id == 0 { return nil, errors.New("invalid feedback ID") } feedback, err := s.feedbackRepository.GetByID(id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("feedback with ID %d not found", id) } return nil, fmt.Errorf("failed to get feedback: %w", err) } return feedback, nil } // Update обновляет существующий отзыв func (s *feedbackServiceImpl) Update(ctx context.Context, feedback *models.Feedback) error { // Проверяем существование отзыва existing, err := s.feedbackRepository.GetByID(feedback.ID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("feedback with ID %d not found", feedback.ID) } return fmt.Errorf("failed to get feedback: %w", err) } // Валидация обновленных данных if err := s.validateFeedback(feedback); err != nil { return fmt.Errorf("validation failed: %w", err) } // Сохраняем оригинальный счетчик комментариев feedback.CommentCount = existing.CommentCount // Обновляем отзыв if err := s.feedbackRepository.Update(feedback); err != nil { return fmt.Errorf("failed to update feedback: %w", err) } return nil } // Delete удаляет отзыв func (s *feedbackServiceImpl) Delete(ctx context.Context, id uint) error { if id == 0 { return errors.New("invalid feedback ID") } // Проверяем существование отзыва _, err := s.feedbackRepository.GetByID(id) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("feedback with ID %d not found", id) } return fmt.Errorf("failed to get feedback: %w", err) } // Удаляем отзыв if err := s.feedbackRepository.Delete(id); err != nil { return fmt.Errorf("failed to delete feedback: %w", err) } return nil } // List возвращает список отзывов с пагинацией func (s *feedbackServiceImpl) List(ctx context.Context, page, pageSize int) ([]models.Feedback, int64, error) { // Нормализация параметров пагинации offset, limit := s.normalizePagination(page, pageSize) // Получаем список отзывов feedbacks, err := s.feedbackRepository.List(offset, limit) if err != nil { return nil, 0, fmt.Errorf("failed to list feedbacks: %w", err) } // Получаем общее количество total, err := s.feedbackRepository.Count() if err != nil { return nil, 0, fmt.Errorf("failed to count feedbacks: %w", err) } return feedbacks, total, nil } // ListByOwner возвращает отзывы по владельцу func (s *feedbackServiceImpl) ListByOwner(ctx context.Context, ownerID uint, page, pageSize int) ([]models.Feedback, error) { if ownerID == 0 { return nil, errors.New("invalid owner ID") } offset, limit := s.normalizePagination(page, pageSize) feedbacks, err := s.feedbackRepository.ListByOwner(ownerID, offset, limit) if err != nil { return nil, fmt.Errorf("failed to list feedbacks by owner: %w", err) } return feedbacks, nil } // ListByObject возвращает отзывы по объекту func (s *feedbackServiceImpl) ListByObject(ctx context.Context, objectID uint, page, pageSize int) ([]models.Feedback, error) { if objectID == 0 { return nil, errors.New("invalid object ID") } offset, limit := s.normalizePagination(page, pageSize) feedbacks, err := s.feedbackRepository.ListByObject(objectID, offset, limit) if err != nil { return nil, fmt.Errorf("failed to list feedbacks by object: %w", err) } return feedbacks, nil } // ListByPlatform возвращает отзывы по платформе func (s *feedbackServiceImpl) ListByPlatform(ctx context.Context, platform models.PlatformType, page, pageSize int) ([]models.Feedback, error) { // Валидация платформы if !s.isValidPlatform(platform) { return nil, fmt.Errorf("invalid platform: %s", platform) } offset, limit := s.normalizePagination(page, pageSize) feedbacks, err := s.feedbackRepository.ListByPlatform(platform, offset, limit) if err != nil { return nil, fmt.Errorf("failed to list feedbacks by platform: %w", err) } return feedbacks, nil } // Search ищет отзывы по тексту func (s *feedbackServiceImpl) Search(ctx context.Context, query string, page, pageSize int) ([]models.Feedback, error) { if strings.TrimSpace(query) == "" { return nil, errors.New("search query cannot be empty") } offset, limit := s.normalizePagination(page, pageSize) feedbacks, err := s.feedbackRepository.Search(query, offset, limit) if err != nil { return nil, fmt.Errorf("failed to search feedbacks: %w", err) } return feedbacks, nil } // AddComment добавляет комментарий к отзыву func (s *feedbackServiceImpl) AddComment(ctx context.Context, feedbackID uint, comment *models.Comment) error { if feedbackID == 0 { return errors.New("invalid feedback ID") } // Проверяем существование отзыва feedback, err := s.feedbackRepository.GetByID(feedbackID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return fmt.Errorf("feedback with ID %d not found", feedbackID) } return fmt.Errorf("failed to get feedback: %w", err) } // Валидация комментария if err := s.validateComment(comment); err != nil { return fmt.Errorf("validation failed: %w", err) } // Устанавливаем связь с отзывом comment.FeedbackID = feedbackID // Сохраняем комментарий (предполагается, что в репозитории есть метод CreateComment) // Временно используем прямое создание через репозиторий // Для полной реализации нужно добавить метод CreateComment в FeedbackRepository // Обновляем счетчик комментариев newCount := feedback.CommentCount + 1 if err := s.feedbackRepository.UpdateCommentCount(feedbackID, newCount); err != nil { return fmt.Errorf("failed to update comment count: %w", err) } return nil } // GetComments возвращает комментарии к отзыву func (s *feedbackServiceImpl) GetComments(ctx context.Context, feedbackID uint, page, pageSize int) ([]models.Comment, error) { if feedbackID == 0 { return nil, errors.New("invalid feedback ID") } // Проверяем существование отзыва _, err := s.feedbackRepository.GetByID(feedbackID) if err != nil { if errors.Is(err, gorm.ErrRecordNotFound) { return nil, fmt.Errorf("feedback with ID %d not found", feedbackID) } return nil, fmt.Errorf("failed to get feedback: %w", err) } offset, limit := s.normalizePagination(page, pageSize) comments, err := s.feedbackRepository.GetComments(feedbackID, offset, limit) if err != nil { return nil, fmt.Errorf("failed to get comments: %w", err) } return comments, nil } // UpdateComment обновляет комментарий func (s *feedbackServiceImpl) UpdateComment(ctx context.Context, commentID uint, text string) error { if commentID == 0 { return errors.New("invalid comment ID") } if strings.TrimSpace(text) == "" { return errors.New("comment text cannot be empty") } // Здесь нужно добавить метод UpdateComment в репозиторий // Для текущей реализации используем прямой доступ к БД через репозиторий // Временно возвращаем ошибку о необходимости реализации return fmt.Errorf("UpdateComment method not implemented in repository") } // DeleteComment удаляет комментарий func (s *feedbackServiceImpl) DeleteComment(ctx context.Context, commentID uint) error { if commentID == 0 { return errors.New("invalid comment ID") } // Здесь нужно добавить метод DeleteComment в репозиторий // Для текущей реализации используем прямой доступ к БД через репозиторий // Временно возвращаем ошибку о необходимости реализации return fmt.Errorf("DeleteComment method not implemented in repository") } // Вспомогательные методы // validateFeedback валидирует данные отзыва func (s *feedbackServiceImpl) validateFeedback(feedback *models.Feedback) error { if feedback.OwnerID == 0 { return errors.New("owner ID is required") } if feedback.ObjectID == 0 { return errors.New("object ID is required") } if feedback.Score < 1 || feedback.Score > 5 { return errors.New("score must be between 1 and 5") } if strings.TrimSpace(feedback.Text) == "" { return errors.New("feedback text cannot be empty") } if len(feedback.Text) > 5000 { return errors.New("feedback text cannot exceed 5000 characters") } if !s.isValidPlatform(feedback.Platform) { return fmt.Errorf("invalid platform: %s", feedback.Platform) } return nil } // validateComment валидирует комментарий func (s *feedbackServiceImpl) validateComment(comment *models.Comment) error { if strings.TrimSpace(comment.Text) == "" { return errors.New("comment text cannot be empty") } if len(comment.Text) > 1000 { return errors.New("comment text cannot exceed 1000 characters") } if comment.OwnerID == 0 { return errors.New("owner ID is required") } return nil } // normalizePagination нормализует параметры пагинации func (s *feedbackServiceImpl) normalizePagination(page, pageSize int) (offset, limit int) { if page < 1 { page = 1 } if pageSize < 1 { pageSize = 10 } if pageSize > 100 { pageSize = 100 } offset = (page - 1) * pageSize limit = pageSize return offset, limit } // isValidPlatform проверяет корректность платформы func (s *feedbackServiceImpl) isValidPlatform(platform models.PlatformType) bool { validPlatforms := []models.PlatformType{"entrepreneur", "tourist", "platform1", "platform2"} // Добавьте реальные платформы из вашего models.PlatformType for _, p := range validPlatforms { if p == platform { return true } } return false }