ReviewsController.java

1
package edu.ucsb.cs156.dining.controllers;
2
3
import edu.ucsb.cs156.dining.entities.Review;
4
import edu.ucsb.cs156.dining.errors.EntityNotFoundException;
5
import edu.ucsb.cs156.dining.repositories.ReviewRepository;
6
7
import io.swagger.v3.oas.annotations.Operation;
8
import io.swagger.v3.oas.annotations.Parameter;
9
import io.swagger.v3.oas.annotations.tags.Tag;
10
import lombok.extern.slf4j.Slf4j;
11
12
import com.fasterxml.jackson.core.JsonProcessingException;
13
14
import org.springframework.beans.factory.annotation.Autowired;
15
import org.springframework.format.annotation.DateTimeFormat;
16
import org.springframework.security.access.prepost.PreAuthorize;
17
import org.springframework.web.bind.annotation.DeleteMapping;
18
import org.springframework.web.bind.annotation.GetMapping;
19
import org.springframework.web.bind.annotation.PostMapping;
20
import org.springframework.web.bind.annotation.PutMapping;
21
import org.springframework.web.bind.annotation.RequestBody;
22
import org.springframework.web.bind.annotation.RequestMapping;
23
import org.springframework.web.bind.annotation.RequestParam;
24
import org.springframework.web.bind.annotation.RestController;
25
import org.springframework.web.bind.annotation.ResponseStatus;
26
import org.springframework.web.bind.annotation.ExceptionHandler;
27
28
import org.springframework.http.HttpStatus;
29
30
import jakarta.validation.Valid;
31
32
import java.time.LocalDateTime;
33
import java.time.format.DateTimeFormatter;
34
import java.time.temporal.ChronoUnit;
35
36
import java.util.Arrays;
37
import java.util.ArrayList;
38
39
/**
40
 * This is a REST controller for Reviews
41
 */
42
43
@Tag(name = "Reviews")
44
@RequestMapping("/api/reviews")
45
@RestController
46
@Slf4j
47
public class ReviewsController extends ApiController {
48
49
    @Autowired
50
    ReviewRepository reviewsRepository;
51
52
    
53
    @ResponseStatus(HttpStatus.BAD_REQUEST)
54
    @ExceptionHandler(IllegalArgumentException.class)
55
    public void handleIllegalArgumentException() {
56
57
    }
58
59
    /**
60
     * List all reviews
61
     * 
62
     * @return an iterable of Review
63
     */
64
    @Operation(summary= "List all reviews")
65
    @PreAuthorize("hasRole('ROLE_ADMIN')")
66
    @GetMapping("/all")
67
    public Iterable<Review> allReviews() {
68
        Iterable<Review> reviews = reviewsRepository.findAll();
69 1 1. allReviews : replaced return value with Collections.emptyList for edu/ucsb/cs156/dining/controllers/ReviewsController::allReviews → KILLED
        return reviews;
70
    }
71
72
    /**
73
     * List all reviews created by a specific user
74
     * 
75
     * @return an iterable of Review
76
     */
77
    @Operation(summary= "List all reviews created by a specific user")
78
    @PreAuthorize("hasRole('ROLE_USER')")
79
    @GetMapping("")
80
    public Iterable<Review> getReviewsByUser() {
81
        Iterable<Review> reviews = reviewsRepository.findAllByReviewerId(getCurrentUser().getUser().getId());
82 1 1. getReviewsByUser : replaced return value with Collections.emptyList for edu/ucsb/cs156/dining/controllers/ReviewsController::getReviewsByUser → KILLED
        return reviews;
83
    }
84
85
    /**
86
     * List all reviews needing moderation
87
     * 
88
     * @return an iterable of Review
89
     */
90
    @Operation(summary= "List all reviews needing moderation")
91
    @PreAuthorize("hasRole('ROLE_ADMIN')")
92
    @GetMapping("/needsmoderation")
93
    public Iterable<Review> getReviewsNeedingModeration() {
94
        Iterable<Review> reviews = reviewsRepository.findAllByStatus("Awaiting Moderation");
95 1 1. getReviewsNeedingModeration : replaced return value with Collections.emptyList for edu/ucsb/cs156/dining/controllers/ReviewsController::getReviewsNeedingModeration → KILLED
        return reviews;
96
    }
97
98
    /**
99
     * Create a new review
100
     * 
101
     * @param itemId            id of item in DiningCommonsMenuItem table
102
     * @param dateServed        date item was served
103
     * @param stars             rating from 0-5 inclusive
104
     * @param reviewText        reviewer comments
105
     * @return the saved review
106
     */
107
    @Operation(summary= "Create a new review")
108
    @PreAuthorize("hasRole('ROLE_USER')")
109
    @PostMapping("/post")
110
    public Review postReview(
111
            @Parameter(name="itemId") @RequestParam long itemId,
112
            @Parameter(name="dateServed", description="date (in iso format, e.g. YYYY-mm-ddTHH:MM:SS") @RequestParam("dateServed") @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME) LocalDateTime dateServed,
113
            @Parameter(name="stars") @RequestParam long stars,
114
            @Parameter(name="reviewText") @RequestParam String reviewText)
