package feetback import ( "api_yal/internal/models" "api_yal/internal/repository" "errors" "gorm.io/gorm" ) // FeedbackService интерфейс сервиса отзывов type FeedbackService interface { Create(feedback *models.Feedback, AuthorID uint) error GetByID(id uint) (*models.Feedback, error) Update(id uint, AuthorID uint, updates map[string]interface{}) error Delete(id uint, AuthorID uint, isAdmin bool) error List(offset, limit int) ([]models.Feedback, int64, error) ListByOwner(ownerID uint, offset, limit int) ([]models.Feedback, int64, error) ListByObject(objectID uint, offset, limit int) ([]models.Feedback, int64, error) ListByPlatform(platform models.PlatformType, offset, limit int) ([]models.Feedback, int64, error) Search(query string, offset, limit int) ([]models.Feedback, int64, error) GetComments(feedbackID uint, offset, limit int) ([]models.Comment, int, error) AddComment(feedbackID uint, AuthorID uint, text string) (*models.Comment, error) UpdateComment(commentID uint, AuthorID uint, text string, isAdmin bool) error DeleteComment(commentID uint, AuthorID uint, isAdmin bool) error GetStats() (*FeedbackStatsResponse, error) } // FeedbackServiceImpl реализация сервиса отзывов type FeedbackServiceImpl struct { feedbackRepo repository.FeedbackRepository db *gorm.DB } // NewFeedbackServiceImpl создает новый экземпляр сервиса func NewFeedbackServiceImpl(feedbackRepo repository.FeedbackRepository, db *gorm.DB) FeedbackService { return &FeedbackServiceImpl{ feedbackRepo: feedbackRepo, db: db, } } // Create создает новый отзыв func (s *FeedbackServiceImpl) Create(feedback *models.Feedback, AuthorID uint) error { feedback.OwnerID = AuthorID feedback.CommentCount = 0 return s.feedbackRepo.Create(feedback) } // GetByID возвращает отзыв по ID func (s *FeedbackServiceImpl) GetByID(id uint) (*models.Feedback, error) { return s.feedbackRepo.GetByID(id) } // Update обновляет отзыв func (s *FeedbackServiceImpl) Update(id uint, AuthorID uint, updates map[string]interface{}) error { // Получаем существующий отзыв feedback, err := s.feedbackRepo.GetByID(id) if err != nil { return err } // Проверяем права (только владелец может редактировать) if feedback.OwnerID != AuthorID { return errors.New("you can only update your own feedback") } // Применяем обновления return s.db.Model(&models.Feedback{}).Where("id = ?", id).Updates(updates).Error } // Delete удаляет отзыв func (s *FeedbackServiceImpl) Delete(id uint, AuthorID uint, isAdmin bool) error { // Получаем существующий отзыв feedback, err := s.feedbackRepo.GetByID(id) if err != nil { return err } // Проверяем права (владелец или админ) if feedback.OwnerID != AuthorID && !isAdmin { return errors.New("you can only delete your own feedback") } return s.feedbackRepo.Delete(id) } // List возвращает список отзывов с пагинацией func (s *FeedbackServiceImpl) List(offset, limit int) ([]models.Feedback, int64, error) { if limit <= 0 || limit > 100 { limit = 20 } if offset < 0 { offset = 0 } feedbacks, err := s.feedbackRepo.List(offset, limit) if err != nil { return nil, 0, err } total, err := s.feedbackRepo.Count() if err != nil { return nil, 0, err } return feedbacks, total, nil } // ListByOwner возвращает отзывы по владельцу func (s *FeedbackServiceImpl) ListByOwner(ownerID uint, offset, limit int) ([]models.Feedback, int64, error) { if limit <= 0 || limit > 100 { limit = 20 } if offset < 0 { offset = 0 } feedbacks, err := s.feedbackRepo.ListByOwner(ownerID, offset, limit) if err != nil { return nil, 0, err } // Считаем общее количество отзывов пользователя var total int64 err = s.db.Model(&models.Feedback{}).Where("owner_id = ?", ownerID).Count(&total).Error return feedbacks, total, err } // ListByObject возвращает отзывы по объекту func (s *FeedbackServiceImpl) ListByObject(objectID uint, offset, limit int) ([]models.Feedback, int64, error) { if limit <= 0 || limit > 100 { limit = 20 } if offset < 0 { offset = 0 } feedbacks, err := s.feedbackRepo.ListByObject(objectID, offset, limit) if err != nil { return nil, 0, err } var total int64 err = s.db.Model(&models.Feedback{}).Where("object_id = ?", objectID).Count(&total).Error return feedbacks, total, err } // ListByPlatform возвращает отзывы по платформе func (s *FeedbackServiceImpl) ListByPlatform(platform models.PlatformType, offset, limit int) ([]models.Feedback, int64, error) { if limit <= 0 || limit > 100 { limit = 20 } if offset < 0 { offset = 0 } feedbacks, err := s.feedbackRepo.ListByPlatform(platform, offset, limit) if err != nil { return nil, 0, err } var total int64 err = s.db.Model(&models.Feedback{}).Where("platform = ?", platform).Count(&total).Error return feedbacks, total, err } // Search ищет отзывы по тексту func (s *FeedbackServiceImpl) Search(query string, offset, limit int) ([]models.Feedback, int64, error) { if limit <= 0 || limit > 100 { limit = 20 } if offset < 0 { offset = 0 } feedbacks, err := s.feedbackRepo.Search(query, offset, limit) if err != nil { return nil, 0, err } var total int64 err = s.db.Model(&models.Feedback{}).Where("text LIKE ?", "%"+query+"%").Count(&total).Error return feedbacks, total, err } // GetComments возвращает комментарии к отзыву func (s *FeedbackServiceImpl) GetComments(feedbackID uint, offset, limit int) ([]models.Comment, int, error) { if limit <= 0 || limit > 50 { limit = 20 } if offset < 0 { offset = 0 } comments, err := s.feedbackRepo.GetComments(feedbackID, offset, limit) if err != nil { return nil, 0, err } total, err := s.feedbackRepo.GetCommentCount(feedbackID) if err != nil { return nil, 0, err } return comments, total, err } // AddComment добавляет комментарий к отзыву func (s *FeedbackServiceImpl) AddComment(feedbackID uint, AuthorID uint, text string) (*models.Comment, error) { // Проверяем существование отзыва _, err := s.feedbackRepo.GetByID(feedbackID) if err != nil { return nil, errors.New("feedback not found") } // Создаем комментарий comment := &models.Comment{ FeedbackID: feedbackID, AuthorID: AuthorID, // Используем AuthorID, а не OwnerID Text: text, } err = s.db.Create(comment).Error if err != nil { return nil, err } // Загружаем аккаунт для комментария s.db.Preload("Account").First(comment, comment.ID) // Обновляем счетчик комментариев newCount, _ := s.feedbackRepo.GetCommentCount(feedbackID) s.feedbackRepo.UpdateCommentCount(feedbackID, newCount) return comment, nil } // UpdateComment обновляет комментарий func (s *FeedbackServiceImpl) UpdateComment(commentID uint, AuthorID uint, text string, isAdmin bool) error { var comment models.Comment err := s.db.First(&comment, commentID).Error if err != nil { return err } // Проверяем права (владелец или админ) if comment.AuthorID != AuthorID && !isAdmin { return errors.New("you can only update your own comments") } return s.db.Model(&comment).Update("text", text).Error } // DeleteComment удаляет комментарий func (s *FeedbackServiceImpl) DeleteComment(commentID uint, AuthorID uint, isAdmin bool) error { var comment models.Comment err := s.db.First(&comment, commentID).Error if err != nil { return err } // Проверяем права (владелец или админ) if comment.AuthorID != AuthorID && !isAdmin { return errors.New("you can only delete your own comments") } feedbackID := comment.FeedbackID err = s.db.Delete(&comment).Error if err != nil { return err } // Обновляем счетчик комментариев у отзыва newCount, _ := s.feedbackRepo.GetCommentCount(feedbackID) s.feedbackRepo.UpdateCommentCount(feedbackID, newCount) return nil } // GetStats возвращает статистику по отзывам func (s *FeedbackServiceImpl) GetStats() (*FeedbackStatsResponse, error) { stats := &FeedbackStatsResponse{ RatingDistribution: make(map[int]int64), PlatformStats: make(map[models.PlatformType]int64), } // Общее количество s.db.Model(&models.Feedback{}).Count(&stats.TotalFeedbacks) // Средний рейтинг var avgRating float64 s.db.Model(&models.Feedback{}).Select("COALESCE(AVG(rating), 0)").Row().Scan(&avgRating) stats.AverageRating = avgRating // Распределение рейтингов for i := 1; i <= 5; i++ { var count int64 s.db.Model(&models.Feedback{}).Where("rating = ?", i).Count(&count) stats.RatingDistribution[i] = count } // Статистика по платформам platforms := []models.PlatformType{"google", "yandex", "2gis", "whatsapp", "telegram", "vk"} for _, platform := range platforms { var count int64 s.db.Model(&models.Feedback{}).Where("platform = ?", platform).Count(&count) stats.PlatformStats[platform] = count } return stats, nil }