@PostMapping(
        path = "/api/{namespace}/{extension}/review",
        consumes = MediaType.APPLICATION_JSON_VALUE,
        produces = MediaType.APPLICATION_JSON_VALUE
    )
    @Operation(hidden = true)
    public ResponseEntity<ResultJson> postReview(
            @RequestBody(required = false) ReviewJson review,
            @PathVariable String namespace,
            @PathVariable String extension
    ) {
        if (review == null) {
            var json = ResultJson.error("No JSON input.");
            return new ResponseEntity<>(json, HttpStatus.BAD_REQUEST);
        }
        if (review.rating < 0 || review.rating > 5) {
            var json = ResultJson.error("The rating must be an integer number between 0 and 5.");
            return new ResponseEntity<>(json, HttpStatus.BAD_REQUEST);
        }
        if (review.title != null && review.title.length() > REVIEW_TITLE_SIZE) {
            var json = ResultJson.error("The title must not be longer than " + REVIEW_TITLE_SIZE + " characters.");
            return new ResponseEntity<>(json, HttpStatus.BAD_REQUEST);
        }
        if (review.comment != null && review.comment.length() > REVIEW_COMMENT_SIZE) {
            var json = ResultJson.error("The review must not be longer than " + REVIEW_COMMENT_SIZE + " characters.");
            return new ResponseEntity<>(json, HttpStatus.BAD_REQUEST);
        }
        var json = local.postReview(review, namespace, extension);
        if (json.error == null) {
            return new ResponseEntity<>(json, HttpStatus.CREATED);
        } else {
            return new ResponseEntity<>(json, HttpStatus.BAD_REQUEST);
        }
    }
@Test
    public void testPostReview() throws Exception {
        var user = mockUserData();
        var extVersion = mockExtension();
        var extension = extVersion.getExtension();
        Mockito.when(repositories.findExtension("bar", "foo"))
                .thenReturn(extension);
        Mockito.when(repositories.findActiveReviews(extension, user))
                .thenReturn(Streamable.empty());
        Mockito.when(repositories.findActiveReviews(extension))
                .thenReturn(Streamable.empty());

        mockMvc.perform(post("/api/{namespace}/{extension}/review", "foo", "bar")
                .contentType(MediaType.APPLICATION_JSON)
                .content(reviewJson(r -> {
                    r.rating = 3;
                }))
                .with(user("test_user"))
                .with(csrf().asHeader()))
                .andExpect(status().isCreated())
                .andExpect(content().json(successJson("Added review for foo.bar")));
    }