Commit a5ae21c4 authored by Aleksandr Verevkin's avatar Aleksandr Verevkin
Browse files

Merge branch 'main' into 'main'

implementation of rating service

See merge request xheinz/pa165_movie_recommender!13
parents 8acbce0a 488bdeb2
Loading
Loading
Loading
Loading
+39 −0
Original line number Diff line number Diff line
@@ -12,4 +12,43 @@

	<name>Movie Recommender - Ratings and Reviews</name>
	<description>Ratings and Reviews microservice for the Movie Recommender Catalogue</description>
	<dependencies>
		<dependency>
			<groupId>com.h2database</groupId>
			<artifactId>h2</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.projectlombok</groupId>
			<artifactId>lombok</artifactId>
			<scope>provided</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jpa</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
        <dependency>
            <groupId>jakarta.validation</groupId>
            <artifactId>jakarta.validation-api</artifactId>
            <version>3.0.2</version>
        </dependency>
		<dependency>
			<groupId>io.swagger.core.v3</groupId>
			<artifactId>swagger-annotations-jakarta</artifactId>
			<version>2.2.20</version>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-actuator</artifactId>
		</dependency>
		<dependency>
			<groupId>org.mapstruct</groupId>
			<artifactId>mapstruct</artifactId>
			<version>1.5.5.Final</version>
		</dependency>
	</dependencies>
</project>
+130 −0
Original line number Diff line number Diff line
package cz.muni.fi.pa165.ratingsandreviews.controller;

import cz.muni.fi.pa165.ratingsandreviews.dto.ReviewDTO;
import cz.muni.fi.pa165.ratingsandreviews.facade.ReviewFacade;
import cz.muni.fi.pa165.ratingsandreviews.model.FilmProperty;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.DeleteMapping;
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.PutMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

/**
 * Controller for handling review-related operations.
 */
@RestController
@RequestMapping(path = "/api/reviews", produces = MediaType.APPLICATION_JSON_VALUE)
public class ReviewController {
    /**
     * The ReviewFacade instance.
     */
    private final ReviewFacade reviewFacade;

    /**
     * Constructs a ReviewController with the given ReviewFacade.
     *
     * @param facade The ReviewFacade to be used.
     */
    public ReviewController(final ReviewFacade facade) {
        this.reviewFacade = facade;
    }

    /**
     * Adds a new review.
     *
     * @param newReview The review to be added.
     * @return The added review DTO.
     */
    @PostMapping()
    public ResponseEntity<ReviewDTO> addReview(@RequestBody final ReviewDTO newReview) {
        ReviewDTO addedReview = reviewFacade.addReview(newReview);
        return ResponseEntity.status(HttpStatus.CREATED).body(addedReview);
    }

    /**
     * Deletes a review by its ID.
     *
     * @param reviewId The ID of the review to be deleted.
     * @return The deleted review DTO.
     */
    @DeleteMapping("/{reviewId}")
    public ResponseEntity<ReviewDTO> deleteReview(@PathVariable final Long reviewId) {
        ReviewDTO deletedReview = reviewFacade.deleteReview(reviewId);
        return ResponseEntity.ok(deletedReview);
    }

    /**
     * Updates a review.
     *
     * @param updatedReview The updated review.
     * @return The updated review DTO.
     */
    @PutMapping("/{reviewId}")
    public ResponseEntity<ReviewDTO> updateReview(@RequestBody final ReviewDTO updatedReview) {
        ReviewDTO updated = reviewFacade.updateReview(updatedReview);
        return ResponseEntity.ok(updated);
    }

    /**
     * Retrieves a review by its ID.
     *
     * @param reviewId The ID of the review to be retrieved.
     * @return The retrieved review DTO.
     */
    @GetMapping("/{reviewId}")
    public ResponseEntity<ReviewDTO> getReview(@PathVariable final Long reviewId) {
        ReviewDTO review = reviewFacade.getReview(reviewId);
        return ResponseEntity.ok(review);
    }

    /**
     * Retrieves reviews by user ID.
     *
     * @param userId The ID of the user whose reviews are to be retrieved.
     * @return List of review DTOs.
     */
    @GetMapping("/getByUserId")
    public ResponseEntity<List<ReviewDTO>> getReviewsByUserId(@RequestParam final Long userId) {
        List<ReviewDTO> reviews = reviewFacade.getReviewsByUserId(userId);
        return ResponseEntity.ok(reviews);
    }