115
            throws JsonProcessingException {
116
117
        // For an explanation of @DateTimeFormat(iso = DateTimeFormat.ISO.DATE_TIME)
118
        // See: https://www.baeldung.com/spring-date-parameters
119
120
        LocalDateTime createdDate = LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS);
121
122
        log.info("createdDate={}", createdDate.format(DateTimeFormatter.ISO_DATE_TIME));
123
124
        Review reviews = new Review();
125 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setReviewerId → KILLED
        reviews.setReviewerId(getCurrentUser().getUser().getId());
126 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setItemId → KILLED
        reviews.setItemId(itemId);
127 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setDateServed → KILLED
        reviews.setDateServed(dateServed);
128 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setStars → KILLED
        reviews.setStars(stars);
129 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setReviewText → KILLED
        reviews.setReviewText(reviewText);
130 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setStatus → KILLED
        reviews.setStatus("Awaiting Moderation");
131 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setCreatedDate → KILLED
        reviews.setCreatedDate(createdDate);
132 1 1. postReview : removed call to edu/ucsb/cs156/dining/entities/Review::setLastEditedDate → KILLED
        reviews.setLastEditedDate(createdDate);
133
134
        Review savedReview = reviewsRepository.save(reviews);
135
136 1 1. postReview : replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::postReview → KILLED
        return savedReview;
137
    }
138
    
139
    /**
140
     * Update a single review
141
     * 
142
     * @param id        id of the review to update
143
     * @param incoming  the new review
144
     * @return the updated review object
145
     */
146
    @Operation(summary= "Update a single review")
147
    @PreAuthorize("hasRole('ROLE_USER')")
148
    @PutMapping("/reviewer")
