Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[IL-286] Average Rating, Review Exists Check #254

Merged
merged 15 commits into from
Mar 18, 2024
Merged
6 changes: 3 additions & 3 deletions pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -604,9 +604,9 @@
</configOptions>
</configuration>
</execution>
<!-- Generate from Product productRating OpenAPI Spec -->
<!-- Generate from Product Rating OpenAPI Spec -->
<execution>
<id>generate-from-product-productRating-openapi-spec</id>
<id>generate-from-product-rating-openapi-spec</id>
<goals>
<goal>generate</goal>
</goals>
Expand All @@ -615,7 +615,7 @@
<generatorName>spring</generatorName>
<configOptions>
<useJakartaEe>true</useJakartaEe>
<apiPackage>${openapi-package}.order.api</apiPackage>
<apiPackage>${openapi-package}.product.rating.api</apiPackage>
<modelPackage>${openapi-package-with-dto}</modelPackage>
<interfaceOnly>true</interfaceOnly>
<useTags>true</useTags>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import com.zufar.icedlatte.common.exception.ResourceNotFoundException;
import com.zufar.icedlatte.common.exception.dto.ApiErrorResponse;
import jakarta.validation.ConstraintViolationException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -45,5 +46,14 @@ public ApiErrorResponse handleResourceNotFoundException(final ResourceNotFoundEx

return apiErrorResponse;
}