    /**
     * Retrieves all reviews sorted by a specific film property in chosen order.
     *
     * @param property The film property to sort by.
     * @param order order -> ASC/DESC
     * @return List of review DTOs.
     */
    @GetMapping("/sortedByProperty/{property}/{order}")
    public ResponseEntity<List<ReviewDTO>> getAllReviewsSortedByProperty(
            @PathVariable("property") final FilmProperty property,
            @PathVariable("order") final String order) {
        boolean descending = "desc".equalsIgnoreCase(order);
        List<ReviewDTO> reviews = reviewFacade.getAllReviewsSortedByProperty(property, descending);
        return ResponseEntity.ok(reviews);
    }

    /**
     * Retrieves all reviews sorted by overall rating of film.
     *
     * @param order order -> ASC/DESC
     * @return List of review DTOs.
     */
    @GetMapping("/sortedByRating/{order}")
    public ResponseEntity<List<ReviewDTO>> getAllReviewssSortedByProperty(
            @PathVariable("order") final String order) {
        boolean descending = "desc".equalsIgnoreCase(order);
        List<ReviewDTO> reviews = reviewFacade.getAllReviewsSortedByRating(descending);
        return ResponseEntity.ok(reviews);
    }
}
+78 −0
Original line number Diff line number Diff line
package cz.muni.fi.pa165.ratingsandreviews.dto;

import cz.muni.fi.pa165.ratingsandreviews.model.FilmProperty;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.Setter;

import java.util.Map;

/**
 * Data Transfer Object for representing a review.
 */
@Setter
@Getter
@Schema(title = "ReviewDTO", description = "Represents a standard review DTO object")
public class ReviewDTO {

    /**
     * -- SETTER --
     *  Sets the ID of the movie to which the review relates.
     * <p>
     * -- GETTER --
     *  Retrieves the ID of the movie to which the review relates.
     *

     */
    @Schema(description = "ID of the movie to which the review relates", example = "1234")
    private Long movieId;

    /**
     * -- GETTER --
     *  Retrieves the ID of the user who created the review.
     * <p>
     *
     * -- SETTER --
     *  Sets the ID of the user who created the review.
     *
     */
    @Schema(description = "ID of the user who created the review", example = "5678")
    private Long userId;

    /**
     * -- SETTER --
     *  Sets the ID of the review.
     * <p>
     * -- GETTER --
     *  Retrieves the ID of the review.
     *

     */
    @Schema(description = "ID of the review", example = "9876")
    private Long id;

    /**
     * -- GETTER --
     *  Retrieves the ratings for different aspects of the movie.
     * <p>
     *
     * -- SETTER --
     *  Sets the ratings for different aspects of the movie.
     *
     */
    @Schema(description = "Ratings for different aspects of the movie")
    private Map<FilmProperty, Float> ratings;

    /**
     * -- GETTER --
     *  Retrieves the overall rating of the movie.
     * <p>
     *
     * -- SETTER --
     *  Sets the overall rating of the movie.
     *
     */
    @Schema(description = "Overall rating of the movie", example = "8.5")
    private Double overallRating;

}
+72 −0
Original line number Diff line number Diff line
package cz.muni.fi.pa165.ratingsandreviews.facade;

import cz.muni.fi.pa165.ratingsandreviews.dto.ReviewDTO;
import cz.muni.fi.pa165.ratingsandreviews.model.FilmProperty;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
@Primary
public interface ReviewFacade {

    /**
     * Adds a new review.
     *
     * @param newReview The review to be added.
     * @return The added review DTO.
     */
    ReviewDTO addReview(ReviewDTO newReview);

    /**
     * Deletes a review by its ID.
     *
     * @param reviewId The ID of the review to be deleted.
     * @return The deleted review DTO.
     */
    ReviewDTO deleteReview(Long reviewId);

    /**
     * Updates a review.
     *
     * @param updatedReview The updated review.
     * @return The updated review DTO.
     */
    ReviewDTO updateReview(ReviewDTO updatedReview);

    /**
     * Retrieves a review by its ID.
     *
     * @param reviewId The ID of the review to be retrieved.
     * @return The retrieved review DTO.
     */
    ReviewDTO getReview(Long reviewId);

    /**
     * Retrieves reviews by user ID.
     *
     * @param userId The ID of the user whose reviews are to be retrieved.
     * @return List of review DTOs.
     */
    List<ReviewDTO> getReviewsByUserId(Long userId);

    /**
     * Retrieves reviews sorted by value of its property rating.
     *
     * @param property The property on which sort wil be done
     * @param descending Boolean value -> true if sort is descending
     * @return List of sorted reviews
     */
    List<ReviewDTO> getAllReviewsSortedByProperty(FilmProperty property, Boolean descending);