149
    public Review updateReview(
150
            @Parameter(name="id") @RequestParam Long id,
151
            @RequestBody @Valid Review incoming) {
152
            
153
        Review review = reviewsRepository.findById(id)
154 1 1. lambda$updateReview$0 : replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::lambda$updateReview$0 → KILLED
                .orElseThrow(() -> new EntityNotFoundException(Review.class, id));
155
156 1 1. updateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setStars → KILLED
        review.setStars(incoming.getStars());
157 1 1. updateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setReviewText → KILLED
        review.setReviewText(incoming.getReviewText());
158 1 1. updateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setStatus → KILLED
        review.setStatus("Awaiting Moderation");
159 1 1. updateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setModId → KILLED
        review.setModId(null);
160 1 1. updateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setModComments → KILLED
        review.setModComments(null);
161 1 1. updateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setLastEditedDate → KILLED
        review.setLastEditedDate(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
162
163
        reviewsRepository.save(review);
164
165 1 1. updateReview : replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::updateReview → KILLED
        return review;
166
    }
167
168
    /**
169
     * Moderate a single review
170
     * 
171
     * @param id        id of the review to moderate
172
     * @param incoming  the new review
173
     * @return the updated review object
174
     */
175
    @Operation(summary= "Moderate a single review")
176
    @PreAuthorize("hasRole('ROLE_ADMIN')")
177
    @PutMapping("/moderator")
178
    public Review moderateReview(
179
            @Parameter(name="id") @RequestParam Long id,
180
            @RequestBody @Valid Review incoming) {
181
182
183
        Review review = reviewsRepository.findById(id)
184 1 1. lambda$moderateReview$1 : replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::lambda$moderateReview$1 → KILLED
                .orElseThrow(() -> new EntityNotFoundException(Review.class, id));
185
        
186
        ArrayList<String> validStatus = new ArrayList<>(Arrays.asList("Approved", "Awaiting Moderation", "Rejected"));
187
188 1 1. moderateReview : negated conditional → KILLED
        if( !validStatus.contains(incoming.getStatus()) ) {
189
            throw new IllegalArgumentException("Status must be one of: " + validStatus);
190
        } 
191
192 1 1. moderateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setStatus → KILLED
        review.setStatus(incoming.getStatus());
193 1 1. moderateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setModComments → KILLED
        review.setModComments(incoming.getModComments());
194 1 1. moderateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setModId → KILLED
        review.setModId(getCurrentUser().getUser().getId());
195 1 1. moderateReview : removed call to edu/ucsb/cs156/dining/entities/Review::setLastEditedDate → KILLED
        review.setLastEditedDate(LocalDateTime.now().truncatedTo(ChronoUnit.SECONDS));
196
197
        reviewsRepository.save(review);
198
199 1 1. moderateReview : replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::moderateReview → KILLED
        return review;
200
    }
201
202
}

Mutations

69

1.1
Location : allReviews
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_can_get_all_reviews()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/dining/controllers/ReviewsController::allReviews → KILLED

82

1.1
Location : getReviewsByUser
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_get_their_reviews()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/dining/controllers/ReviewsController::getReviewsByUser → KILLED

95

1.1
Location : getReviewsNeedingModeration
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:an_admin_user_can_get_reviews_needing_moderation()]
replaced return value with Collections.emptyList for edu/ucsb/cs156/dining/controllers/ReviewsController::getReviewsNeedingModeration → KILLED

125

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setReviewerId → KILLED

126

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setItemId → KILLED

127

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setDateServed → KILLED

128

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setStars → KILLED

129

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setReviewText → KILLED

130

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setStatus → KILLED

131

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setCreatedDate → KILLED

132

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setLastEditedDate → KILLED

136

1.1
Location : postReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_post_a_new_review()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::postReview → KILLED

154

1.1
Location : lambda$updateReview$0
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_cannot_edit_review_that_does_not_exist()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::lambda$updateReview$0 → KILLED

156

1.1
Location : updateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_edit_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setStars → KILLED

157

1.1
Location : updateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_edit_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setReviewText → KILLED

158

1.1
Location : updateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_edit_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setStatus → KILLED

159

1.1
Location : updateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_edit_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setModId → KILLED

160

1.1
Location : updateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_edit_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setModComments → KILLED

161

1.1
Location : updateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_edit_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setLastEditedDate → KILLED

165

1.1
Location : updateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:logged_in_user_can_edit_an_existing_review()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::updateReview → KILLED

184

1.1
Location : lambda$moderateReview$1
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_cannot_moderate_review_that_does_not_exist()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::lambda$moderateReview$1 → KILLED

188

1.1
Location : moderateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_inputs_valid_moderation_status()]
negated conditional → KILLED

192

1.1
Location : moderateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_can_moderate_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setStatus → KILLED

193

1.1
Location : moderateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_can_moderate_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setModComments → KILLED

194

1.1
Location : moderateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_can_moderate_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setModId → KILLED

195

1.1
Location : moderateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_can_moderate_an_existing_review()]
removed call to edu/ucsb/cs156/dining/entities/Review::setLastEditedDate → KILLED

199

1.1
Location : moderateReview
Killed by : edu.ucsb.cs156.dining.controllers.ReviewsControllerTests.[engine:junit-jupiter]/[class:edu.ucsb.cs156.dining.controllers.ReviewsControllerTests]/[method:admin_user_can_moderate_an_existing_review()]
replaced return value with null for edu/ucsb/cs156/dining/controllers/ReviewsController::moderateReview → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0