feat: add support for fetching replies alongside comment list (#5505)

#### What type of PR is this?
/kind feature
/area core
/milestone 2.14.x
/kind api-change

#### What this PR does / why we need it:
主题端评论列表支持同时获得评论数据

Resolves #5435

#### Does this PR introduce a user-facing change?
```release-note
主题端评论列表支持同时获得评论数据
```
pull/5516/head
guqing 2024-03-16 22:52:07 +08:00 committed by GitHub
parent 7c3f8b9be2
commit 5e073bfe3c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 85 additions and 10 deletions

View File

@ -20,7 +20,6 @@ import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.StringUtils;
import org.springdoc.core.fn.builders.schema.Builder;
import org.springdoc.webflux.core.fn.SpringdocRouteBuilder;
import org.springframework.context.MessageSource;
import org.springframework.data.domain.Sort;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Component;
@ -55,6 +54,7 @@ import run.halo.app.infra.utils.IpAddressUtils;
import run.halo.app.theme.finders.CommentFinder;
import run.halo.app.theme.finders.CommentPublicQueryService;
import run.halo.app.theme.finders.vo.CommentVo;
import run.halo.app.theme.finders.vo.CommentWithReplyVo;
import run.halo.app.theme.finders.vo.ReplyVo;
/**
@ -69,7 +69,6 @@ public class CommentFinderEndpoint implements CustomEndpoint {
private final ReplyService replyService;
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
private final RateLimiterRegistry rateLimiterRegistry;
private final MessageSource messageSource;
@Override
public RouterFunction<ServerResponse> endpoint() {
@ -112,7 +111,7 @@ public class CommentFinderEndpoint implements CustomEndpoint {
.description("List comments.")
.tag(tag)
.response(responseBuilder()
.implementation(ListResult.generateGenericClass(CommentVo.class))
.implementation(ListResult.generateGenericClass(CommentWithReplyVo.class))
);
QueryParamBuildUtil.buildParametersFromType(builder, CommentQuery.class);
})
@ -212,6 +211,13 @@ public class CommentFinderEndpoint implements CustomEndpoint {
Mono<ServerResponse> listComments(ServerRequest request) {
CommentQuery commentQuery = new CommentQuery(request);
return commentPublicQueryService.list(commentQuery.toRef(), commentQuery.toPageRequest())
.flatMap(result -> {
if (commentQuery.getWithReplies()) {
return commentPublicQueryService.convertToWithReplyVo(result,
commentQuery.getReplySize());
}
return Mono.just(result);
})
.flatMap(list -> ServerResponse.ok().bodyValue(list));
}
@ -278,6 +284,20 @@ public class CommentFinderEndpoint implements CustomEndpoint {
return name;
}
@Schema(description = "Whether to include replies. Default is false.",
defaultValue = "false")
public Boolean getWithReplies() {
var withReplies = queryParams.getFirst("withReplies");
return StringUtils.isNotBlank(withReplies) && Boolean.parseBoolean(withReplies);
}
@Schema(description = "Reply size of the comment, default is 10, only works when "
+ "withReplies is true.", defaultValue = "10")
public int getReplySize() {
var replySize = queryParams.getFirst("replySize");
return StringUtils.isNotBlank(replySize) ? Integer.parseInt(replySize) : 10;
}
@ArraySchema(uniqueItems = true,
arraySchema = @Schema(name = "sort",
description = "Sort property and direction of the list result. Supported fields: "

View File

@ -6,6 +6,7 @@ import run.halo.app.extension.ListResult;
import run.halo.app.extension.PageRequest;
import run.halo.app.extension.Ref;
import run.halo.app.theme.finders.vo.CommentVo;
import run.halo.app.theme.finders.vo.CommentWithReplyVo;
import run.halo.app.theme.finders.vo.ReplyVo;
/**
@ -21,6 +22,9 @@ public interface CommentPublicQueryService {
Mono<ListResult<CommentVo>> list(Ref ref, @Nullable PageRequest pageRequest);
Mono<ListResult<CommentWithReplyVo>> convertToWithReplyVo(ListResult<CommentVo> comments,
int replySize);
Mono<ListResult<ReplyVo>> listReply(String commentName, @Nullable Integer page,
@Nullable Integer size);

View File

@ -40,6 +40,7 @@ import run.halo.app.metrics.MeterUtils;
import run.halo.app.theme.finders.CommentPublicQueryService;
import run.halo.app.theme.finders.vo.CommentStatsVo;
import run.halo.app.theme.finders.vo.CommentVo;
import run.halo.app.theme.finders.vo.CommentWithReplyVo;
import run.halo.app.theme.finders.vo.ExtensionVoOperator;
import run.halo.app.theme.finders.vo.ReplyVo;
@ -94,6 +95,26 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
.defaultIfEmpty(ListResult.emptyResult());
}
@Override
public Mono<ListResult<CommentWithReplyVo>> convertToWithReplyVo(ListResult<CommentVo> comments,
int replySize) {
return Flux.fromIterable(comments.getItems())
.flatMap(commentVo -> {
var commentName = commentVo.getMetadata().getName();
return listReply(commentName, 1, replySize)
.map(replyList -> CommentWithReplyVo.from(commentVo)
.setReplies(replyList)
);
})
.collectList()
.map(result -> new ListResult<>(
comments.getPage(),
comments.getSize(),
comments.getTotal(),
result)
);
}
@Override
public Mono<ListResult<ReplyVo>> listReply(String commentName, Integer page, Integer size) {
return listReply(commentName, PageRequestImpl.of(pageNullSafe(page), sizeNullSafe(size),

View File

@ -3,9 +3,9 @@ package run.halo.app.theme.finders.vo;
import static io.swagger.v3.oas.annotations.media.Schema.RequiredMode.REQUIRED;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import run.halo.app.content.comment.OwnerInfo;
import run.halo.app.core.extension.content.Comment;
import run.halo.app.extension.MetadataOperator;
@ -17,7 +17,7 @@ import run.halo.app.extension.MetadataOperator;
* @since 2.0.0
*/
@Data
@Builder
@Accessors(chain = true)
@EqualsAndHashCode
public class CommentVo implements ExtensionVoOperator {
@ -42,10 +42,9 @@ public class CommentVo implements ExtensionVoOperator {
* @return a value object for {@link Comment}
*/
public static CommentVo from(Comment comment) {
return CommentVo.builder()
.metadata(comment.getMetadata())
.spec(comment.getSpec())
.status(comment.getStatus())
.build();
return new CommentVo()
.setMetadata(comment.getMetadata())
.setSpec(comment.getSpec())
.setStatus(comment.getStatus());
}
}

View File

@ -0,0 +1,31 @@
package run.halo.app.theme.finders.vo;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;
import org.springframework.beans.BeanUtils;
import run.halo.app.extension.ListResult;
/**
* <p>A value object for comment with reply.</p>
*
* @author guqing
* @since 2.14.0
*/
@Data
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = true)
public class CommentWithReplyVo extends CommentVo {
private ListResult<ReplyVo> replies;
/**
* Convert {@link CommentVo} to {@link CommentWithReplyVo}.
*/
public static CommentWithReplyVo from(CommentVo commentVo) {
var commentWithReply = new CommentWithReplyVo();
BeanUtils.copyProperties(commentVo, commentWithReply);
commentWithReply.setReplies(ListResult.emptyResult());
return commentWithReply;
}
}