6d8e179f90
modified: serv_nginx/api_bb/internal/handlers/handlers.go new file: serv_nginx/api_bb/internal/handlers/review_handler.go new file: serv_nginx/api_bb/internal/models/review.go new file: serv_nginx/api_bb/internal/repository/review_repository.go modified: serv_nginx/api_bb/internal/routes/routes.go new file: serv_nginx/api_bb/internal/service/review_service.go set reviews router, handler, service, repository
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,
|
|
},
|
|
}
|
|
}
|