15357fd3c0
yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarbacreate and moove into new directories for BegushiyBashkir and yalarba
197 lines
5.8 KiB
Go
197 lines
5.8 KiB
Go
// service/review_service.go
|
|
package service
|
|
|
|
import (
|
|
"api_bb/internal/models"
|
|
"api_bb/internal/repository"
|
|
"api_bb/pkg/logger"
|
|
"errors"
|
|
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
type ReviewService interface {
|
|
CreateReview(req *models.CreateReviewRequest, authorID uint) (*models.ReviewResponse, error)
|
|
GetReviewByID(id uint) (*models.ReviewResponse, error)
|
|
GetAllReviews(page, limit int, sortBy, filter string) ([]models.ReviewResponse, int, error)
|
|
GetUserReviews(userID uint) ([]models.ReviewResponse, error)
|
|
UpdateReview(id uint, req *models.UpdateReviewRequest, userID uint, isAdmin bool) (*models.ReviewResponse, error)
|
|
DeleteReview(id uint, userID uint, isAdmin bool) error
|
|
GetReviewsStats() (*models.ReviewsStatsResponse, error)
|
|
}
|
|
|
|
type reviewService struct {
|
|
reviewRepo repository.ReviewRepository
|
|
logger logger.LoggerInterface
|
|
}
|
|
|
|
func NewReviewService(reviewRepo repository.ReviewRepository, logger logger.LoggerInterface) ReviewService {
|
|
return &reviewService{
|
|
reviewRepo: reviewRepo,
|
|
logger: logger,
|
|
}
|
|
}
|
|
|
|
func (s *reviewService) CreateReview(req *models.CreateReviewRequest, authorID uint) (*models.ReviewResponse, error) {
|
|
review := &models.Review{
|
|
Rating: req.Rating,
|
|
Text: req.Text,
|
|
Achievement: req.Achievement,
|
|
Distance: req.Distance,
|
|
Improvement: req.Improvement,
|
|
Trainings: req.Trainings,
|
|
AuthorID: authorID,
|
|
Verified: false, // По умолчанию непроверенный
|
|
}
|
|
|
|
if err := s.reviewRepo.Create(review); err != nil {
|
|
s.logger.Error("Failed to create review", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
// Получаем созданный отзыв с информацией об авторе
|
|
createdReview, err := s.reviewRepo.GetByID(review.ID)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get created review", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
return s.toReviewResponse(createdReview), nil
|
|
}
|
|
|
|
func (s *reviewService) GetReviewByID(id uint) (*models.ReviewResponse, error) {
|
|
review, err := s.reviewRepo.GetByID(id)
|
|
if err != nil {
|
|
s.logger.With(zap.Int("id", int(id))).Error("Failed to get review by ID", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
return s.toReviewResponse(review), nil
|
|
}
|
|
|
|
func (s *reviewService) GetAllReviews(page, limit int, sortBy, filter string) ([]models.ReviewResponse, int, error) {
|
|
if page < 1 {
|
|
page = 1
|
|
}
|
|
if limit < 1 {
|
|
limit = 10
|
|
}
|
|
|
|
reviews, total, err := s.reviewRepo.GetAll(page, limit, sortBy, filter)
|
|
if err != nil {
|
|
s.logger.Error("Failed to get all reviews", zap.Error(err))
|
|
return nil, 0, err
|
|
}
|
|
|
|
responses := make([]models.ReviewResponse, len(reviews))
|
|
for i, review := range reviews {
|
|
responses[i] = *s.toReviewResponse(&review)
|
|
}
|
|
|
|
totalPages := (int(total) + limit - 1) / limit
|
|
|
|
return responses, totalPages, nil
|
|
}
|
|
|
|
func (s *reviewService) GetUserReviews(userID uint) ([]models.ReviewResponse, error) {
|
|
reviews, err := s.reviewRepo.GetByAuthorID(userID)
|
|
if err != nil {
|
|
s.logger.With(zap.Int("userID", int(userID))).Error("Failed to get user reviews", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
responses := make([]models.ReviewResponse, len(reviews))
|
|
for i, review := range reviews {
|
|
responses[i] = *s.toReviewResponse(&review)
|
|
}
|
|
|
|
return responses, nil
|
|
}
|
|
|
|
func (s *reviewService) UpdateReview(id uint, req *models.UpdateReviewRequest, userID uint, isAdmin bool) (*models.ReviewResponse, error) {
|
|
review, err := s.reviewRepo.GetByID(id)
|
|
if err != nil {
|
|
s.logger.With(zap.Int("id", int(id))).Error("Failed to get review for update", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
// Проверяем права доступа
|
|
if review.AuthorID != userID && !isAdmin {
|
|
s.logger.With(zap.Int("userID", int(userID))).With(zap.Int("reviewAuthorID", int(review.AuthorID))).Error("Unauthorized attempt to update review", zap.Error(err))
|
|
}
|
|
|
|
// Обновляем поля
|
|
if req.Rating != 0 {
|
|
review.Rating = req.Rating
|
|
}
|
|
if req.Text != "" {
|
|
review.Text = req.Text
|
|
}
|
|
if req.Achievement != "" {
|
|
review.Achievement = req.Achievement
|
|
}
|
|
if req.Distance != "" {
|
|
review.Distance = req.Distance
|
|
}
|
|
if req.Improvement != "" {
|
|
review.Improvement = req.Improvement
|
|
}
|
|
if req.Trainings != 0 {
|
|
review.Trainings = req.Trainings
|
|
}
|
|
|
|
if err := s.reviewRepo.Update(review); err != nil {
|
|
s.logger.With(zap.Int("id", int(id))).Error("Failed to update review", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
// Получаем обновленный отзыв
|
|
updatedReview, err := s.reviewRepo.GetByID(id)
|
|
if err != nil {
|
|
s.logger.With(zap.Int("id", int(id))).Error("Failed to get updated review", zap.Error(err))
|
|
return nil, err
|
|
}
|
|
|
|
return s.toReviewResponse(updatedReview), nil
|
|
}
|
|
|
|
func (s *reviewService) DeleteReview(id uint, userID uint, isAdmin bool) error {
|
|
review, err := s.reviewRepo.GetByID(id)
|
|
if err != nil {
|
|
s.logger.With(zap.Int("id", int(id))).Error("Failed to get review for deletion", zap.Error(err))
|
|
return err
|
|
}
|
|
|
|
// Проверяем права доступа
|
|
if review.AuthorID != userID && !isAdmin {
|
|
s.logger.With(zap.Int("userID", int(userID))).With(zap.Int("reviewAuthorID", int(review.AuthorID))).Error("Unauthorized attempt to delete review", zap.Error(err))
|
|
return errors.New("unauthorized")
|
|
}
|
|
|
|
return s.reviewRepo.Delete(id)
|
|
}
|
|
|
|
func (s *reviewService) GetReviewsStats() (*models.ReviewsStatsResponse, error) {
|
|
return s.reviewRepo.GetStats()
|
|
}
|
|
|
|
func (s *reviewService) toReviewResponse(review *models.Review) *models.ReviewResponse {
|
|
return &models.ReviewResponse{
|
|
ID: review.ID,
|
|
CreatedAt: review.CreatedAt,
|
|
Rating: review.Rating,
|
|
Text: review.Text,
|
|
Achievement: review.Achievement,
|
|
Distance: review.Distance,
|
|
Improvement: review.Improvement,
|
|
Trainings: review.Trainings,
|
|
Verified: review.Verified,
|
|
Author: models.AuthorInfo{
|
|
ID: review.Author.ID,
|
|
FirstName: review.Author.FirstName,
|
|
LastName: review.Author.LastName,
|
|
Email: review.Author.Email,
|
|
},
|
|
}
|
|
}
|