feat: support for obtaining the newest comments on theme-side (#4104)

#### What type of PR is this?
/kind feature
/milestone 2.7.x
/area core
/area theme

#### What this PR does / why we need it:
主题端支持获取最新评论

可能存在的问题:
主题端如果想展示评论所属的具体的主体比如 Moment 可能不好展示

how to test it?
通过 list 方法获取评论看排序和数据是否正确
```html
<p th:each="result : ${commentFinder.list(null,1,10)}">
  <span th:text="${result.spec.raw}"></span>
  -> <span th:text="${#temporals.format(result.spec.creationTime, 'yyyy-MM-dd HH:mm:ss')}"></span>
  -> <span th:text="${result.spec.subjectRef}"></span>
</p>
```
#### Which issue(s) this PR fixes:
Fixes #4088

#### Does this PR introduce a user-facing change?
```release-note
主题端支持获取最新评论
```
pull/4146/head
guqing 2023-06-28 23:48:11 +08:00 committed by GitHub
parent 00dd95ca6d
commit 55cb21ccaa
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 26 additions and 17 deletions

View File

@ -9,7 +9,7 @@ tab_width = 4
ij_continuation_indent_size = 8
ij_formatter_off_tag = @formatter:off
ij_formatter_on_tag = @formatter:on
ij_formatter_tags_enabled = false
ij_formatter_tags_enabled = true
ij_smart_tabs = false
ij_wrap_on_typing = false

View File

@ -45,6 +45,7 @@ public class Comment extends AbstractExtension {
}
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public static class CommentSpec extends BaseCommentSpec {

View File

@ -18,7 +18,7 @@ public interface CommentFinder {
Mono<CommentVo> getByName(String name);
Mono<ListResult<CommentVo>> list(Ref ref, @Nullable Integer page,
Mono<ListResult<CommentVo>> list(@Nullable Ref ref, @Nullable Integer page,
@Nullable Integer size);
Mono<ListResult<ReplyVo>> listReply(String commentName, @Nullable Integer page,

View File

@ -11,6 +11,7 @@ import lombok.RequiredArgsConstructor;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;
import org.springframework.security.core.context.ReactiveSecurityContextHolder;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Component;
@ -44,6 +45,7 @@ import run.halo.app.theme.finders.vo.ReplyVo;
@Component
@RequiredArgsConstructor
public class CommentPublicQueryServiceImpl implements CommentPublicQueryService {
private static final int DEFAULT_SIZE = 10;
private final ReactiveExtensionClient client;
private final UserService userService;
@ -117,7 +119,7 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
.doOnNext(commentVo::setOwner)
.thenReturn(commentVo)
)
.flatMap(commentVo -> filterCommentSensitiveData(commentVo));
.flatMap(this::filterCommentSensitiveData);
}
private Mono<? extends CommentVo> filterCommentSensitiveData(CommentVo commentVo) {
@ -138,8 +140,9 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
return Mono.just(commentVo);
}
private <E extends AbstractExtension, T extends ExtensionVoOperator> Mono<CommentStatsVo>
populateStats(Class<E> clazz, T vo) {
// @formatter:off
private <E extends AbstractExtension, T extends ExtensionVoOperator>
Mono<CommentStatsVo> populateStats(Class<E> clazz, T vo) {
return counterService.getByName(MeterUtils.nameOf(clazz, vo.getMetadata()
.getName()))
.map(counter -> CommentStatsVo.builder()
@ -148,6 +151,7 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
)
.defaultIfEmpty(CommentStatsVo.empty());
}
// @formatter:on
Mono<ReplyVo> toReplyVo(Reply reply) {
return Mono.just(ReplyVo.from(reply))
@ -158,7 +162,7 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
.doOnNext(replyVo::setOwner)
.thenReturn(replyVo)
)
.flatMap(replyVo -> filterReplySensitiveData(replyVo));
.flatMap(this::filterReplySensitiveData);
}
private Mono<? extends ReplyVo> filterReplySensitiveData(ReplyVo replyVo) {
@ -187,11 +191,13 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
.map(OwnerInfo::from);
}
private Mono<Predicate<Comment>> fixedCommentPredicate(Ref ref) {
Assert.notNull(ref, "Comment subject reference must not be null");
// Ref must be equal to the comment subject
Predicate<Comment> refPredicate = comment -> comment.getSpec().getSubjectRef().equals(ref)
&& comment.getMetadata().getDeletionTimestamp() == null;
private Mono<Predicate<Comment>> fixedCommentPredicate(@Nullable Ref ref) {
Predicate<Comment> basePredicate =
comment -> comment.getMetadata().getDeletionTimestamp() == null;
if (ref != null) {
basePredicate = basePredicate
.and(comment -> comment.getSpec().getSubjectRef().equals(ref));
}
// is approved and not hidden
Predicate<Comment> approvedPredicate =
@ -206,7 +212,7 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
return approvedPredicate.or(isOwner);
})
.defaultIfEmpty(approvedPredicate)
.map(refPredicate::and);
.map(basePredicate::and);
}
private Mono<Predicate<Reply>> fixedReplyPredicate(String commentName) {
@ -277,6 +283,6 @@ public class CommentPublicQueryServiceImpl implements CommentPublicQueryService
}
int sizeNullSafe(Integer size) {
return ObjectUtils.defaultIfNull(size, 10);
return ObjectUtils.defaultIfNull(size, DEFAULT_SIZE);
}
}

View File

@ -1,5 +1,7 @@
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;
@ -19,18 +21,18 @@ import run.halo.app.extension.MetadataOperator;
@EqualsAndHashCode
public class CommentVo implements ExtensionVoOperator {
@Schema(required = true)
@Schema(requiredMode = REQUIRED)
private MetadataOperator metadata;
@Schema(required = true)
@Schema(requiredMode = REQUIRED)
private Comment.CommentSpec spec;
private Comment.CommentStatus status;
@Schema(required = true)
@Schema(requiredMode = REQUIRED)
private OwnerInfo owner;
@Schema(required = true)
@Schema(requiredMode = REQUIRED)
private CommentStatsVo stats;
/**