RatingService.java
package com.learning.yasminishop.rating;
import com.learning.yasminishop.common.dto.PaginationResponse;
import com.learning.yasminishop.common.entity.Product;
import com.learning.yasminishop.common.entity.Rating;
import com.learning.yasminishop.common.entity.User;
import com.learning.yasminishop.common.exception.AppException;
import com.learning.yasminishop.common.exception.ErrorCode;
import com.learning.yasminishop.product.ProductRepository;
import com.learning.yasminishop.rating.dto.request.RatingRequest;
import com.learning.yasminishop.rating.dto.response.RatingResponse;
import com.learning.yasminishop.rating.mapper.RatingMapper;
import com.learning.yasminishop.user.UserRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import java.util.List;
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
@Slf4j
public class RatingService {
private final RatingRepository ratingRepository;
private final ProductRepository productRepository;
private final UserRepository userRepository;
private final RatingMapper ratingMapper;
@Transactional
@PreAuthorize("hasRole('USER')")
public RatingResponse create(RatingRequest request) {
Product product = productRepository.findById(request.getProductId())
.orElseThrow(() -> new AppException(ErrorCode.PRODUCT_NOT_FOUND));
// check if the user exists
var context = SecurityContextHolder.getContext();
String email = context.getAuthentication().getName();
User user = userRepository.findByEmail(email).orElseThrow(() -> new AppException(ErrorCode.USER_NOT_FOUND));
// check if the user has already rated the product
if (ratingRepository.existsByProductAndUser(product, user)) {
throw new AppException(ErrorCode.RATING_ALREADY_EXISTS);
}
// create the rating
Rating rating = ratingMapper.toRating(request);
rating.setProduct(product);
rating.setUser(user);
rating = ratingRepository.save(rating);
// calculate the average rating
calculateAverageRating(product);
return ratingMapper.toRatingResponse(rating);
}
public void calculateAverageRating(Product product) {
List<Rating> ratings = ratingRepository.findByProductId(product.getId());
double averageRating = ratings.stream()
.mapToInt(Rating::getStar)
.average()
.orElse(0.0);
product.setAverageRating((float) averageRating);
productRepository.save(product);
}
public PaginationResponse<RatingResponse> getRatings(String productId, Pageable pageable) {
Product product = productRepository.findById(productId)
.orElseThrow(() -> new AppException(ErrorCode.PRODUCT_NOT_FOUND));
Page<Rating> ratingResponseList = ratingRepository.findByProductOrderByCreatedDateDesc(product, pageable);
return PaginationResponse.<RatingResponse>builder()
.page(pageable.getPageNumber() + 1)
.total(ratingResponseList.getTotalElements())
.itemsPerPage(pageable.getPageSize())
.data(ratingResponseList.map(ratingMapper::toRatingResponse).toList())
.build();
}
}