    /**
     * Retrieves reviews sorted by value of its overall rating.
     *
     * @param descending Boolean value -> true if sort is descending
     * @return List of sorted reviews
     */
    List<ReviewDTO> getAllReviewsSortedByRating(Boolean descending);


}
+140 −0
Original line number Diff line number Diff line
package cz.muni.fi.pa165.ratingsandreviews.facade;

import cz.muni.fi.pa165.ratingsandreviews.dto.ReviewDTO;
import cz.muni.fi.pa165.ratingsandreviews.mapper.ReviewMapper;
import cz.muni.fi.pa165.ratingsandreviews.model.FilmProperty;
import cz.muni.fi.pa165.ratingsandreviews.model.Review;
import cz.muni.fi.pa165.ratingsandreviews.service.ReviewService;
import jakarta.transaction.Transactional;
import org.springframework.stereotype.Service;

import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * Implementation of ReviewFacade.
 */
@Service
public class ReviewFacadeImpl implements ReviewFacade {

    /**
     * The ReviewMapper instance.
     */
    private final ReviewMapper reviewMapper;

    /**
     * The ReviewService instance.
     */
    private final ReviewService reviewService;

    /**
     * Constructs ReviewFacadeImpl.
     *
     * @param service review service
     * @param mapper  the review mapper
     */
    public ReviewFacadeImpl(final ReviewMapper mapper,
                            final ReviewService service) {
        this.reviewService = service;
        this.reviewMapper = mapper;
    }

    /**
     * Adds a new review.
     *
     * @param newReview the review to add
     * @return the added review DTO
     */
    @Override
    public ReviewDTO addReview(final ReviewDTO newReview) {
        reviewService.addReview(reviewMapper.dtoToEntity(newReview));
        return newReview;
    }

    /**
     * Deletes a review by ID.
     *
     * @param reviewId the ID of the review to delete
     * @return the deleted review DTO
     */
    @Override
    @Transactional
    public ReviewDTO deleteReview(final Long reviewId) {
        return reviewMapper.entityToDto(reviewService.deleteReview(reviewId));
    }

    /**
     * Updates an existing review.
     *
     * @param updatedReview the updated review
     * @return the updated review DTO
     */
    @Override
    @Transactional
    public ReviewDTO updateReview(final ReviewDTO updatedReview) {
        reviewService.addReview(reviewMapper.dtoToEntity(updatedReview));
        return updatedReview;
    }

    /**
     * Retrieves a review by ID.
     *
     * @param reviewId the ID of the review to retrieve
     * @return the retrieved review DTO
     */
    @Override
    @Transactional
    public ReviewDTO getReview(final Long reviewId) {
        return reviewMapper.entityToDto(reviewService.getReview(reviewId));
    }

    /**
     * Retrieves reviews by user ID.
     *
     * @param userId the ID of the user
     * @return list of review DTOs by the user
     */
    @Override
    @Transactional
    public List<ReviewDTO> getReviewsByUserId(final Long userId) {
        return reviewService.getAllReviews().stream()
                .filter(review -> review.getId().equals(userId))
                .map(reviewMapper::entityToDto)
                .collect(Collectors.toList());
    }

    /**
     * Retrieves all reviews sorted by overall rating.
     * @param descending Boolean value -> true if sort is descending
     * @return list of review DTOs sorted by overall rating
     */
    @Override
    @Transactional
    public List<ReviewDTO> getAllReviewsSortedByRating(final Boolean descending) {
        Comparator<Review> comparator = Comparator.comparing(Review::getOverallRating);

        return reviewService.getAllReviews().stream()
                .sorted(descending ? comparator.reversed() : comparator)
                .map(reviewMapper::entityToDto)
                .collect(Collectors.toList());
    }
    /**
     * Retrieves all reviews sorted by the specified property.
     * @param property The property on which sort will be done
     * @param descending Boolean value -> true if sort is descending
     * @return list of review DTOs sorted by the specified property
     */
    @Override
    @Transactional
    public List<ReviewDTO> getAllReviewsSortedByProperty(final FilmProperty property, final Boolean descending) {
        Comparator<Review> comparator = Comparator.comparing(review -> review.getRatings()
                .getOrDefault(property, 0.0f));

        return reviewService.getAllReviews().stream()
                .sorted(descending ? comparator.reversed() : comparator)
                .map(reviewMapper::entityToDto)
                .collect(Collectors.toList());
    }

}
Loading