@ExceptionHandler(ConstraintViolationException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
public ApiErrorResponse handleConstraintViolationException(final ConstraintViolationException exception) {
ApiErrorResponse apiErrorResponse = apiErrorResponseCreator.buildResponse(exception, HttpStatus.BAD_REQUEST);
log.warn("Handle constraint violation exception: failed: message: {}, debugMessage: {}.",
apiErrorResponse.message(), errorDebugMessageCreator.buildErrorDebugMessage(exception));
return apiErrorResponse;
}
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package com.zufar.icedlatte.review.api;

import com.zufar.icedlatte.openapi.dto.AverageProductRatingDto;
import com.zufar.icedlatte.review.repository.ProductRatingRepository;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
@RequiredArgsConstructor
public class ProductRatingProvider {

private final ProductRatingRepository ratingRepository;

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public AverageProductRatingDto getAvgRatingByProductId(final UUID productId) {
Double averageRating = ratingRepository.getAvgRatingByProductId(productId);
return new AverageProductRatingDto(productId, averageRating);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package com.zufar.icedlatte.review.api;

import com.zufar.icedlatte.openapi.dto.ProductRatingDto;
import com.zufar.icedlatte.product.api.ProductApi;
import com.zufar.icedlatte.product.entity.ProductInfo;
import com.zufar.icedlatte.review.converter.ProductRatingDtoConverter;
import com.zufar.icedlatte.review.entity.ProductRating;
import com.zufar.icedlatte.review.repository.ProductRatingRepository;
import com.zufar.icedlatte.user.api.SingleUserProvider;
import com.zufar.icedlatte.user.entity.UserEntity;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.UUID;

@Service
@RequiredArgsConstructor
public class ProductRatingUpdater {

private final ProductRatingRepository ratingRepository;
private final SingleUserProvider singleUserProvider;
private final ProductApi productApi;
private final ProductRatingDtoConverter ratingConverter;

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED)
public ProductRatingDto addRating(final UUID userId, final UUID productId, final Integer rating) {
final UserEntity user = singleUserProvider.getUserEntityById(userId);
final ProductInfo product = productApi.getProductEntityById(productId);

ProductRating productRatingEntity = ProductRating.builder()
.user(user)
.productInfo(product)
.productRating(rating)
.build();

ratingRepository.save(productRatingEntity);
return ratingConverter.convertToDto(productRatingEntity);
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package com.zufar.icedlatte.review.api;

import com.zufar.icedlatte.openapi.dto.ProductReviewStatus;
import com.zufar.icedlatte.product.api.SingleProductProvider;
import com.zufar.icedlatte.review.entity.ProductReview;
import com.zufar.icedlatte.review.exception.ProductReviewNotFoundException;
import com.zufar.icedlatte.review.repository.ProductReviewRepository;
import com.zufar.icedlatte.security.api.SecurityPrincipalProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
Expand All @@ -18,6 +21,8 @@
public class ProductReviewProvider {

private final ProductReviewRepository reviewRepository;
private final SecurityPrincipalProvider securityPrincipalProvider;
private final SingleProductProvider singleProductProvider;

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, readOnly = true)
public ProductReview getReviewEntityById(final UUID reviewId) {
Expand All @@ -27,4 +32,12 @@ public ProductReview getReviewEntityById(final UUID reviewId) {
return new ProductReviewNotFoundException(reviewId);
});
}

@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, readOnly = true)
public ProductReviewStatus getProductReviewByUser(UUID productId) {
singleProductProvider.getProductEntityById(productId);
var userId = securityPrincipalProvider.getUserId();
var review = reviewRepository.findByUserIdAndProductInfoProductId(userId, productId);
return new ProductReviewStatus().exists(review.isPresent());
}
}
38 changes: 0 additions & 38 deletions src/main/java/com/zufar/icedlatte/review/api/RatingUpdater.java

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.zufar.icedlatte.review.converter;

import com.zufar.icedlatte.openapi.dto.ProductRatingDto;
import com.zufar.icedlatte.review.entity.ProductRating;
import org.springframework.stereotype.Service;

@Service
public class ProductRatingDtoConverter {

public ProductRatingDto convertToDto(ProductRating productRating) {
return new ProductRatingDto(
productRating.getProductInfo().getProductId(),
productRating.getProductRating()
);
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,15 +1,20 @@
package com.zufar.icedlatte.review.endpoint;

import com.zufar.icedlatte.openapi.dto.AddNewProductRatingRequest;
import com.zufar.icedlatte.openapi.dto.AverageProductRatingDto;
import com.zufar.icedlatte.openapi.dto.ProductRatingDto;
import com.zufar.icedlatte.review.api.RatingUpdater;
import com.zufar.icedlatte.openapi.product.rating.api.ProductRatingApi;
import com.zufar.icedlatte.review.api.ProductRatingProvider;
import com.zufar.icedlatte.review.api.ProductRatingUpdater;
import com.zufar.icedlatte.security.api.SecurityPrincipalProvider;
import jakarta.validation.constraints.Max;
import jakarta.validation.constraints.Min;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

Expand All @@ -20,19 +25,30 @@
@RequiredArgsConstructor
@Validated
@RequestMapping(value = ProductRatingEndpoint.RATING_URL)
public class ProductRatingEndpoint {
public class ProductRatingEndpoint implements ProductRatingApi {

public static final String RATING_URL = "/api/v1/rating/product";
public static final String RATING_URL = "/api/v1/products/";

private final RatingUpdater ratingUpdater;
private final ProductRatingUpdater ratingUpdater;
private final ProductRatingProvider ratingProvider;
private final SecurityPrincipalProvider securityPrincipalProvider;

@PostMapping
public ResponseEntity<ProductRatingDto> addNewProductRating(@RequestBody final AddNewProductRatingRequest rating) {
log.info("Received the request to add product's rating");
@Override
@PostMapping("/{productId}/ratings/{rating}")
public ResponseEntity<ProductRatingDto> addNewProductRating(@PathVariable final UUID productId, @PathVariable @Max(5) @Min(1) final Integer rating) {
log.info("Received the request to add new rating to product");
final UUID userId = securityPrincipalProvider.getUserId();
final ProductRatingDto ratingDto = ratingUpdater.addRating(rating, userId);
log.info("New Product's Rating was added");
final ProductRatingDto ratingDto = ratingUpdater.addRating(userId, productId, rating);
log.info("Rating was added");
return ResponseEntity.ok().body(ratingDto);
}

@Override
@GetMapping("/{productId}/ratings")
public ResponseEntity<AverageProductRatingDto> getRatingByProductId(@PathVariable final UUID productId) {
log.info("Received the request to get average rating for product id: {}", productId);
final AverageProductRatingDto averageRating = ratingProvider.getAvgRatingByProductId(productId);
log.info("Rating by product id retrieval processed");
return ResponseEntity.ok().body(averageRating);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import com.zufar.icedlatte.openapi.dto.ProductReviewRequest;
import com.zufar.icedlatte.openapi.dto.ProductReviewResponse;
import com.zufar.icedlatte.openapi.dto.ProductReviewStatus;
import com.zufar.icedlatte.openapi.dto.ProductReviewsAndRatingsWithPagination;
import com.zufar.icedlatte.review.api.PageableReviewsAndRatingsProvider;
import com.zufar.icedlatte.review.api.ProductReviewCreator;
import com.zufar.icedlatte.review.api.ProductReviewDeleter;
import com.zufar.icedlatte.review.api.ProductReviewProvider;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
Expand Down Expand Up @@ -33,6 +35,7 @@ public class ProductReviewEndpoint implements com.zufar.icedlatte.openapi.produc
private final ProductReviewCreator productReviewCreator;
private final ProductReviewDeleter productReviewDeleter;
private final PageableReviewsAndRatingsProvider pageableReviewsProvider;
private final ProductReviewProvider productReviewProvider;

@Override
@PostMapping(value = "/{productId}/reviews")
Expand Down Expand Up @@ -67,4 +70,13 @@ public ResponseEntity<ProductReviewsAndRatingsWithPagination> getProductReviewsA
log.info("Product reviews and ratings were retrieved successfully");
return ResponseEntity.ok().body(reviewsPaginationDto);
}

@Override
@GetMapping(value = "/{productId}/reviews/exists")
public ResponseEntity<ProductReviewStatus> getProductReview(@PathVariable final UUID productId){
log.info("Received the request to get product review status product {}", productId);
ProductReviewStatus reviewsStatus = productReviewProvider.getProductReviewByUser(productId);
log.info("Product review status was retrieved successfully");
return ResponseEntity.ok().body(reviewsStatus);
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package com.zufar.icedlatte.review.repository;

import com.zufar.icedlatte.review.entity.ProductRating;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.stereotype.Repository;

import java.util.UUID;

@Repository
public interface ProductRatingRepository extends JpaRepository<ProductRating, UUID> {

@Query("SELECT AVG(pr.productRating) FROM ProductRating pr WHERE pr.productInfo.id = :productId")
Double getAvgRatingByProductId(UUID productId);
}

This file was deleted.

Loading
Loading