Mono<ServerResponse> createReply(ServerRequest request) {
        String commentName = request.pathVariable("name");
        return request.bodyToMono(ReplyRequest.class)
            .flatMap(replyRequest -> {
                Reply reply = replyRequest.toReply();
                reply.getSpec().setIpAddress(IpAddressUtils.getIpAddress(request));
                reply.getSpec().setUserAgent(HaloUtils.userAgentFrom(request));
                // fix gh-2951
                reply.getSpec().setHidden(false);
                return environmentFetcher.fetchComment()
                    .map(commentSetting -> {
                        if (isFalse(commentSetting.getEnable())) {
                            throw new AccessDeniedException(
                                "The comment function has been turned off.",
                                "problemDetail.comment.turnedOff", null);
                        }
                        if (checkReplyOwner(reply, commentSetting.getSystemUserOnly())) {
                            throw new AccessDeniedException("Allow only system users to comment.",
                                "problemDetail.comment.systemUsersOnly", null);
                        }
                        reply.getSpec()
                            .setApproved(isFalse(commentSetting.getRequireReviewForNew()));
                        return reply;
                    })
                    .defaultIfEmpty(reply);
            })
            .flatMap(reply -> replyService.create(commentName, reply))
            .flatMap(comment -> ServerResponse.ok().bodyValue(comment))
            .transformDeferred(createIpBasedRateLimiter(request))
            .onErrorMap(RequestNotPermitted.class, RateLimitExceededException::new);
    }
@Test
    void createReply() {
        when(replyService.create(any(), any())).thenReturn(Mono.empty());

        final ReplyRequest replyRequest = new ReplyRequest();
        replyRequest.setRaw("raw");
        replyRequest.setContent("content");
        replyRequest.setAllowNotification(true);

        when(rateLimiterRegistry.rateLimiter("comment-creation-from-ip-127.0.0.1",
            "comment-creation"))
            .thenReturn(RateLimiter.ofDefaults("comment-creation"));

        webTestClient.post()
            .uri("/comments/test-comment/reply")
            .header("X-Forwarded-For", "127.0.0.1")
            .bodyValue(replyRequest)
            .exchange()
            .expectStatus()
            .isOk();

        ArgumentCaptor<Reply> captor = ArgumentCaptor.forClass(Reply.class);
        verify(replyService, times(1)).create(eq("test-comment"), captor.capture());
        Reply value = captor.getValue();
        assertThat(value.getSpec().getIpAddress()).isNotNull();
        assertThat(value.getSpec().getUserAgent()).isNotNull();
        assertThat(value.getSpec().getQuoteReply()).isNull();

        verify(rateLimiterRegistry).rateLimiter("comment-creation-from-ip-127.0.0.1",
            "comment-creation");
    }