From 9f53cd1123056f5e34efdb9ae4281f641e2d8283 Mon Sep 17 00:00:00 2001 From: guqing <38999863+guqing@users.noreply.github.com> Date: Thu, 17 Nov 2022 10:48:22 +0800 Subject: [PATCH] feat: theme finders supports the reactive API (#2695) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit #### What type of PR is this? /kind feature /area core /milestone 2.0 #### What this PR does / why we need it: 将所有 Finder 的返回值都修改为 Mono 或 Flux #### Which issue(s) this PR fixes: Fixes #2671 #### Special notes for your reviewer: how to test it? 切换几个主题都点一下,没有报错即为正常 /cc @halo-dev/sig-halo #### Does this PR introduce a user-facing change? ```release-note 主题端 Finder 支持 Reactive API ``` --- .../app/theme/ReactivePropertyAccessor.java | 121 ++++++++++ ...activeSpelVariableExpressionEvaluator.java | 44 ++++ .../halo/app/theme/TemplateEngineManager.java | 9 + .../ThemeContextBasedVariablesAcquirer.java | 15 +- ...dePropertyAccessorBoundariesProcessor.java | 4 + .../dialect/PostTemplateHeadProcessor.java | 2 +- .../theme/endpoint/CommentFinderEndpoint.java | 10 +- .../app/theme/finders/CategoryFinder.java | 12 +- .../halo/app/theme/finders/CommentFinder.java | 7 +- .../app/theme/finders/ContributorFinder.java | 6 +- .../halo/app/theme/finders/MenuFinder.java | 5 +- .../halo/app/theme/finders/PostFinder.java | 21 +- .../app/theme/finders/SinglePageFinder.java | 8 +- .../app/theme/finders/SiteStatsFinder.java | 3 +- .../run/halo/app/theme/finders/TagFinder.java | 10 +- .../halo/app/theme/finders/ThemeFinder.java | 5 +- .../finders/impl/CategoryFinderImpl.java | 67 +++--- .../theme/finders/impl/CommentFinderImpl.java | 18 +- .../finders/impl/ContributorFinderImpl.java | 18 +- .../theme/finders/impl/MenuFinderImpl.java | 101 ++++---- .../theme/finders/impl/PostFinderImpl.java | 225 ++++++++++-------- .../finders/impl/SinglePageFinderImpl.java | 88 ++++--- .../finders/impl/SiteStatsFinderImpl.java | 5 +- .../app/theme/finders/impl/TagFinderImpl.java | 25 +- .../theme/finders/impl/ThemeFinderImpl.java | 12 +- .../halo/app/theme/finders/vo/ContentVo.java | 10 + .../app/theme/finders/vo/ListedPostVo.java | 59 +++++ .../theme/finders/vo/ListedSinglePageVo.java | 53 +++++ .../finders/vo/PostArchiveYearMonthVo.java | 2 +- .../run/halo/app/theme/finders/vo/PostVo.java | 42 ++-- .../app/theme/finders/vo/SinglePageVo.java | 21 +- .../strategy/ArchivesRouteStrategy.java | 9 +- .../strategy/CategoriesRouteStrategy.java | 10 +- .../strategy/CategoryRouteStrategy.java | 24 +- .../router/strategy/IndexRouteStrategy.java | 15 +- .../router/strategy/PostRouteStrategy.java | 10 +- .../strategy/SinglePageRouteStrategy.java | 10 +- .../router/strategy/TagRouteStrategy.java | 23 +- .../router/strategy/TagsRouteStrategy.java | 10 +- .../dialect/HaloProcessorDialectTest.java | 2 +- .../endpoint/CommentFinderEndpointTest.java | 14 +- .../finders/impl/CategoryFinderImplTest.java | 8 +- .../finders/impl/MenuFinderImplTest.java | 2 +- .../finders/impl/PostFinderImplTest.java | 10 +- .../theme/finders/impl/TagFinderImplTest.java | 4 +- .../strategy/ArchivesRouteStrategyTest.java | 10 - .../strategy/CategoriesRouteStrategyTest.java | 10 +- .../strategy/CategoryRouteStrategyTest.java | 14 +- .../strategy/IndexRouteStrategyTest.java | 10 - .../strategy/PostRouteStrategyTest.java | 3 +- .../strategy/SinglePageRouteStrategyTest.java | 12 +- .../router/strategy/TagRouteStrategyTest.java | 16 +- .../strategy/TagsRouteStrategyTest.java | 9 +- 53 files changed, 750 insertions(+), 513 deletions(-) create mode 100644 src/main/java/run/halo/app/theme/ReactivePropertyAccessor.java create mode 100644 src/main/java/run/halo/app/theme/ReactiveSpelVariableExpressionEvaluator.java create mode 100644 src/main/java/run/halo/app/theme/finders/vo/ListedPostVo.java create mode 100644 src/main/java/run/halo/app/theme/finders/vo/ListedSinglePageVo.java diff --git a/src/main/java/run/halo/app/theme/ReactivePropertyAccessor.java b/src/main/java/run/halo/app/theme/ReactivePropertyAccessor.java new file mode 100644 index 000000000..572396aef --- /dev/null +++ b/src/main/java/run/halo/app/theme/ReactivePropertyAccessor.java @@ -0,0 +1,121 @@ +package run.halo.app.theme; + +import com.fasterxml.jackson.databind.JsonNode; +import java.util.ArrayList; +import java.util.List; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.integration.json.JsonPropertyAccessor; +import org.springframework.lang.NonNull; +import org.springframework.lang.Nullable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; +import run.halo.app.infra.utils.JsonUtils; + +/** + * A SpEL PropertyAccessor that knows how to read properties from {@link Mono} or {@link Flux} + * object. It first converts the target to the actual value and then calls other + * {@link PropertyAccessor}s to parse the result, If it still cannot be resolved, + * {@link JsonPropertyAccessor} will be used to resolve finally. + * + * @author guqing + * @since 2.0.0 + */ +public class ReactivePropertyAccessor implements PropertyAccessor { + private static final Class[] SUPPORTED_CLASSES = { + Mono.class, + Flux.class + }; + private final JsonPropertyAccessor jsonPropertyAccessor = new JsonPropertyAccessor(); + + @Override + public Class[] getSpecificTargetClasses() { + return SUPPORTED_CLASSES; + } + + @Override + public boolean canRead(@NonNull EvaluationContext context, Object target, @NonNull String name) + throws AccessException { + if (target == null) { + return false; + } + return Mono.class.isAssignableFrom(target.getClass()) + || Flux.class.isAssignableFrom(target.getClass()); + } + + @Override + @NonNull + public TypedValue read(@NonNull EvaluationContext context, Object target, @NonNull String name) + throws AccessException { + if (target == null) { + return TypedValue.NULL; + } + Class clazz = target.getClass(); + Object value = null; + if (Mono.class.isAssignableFrom(clazz)) { + value = ((Mono) target).block(); + } else if (Flux.class.isAssignableFrom(clazz)) { + value = ((Flux) target).toIterable(); + } + + if (value == null) { + return TypedValue.NULL; + } + + List propertyAccessorsToTry = + getPropertyAccessorsToTry(value, context.getPropertyAccessors()); + for (PropertyAccessor propertyAccessor : propertyAccessorsToTry) { + try { + return propertyAccessor.read(context, target, name); + } catch (AccessException e) { + // ignore + } + } + JsonNode jsonNode = JsonUtils.DEFAULT_JSON_MAPPER.convertValue(value, JsonNode.class); + return jsonPropertyAccessor.read(context, jsonNode, name); + } + + private List getPropertyAccessorsToTry( + @Nullable Object contextObject, List propertyAccessors) { + + Class targetType = (contextObject != null ? contextObject.getClass() : null); + + List specificAccessors = new ArrayList<>(); + List generalAccessors = new ArrayList<>(); + for (PropertyAccessor resolver : propertyAccessors) { + Class[] targets = resolver.getSpecificTargetClasses(); + if (targets == null) { + // generic resolver that says it can be used for any type + generalAccessors.add(resolver); + } else if (targetType != null) { + for (Class clazz : targets) { + if (clazz == targetType) { + specificAccessors.add(resolver); + break; + } else if (clazz.isAssignableFrom(targetType)) { + generalAccessors.add(resolver); + } + } + } + } + List resolvers = new ArrayList<>(specificAccessors); + generalAccessors.removeAll(specificAccessors); + resolvers.addAll(generalAccessors); + return resolvers; + } + + @Override + public boolean canWrite(@NonNull EvaluationContext context, Object target, @NonNull String name) + throws AccessException { + return false; + } + + @Override + public void write(@NonNull EvaluationContext context, Object target, @NonNull String name, + Object newValue) + throws AccessException { + throw new UnsupportedOperationException("Write is not supported"); + } +} diff --git a/src/main/java/run/halo/app/theme/ReactiveSpelVariableExpressionEvaluator.java b/src/main/java/run/halo/app/theme/ReactiveSpelVariableExpressionEvaluator.java new file mode 100644 index 000000000..b09b25c60 --- /dev/null +++ b/src/main/java/run/halo/app/theme/ReactiveSpelVariableExpressionEvaluator.java @@ -0,0 +1,44 @@ +package run.halo.app.theme; + +import org.thymeleaf.context.IExpressionContext; +import org.thymeleaf.spring6.expression.SPELVariableExpressionEvaluator; +import org.thymeleaf.standard.expression.IStandardVariableExpression; +import org.thymeleaf.standard.expression.IStandardVariableExpressionEvaluator; +import org.thymeleaf.standard.expression.StandardExpressionExecutionContext; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; + +/** + * Reactive SPEL variable expression evaluator. + * + * @author guqing + * @since 2.0.0 + */ +public class ReactiveSpelVariableExpressionEvaluator + implements IStandardVariableExpressionEvaluator { + + private final SPELVariableExpressionEvaluator delegate = + SPELVariableExpressionEvaluator.INSTANCE; + + public static final ReactiveSpelVariableExpressionEvaluator INSTANCE = + new ReactiveSpelVariableExpressionEvaluator(); + + @Override + public Object evaluate(IExpressionContext context, IStandardVariableExpression expression, + StandardExpressionExecutionContext expContext) { + Object returnValue = delegate.evaluate(context, expression, expContext); + if (returnValue == null) { + return null; + } + + Class clazz = returnValue.getClass(); + // Note that: 3 instanceof Foo -> syntax error + if (Mono.class.isAssignableFrom(clazz)) { + return ((Mono) returnValue).block(); + } + if (Flux.class.isAssignableFrom(clazz)) { + return ((Flux) returnValue).toIterable(); + } + return returnValue; + } +} diff --git a/src/main/java/run/halo/app/theme/TemplateEngineManager.java b/src/main/java/run/halo/app/theme/TemplateEngineManager.java index 1dac1662e..4d1f7473c 100644 --- a/src/main/java/run/halo/app/theme/TemplateEngineManager.java +++ b/src/main/java/run/halo/app/theme/TemplateEngineManager.java @@ -9,6 +9,8 @@ import org.springframework.util.ConcurrentLruCache; import org.springframework.util.ResourceUtils; import org.thymeleaf.dialect.IDialect; import org.thymeleaf.spring6.ISpringWebFluxTemplateEngine; +import org.thymeleaf.spring6.dialect.SpringStandardDialect; +import org.thymeleaf.standard.expression.IStandardVariableExpressionEvaluator; import org.thymeleaf.templateresolver.FileTemplateResolver; import org.thymeleaf.templateresolver.ITemplateResolver; import run.halo.app.infra.ExternalUrlSupplier; @@ -86,6 +88,13 @@ public class TemplateEngineManager { var mainResolver = haloTemplateResolver(); mainResolver.setPrefix(theme.getPath() + "/templates/"); engine.addTemplateResolver(mainResolver); + // replace StandardDialect with SpringStandardDialect + engine.setDialect(new SpringStandardDialect() { + @Override + public IStandardVariableExpressionEvaluator getVariableExpressionEvaluator() { + return ReactiveSpelVariableExpressionEvaluator.INSTANCE; + } + }); engine.addDialect(new HaloProcessorDialect()); templateResolvers.orderedStream().forEach(engine::addTemplateResolver); diff --git a/src/main/java/run/halo/app/theme/ThemeContextBasedVariablesAcquirer.java b/src/main/java/run/halo/app/theme/ThemeContextBasedVariablesAcquirer.java index 151937d5e..cb889ad19 100644 --- a/src/main/java/run/halo/app/theme/ThemeContextBasedVariablesAcquirer.java +++ b/src/main/java/run/halo/app/theme/ThemeContextBasedVariablesAcquirer.java @@ -4,9 +4,7 @@ import java.util.Map; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import run.halo.app.theme.finders.ThemeFinder; -import run.halo.app.theme.finders.vo.ThemeVo; /** * Theme context based variables acquirer. @@ -28,14 +26,11 @@ public class ThemeContextBasedVariablesAcquirer implements ViewContextBasedVaria @Override public Mono> acquire(ServerWebExchange exchange) { return themeResolver.getTheme(exchange.getRequest()) - .publishOn(Schedulers.boundedElastic()) - .map(themeContext -> { + .flatMap(themeContext -> { String name = themeContext.getName(); - ThemeVo themeVo = themeFinder.getByName(name); - if (themeVo == null) { - return Map.of(); - } - return Map.of("theme", themeVo); - }); + return themeFinder.getByName(name); + }) + .map(themeVo -> Map.of("theme", themeVo)) + .defaultIfEmpty(Map.of()); } } diff --git a/src/main/java/run/halo/app/theme/dialect/JsonNodePropertyAccessorBoundariesProcessor.java b/src/main/java/run/halo/app/theme/dialect/JsonNodePropertyAccessorBoundariesProcessor.java index 3b69a0cdc..0ab86fffe 100644 --- a/src/main/java/run/halo/app/theme/dialect/JsonNodePropertyAccessorBoundariesProcessor.java +++ b/src/main/java/run/halo/app/theme/dialect/JsonNodePropertyAccessorBoundariesProcessor.java @@ -9,6 +9,7 @@ import org.thymeleaf.processor.templateboundaries.ITemplateBoundariesStructureHa import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext; import org.thymeleaf.standard.StandardDialect; import org.thymeleaf.templatemode.TemplateMode; +import run.halo.app.theme.ReactivePropertyAccessor; /** * A template boundaries processor for add {@link JsonPropertyAccessor} to @@ -21,6 +22,8 @@ public class JsonNodePropertyAccessorBoundariesProcessor extends AbstractTemplateBoundariesProcessor { private static final int PRECEDENCE = StandardDialect.PROCESSOR_PRECEDENCE; private static final JsonPropertyAccessor JSON_PROPERTY_ACCESSOR = new JsonPropertyAccessor(); + private static final ReactivePropertyAccessor REACTIVE_PROPERTY_ACCESSOR = + new ReactivePropertyAccessor(); public JsonNodePropertyAccessorBoundariesProcessor() { super(TemplateMode.HTML, PRECEDENCE); @@ -34,6 +37,7 @@ public class JsonNodePropertyAccessorBoundariesProcessor ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME); if (evaluationContext != null) { evaluationContext.addPropertyAccessor(JSON_PROPERTY_ACCESSOR); + evaluationContext.addPropertyAccessor(REACTIVE_PROPERTY_ACCESSOR); } } diff --git a/src/main/java/run/halo/app/theme/dialect/PostTemplateHeadProcessor.java b/src/main/java/run/halo/app/theme/dialect/PostTemplateHeadProcessor.java index ba1a839db..9c26c9f47 100644 --- a/src/main/java/run/halo/app/theme/dialect/PostTemplateHeadProcessor.java +++ b/src/main/java/run/halo/app/theme/dialect/PostTemplateHeadProcessor.java @@ -36,7 +36,7 @@ public class PostTemplateHeadProcessor implements TemplateHeadProcessor { return Mono.empty(); } return Mono.justOrEmpty((String) context.getVariable(POST_NAME_VARIABLE)) - .map(postFinder::getByName) + .flatMap(postFinder::getByName) .doOnNext(postVo -> { List> htmlMetas = postVo.getSpec().getHtmlMetas(); String metaHtml = headMetaBuilder(htmlMetas); diff --git a/src/main/java/run/halo/app/theme/endpoint/CommentFinderEndpoint.java b/src/main/java/run/halo/app/theme/endpoint/CommentFinderEndpoint.java index ceddd0d65..bf489a541 100644 --- a/src/main/java/run/halo/app/theme/endpoint/CommentFinderEndpoint.java +++ b/src/main/java/run/halo/app/theme/endpoint/CommentFinderEndpoint.java @@ -165,10 +165,8 @@ public class CommentFinderEndpoint implements CustomEndpoint { Mono listComments(ServerRequest request) { CommentQuery commentQuery = new CommentQuery(request.queryParams()); - return Mono.defer(() -> Mono.just( - commentFinder.list(commentQuery.toRef(), commentQuery.getPage(), - commentQuery.getSize()))) - .subscribeOn(Schedulers.boundedElastic()) + return commentFinder.list(commentQuery.toRef(), commentQuery.getPage(), + commentQuery.getSize()) .flatMap(list -> ServerResponse.ok().bodyValue(list)); } @@ -183,9 +181,7 @@ public class CommentFinderEndpoint implements CustomEndpoint { String commentName = request.pathVariable("name"); IListRequest.QueryListRequest queryParams = new IListRequest.QueryListRequest(request.queryParams()); - return Mono.defer(() -> Mono.just( - commentFinder.listReply(commentName, queryParams.getPage(), queryParams.getSize()))) - .subscribeOn(Schedulers.boundedElastic()) + return commentFinder.listReply(commentName, queryParams.getPage(), queryParams.getSize()) .flatMap(list -> ServerResponse.ok().bodyValue(list)); } diff --git a/src/main/java/run/halo/app/theme/finders/CategoryFinder.java b/src/main/java/run/halo/app/theme/finders/CategoryFinder.java index 77f556098..7b0406e9e 100644 --- a/src/main/java/run/halo/app/theme/finders/CategoryFinder.java +++ b/src/main/java/run/halo/app/theme/finders/CategoryFinder.java @@ -2,6 +2,8 @@ package run.halo.app.theme.finders; import java.util.List; import org.springframework.lang.Nullable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.Category; import run.halo.app.extension.ListResult; import run.halo.app.theme.finders.vo.CategoryTreeVo; @@ -15,13 +17,13 @@ import run.halo.app.theme.finders.vo.CategoryVo; */ public interface CategoryFinder { - CategoryVo getByName(String name); + Mono getByName(String name); - List getByNames(List names); + Flux getByNames(List names); - ListResult list(@Nullable Integer page, @Nullable Integer size); + Mono> list(@Nullable Integer page, @Nullable Integer size); - List listAll(); + Flux listAll(); - List listAsTree(); + Flux listAsTree(); } diff --git a/src/main/java/run/halo/app/theme/finders/CommentFinder.java b/src/main/java/run/halo/app/theme/finders/CommentFinder.java index a420f8d8e..b678c52b2 100644 --- a/src/main/java/run/halo/app/theme/finders/CommentFinder.java +++ b/src/main/java/run/halo/app/theme/finders/CommentFinder.java @@ -1,6 +1,7 @@ package run.halo.app.theme.finders; import org.springframework.lang.Nullable; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.Comment; import run.halo.app.extension.ListResult; import run.halo.app.extension.Ref; @@ -15,11 +16,11 @@ import run.halo.app.theme.finders.vo.ReplyVo; */ public interface CommentFinder { - CommentVo getByName(String name); + Mono getByName(String name); - ListResult list(Ref ref, @Nullable Integer page, + Mono> list(Ref ref, @Nullable Integer page, @Nullable Integer size); - ListResult listReply(String commentName, @Nullable Integer page, + Mono> listReply(String commentName, @Nullable Integer page, @Nullable Integer size); } diff --git a/src/main/java/run/halo/app/theme/finders/ContributorFinder.java b/src/main/java/run/halo/app/theme/finders/ContributorFinder.java index 89fb77590..fa1b16317 100644 --- a/src/main/java/run/halo/app/theme/finders/ContributorFinder.java +++ b/src/main/java/run/halo/app/theme/finders/ContributorFinder.java @@ -1,6 +1,8 @@ package run.halo.app.theme.finders; import java.util.List; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.User; import run.halo.app.theme.finders.vo.Contributor; @@ -9,7 +11,7 @@ import run.halo.app.theme.finders.vo.Contributor; */ public interface ContributorFinder { - Contributor getContributor(String name); + Mono getContributor(String name); - List getContributors(List names); + Flux getContributors(List names); } diff --git a/src/main/java/run/halo/app/theme/finders/MenuFinder.java b/src/main/java/run/halo/app/theme/finders/MenuFinder.java index d7de4bb6e..af45f2993 100644 --- a/src/main/java/run/halo/app/theme/finders/MenuFinder.java +++ b/src/main/java/run/halo/app/theme/finders/MenuFinder.java @@ -1,5 +1,6 @@ package run.halo.app.theme.finders; +import reactor.core.publisher.Mono; import run.halo.app.theme.finders.vo.MenuVo; /** @@ -10,7 +11,7 @@ import run.halo.app.theme.finders.vo.MenuVo; */ public interface MenuFinder { - MenuVo getByName(String name); + Mono getByName(String name); - MenuVo getPrimary(); + Mono getPrimary(); } diff --git a/src/main/java/run/halo/app/theme/finders/PostFinder.java b/src/main/java/run/halo/app/theme/finders/PostFinder.java index 4ed7fb0d7..ddc6cdcfb 100644 --- a/src/main/java/run/halo/app/theme/finders/PostFinder.java +++ b/src/main/java/run/halo/app/theme/finders/PostFinder.java @@ -1,9 +1,11 @@ package run.halo.app.theme.finders; import org.springframework.lang.Nullable; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.Post; import run.halo.app.extension.ListResult; import run.halo.app.theme.finders.vo.ContentVo; +import run.halo.app.theme.finders.vo.ListedPostVo; import run.halo.app.theme.finders.vo.NavigationPostVo; import run.halo.app.theme.finders.vo.PostArchiveVo; import run.halo.app.theme.finders.vo.PostVo; @@ -16,22 +18,23 @@ import run.halo.app.theme.finders.vo.PostVo; */ public interface PostFinder { - PostVo getByName(String postName); + Mono getByName(String postName); - ContentVo content(String postName); + Mono content(String postName); - NavigationPostVo cursor(String current); + Mono cursor(String current); - ListResult list(@Nullable Integer page, @Nullable Integer size); + Mono> list(@Nullable Integer page, @Nullable Integer size); - ListResult listByCategory(@Nullable Integer page, @Nullable Integer size, + Mono> listByCategory(@Nullable Integer page, @Nullable Integer size, String categoryName); - ListResult listByTag(@Nullable Integer page, @Nullable Integer size, String tag); + Mono> listByTag(@Nullable Integer page, @Nullable Integer size, + String tag); - ListResult archives(Integer page, Integer size); + Mono> archives(Integer page, Integer size); - ListResult archives(Integer page, Integer size, String year); + Mono> archives(Integer page, Integer size, String year); - ListResult archives(Integer page, Integer size, String year, String month); + Mono> archives(Integer page, Integer size, String year, String month); } diff --git a/src/main/java/run/halo/app/theme/finders/SinglePageFinder.java b/src/main/java/run/halo/app/theme/finders/SinglePageFinder.java index 3d704ed0a..3e811bab9 100644 --- a/src/main/java/run/halo/app/theme/finders/SinglePageFinder.java +++ b/src/main/java/run/halo/app/theme/finders/SinglePageFinder.java @@ -1,9 +1,11 @@ package run.halo.app.theme.finders; import org.springframework.lang.Nullable; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.SinglePage; import run.halo.app.extension.ListResult; import run.halo.app.theme.finders.vo.ContentVo; +import run.halo.app.theme.finders.vo.ListedSinglePageVo; import run.halo.app.theme.finders.vo.SinglePageVo; /** @@ -14,9 +16,9 @@ import run.halo.app.theme.finders.vo.SinglePageVo; */ public interface SinglePageFinder { - SinglePageVo getByName(String pageName); + Mono getByName(String pageName); - ContentVo content(String pageName); + Mono content(String pageName); - ListResult list(@Nullable Integer page, @Nullable Integer size); + Mono> list(@Nullable Integer page, @Nullable Integer size); } diff --git a/src/main/java/run/halo/app/theme/finders/SiteStatsFinder.java b/src/main/java/run/halo/app/theme/finders/SiteStatsFinder.java index 77cb55257..06b2e38d4 100644 --- a/src/main/java/run/halo/app/theme/finders/SiteStatsFinder.java +++ b/src/main/java/run/halo/app/theme/finders/SiteStatsFinder.java @@ -1,5 +1,6 @@ package run.halo.app.theme.finders; +import reactor.core.publisher.Mono; import run.halo.app.theme.finders.vo.SiteStatsVo; /** @@ -10,5 +11,5 @@ import run.halo.app.theme.finders.vo.SiteStatsVo; */ public interface SiteStatsFinder { - SiteStatsVo getStats(); + Mono getStats(); } diff --git a/src/main/java/run/halo/app/theme/finders/TagFinder.java b/src/main/java/run/halo/app/theme/finders/TagFinder.java index 02f2b61b0..0da6b3358 100644 --- a/src/main/java/run/halo/app/theme/finders/TagFinder.java +++ b/src/main/java/run/halo/app/theme/finders/TagFinder.java @@ -2,6 +2,8 @@ package run.halo.app.theme.finders; import java.util.List; import org.springframework.lang.Nullable; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.Tag; import run.halo.app.extension.ListResult; import run.halo.app.theme.finders.vo.TagVo; @@ -14,11 +16,11 @@ import run.halo.app.theme.finders.vo.TagVo; */ public interface TagFinder { - TagVo getByName(String name); + Mono getByName(String name); - List getByNames(List names); + Flux getByNames(List names); - ListResult list(@Nullable Integer page, @Nullable Integer size); + Mono> list(@Nullable Integer page, @Nullable Integer size); - List listAll(); + Flux listAll(); } diff --git a/src/main/java/run/halo/app/theme/finders/ThemeFinder.java b/src/main/java/run/halo/app/theme/finders/ThemeFinder.java index aed5db34c..239226f17 100644 --- a/src/main/java/run/halo/app/theme/finders/ThemeFinder.java +++ b/src/main/java/run/halo/app/theme/finders/ThemeFinder.java @@ -1,5 +1,6 @@ package run.halo.app.theme.finders; +import reactor.core.publisher.Mono; import run.halo.app.theme.finders.vo.ThemeVo; /** @@ -10,7 +11,7 @@ import run.halo.app.theme.finders.vo.ThemeVo; */ public interface ThemeFinder { - ThemeVo activation(); + Mono activation(); - ThemeVo getByName(String themeName); + Mono getByName(String themeName); } diff --git a/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java index ea5f16f3c..0e085a20c 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/CategoryFinderImpl.java @@ -10,6 +10,8 @@ import java.util.function.Function; import java.util.stream.Collectors; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ObjectUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.Category; import run.halo.app.extension.ListResult; import run.halo.app.extension.ReactiveExtensionClient; @@ -34,24 +36,22 @@ public class CategoryFinderImpl implements CategoryFinder { } @Override - public CategoryVo getByName(String name) { + public Mono getByName(String name) { return client.fetch(Category.class, name) - .map(CategoryVo::from) - .block(); + .map(CategoryVo::from); } @Override - public List getByNames(List names) { + public Flux getByNames(List names) { if (names == null) { - return List.of(); + return Flux.empty(); } - return names.stream().map(this::getByName) - .filter(Objects::nonNull) - .toList(); + return Flux.fromIterable(names) + .flatMap(this::getByName); } @Override - public ListResult list(Integer page, Integer size) { + public Mono> list(Integer page, Integer size) { return client.list(Category.class, null, defaultComparator(), pageNullSafe(page), sizeNullSafe(size)) .map(list -> { @@ -61,38 +61,39 @@ public class CategoryFinderImpl implements CategoryFinder { return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), categoryVos); }) - .block(); + .defaultIfEmpty(new ListResult<>(page, size, 0L, List.of())); } @Override - public List listAll() { + public Flux listAll() { return client.list(Category.class, null, defaultComparator()) - .map(CategoryVo::from) - .collectList() - .block(); + .map(CategoryVo::from); } @Override - public List listAsTree() { - List categoryVos = listAll(); - Map nameIdentityMap = categoryVos.stream() - .map(CategoryTreeVo::from) - .collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(), - Function.identity())); + public Flux listAsTree() { + return listAll() + .collectList() + .flatMapIterable(categoryVos -> { + Map nameIdentityMap = categoryVos.stream() + .map(CategoryTreeVo::from) + .collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(), + Function.identity())); - nameIdentityMap.forEach((name, value) -> { - List children = value.getSpec().getChildren(); - if (children == null) { - return; - } - for (String child : children) { - CategoryTreeVo childNode = nameIdentityMap.get(child); - if (childNode != null) { - childNode.setParentName(name); - } - } - }); - return listToTree(nameIdentityMap.values()); + nameIdentityMap.forEach((name, value) -> { + List children = value.getSpec().getChildren(); + if (children == null) { + return; + } + for (String child : children) { + CategoryTreeVo childNode = nameIdentityMap.get(child); + if (childNode != null) { + childNode.setParentName(name); + } + } + }); + return listToTree(nameIdentityMap.values()); + }); } static List listToTree(Collection list) { diff --git a/src/main/java/run/halo/app/theme/finders/impl/CommentFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/CommentFinderImpl.java index 6a3e5af22..67ca8c8c7 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/CommentFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/CommentFinderImpl.java @@ -2,6 +2,7 @@ package run.halo.app.theme.finders.impl; import java.time.Instant; import java.util.Comparator; +import java.util.List; import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; @@ -37,14 +38,13 @@ public class CommentFinderImpl implements CommentFinder { } @Override - public CommentVo getByName(String name) { + public Mono getByName(String name) { return client.fetch(Comment.class, name) - .flatMap(this::toCommentVo) - .block(); + .flatMap(this::toCommentVo); } @Override - public ListResult list(Ref ref, Integer page, Integer size) { + public Mono> list(Ref ref, Integer page, Integer size) { return client.list(Comment.class, fixedPredicate(ref), defaultComparator(), pageNullSafe(page), sizeNullSafe(size)) @@ -55,11 +55,11 @@ public class CommentFinderImpl implements CommentFinder { commentVos) ) ) - .block(); + .defaultIfEmpty(new ListResult<>(page, size, 0L, List.of())); } @Override - public ListResult listReply(String commentName, Integer page, Integer size) { + public Mono> listReply(String commentName, Integer page, Integer size) { Comparator comparator = Comparator.comparing(reply -> reply.getMetadata().getCreationTimestamp()); return client.list(Reply.class, @@ -73,7 +73,7 @@ public class CommentFinderImpl implements CommentFinder { .map(replyVos -> new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), replyVos)) ) - .block(); + .defaultIfEmpty(new ListResult<>(page, size, 0L, List.of())); } private Mono toCommentVo(Comment comment) { @@ -81,6 +81,7 @@ public class CommentFinderImpl implements CommentFinder { return Mono.just(CommentVo.from(comment)) .flatMap(commentVo -> getOwnerInfo(owner) .map(commentVo::withOwner) + .defaultIfEmpty(commentVo) ); } @@ -88,6 +89,7 @@ public class CommentFinderImpl implements CommentFinder { return Mono.just(ReplyVo.from(reply)) .flatMap(replyVo -> getOwnerInfo(reply.getSpec().getOwner()) .map(replyVo::withOwner) + .defaultIfEmpty(replyVo) ); } @@ -97,7 +99,7 @@ public class CommentFinderImpl implements CommentFinder { } return client.fetch(User.class, owner.getName()) .map(OwnerInfo::from) - .switchIfEmpty(Mono.just(OwnerInfo.ghostUser())); + .defaultIfEmpty(OwnerInfo.ghostUser()); } private Predicate fixedPredicate(Ref ref) { diff --git a/src/main/java/run/halo/app/theme/finders/impl/ContributorFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/ContributorFinderImpl.java index ee3866e05..ecbcbf28b 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/ContributorFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/ContributorFinderImpl.java @@ -1,7 +1,8 @@ package run.halo.app.theme.finders.impl; import java.util.List; -import java.util.Objects; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.User; import run.halo.app.extension.ReactiveExtensionClient; import run.halo.app.theme.finders.ContributorFinder; @@ -24,20 +25,17 @@ public class ContributorFinderImpl implements ContributorFinder { } @Override - public Contributor getContributor(String name) { + public Mono getContributor(String name) { return client.fetch(User.class, name) - .map(Contributor::from) - .block(); + .map(Contributor::from); } @Override - public List getContributors(List names) { + public Flux getContributors(List names) { if (names == null) { - return List.of(); + return Flux.empty(); } - return names.stream() - .map(this::getContributor) - .filter(Objects::nonNull) - .toList(); + return Flux.fromIterable(names) + .flatMap(this::getContributor); } } diff --git a/src/main/java/run/halo/app/theme/finders/impl/MenuFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/MenuFinderImpl.java index 5b6819252..a81843cd4 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/MenuFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/MenuFinderImpl.java @@ -10,9 +10,10 @@ import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; import lombok.AllArgsConstructor; -import org.apache.commons.lang3.StringUtils; import org.springframework.util.CollectionUtils; import org.springframework.util.comparator.Comparators; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.Menu; import run.halo.app.core.extension.MenuItem; import run.halo.app.extension.ReactiveExtensionClient; @@ -37,56 +38,58 @@ public class MenuFinderImpl implements MenuFinder { private final SystemConfigurableEnvironmentFetcher environmentFetcher; @Override - public MenuVo getByName(String name) { - return listAsTree().stream() + public Mono getByName(String name) { + return listAsTree() .filter(menu -> menu.getMetadata().getName().equals(name)) - .findAny() - .orElse(null); + .next(); } @Override - public MenuVo getPrimary() { - List menuVos = listAsTree(); - if (CollectionUtils.isEmpty(menuVos)) { - return null; - } - return environmentFetcher.fetch(SystemSetting.Menu.GROUP, SystemSetting.Menu.class) - .blockOptional() - .map(SystemSetting.Menu::getPrimary) - .filter(StringUtils::isNotBlank) - .flatMap(primary -> menuVos.stream() - .filter(menuVo -> menuVo.getMetadata().getName().equals(primary)) - .findAny()) - .orElse(menuVos.get(0)); - } - - List listAll() { - return client.list(Menu.class, null, null) - .map(MenuVo::from) - .collectList() - .block(); - } - - List listAsTree() { - Collection menuItemVos = populateParentName(listAllMenuItem()); - List treeList = listToTree(menuItemVos); - Map nameItemRootNodeMap = treeList.stream() - .collect(Collectors.toMap(item -> item.getMetadata().getName(), Function.identity())); - - return listAll().stream() - .map(menuVo -> { - LinkedHashSet menuItemNames = menuVo.getSpec().getMenuItems(); - if (menuItemNames == null) { - return menuVo.withMenuItems(List.of()); + public Mono getPrimary() { + return listAsTree().collectList() + .flatMap(menuVos -> { + if (CollectionUtils.isEmpty(menuVos)) { + return Mono.empty(); } - List menuItems = menuItemNames.stream() - .map(nameItemRootNodeMap::get) - .filter(Objects::nonNull) - .sorted(defaultTreeNodeComparator()) - .toList(); - return menuVo.withMenuItems(menuItems); - }) - .toList(); + return environmentFetcher.fetch(SystemSetting.Menu.GROUP, SystemSetting.Menu.class) + .map(SystemSetting.Menu::getPrimary) + .map(primaryConfig -> menuVos.stream() + .filter(menuVo -> menuVo.getMetadata().getName().equals(primaryConfig)) + .findAny() + .orElse(menuVos.get(0)) + ) + .defaultIfEmpty(menuVos.get(0)); + }); + } + + Flux listAll() { + return client.list(Menu.class, null, null) + .map(MenuVo::from); + } + + Flux listAsTree() { + return listAllMenuItem() + .collectList() + .map(MenuFinderImpl::populateParentName) + .flatMapMany(menuItemVos -> { + List treeList = listToTree(menuItemVos); + Map nameItemRootNodeMap = treeList.stream() + .collect(Collectors.toMap(item -> item.getMetadata().getName(), + Function.identity())); + return listAll() + .map(menuVo -> { + LinkedHashSet menuItemNames = menuVo.getSpec().getMenuItems(); + if (menuItemNames == null) { + return menuVo.withMenuItems(List.of()); + } + List menuItems = menuItemNames.stream() + .map(nameItemRootNodeMap::get) + .filter(Objects::nonNull) + .sorted(defaultTreeNodeComparator()) + .toList(); + return menuVo.withMenuItems(menuItems); + }); + }); } static List listToTree(Collection list) { @@ -109,11 +112,9 @@ public class MenuFinderImpl implements MenuFinder { .collect(Collectors.toList()); } - List listAllMenuItem() { + Flux listAllMenuItem() { return client.list(MenuItem.class, null, null) - .map(MenuItemVo::from) - .collectList() - .block(); + .map(MenuItemVo::from); } static Comparator defaultTreeNodeComparator() { diff --git a/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java index b6a90c093..6c7225358 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java @@ -15,7 +15,10 @@ import org.apache.commons.lang3.ObjectUtils; import org.apache.commons.lang3.StringUtils; import org.apache.commons.lang3.tuple.Pair; import org.springframework.lang.NonNull; +import org.springframework.util.CollectionUtils; import org.springframework.util.comparator.Comparators; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import reactor.util.function.Tuple2; import run.halo.app.content.ContentService; import run.halo.app.core.extension.Counter; @@ -30,15 +33,13 @@ import run.halo.app.theme.finders.ContributorFinder; import run.halo.app.theme.finders.Finder; import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.finders.TagFinder; -import run.halo.app.theme.finders.vo.CategoryVo; import run.halo.app.theme.finders.vo.ContentVo; -import run.halo.app.theme.finders.vo.Contributor; +import run.halo.app.theme.finders.vo.ListedPostVo; import run.halo.app.theme.finders.vo.NavigationPostVo; import run.halo.app.theme.finders.vo.PostArchiveVo; import run.halo.app.theme.finders.vo.PostArchiveYearMonthVo; import run.halo.app.theme.finders.vo.PostVo; import run.halo.app.theme.finders.vo.StatsVo; -import run.halo.app.theme.finders.vo.TagVo; /** * A finder for {@link Post}. @@ -50,8 +51,8 @@ import run.halo.app.theme.finders.vo.TagVo; public class PostFinderImpl implements PostFinder { public static final Predicate FIXED_PREDICATE = post -> post.isPublished() - && Objects.equals(false, post.getSpec().getDeleted()) - && Post.VisibleEnum.PUBLIC.equals(post.getSpec().getVisible()); + && Objects.equals(false, post.getSpec().getDeleted()) + && Post.VisibleEnum.PUBLIC.equals(post.getSpec().getVisible()); private final ReactiveExtensionClient client; private final ContentService contentService; @@ -78,53 +79,49 @@ public class PostFinderImpl implements PostFinder { } @Override - public PostVo getByName(String postName) { - Post post = client.fetch(Post.class, postName) - .block(); - if (post == null) { - return null; - } - PostVo postVo = getPostVo(post); - postVo.setContent(content(postName)); - return postVo; + public Mono getByName(String postName) { + return client.fetch(Post.class, postName) + .flatMap(this::getListedPostVo) + .map(PostVo::from) + .flatMap(postVo -> content(postName) + .doOnNext(postVo::setContent) + .thenReturn(postVo) + ); } @Override - public ContentVo content(String postName) { + public Mono content(String postName) { return client.fetch(Post.class, postName) .map(post -> post.getSpec().getReleaseSnapshot()) .flatMap(contentService::getContent) .map(wrapper -> ContentVo.builder().content(wrapper.getContent()) - .raw(wrapper.getRaw()).build()) - .block(); + .raw(wrapper.getRaw()).build()); } @Override - public NavigationPostVo cursor(String currentName) { + public Mono cursor(String currentName) { // TODO Optimize the post names query here - List postNames = client.list(Post.class, FIXED_PREDICATE, defaultComparator()) + return client.list(Post.class, FIXED_PREDICATE, defaultComparator()) .map(post -> post.getMetadata().getName()) .collectList() - .block(); - if (postNames == null) { - return NavigationPostVo.empty(); - } - - NavigationPostVo.NavigationPostVoBuilder builder = NavigationPostVo.builder() - .current(getByName(currentName)); - - Pair previousNextPair = postPreviousNextPair(postNames, currentName); - String previousPostName = previousNextPair.getLeft(); - String nextPostName = previousNextPair.getRight(); - - if (previousPostName != null) { - builder.previous(getByName(previousPostName)); - } - - if (nextPostName != null) { - builder.next(getByName(nextPostName)); - } - return builder.build(); + .flatMap(postNames -> Mono.just(NavigationPostVo.builder()) + .flatMap(builder -> getByName(currentName) + .doOnNext(builder::current) + .thenReturn(builder) + ) + .flatMap(builder -> { + Pair previousNextPair = + postPreviousNextPair(postNames, currentName); + String previousPostName = previousNextPair.getLeft(); + String nextPostName = previousNextPair.getRight(); + return getByName(previousPostName) + .doOnNext(builder::previous) + .then(getByName(nextPostName)) + .doOnNext(builder::next) + .thenReturn(builder); + }) + .map(NavigationPostVo.NavigationPostVoBuilder::build)) + .defaultIfEmpty(NavigationPostVo.empty()); } static Pair postPreviousNextPair(List postNames, @@ -201,36 +198,37 @@ public class PostFinderImpl implements PostFinder { } @Override - public ListResult list(Integer page, Integer size) { + public Mono> list(Integer page, Integer size) { return listPost(page, size, null, defaultComparator()); } @Override - public ListResult listByCategory(Integer page, Integer size, String categoryName) { + public Mono> listByCategory(Integer page, Integer size, + String categoryName) { return listPost(page, size, post -> contains(post.getSpec().getCategories(), categoryName), defaultComparator()); } @Override - public ListResult listByTag(Integer page, Integer size, String tag) { + public Mono> listByTag(Integer page, Integer size, String tag) { return listPost(page, size, post -> contains(post.getSpec().getTags(), tag), defaultComparator()); } @Override - public ListResult archives(Integer page, Integer size) { + public Mono> archives(Integer page, Integer size) { return archives(page, size, null, null); } @Override - public ListResult archives(Integer page, Integer size, String year) { + public Mono> archives(Integer page, Integer size, String year) { return archives(page, size, year, null); } @Override - public ListResult archives(Integer page, Integer size, String year, + public Mono> archives(Integer page, Integer size, String year, String month) { - ListResult list = listPost(page, size, post -> { + return listPost(page, size, post -> { Map labels = post.getMetadata().getLabels(); if (labels == null) { return false; @@ -240,34 +238,37 @@ public class PostFinderImpl implements PostFinder { boolean monthMatch = StringUtils.isBlank(month) || month.equals(labels.get(Post.ARCHIVE_MONTH_LABEL)); return yearMatch && monthMatch; - }, archiveComparator()); - - Map> yearPosts = list.get() - .collect(Collectors.groupingBy( - post -> HaloUtils.getYearText(post.getSpec().getPublishTime()))); - List postArchives = - yearPosts.entrySet().stream().map(entry -> { - String key = entry.getKey(); - // archives by month - Map> monthPosts = entry.getValue().stream() + }, archiveComparator()) + .map(list -> { + Map> yearPosts = list.get() .collect(Collectors.groupingBy( - post -> HaloUtils.getMonthText(post.getSpec().getPublishTime()))); - // convert to archive year month value objects - List monthArchives = monthPosts.entrySet() - .stream() - .sorted(Map.Entry.comparingByKey()) - .map(monthEntry -> PostArchiveYearMonthVo.builder() - .posts(monthEntry.getValue()) - .month(monthEntry.getKey()) - .build() - ) - .toList(); - return PostArchiveVo.builder() - .year(String.valueOf(key)) - .months(monthArchives) - .build(); - }).toList(); - return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), postArchives); + post -> HaloUtils.getYearText(post.getSpec().getPublishTime()))); + List postArchives = + yearPosts.entrySet().stream().map(entry -> { + String key = entry.getKey(); + // archives by month + Map> monthPosts = entry.getValue().stream() + .collect(Collectors.groupingBy( + post -> HaloUtils.getMonthText(post.getSpec().getPublishTime()))); + // convert to archive year month value objects + List monthArchives = monthPosts.entrySet() + .stream() + .sorted(Map.Entry.comparingByKey()) + .map(monthEntry -> PostArchiveYearMonthVo.builder() + .posts(monthEntry.getValue()) + .month(monthEntry.getKey()) + .build() + ) + .toList(); + return PostArchiveVo.builder() + .year(String.valueOf(key)) + .months(monthArchives) + .build(); + }).toList(); + return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), + postArchives); + }) + .defaultIfEmpty(new ListResult<>(page, size, 0, List.of())); } private boolean contains(List c, String key) { @@ -277,24 +278,29 @@ public class PostFinderImpl implements PostFinder { return c.contains(key); } - private ListResult listPost(Integer page, Integer size, Predicate postPredicate, + private Mono> listPost(Integer page, Integer size, + Predicate postPredicate, Comparator comparator) { Predicate predicate = FIXED_PREDICATE .and(postPredicate == null ? post -> true : postPredicate); - ListResult list = client.list(Post.class, predicate, + return client.list(Post.class, predicate, comparator, pageNullSafe(page), sizeNullSafe(size)) - .block(); - if (list == null) { - return new ListResult<>(List.of()); - } - List postVos = list.get() - .map(this::getPostVo) - .peek(this::populateStats) - .toList(); - return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), postVos); + .flatMap(list -> Flux.fromStream(list.get()) + .flatMap(post -> getListedPostVo(post) + .map(postVo -> { + populateStats(postVo); + return postVo; + }) + ) + .collectList() + .map(postVos -> new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), + postVos) + ) + ) + .defaultIfEmpty(new ListResult<>(page, size, 0L, List.of())); } - private void populateStats(PostVo postVo) { + private void populateStats(T postVo) { Counter counter = counterService.getByName(MeterUtils.nameOf(Post.class, postVo.getMetadata() .getName())); @@ -306,18 +312,45 @@ public class PostFinderImpl implements PostFinder { postVo.setStats(statsVo); } - private PostVo getPostVo(@NonNull Post post) { - List tags = tagFinder.getByNames(post.getSpec().getTags()); - List categoryVos = categoryFinder.getByNames(post.getSpec().getCategories()); - List contributors = - contributorFinder.getContributors(post.getStatus().getContributors()); - PostVo postVo = PostVo.from(post); - postVo.setCategories(categoryVos); - postVo.setTags(tags); - postVo.setContributors(contributors); - postVo.setOwner(contributorFinder.getContributor(post.getSpec().getOwner())); + private Mono getListedPostVo(@NonNull Post post) { + ListedPostVo postVo = ListedPostVo.from(post); + postVo.setCategories(List.of()); + postVo.setTags(List.of()); + postVo.setContributors(List.of()); populateStats(postVo); - return postVo; + return Mono.just(postVo) + .flatMap(p -> { + String owner = p.getSpec().getOwner(); + return contributorFinder.getContributor(owner) + .doOnNext(p::setOwner) + .thenReturn(p); + }) + .flatMap(p -> { + List tagNames = p.getSpec().getTags(); + if (CollectionUtils.isEmpty(tagNames)) { + return Mono.just(p); + } + return tagFinder.getByNames(tagNames) + .collectList() + .doOnNext(p::setTags) + .thenReturn(p); + }) + .flatMap(p -> { + List categoryNames = p.getSpec().getCategories(); + if (CollectionUtils.isEmpty(categoryNames)) { + return Mono.just(p); + } + return categoryFinder.getByNames(categoryNames) + .collectList() + .doOnNext(p::setCategories) + .thenReturn(p); + }) + .flatMap(p -> contributorFinder.getContributors(p.getStatus().getContributors()) + .collectList() + .doOnNext(p::setContributors) + .thenReturn(p) + ) + .defaultIfEmpty(postVo); } static Comparator defaultComparator() { diff --git a/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java index fa86048be..d2b737d98 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java @@ -7,6 +7,9 @@ import java.util.Objects; import java.util.function.Function; import java.util.function.Predicate; import org.apache.commons.lang3.ObjectUtils; +import org.springframework.util.CollectionUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.content.ContentService; import run.halo.app.core.extension.Counter; import run.halo.app.core.extension.Post; @@ -19,7 +22,7 @@ import run.halo.app.theme.finders.ContributorFinder; import run.halo.app.theme.finders.Finder; import run.halo.app.theme.finders.SinglePageFinder; import run.halo.app.theme.finders.vo.ContentVo; -import run.halo.app.theme.finders.vo.Contributor; +import run.halo.app.theme.finders.vo.ListedSinglePageVo; import run.halo.app.theme.finders.vo.SinglePageVo; import run.halo.app.theme.finders.vo.StatsVo; @@ -53,54 +56,56 @@ public class SinglePageFinderImpl implements SinglePageFinder { } @Override - public SinglePageVo getByName(String pageName) { - SinglePage page = client.fetch(SinglePage.class, pageName) - .block(); - if (page == null) { - return null; - } - List contributors = - contributorFinder.getContributors(page.getStatus().getContributors()); - SinglePageVo pageVo = SinglePageVo.from(page); - pageVo.setContributors(contributors); - pageVo.setContent(content(pageName)); - pageVo.setOwner(contributorFinder.getContributor(page.getSpec().getOwner())); - populateStats(pageVo); - return pageVo; + public Mono getByName(String pageName) { + return client.fetch(SinglePage.class, pageName) + .map(page -> { + SinglePageVo pageVo = SinglePageVo.from(page); + pageVo.setContributors(List.of()); + pageVo.setContent(ContentVo.empty()); + populateStats(pageVo); + return pageVo; + }) + .flatMap(this::populateContributors) + .flatMap(page -> content(pageName) + .doOnNext(page::setContent) + .thenReturn(page) + ) + .flatMap(page -> contributorFinder.getContributor(page.getSpec().getOwner()) + .doOnNext(page::setOwner) + .thenReturn(page) + ); } @Override - public ContentVo content(String pageName) { + public Mono content(String pageName) { return client.fetch(SinglePage.class, pageName) .map(page -> page.getSpec().getReleaseSnapshot()) .flatMap(contentService::getContent) .map(wrapper -> ContentVo.builder().content(wrapper.getContent()) - .raw(wrapper.getRaw()).build()) - .block(); + .raw(wrapper.getRaw()).build()); } @Override - public ListResult list(Integer page, Integer size) { - ListResult list = client.list(SinglePage.class, FIXED_PREDICATE, + public Mono> list(Integer page, Integer size) { + return client.list(SinglePage.class, FIXED_PREDICATE, defaultComparator(), pageNullSafe(page), sizeNullSafe(size)) - .block(); - if (list == null) { - return new ListResult<>(0, 0, 0, List.of()); - } - List pageVos = list.get() - .map(sp -> { - List contributors = - contributorFinder.getContributors(sp.getStatus().getContributors()); - SinglePageVo pageVo = SinglePageVo.from(sp); - pageVo.setContributors(contributors); - populateStats(pageVo); - return pageVo; - }) - .toList(); - return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), pageVos); + .flatMap(list -> Flux.fromStream(list.get()) + .map(singlePage -> { + ListedSinglePageVo pageVo = ListedSinglePageVo.from(singlePage); + pageVo.setContributors(List.of()); + populateStats(pageVo); + return pageVo; + }) + .flatMap(this::populateContributors) + .collectList() + .map(pageVos -> new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), + pageVos) + ) + ) + .defaultIfEmpty(new ListResult<>(0, 0, 0, List.of())); } - void populateStats(SinglePageVo pageVo) { + void populateStats(T pageVo) { String name = pageVo.getMetadata().getName(); Counter counter = counterService.getByName(MeterUtils.nameOf(SinglePage.class, name)); @@ -112,6 +117,17 @@ public class SinglePageFinderImpl implements SinglePageFinder { pageVo.setStats(statsVo); } + Mono populateContributors(T pageVo) { + List names = pageVo.getStatus().getContributors(); + if (CollectionUtils.isEmpty(names)) { + return Mono.just(pageVo); + } + return contributorFinder.getContributors(names) + .collectList() + .doOnNext(pageVo::setContributors) + .thenReturn(pageVo); + } + static Comparator defaultComparator() { Function pinned = page -> Objects.requireNonNullElse(page.getSpec().getPinned(), false); diff --git a/src/main/java/run/halo/app/theme/finders/impl/SiteStatsFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/SiteStatsFinderImpl.java index 71bfc14b8..eb1e8169b 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/SiteStatsFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/SiteStatsFinderImpl.java @@ -22,7 +22,7 @@ public class SiteStatsFinderImpl implements SiteStatsFinder { private final ReactiveExtensionClient client; @Override - public SiteStatsVo getStats() { + public Mono getStats() { return client.list(Counter.class, null, null) .reduce(SiteStatsVo.empty(), (stats, counter) -> { stats.setVisit(stats.getVisit() + counter.getVisit()); @@ -36,8 +36,7 @@ public class SiteStatsFinderImpl implements SiteStatsFinder { ) .flatMap(siteStatsVo -> categoryCount() .doOnNext(siteStatsVo::setCategory) - .thenReturn(siteStatsVo)) - .block(); + .thenReturn(siteStatsVo)); } Mono postCount() { diff --git a/src/main/java/run/halo/app/theme/finders/impl/TagFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/TagFinderImpl.java index 7d50af0d7..84109a914 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/TagFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/TagFinderImpl.java @@ -2,9 +2,10 @@ package run.halo.app.theme.finders.impl; import java.util.Comparator; import java.util.List; -import java.util.Objects; import java.util.stream.Collectors; import org.apache.commons.lang3.ObjectUtils; +import reactor.core.publisher.Flux; +import reactor.core.publisher.Mono; import run.halo.app.core.extension.Tag; import run.halo.app.extension.ListResult; import run.halo.app.extension.ReactiveExtensionClient; @@ -31,21 +32,19 @@ public class TagFinderImpl implements TagFinder { } @Override - public TagVo getByName(String name) { + public Mono getByName(String name) { return client.fetch(Tag.class, name) - .map(TagVo::from) - .block(); + .map(TagVo::from); } @Override - public List getByNames(List names) { - return names.stream().map(this::getByName) - .filter(Objects::nonNull) - .toList(); + public Flux getByNames(List names) { + return Flux.fromIterable(names) + .flatMap(this::getByName); } @Override - public ListResult list(Integer page, Integer size) { + public Mono> list(Integer page, Integer size) { return client.list(Tag.class, null, DEFAULT_COMPARATOR.reversed(), pageNullSafe(page), sizeNullSafe(size)) .map(list -> { @@ -54,16 +53,14 @@ public class TagFinderImpl implements TagFinder { .collect(Collectors.toList()); return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), tagVos); }) - .block(); + .defaultIfEmpty(new ListResult<>(page, size, 0L, List.of())); } @Override - public List listAll() { + public Flux listAll() { return client.list(Tag.class, null, DEFAULT_COMPARATOR.reversed()) - .map(TagVo::from) - .collectList() - .block(); + .map(TagVo::from); } int pageNullSafe(Integer page) { diff --git a/src/main/java/run/halo/app/theme/finders/impl/ThemeFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/ThemeFinderImpl.java index aba9b9102..5c463fd7b 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/ThemeFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/ThemeFinderImpl.java @@ -34,19 +34,17 @@ public class ThemeFinderImpl implements ThemeFinder { } @Override - public ThemeVo activation() { + public Mono activation() { return environmentFetcher.fetch(SystemSetting.Theme.GROUP, SystemSetting.Theme.class) .map(SystemSetting.Theme::getActive) .flatMap(themeName -> client.fetch(Theme.class, themeName)) - .flatMap(theme -> themeWithConfig(ThemeVo.from(theme))) - .block(); + .flatMap(theme -> themeWithConfig(ThemeVo.from(theme))); } @Override - public ThemeVo getByName(String themeName) { + public Mono getByName(String themeName) { return client.fetch(Theme.class, themeName) - .flatMap(theme -> themeWithConfig(ThemeVo.from(theme))) - .block(); + .flatMap(theme -> themeWithConfig(ThemeVo.from(theme))); } private Mono themeWithConfig(ThemeVo themeVo) { @@ -63,6 +61,6 @@ public class ThemeFinderImpl implements ThemeFinder { JsonNode configJson = JsonUtils.mapToObject(config, JsonNode.class); return themeVo.withConfig(configJson); }) - .switchIfEmpty(Mono.just(themeVo)); + .defaultIfEmpty(themeVo); } } diff --git a/src/main/java/run/halo/app/theme/finders/vo/ContentVo.java b/src/main/java/run/halo/app/theme/finders/vo/ContentVo.java index 6124dc897..ea0157761 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/ContentVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/ContentVo.java @@ -19,4 +19,14 @@ public class ContentVo { String raw; String content; + + /** + * Empty content object. + */ + public static ContentVo empty() { + return ContentVo.builder() + .raw("") + .content("") + .build(); + } } diff --git a/src/main/java/run/halo/app/theme/finders/vo/ListedPostVo.java b/src/main/java/run/halo/app/theme/finders/vo/ListedPostVo.java new file mode 100644 index 000000000..8bcdbfdcd --- /dev/null +++ b/src/main/java/run/halo/app/theme/finders/vo/ListedPostVo.java @@ -0,0 +1,59 @@ +package run.halo.app.theme.finders.vo; + +import java.util.List; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import org.springframework.util.Assert; +import run.halo.app.core.extension.Post; +import run.halo.app.extension.MetadataOperator; + +/** + * A value object for {@link Post}. + * + * @author guqing + * @since 2.0.0 + */ +@Data +@SuperBuilder +@ToString +@EqualsAndHashCode +public class ListedPostVo { + + private MetadataOperator metadata; + + private Post.PostSpec spec; + + private Post.PostStatus status; + + private List categories; + + private List tags; + + private List contributors; + + private Contributor owner; + + private StatsVo stats; + + /** + * Convert {@link Post} to {@link ListedPostVo}. + * + * @param post post extension + * @return post value object + */ + public static ListedPostVo from(Post post) { + Assert.notNull(post, "The post must not be null."); + Post.PostSpec spec = post.getSpec(); + Post.PostStatus postStatus = post.getStatusOrDefault(); + return ListedPostVo.builder() + .metadata(post.getMetadata()) + .spec(spec) + .status(postStatus) + .categories(List.of()) + .tags(List.of()) + .contributors(List.of()) + .build(); + } +} diff --git a/src/main/java/run/halo/app/theme/finders/vo/ListedSinglePageVo.java b/src/main/java/run/halo/app/theme/finders/vo/ListedSinglePageVo.java new file mode 100644 index 000000000..d891261ed --- /dev/null +++ b/src/main/java/run/halo/app/theme/finders/vo/ListedSinglePageVo.java @@ -0,0 +1,53 @@ +package run.halo.app.theme.finders.vo; + +import java.util.List; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.ToString; +import lombok.experimental.SuperBuilder; +import org.springframework.util.Assert; +import run.halo.app.core.extension.SinglePage; +import run.halo.app.extension.MetadataOperator; + +/** + * A value object for {@link SinglePage}. + * + * @author guqing + * @since 2.0.0 + */ +@Data +@SuperBuilder +@ToString +@EqualsAndHashCode +public class ListedSinglePageVo { + + private MetadataOperator metadata; + + private SinglePage.SinglePageSpec spec; + + private SinglePage.SinglePageStatus status; + + private StatsVo stats; + + private List contributors; + + private Contributor owner; + + /** + * Convert {@link SinglePage} to {@link ListedSinglePageVo}. + * + * @param singlePage single page extension + * @return special page value object + */ + public static ListedSinglePageVo from(SinglePage singlePage) { + Assert.notNull(singlePage, "The singlePage must not be null."); + SinglePage.SinglePageSpec spec = singlePage.getSpec(); + SinglePage.SinglePageStatus pageStatus = singlePage.getStatus(); + return ListedSinglePageVo.builder() + .metadata(singlePage.getMetadata()) + .spec(spec) + .status(pageStatus) + .contributors(List.of()) + .build(); + } +} diff --git a/src/main/java/run/halo/app/theme/finders/vo/PostArchiveYearMonthVo.java b/src/main/java/run/halo/app/theme/finders/vo/PostArchiveYearMonthVo.java index fa0e2e315..a145bc0cf 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/PostArchiveYearMonthVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/PostArchiveYearMonthVo.java @@ -16,5 +16,5 @@ public class PostArchiveYearMonthVo { String month; - List posts; + List posts; } diff --git a/src/main/java/run/halo/app/theme/finders/vo/PostVo.java b/src/main/java/run/halo/app/theme/finders/vo/PostVo.java index d37b32dcf..a530829aa 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/PostVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/PostVo.java @@ -1,13 +1,12 @@ package run.halo.app.theme.finders.vo; import java.util.List; -import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import lombok.experimental.SuperBuilder; import org.springframework.util.Assert; import run.halo.app.core.extension.Post; -import run.halo.app.extension.MetadataOperator; /** * A value object for {@link Post}. @@ -16,29 +15,13 @@ import run.halo.app.extension.MetadataOperator; * @since 2.0.0 */ @Data -@Builder +@SuperBuilder @ToString -@EqualsAndHashCode -public class PostVo { - - private MetadataOperator metadata; - - private Post.PostSpec spec; - - private Post.PostStatus status; +@EqualsAndHashCode(callSuper = true) +public class PostVo extends ListedPostVo { private ContentVo content; - private List categories; - - private List tags; - - private List contributors; - - private Contributor owner; - - private StatsVo stats; - /** * Convert {@link Post} to {@link PostVo}. * @@ -59,4 +42,21 @@ public class PostVo { .content(new ContentVo(null, null)) .build(); } + + /** + * Convert {@link Post} to {@link PostVo}. + */ + public static PostVo from(ListedPostVo postVo) { + return builder() + .metadata(postVo.getMetadata()) + .spec(postVo.getSpec()) + .status(postVo.getStatus()) + .categories(postVo.getCategories()) + .tags(postVo.getTags()) + .contributors(postVo.getContributors()) + .owner(postVo.getOwner()) + .stats(postVo.getStats()) + .content(new ContentVo("", "")) + .build(); + } } diff --git a/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java b/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java index cca5426f5..6b3521a00 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java @@ -1,13 +1,12 @@ package run.halo.app.theme.finders.vo; import java.util.List; -import lombok.Builder; import lombok.Data; import lombok.EqualsAndHashCode; import lombok.ToString; +import lombok.experimental.SuperBuilder; import org.springframework.util.Assert; import run.halo.app.core.extension.SinglePage; -import run.halo.app.extension.MetadataOperator; /** * A value object for {@link SinglePage}. @@ -16,25 +15,13 @@ import run.halo.app.extension.MetadataOperator; * @since 2.0.0 */ @Data -@Builder +@SuperBuilder @ToString -@EqualsAndHashCode -public class SinglePageVo { - - private MetadataOperator metadata; - - private SinglePage.SinglePageSpec spec; - - private SinglePage.SinglePageStatus status; +@EqualsAndHashCode(callSuper = true) +public class SinglePageVo extends ListedSinglePageVo { private ContentVo content; - private StatsVo stats; - - private List contributors; - - private Contributor owner; - /** * Convert {@link SinglePage} to {@link SinglePageVo}. * diff --git a/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java index f61f09261..42d182209 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java @@ -13,8 +13,6 @@ import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; -import run.halo.app.extension.ListResult; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.utils.PathUtils; import run.halo.app.theme.DefaultTemplateEnum; @@ -47,7 +45,7 @@ public class ArchivesRouteStrategy implements ListPageRouteHandlerStrategy { String path = request.path(); return environmentFetcher.fetchPost() .map(postSetting -> defaultIfNull(postSetting.getArchivePageSize(), DEFAULT_PAGE_SIZE)) - .flatMap(pageSize -> listPost(pageNum(request), pageSize, year, month)) + .flatMap(pageSize -> postFinder.archives(pageNum(request), pageSize, year, month)) .map(list -> new UrlContextListResult.Builder() .listResult(list) .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) @@ -55,11 +53,6 @@ public class ArchivesRouteStrategy implements ListPageRouteHandlerStrategy { .build()); } - Mono> listPost(int pageNum, int pageSize, String year, String month) { - return Mono.fromCallable(() -> postFinder.archives(pageNum, pageSize, year, month)) - .subscribeOn(Schedulers.boundedElastic()); - } - private String pathVariable(ServerRequest request, String name) { Map pathVariables = request.pathVariables(); if (pathVariables.containsKey(name)) { diff --git a/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java index 70fe2b8e2..084860ea6 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java @@ -7,11 +7,8 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerResponse; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.CategoryFinder; -import run.halo.app.theme.finders.vo.CategoryTreeVo; /** * Categories router strategy for generate {@link HandlerFunction} specific to the template @@ -25,16 +22,11 @@ import run.halo.app.theme.finders.vo.CategoryTreeVo; public class CategoriesRouteStrategy implements ListPageRouteHandlerStrategy { private final CategoryFinder categoryFinder; - private Mono> categories() { - return Mono.defer(() -> Mono.just(categoryFinder.listAsTree())) - .publishOn(Schedulers.boundedElastic()); - } - @Override public HandlerFunction getHandler() { return request -> ServerResponse.ok() .render(DefaultTemplateEnum.CATEGORIES.getValue(), - Map.of("categories", categories(), + Map.of("categories", categoryFinder.listAsTree(), ModelConst.TEMPLATE_ID, DefaultTemplateEnum.CATEGORIES.getValue())); } diff --git a/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java index d49028803..b57061e07 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java @@ -12,17 +12,14 @@ import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.Category; import run.halo.app.extension.GroupVersionKind; -import run.halo.app.extension.ListResult; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemSetting; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.CategoryFinder; import run.halo.app.theme.finders.PostFinder; -import run.halo.app.theme.finders.vo.CategoryVo; -import run.halo.app.theme.finders.vo.PostVo; +import run.halo.app.theme.finders.vo.ListedPostVo; import run.halo.app.theme.router.PageUrlUtils; import run.halo.app.theme.router.UrlContextListResult; import run.halo.app.theme.router.ViewNameResolver; @@ -46,29 +43,20 @@ public class CategoryRouteStrategy implements DetailsPageRouteHandlerStrategy { private final SystemConfigurableEnvironmentFetcher environmentFetcher; - private Mono> postListByCategoryName(String name, + private Mono> postListByCategoryName(String name, ServerRequest request) { String path = request.path(); return environmentFetcher.fetchPost() .map(post -> defaultIfNull(post.getCategoryPageSize(), ModelConst.DEFAULT_PAGE_SIZE)) - .flatMap(pageSize -> listPostsByCategory(pageNum(request), pageSize, name)) - .map(list -> new UrlContextListResult.Builder() + .flatMap( + pageSize -> postFinder.listByCategory(pageNum(request), pageSize, name)) + .map(list -> new UrlContextListResult.Builder() .listResult(list) .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) .prevUrl(PageUrlUtils.prevPageUrl(path)) .build()); } - private Mono categoryByName(String name) { - return Mono.fromCallable(() -> categoryFinder.getByName(name)) - .subscribeOn(Schedulers.boundedElastic()); - } - - public Mono> listPostsByCategory(int page, int size, String categoryName) { - return Mono.fromCallable(() -> postFinder.listByCategory(page, size, categoryName)) - .subscribeOn(Schedulers.boundedElastic()); - } - @Override public HandlerFunction getHandler(SystemSetting.ThemeRouteRules routeRules, String name) { @@ -78,7 +66,7 @@ public class CategoryRouteStrategy implements DetailsPageRouteHandlerStrategy { model.put("posts", postListByCategoryName(name, request)); model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.CATEGORY.getValue()); - return categoryByName(name).flatMap(categoryVo -> { + return categoryFinder.getByName(name).flatMap(categoryVo -> { model.put("category", categoryVo); String template = categoryVo.getSpec().getTemplate(); return viewNameResolver.resolveViewNameOrDefault(request, template, diff --git a/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java index b4f87ce68..c89d01e67 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java @@ -13,12 +13,10 @@ import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; -import run.halo.app.extension.ListResult; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.PostFinder; -import run.halo.app.theme.finders.vo.PostVo; +import run.halo.app.theme.finders.vo.ListedPostVo; import run.halo.app.theme.router.PageUrlUtils; import run.halo.app.theme.router.UrlContextListResult; @@ -36,23 +34,18 @@ public class IndexRouteStrategy implements ListPageRouteHandlerStrategy { private final PostFinder postFinder; private final SystemConfigurableEnvironmentFetcher environmentFetcher; - private Mono> postList(ServerRequest request) { + private Mono> postList(ServerRequest request) { String path = request.path(); return environmentFetcher.fetchPost() .map(p -> defaultIfNull(p.getPostPageSize(), DEFAULT_PAGE_SIZE)) - .flatMap(pageSize -> listPost(pageNum(request), pageSize)) - .map(list -> new UrlContextListResult.Builder() + .flatMap(pageSize -> postFinder.list(pageNum(request), pageSize)) + .map(list -> new UrlContextListResult.Builder() .listResult(list) .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) .prevUrl(PageUrlUtils.prevPageUrl(path)) .build()); } - private Mono> listPost(int page, int size) { - return Mono.fromCallable(() -> postFinder.list(page, size)) - .subscribeOn(Schedulers.boundedElastic()); - } - @Override public HandlerFunction getHandler() { return request -> ServerResponse.ok() diff --git a/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java index 9fcf5497f..dff0523ed 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java @@ -8,15 +8,12 @@ import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.util.pattern.PathPattern; import org.springframework.web.util.pattern.PathPatternParser; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.Post; import run.halo.app.extension.GVK; import run.halo.app.extension.GroupVersionKind; import run.halo.app.infra.SystemSetting; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.PostFinder; -import run.halo.app.theme.finders.vo.PostVo; import run.halo.app.theme.router.ViewNameResolver; /** @@ -57,7 +54,7 @@ public class PostRouteStrategy implements DetailsPageRouteHandlerStrategy { model.put("plural", gvk.plural()); // used by TemplateGlobalHeadProcessor and PostTemplateHeadProcessor model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.POST.getValue()); - return postByName(name) + return postFinder.getByName(name) .flatMap(postVo -> { model.put("post", postVo); String template = postVo.getSpec().getTemplate(); @@ -72,9 +69,4 @@ public class PostRouteStrategy implements DetailsPageRouteHandlerStrategy { public boolean supports(GroupVersionKind gvk) { return groupVersionKind.equals(gvk); } - - private Mono postByName(String name) { - return Mono.fromCallable(() -> postFinder.getByName(name)) - .subscribeOn(Schedulers.boundedElastic()); - } } diff --git a/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java index 503ccf591..8a827c43f 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java @@ -5,15 +5,12 @@ import java.util.Map; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerResponse; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.SinglePage; import run.halo.app.extension.GVK; import run.halo.app.extension.GroupVersionKind; import run.halo.app.infra.SystemSetting; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.SinglePageFinder; -import run.halo.app.theme.finders.vo.SinglePageVo; import run.halo.app.theme.router.ViewNameResolver; /** @@ -40,11 +37,6 @@ public class SinglePageRouteStrategy implements DetailsPageRouteHandlerStrategy return annotation.plural(); } - private Mono singlePageByName(String name) { - return Mono.fromCallable(() -> singlePageFinder.getByName(name)) - .subscribeOn(Schedulers.boundedElastic()); - } - @Override public HandlerFunction getHandler(SystemSetting.ThemeRouteRules routeRules, String name) { @@ -54,7 +46,7 @@ public class SinglePageRouteStrategy implements DetailsPageRouteHandlerStrategy model.put("plural", getPlural()); model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.SINGLE_PAGE.getValue()); - return singlePageByName(name).flatMap(singlePageVo -> { + return singlePageFinder.getByName(name).flatMap(singlePageVo -> { model.put("singlePage", singlePageVo); String template = singlePageVo.getSpec().getTemplate(); return viewNameResolver.resolveViewNameOrDefault(request, template, diff --git a/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java index e1461faa3..56fd8b451 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java @@ -12,17 +12,14 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.Tag; import run.halo.app.extension.GroupVersionKind; -import run.halo.app.extension.ListResult; import run.halo.app.infra.SystemConfigurableEnvironmentFetcher; import run.halo.app.infra.SystemSetting; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.finders.TagFinder; -import run.halo.app.theme.finders.vo.PostVo; -import run.halo.app.theme.finders.vo.TagVo; +import run.halo.app.theme.finders.vo.ListedPostVo; import run.halo.app.theme.router.PageUrlUtils; import run.halo.app.theme.router.UrlContextListResult; @@ -43,28 +40,18 @@ public class TagRouteStrategy implements DetailsPageRouteHandlerStrategy { private final SystemConfigurableEnvironmentFetcher environmentFetcher; - private Mono> postList(ServerRequest request, String name) { + private Mono> postList(ServerRequest request, String name) { String path = request.path(); return environmentFetcher.fetchPost() .map(p -> defaultIfNull(p.getTagPageSize(), ModelConst.DEFAULT_PAGE_SIZE)) - .flatMap(pageSize -> listPostByTag(pageNum(request), pageSize, name)) - .map(list -> new UrlContextListResult.Builder() + .flatMap(pageSize -> postFinder.listByTag(pageNum(request), pageSize, name)) + .map(list -> new UrlContextListResult.Builder() .listResult(list) .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) .prevUrl(PageUrlUtils.prevPageUrl(path)) .build()); } - private Mono> listPostByTag(int page, int size, String name) { - return Mono.fromCallable(() -> postFinder.listByTag(page, size, name)) - .subscribeOn(Schedulers.boundedElastic()); - } - - private Mono tagByName(String name) { - return Mono.defer(() -> Mono.just(tagFinder.getByName(name))) - .publishOn(Schedulers.boundedElastic()); - } - @Override public HandlerFunction getHandler(SystemSetting.ThemeRouteRules routeRules, String name) { @@ -72,7 +59,7 @@ public class TagRouteStrategy implements DetailsPageRouteHandlerStrategy { .render(DefaultTemplateEnum.TAG.getValue(), Map.of("name", name, "posts", postList(request, name), - "tag", tagByName(name), + "tag", tagFinder.getByName(name), ModelConst.TEMPLATE_ID, DefaultTemplateEnum.TAG.getValue() ) ); diff --git a/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java index 2fc1d8e55..d669a238b 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java @@ -6,11 +6,8 @@ import org.apache.commons.lang3.StringUtils; import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.ServerResponse; -import reactor.core.publisher.Mono; -import reactor.core.scheduler.Schedulers; import run.halo.app.theme.DefaultTemplateEnum; import run.halo.app.theme.finders.TagFinder; -import run.halo.app.theme.finders.vo.TagVo; /** * The {@link TagsRouteStrategy} for generate {@link HandlerFunction} specific to the template @@ -28,16 +25,11 @@ public class TagsRouteStrategy implements ListPageRouteHandlerStrategy { this.tagFinder = tagFinder; } - private Mono> tags() { - return Mono.defer(() -> Mono.just(tagFinder.listAll())) - .publishOn(Schedulers.boundedElastic()); - } - @Override public HandlerFunction getHandler() { return request -> ServerResponse.ok() .render(DefaultTemplateEnum.TAGS.getValue(), - Map.of("tags", tags(), + Map.of("tags", tagFinder.listAll(), ModelConst.TEMPLATE_ID, DefaultTemplateEnum.TAGS.getValue() ) ); diff --git a/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java b/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java index f7e574300..14df794ee 100644 --- a/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java +++ b/src/test/java/run/halo/app/theme/dialect/HaloProcessorDialectTest.java @@ -142,7 +142,7 @@ class HaloProcessorDialectTest { PostVo postVo = PostVo.builder() .spec(postSpec) .metadata(metadata).build(); - when(postFinder.getByName(eq("fake-post"))).thenReturn(postVo); + when(postFinder.getByName(eq("fake-post"))).thenReturn(Mono.just(postVo)); SystemSetting.Basic basic = new SystemSetting.Basic(); basic.setFavicon(null); diff --git a/src/test/java/run/halo/app/theme/endpoint/CommentFinderEndpointTest.java b/src/test/java/run/halo/app/theme/endpoint/CommentFinderEndpointTest.java index 0802dc711..b1f7f0f6e 100644 --- a/src/test/java/run/halo/app/theme/endpoint/CommentFinderEndpointTest.java +++ b/src/test/java/run/halo/app/theme/endpoint/CommentFinderEndpointTest.java @@ -60,7 +60,7 @@ class CommentFinderEndpointTest { @Test void listComments() { when(commentFinder.list(any(), anyInt(), anyInt())) - .thenReturn(new ListResult<>(1, 10, 0, List.of())); + .thenReturn(Mono.just(new ListResult<>(1, 10, 0, List.of()))); Ref ref = new Ref(); ref.setGroup("content.halo.run"); @@ -104,15 +104,13 @@ class CommentFinderEndpointTest { @Test void listCommentReplies() { when(commentFinder.listReply(any(), anyInt(), anyInt())) - .thenReturn(new ListResult<>(2, 20, 0, List.of())); + .thenReturn(Mono.just(new ListResult<>(2, 20, 0, List.of()))); webTestClient.get() - .uri(uriBuilder -> { - return uriBuilder.path("/comments/test-comment/reply") - .queryParam("page", 2) - .queryParam("size", 20) - .build(); - }) + .uri(uriBuilder -> uriBuilder.path("/comments/test-comment/reply") + .queryParam("page", 2) + .queryParam("size", 20) + .build()) .exchange() .expectStatus() .isOk(); diff --git a/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java b/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java index b84f4b8f8..25ab95156 100644 --- a/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java +++ b/src/test/java/run/halo/app/theme/finders/impl/CategoryFinderImplTest.java @@ -51,7 +51,7 @@ class CategoryFinderImplTest { void getByName() throws JSONException { when(client.fetch(eq(Category.class), eq("hello"))) .thenReturn(Mono.just(category())); - CategoryVo categoryVo = categoryFinder.getByName("hello"); + CategoryVo categoryVo = categoryFinder.getByName("hello").block(); categoryVo.getMetadata().setCreationTimestamp(null); JSONAssert.assertEquals(""" { @@ -87,7 +87,7 @@ class CategoryFinderImplTest { .toList()); when(client.list(eq(Category.class), eq(null), any(), anyInt(), anyInt())) .thenReturn(Mono.just(categories)); - ListResult list = categoryFinder.list(1, 10); + ListResult list = categoryFinder.list(1, 10).block(); assertThat(list.getItems()).hasSize(3); assertThat(list.get().map(categoryVo -> categoryVo.getMetadata().getName()).toList()) .isEqualTo(List.of("c3", "c2", "hello")); @@ -97,7 +97,7 @@ class CategoryFinderImplTest { void listAsTree() { when(client.list(eq(Category.class), eq(null), any())) .thenReturn(Flux.fromIterable(categoriesForTree())); - List treeVos = categoryFinder.listAsTree(); + List treeVos = categoryFinder.listAsTree().collectList().block(); assertThat(treeVos).hasSize(1); } @@ -110,7 +110,7 @@ class CategoryFinderImplTest { void listAsTreeMore() { when(client.list(eq(Category.class), eq(null), any())) .thenReturn(Flux.fromIterable(moreCategories())); - List treeVos = categoryFinder.listAsTree(); + List treeVos = categoryFinder.listAsTree().collectList().block(); String s = visualizeTree(treeVos); assertThat(s).isEqualTo(""" 全部 (5) diff --git a/src/test/java/run/halo/app/theme/finders/impl/MenuFinderImplTest.java b/src/test/java/run/halo/app/theme/finders/impl/MenuFinderImplTest.java index d31e59f59..58f8a37f5 100644 --- a/src/test/java/run/halo/app/theme/finders/impl/MenuFinderImplTest.java +++ b/src/test/java/run/halo/app/theme/finders/impl/MenuFinderImplTest.java @@ -45,7 +45,7 @@ class MenuFinderImplTest { Mockito.when(client.list(eq(MenuItem.class), eq(null), any())) .thenReturn(Flux.fromIterable(tuple.getT2())); - List menuVos = menuFinder.listAsTree(); + List menuVos = menuFinder.listAsTree().collectList().block(); assertThat(visualizeTree(menuVos)).isEqualTo(""" D └── E diff --git a/src/test/java/run/halo/app/theme/finders/impl/PostFinderImplTest.java b/src/test/java/run/halo/app/theme/finders/impl/PostFinderImplTest.java index f432c8aff..46444b4e9 100644 --- a/src/test/java/run/halo/app/theme/finders/impl/PostFinderImplTest.java +++ b/src/test/java/run/halo/app/theme/finders/impl/PostFinderImplTest.java @@ -18,6 +18,7 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import reactor.core.publisher.Flux; import reactor.core.publisher.Mono; import run.halo.app.content.ContentService; import run.halo.app.content.ContentWrapper; @@ -78,7 +79,7 @@ class PostFinderImplTest { .thenReturn(Mono.just(post)); when(contentService.getContent(post.getSpec().getReleaseSnapshot())) .thenReturn(Mono.just(contentWrapper)); - ContentVo content = postFinder.content("post-1"); + ContentVo content = postFinder.content("post-1").block(); assertThat(content.getContent()).isEqualTo(contentWrapper.getContent()); assertThat(content.getRaw()).isEqualTo(contentWrapper.getRaw()); } @@ -108,7 +109,12 @@ class PostFinderImplTest { ListResult listResult = new ListResult<>(1, 10, 3, postsForArchives()); when(client.list(eq(Post.class), any(), any(), anyInt(), anyInt())) .thenReturn(Mono.just(listResult)); - ListResult archives = postFinder.archives(1, 10); + when(contributorFinder.getContributor(any())).thenReturn(Mono.empty()); + when(contributorFinder.getContributors(any())).thenReturn(Flux.empty()); + + ListResult archives = postFinder.archives(1, 10).block(); + assertThat(archives).isNotNull(); + List items = archives.getItems(); assertThat(items.size()).isEqualTo(2); assertThat(items.get(0).getYear()).isEqualTo("2022"); diff --git a/src/test/java/run/halo/app/theme/finders/impl/TagFinderImplTest.java b/src/test/java/run/halo/app/theme/finders/impl/TagFinderImplTest.java index 66b503b16..172f63d3a 100644 --- a/src/test/java/run/halo/app/theme/finders/impl/TagFinderImplTest.java +++ b/src/test/java/run/halo/app/theme/finders/impl/TagFinderImplTest.java @@ -47,7 +47,7 @@ class TagFinderImplTest { void getByName() throws JSONException { when(client.fetch(eq(Tag.class), eq("t1"))) .thenReturn(Mono.just(tag(1))); - TagVo tagVo = tagFinder.getByName("t1"); + TagVo tagVo = tagFinder.getByName("t1").block(); tagVo.getMetadata().setCreationTimestamp(null); JSONAssert.assertEquals(""" { @@ -82,7 +82,7 @@ class TagFinderImplTest { tags().stream().sorted(TagFinderImpl.DEFAULT_COMPARATOR.reversed()).toList() ) ); - List tags = tagFinder.listAll(); + List tags = tagFinder.listAll().collectList().block(); assertThat(tags).hasSize(3); assertThat(tags.stream() .map(tag -> tag.getMetadata().getName()) diff --git a/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java index 64a66929f..854991657 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java @@ -1,8 +1,5 @@ package run.halo.app.theme.router.strategy; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.lenient; - import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -15,7 +12,6 @@ import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import run.halo.app.theme.finders.PostFinder; -import run.halo.app.theme.router.UrlContextListResult; /** * Tests for {@link ArchivesRouteStrategy}. @@ -31,12 +27,6 @@ class ArchivesRouteStrategyTest extends RouterStrategyTestSuite { @InjectMocks private ArchivesRouteStrategy archivesRouteStrategy; - @Override - public void setUp() { - lenient().when(postFinder.list(any(), any())).thenReturn( - new UrlContextListResult<>(1, 10, 1, List.of(), null, null)); - } - @Test void getRouteFunctionWhenDefaultPattern() { HandlerFunction handler = archivesRouteStrategy.getHandler(); diff --git a/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java index 578f45abe..eae360e26 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java @@ -1,6 +1,6 @@ package run.halo.app.theme.router.strategy; -import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; import java.util.List; import org.junit.jupiter.api.Test; @@ -13,6 +13,7 @@ import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Flux; import run.halo.app.theme.finders.CategoryFinder; /** @@ -29,12 +30,6 @@ class CategoriesRouteStrategyTest extends RouterStrategyTestSuite { @InjectMocks private CategoriesRouteStrategy categoriesRouteStrategy; - @Override - public void setUp() { - lenient().when(categoryFinder.listAsTree()) - .thenReturn(List.of()); - } - @Test void getRouteFunction() { HandlerFunction handler = categoriesRouteStrategy.getHandler(); @@ -47,6 +42,7 @@ class CategoriesRouteStrategyTest extends RouterStrategyTestSuite { permalinkHttpGetRouter.insert(routerPath, handler); } + when(categoryFinder.listAsTree()).thenReturn(Flux.empty()); client.get() .uri("/categories-test") .exchange() diff --git a/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java index e065e8ec8..a07946e6b 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java @@ -1,10 +1,8 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; -import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -14,7 +12,7 @@ import org.springframework.http.HttpStatus; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; -import run.halo.app.extension.ListResult; +import reactor.core.publisher.Mono; import run.halo.app.theme.finders.CategoryFinder; import run.halo.app.theme.finders.PostFinder; @@ -36,12 +34,6 @@ class CategoryRouteStrategyTest extends RouterStrategyTestSuite { @InjectMocks private CategoryRouteStrategy categoryRouteStrategy; - @Override - public void setUp() { - lenient().when(postFinder.listByCategory(anyInt(), anyInt(), any())) - .thenReturn(new ListResult<>(1, 10, 0, List.of())); - } - @Test void getRouteFunction() { RouterFunction routeFunction = getRouterFunction(); @@ -52,6 +44,8 @@ class CategoryRouteStrategyTest extends RouterStrategyTestSuite { permalinkHttpGetRouter.insert("/categories-test/category-slug-2", categoryRouteStrategy.getHandler(null, "category-slug-2")); + when(categoryFinder.getByName(any())).thenReturn(Mono.empty()); + // /{prefix}/{slug} client.get() .uri("/categories-test/category-slug-1") diff --git a/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java index a75f68887..1ae853c43 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java @@ -1,8 +1,5 @@ package run.halo.app.theme.router.strategy; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.lenient; - import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -14,7 +11,6 @@ import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; -import run.halo.app.extension.ListResult; import run.halo.app.theme.finders.PostFinder; /** @@ -31,12 +27,6 @@ class IndexRouteStrategyTest extends RouterStrategyTestSuite { @InjectMocks private IndexRouteStrategy indexRouteStrategy; - @Override - public void setUp() { - lenient().when(postFinder.list(anyInt(), anyInt())) - .thenReturn(new ListResult<>(1, 10, 0, List.of())); - } - @Test void getRouteFunction() { HandlerFunction handler = indexRouteStrategy.getHandler(); diff --git a/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java index 702bf987c..454f26e20 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java @@ -42,7 +42,8 @@ class PostRouteStrategyTest extends RouterStrategyTestSuite { public void setUp() { lenient().when(viewNameResolver.resolveViewNameOrDefault(any(), any(), any())) .thenReturn(Mono.just(DefaultTemplateEnum.POST.getValue())); - lenient().when(postFinder.getByName(any())).thenReturn(PostVo.from(TestPost.postV1())); + lenient().when(postFinder.getByName(any())) + .thenReturn(Mono.just(PostVo.from(TestPost.postV1()))); } @Test diff --git a/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java index 5b11ac9d9..48859f354 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java @@ -1,12 +1,11 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; import static run.halo.app.theme.DefaultTemplateEnum.SINGLE_PAGE; -import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -16,7 +15,6 @@ import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import reactor.core.publisher.Mono; -import run.halo.app.extension.ListResult; import run.halo.app.theme.finders.SinglePageFinder; /** @@ -35,8 +33,6 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite { @Override public void setUp() { - lenient().when(singlePageFinder.list(anyInt(), anyInt())) - .thenReturn(new ListResult<>(1, 10, 0, List.of())); lenient().when(viewResolver.resolveViewName(eq(SINGLE_PAGE.getValue()), any())) .thenReturn(Mono.just(new EmptyView())); } @@ -53,6 +49,7 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite { void shouldResponse200IfPermalinkFound() { permalinkHttpGetRouter.insert("/fake-slug", strategy.getHandler(getThemeRouteRules(), "fake-name")); + when(singlePageFinder.getByName(any())).thenReturn(Mono.empty()); createClient().get() .uri("/fake-slug") .exchange() @@ -64,6 +61,8 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite { void shouldResponse200IfSlugNameContainsSpecialChars() { permalinkHttpGetRouter.insert("/fake / slug", strategy.getHandler(getThemeRouteRules(), "fake-name")); + + when(singlePageFinder.getByName(any())).thenReturn(Mono.empty()); createClient().get() .uri("/fake / slug") .exchange() @@ -74,6 +73,9 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite { void shouldResponse200IfSlugNameContainsChineseChars() { permalinkHttpGetRouter.insert("/中文", strategy.getHandler(getThemeRouteRules(), "fake-name")); + + when(singlePageFinder.getByName(any())).thenReturn(Mono.empty()); + createClient().get() .uri("/中文") .exchange() diff --git a/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java index 6cb6dcbe8..ddb8d37a8 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java @@ -1,10 +1,8 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyInt; -import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; -import java.util.List; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; @@ -14,8 +12,9 @@ import org.springframework.http.HttpStatus; import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; -import run.halo.app.extension.ListResult; +import reactor.core.publisher.Mono; import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.finders.TagFinder; /** * Tests for {@link TagRouteStrategy}. @@ -28,16 +27,12 @@ class TagRouteStrategyTest extends RouterStrategyTestSuite { @Mock private PostFinder postFinder; + @Mock + private TagFinder tagFinder; @InjectMocks private TagRouteStrategy tagRouteStrategy; - @Override - public void setUp() { - lenient().when(postFinder.listByTag(anyInt(), anyInt(), any())) - .thenReturn(new ListResult<>(1, 10, 0, List.of())); - } - @Test void getRouteFunction() { RouterFunction routeFunction = getRouterFunction(); @@ -45,6 +40,7 @@ class TagRouteStrategyTest extends RouterStrategyTestSuite { permalinkHttpGetRouter.insert("/tags-test/fake-slug", tagRouteStrategy.getHandler(getThemeRouteRules(), "fake-name")); + when(tagFinder.getByName(any())).thenReturn(Mono.empty()); client.get() .uri("/tags-test/fake-slug") diff --git a/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java index 3e93d05b9..a30b4fd34 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java @@ -1,6 +1,6 @@ package run.halo.app.theme.router.strategy; -import static org.mockito.Mockito.lenient; +import static org.mockito.Mockito.when; import java.util.List; import org.junit.jupiter.api.Test; @@ -13,6 +13,7 @@ import org.springframework.test.web.reactive.server.WebTestClient; import org.springframework.web.reactive.function.server.HandlerFunction; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Flux; import run.halo.app.theme.finders.TagFinder; /** @@ -30,11 +31,6 @@ class TagsRouteStrategyTest extends RouterStrategyTestSuite { @InjectMocks private TagsRouteStrategy tagsRouteStrategy; - @Override - public void setUp() { - lenient().when(tagFinder.listAll()).thenReturn(List.of()); - } - @Test void getRouteFunction() { RouterFunction routeFunction = getRouterFunction(); @@ -45,6 +41,7 @@ class TagsRouteStrategyTest extends RouterStrategyTestSuite { for (String routerPath : routerPaths) { permalinkHttpGetRouter.insert(routerPath, handler); } + when(tagFinder.listAll()).thenReturn(Flux.empty()); client.get() .uri("/tags-test")