mirror of https://github.com/halo-dev/halo
feat: theme finders supports the reactive API (#2695)
#### 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 ```pull/2712/head
parent
cc984b2bb3
commit
9f53cd1123
|
@ -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<PropertyAccessor> 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<PropertyAccessor> getPropertyAccessorsToTry(
|
||||||
|
@Nullable Object contextObject, List<PropertyAccessor> propertyAccessors) {
|
||||||
|
|
||||||
|
Class<?> targetType = (contextObject != null ? contextObject.getClass() : null);
|
||||||
|
|
||||||
|
List<PropertyAccessor> specificAccessors = new ArrayList<>();
|
||||||
|
List<PropertyAccessor> 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<PropertyAccessor> 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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -9,6 +9,8 @@ import org.springframework.util.ConcurrentLruCache;
|
||||||
import org.springframework.util.ResourceUtils;
|
import org.springframework.util.ResourceUtils;
|
||||||
import org.thymeleaf.dialect.IDialect;
|
import org.thymeleaf.dialect.IDialect;
|
||||||
import org.thymeleaf.spring6.ISpringWebFluxTemplateEngine;
|
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.FileTemplateResolver;
|
||||||
import org.thymeleaf.templateresolver.ITemplateResolver;
|
import org.thymeleaf.templateresolver.ITemplateResolver;
|
||||||
import run.halo.app.infra.ExternalUrlSupplier;
|
import run.halo.app.infra.ExternalUrlSupplier;
|
||||||
|
@ -86,6 +88,13 @@ public class TemplateEngineManager {
|
||||||
var mainResolver = haloTemplateResolver();
|
var mainResolver = haloTemplateResolver();
|
||||||
mainResolver.setPrefix(theme.getPath() + "/templates/");
|
mainResolver.setPrefix(theme.getPath() + "/templates/");
|
||||||
engine.addTemplateResolver(mainResolver);
|
engine.addTemplateResolver(mainResolver);
|
||||||
|
// replace StandardDialect with SpringStandardDialect
|
||||||
|
engine.setDialect(new SpringStandardDialect() {
|
||||||
|
@Override
|
||||||
|
public IStandardVariableExpressionEvaluator getVariableExpressionEvaluator() {
|
||||||
|
return ReactiveSpelVariableExpressionEvaluator.INSTANCE;
|
||||||
|
}
|
||||||
|
});
|
||||||
engine.addDialect(new HaloProcessorDialect());
|
engine.addDialect(new HaloProcessorDialect());
|
||||||
|
|
||||||
templateResolvers.orderedStream().forEach(engine::addTemplateResolver);
|
templateResolvers.orderedStream().forEach(engine::addTemplateResolver);
|
||||||
|
|
|
@ -4,9 +4,7 @@ import java.util.Map;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.server.ServerWebExchange;
|
import org.springframework.web.server.ServerWebExchange;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.core.scheduler.Schedulers;
|
|
||||||
import run.halo.app.theme.finders.ThemeFinder;
|
import run.halo.app.theme.finders.ThemeFinder;
|
||||||
import run.halo.app.theme.finders.vo.ThemeVo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Theme context based variables acquirer.
|
* Theme context based variables acquirer.
|
||||||
|
@ -28,14 +26,11 @@ public class ThemeContextBasedVariablesAcquirer implements ViewContextBasedVaria
|
||||||
@Override
|
@Override
|
||||||
public Mono<Map<String, Object>> acquire(ServerWebExchange exchange) {
|
public Mono<Map<String, Object>> acquire(ServerWebExchange exchange) {
|
||||||
return themeResolver.getTheme(exchange.getRequest())
|
return themeResolver.getTheme(exchange.getRequest())
|
||||||
.publishOn(Schedulers.boundedElastic())
|
.flatMap(themeContext -> {
|
||||||
.map(themeContext -> {
|
|
||||||
String name = themeContext.getName();
|
String name = themeContext.getName();
|
||||||
ThemeVo themeVo = themeFinder.getByName(name);
|
return themeFinder.getByName(name);
|
||||||
if (themeVo == null) {
|
})
|
||||||
return Map.of();
|
.map(themeVo -> Map.<String, Object>of("theme", themeVo))
|
||||||
}
|
.defaultIfEmpty(Map.of());
|
||||||
return Map.of("theme", themeVo);
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import org.thymeleaf.processor.templateboundaries.ITemplateBoundariesStructureHa
|
||||||
import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext;
|
import org.thymeleaf.spring6.expression.ThymeleafEvaluationContext;
|
||||||
import org.thymeleaf.standard.StandardDialect;
|
import org.thymeleaf.standard.StandardDialect;
|
||||||
import org.thymeleaf.templatemode.TemplateMode;
|
import org.thymeleaf.templatemode.TemplateMode;
|
||||||
|
import run.halo.app.theme.ReactivePropertyAccessor;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A template boundaries processor for add {@link JsonPropertyAccessor} to
|
* A template boundaries processor for add {@link JsonPropertyAccessor} to
|
||||||
|
@ -21,6 +22,8 @@ public class JsonNodePropertyAccessorBoundariesProcessor
|
||||||
extends AbstractTemplateBoundariesProcessor {
|
extends AbstractTemplateBoundariesProcessor {
|
||||||
private static final int PRECEDENCE = StandardDialect.PROCESSOR_PRECEDENCE;
|
private static final int PRECEDENCE = StandardDialect.PROCESSOR_PRECEDENCE;
|
||||||
private static final JsonPropertyAccessor JSON_PROPERTY_ACCESSOR = new JsonPropertyAccessor();
|
private static final JsonPropertyAccessor JSON_PROPERTY_ACCESSOR = new JsonPropertyAccessor();
|
||||||
|
private static final ReactivePropertyAccessor REACTIVE_PROPERTY_ACCESSOR =
|
||||||
|
new ReactivePropertyAccessor();
|
||||||
|
|
||||||
public JsonNodePropertyAccessorBoundariesProcessor() {
|
public JsonNodePropertyAccessorBoundariesProcessor() {
|
||||||
super(TemplateMode.HTML, PRECEDENCE);
|
super(TemplateMode.HTML, PRECEDENCE);
|
||||||
|
@ -34,6 +37,7 @@ public class JsonNodePropertyAccessorBoundariesProcessor
|
||||||
ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME);
|
ThymeleafEvaluationContext.THYMELEAF_EVALUATION_CONTEXT_CONTEXT_VARIABLE_NAME);
|
||||||
if (evaluationContext != null) {
|
if (evaluationContext != null) {
|
||||||
evaluationContext.addPropertyAccessor(JSON_PROPERTY_ACCESSOR);
|
evaluationContext.addPropertyAccessor(JSON_PROPERTY_ACCESSOR);
|
||||||
|
evaluationContext.addPropertyAccessor(REACTIVE_PROPERTY_ACCESSOR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,7 +36,7 @@ public class PostTemplateHeadProcessor implements TemplateHeadProcessor {
|
||||||
return Mono.empty();
|
return Mono.empty();
|
||||||
}
|
}
|
||||||
return Mono.justOrEmpty((String) context.getVariable(POST_NAME_VARIABLE))
|
return Mono.justOrEmpty((String) context.getVariable(POST_NAME_VARIABLE))
|
||||||
.map(postFinder::getByName)
|
.flatMap(postFinder::getByName)
|
||||||
.doOnNext(postVo -> {
|
.doOnNext(postVo -> {
|
||||||
List<Map<String, String>> htmlMetas = postVo.getSpec().getHtmlMetas();
|
List<Map<String, String>> htmlMetas = postVo.getSpec().getHtmlMetas();
|
||||||
String metaHtml = headMetaBuilder(htmlMetas);
|
String metaHtml = headMetaBuilder(htmlMetas);
|
||||||
|
|
|
@ -165,10 +165,8 @@ public class CommentFinderEndpoint implements CustomEndpoint {
|
||||||
|
|
||||||
Mono<ServerResponse> listComments(ServerRequest request) {
|
Mono<ServerResponse> listComments(ServerRequest request) {
|
||||||
CommentQuery commentQuery = new CommentQuery(request.queryParams());
|
CommentQuery commentQuery = new CommentQuery(request.queryParams());
|
||||||
return Mono.defer(() -> Mono.just(
|
return commentFinder.list(commentQuery.toRef(), commentQuery.getPage(),
|
||||||
commentFinder.list(commentQuery.toRef(), commentQuery.getPage(),
|
commentQuery.getSize())
|
||||||
commentQuery.getSize())))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic())
|
|
||||||
.flatMap(list -> ServerResponse.ok().bodyValue(list));
|
.flatMap(list -> ServerResponse.ok().bodyValue(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -183,9 +181,7 @@ public class CommentFinderEndpoint implements CustomEndpoint {
|
||||||
String commentName = request.pathVariable("name");
|
String commentName = request.pathVariable("name");
|
||||||
IListRequest.QueryListRequest queryParams =
|
IListRequest.QueryListRequest queryParams =
|
||||||
new IListRequest.QueryListRequest(request.queryParams());
|
new IListRequest.QueryListRequest(request.queryParams());
|
||||||
return Mono.defer(() -> Mono.just(
|
return commentFinder.listReply(commentName, queryParams.getPage(), queryParams.getSize())
|
||||||
commentFinder.listReply(commentName, queryParams.getPage(), queryParams.getSize())))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic())
|
|
||||||
.flatMap(list -> ServerResponse.ok().bodyValue(list));
|
.flatMap(list -> ServerResponse.ok().bodyValue(list));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,8 @@ package run.halo.app.theme.finders;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.lang.Nullable;
|
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.core.extension.Category;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.theme.finders.vo.CategoryTreeVo;
|
import run.halo.app.theme.finders.vo.CategoryTreeVo;
|
||||||
|
@ -15,13 +17,13 @@ import run.halo.app.theme.finders.vo.CategoryVo;
|
||||||
*/
|
*/
|
||||||
public interface CategoryFinder {
|
public interface CategoryFinder {
|
||||||
|
|
||||||
CategoryVo getByName(String name);
|
Mono<CategoryVo> getByName(String name);
|
||||||
|
|
||||||
List<CategoryVo> getByNames(List<String> names);
|
Flux<CategoryVo> getByNames(List<String> names);
|
||||||
|
|
||||||
ListResult<CategoryVo> list(@Nullable Integer page, @Nullable Integer size);
|
Mono<ListResult<CategoryVo>> list(@Nullable Integer page, @Nullable Integer size);
|
||||||
|
|
||||||
List<CategoryVo> listAll();
|
Flux<CategoryVo> listAll();
|
||||||
|
|
||||||
List<CategoryTreeVo> listAsTree();
|
Flux<CategoryTreeVo> listAsTree();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
package run.halo.app.theme.finders;
|
package run.halo.app.theme.finders;
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.core.extension.Comment;
|
import run.halo.app.core.extension.Comment;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.extension.Ref;
|
import run.halo.app.extension.Ref;
|
||||||
|
@ -15,11 +16,11 @@ import run.halo.app.theme.finders.vo.ReplyVo;
|
||||||
*/
|
*/
|
||||||
public interface CommentFinder {
|
public interface CommentFinder {
|
||||||
|
|
||||||
CommentVo getByName(String name);
|
Mono<CommentVo> getByName(String name);
|
||||||
|
|
||||||
ListResult<CommentVo> list(Ref ref, @Nullable Integer page,
|
Mono<ListResult<CommentVo>> list(Ref ref, @Nullable Integer page,
|
||||||
@Nullable Integer size);
|
@Nullable Integer size);
|
||||||
|
|
||||||
ListResult<ReplyVo> listReply(String commentName, @Nullable Integer page,
|
Mono<ListResult<ReplyVo>> listReply(String commentName, @Nullable Integer page,
|
||||||
@Nullable Integer size);
|
@Nullable Integer size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package run.halo.app.theme.finders;
|
package run.halo.app.theme.finders;
|
||||||
|
|
||||||
import java.util.List;
|
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.core.extension.User;
|
||||||
import run.halo.app.theme.finders.vo.Contributor;
|
import run.halo.app.theme.finders.vo.Contributor;
|
||||||
|
|
||||||
|
@ -9,7 +11,7 @@ import run.halo.app.theme.finders.vo.Contributor;
|
||||||
*/
|
*/
|
||||||
public interface ContributorFinder {
|
public interface ContributorFinder {
|
||||||
|
|
||||||
Contributor getContributor(String name);
|
Mono<Contributor> getContributor(String name);
|
||||||
|
|
||||||
List<Contributor> getContributors(List<String> names);
|
Flux<Contributor> getContributors(List<String> names);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.theme.finders;
|
package run.halo.app.theme.finders;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.theme.finders.vo.MenuVo;
|
import run.halo.app.theme.finders.vo.MenuVo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +11,7 @@ import run.halo.app.theme.finders.vo.MenuVo;
|
||||||
*/
|
*/
|
||||||
public interface MenuFinder {
|
public interface MenuFinder {
|
||||||
|
|
||||||
MenuVo getByName(String name);
|
Mono<MenuVo> getByName(String name);
|
||||||
|
|
||||||
MenuVo getPrimary();
|
Mono<MenuVo> getPrimary();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package run.halo.app.theme.finders;
|
package run.halo.app.theme.finders;
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.core.extension.Post;
|
import run.halo.app.core.extension.Post;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.theme.finders.vo.ContentVo;
|
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.NavigationPostVo;
|
||||||
import run.halo.app.theme.finders.vo.PostArchiveVo;
|
import run.halo.app.theme.finders.vo.PostArchiveVo;
|
||||||
import run.halo.app.theme.finders.vo.PostVo;
|
import run.halo.app.theme.finders.vo.PostVo;
|
||||||
|
@ -16,22 +18,23 @@ import run.halo.app.theme.finders.vo.PostVo;
|
||||||
*/
|
*/
|
||||||
public interface PostFinder {
|
public interface PostFinder {
|
||||||
|
|
||||||
PostVo getByName(String postName);
|
Mono<PostVo> getByName(String postName);
|
||||||
|
|
||||||
ContentVo content(String postName);
|
Mono<ContentVo> content(String postName);
|
||||||
|
|
||||||
NavigationPostVo cursor(String current);
|
Mono<NavigationPostVo> cursor(String current);
|
||||||
|
|
||||||
ListResult<PostVo> list(@Nullable Integer page, @Nullable Integer size);
|
Mono<ListResult<ListedPostVo>> list(@Nullable Integer page, @Nullable Integer size);
|
||||||
|
|
||||||
ListResult<PostVo> listByCategory(@Nullable Integer page, @Nullable Integer size,
|
Mono<ListResult<ListedPostVo>> listByCategory(@Nullable Integer page, @Nullable Integer size,
|
||||||
String categoryName);
|
String categoryName);
|
||||||
|
|
||||||
ListResult<PostVo> listByTag(@Nullable Integer page, @Nullable Integer size, String tag);
|
Mono<ListResult<ListedPostVo>> listByTag(@Nullable Integer page, @Nullable Integer size,
|
||||||
|
String tag);
|
||||||
|
|
||||||
ListResult<PostArchiveVo> archives(Integer page, Integer size);
|
Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size);
|
||||||
|
|
||||||
ListResult<PostArchiveVo> archives(Integer page, Integer size, String year);
|
Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size, String year);
|
||||||
|
|
||||||
ListResult<PostArchiveVo> archives(Integer page, Integer size, String year, String month);
|
Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size, String year, String month);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
package run.halo.app.theme.finders;
|
package run.halo.app.theme.finders;
|
||||||
|
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.core.extension.SinglePage;
|
import run.halo.app.core.extension.SinglePage;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.theme.finders.vo.ContentVo;
|
import run.halo.app.theme.finders.vo.ContentVo;
|
||||||
|
import run.halo.app.theme.finders.vo.ListedSinglePageVo;
|
||||||
import run.halo.app.theme.finders.vo.SinglePageVo;
|
import run.halo.app.theme.finders.vo.SinglePageVo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -14,9 +16,9 @@ import run.halo.app.theme.finders.vo.SinglePageVo;
|
||||||
*/
|
*/
|
||||||
public interface SinglePageFinder {
|
public interface SinglePageFinder {
|
||||||
|
|
||||||
SinglePageVo getByName(String pageName);
|
Mono<SinglePageVo> getByName(String pageName);
|
||||||
|
|
||||||
ContentVo content(String pageName);
|
Mono<ContentVo> content(String pageName);
|
||||||
|
|
||||||
ListResult<SinglePageVo> list(@Nullable Integer page, @Nullable Integer size);
|
Mono<ListResult<ListedSinglePageVo>> list(@Nullable Integer page, @Nullable Integer size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.theme.finders;
|
package run.halo.app.theme.finders;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.theme.finders.vo.SiteStatsVo;
|
import run.halo.app.theme.finders.vo.SiteStatsVo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,5 +11,5 @@ import run.halo.app.theme.finders.vo.SiteStatsVo;
|
||||||
*/
|
*/
|
||||||
public interface SiteStatsFinder {
|
public interface SiteStatsFinder {
|
||||||
|
|
||||||
SiteStatsVo getStats();
|
Mono<SiteStatsVo> getStats();
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,8 @@ package run.halo.app.theme.finders;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.springframework.lang.Nullable;
|
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.core.extension.Tag;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.theme.finders.vo.TagVo;
|
import run.halo.app.theme.finders.vo.TagVo;
|
||||||
|
@ -14,11 +16,11 @@ import run.halo.app.theme.finders.vo.TagVo;
|
||||||
*/
|
*/
|
||||||
public interface TagFinder {
|
public interface TagFinder {
|
||||||
|
|
||||||
TagVo getByName(String name);
|
Mono<TagVo> getByName(String name);
|
||||||
|
|
||||||
List<TagVo> getByNames(List<String> names);
|
Flux<TagVo> getByNames(List<String> names);
|
||||||
|
|
||||||
ListResult<TagVo> list(@Nullable Integer page, @Nullable Integer size);
|
Mono<ListResult<TagVo>> list(@Nullable Integer page, @Nullable Integer size);
|
||||||
|
|
||||||
List<TagVo> listAll();
|
Flux<TagVo> listAll();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.theme.finders;
|
package run.halo.app.theme.finders;
|
||||||
|
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.theme.finders.vo.ThemeVo;
|
import run.halo.app.theme.finders.vo.ThemeVo;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -10,7 +11,7 @@ import run.halo.app.theme.finders.vo.ThemeVo;
|
||||||
*/
|
*/
|
||||||
public interface ThemeFinder {
|
public interface ThemeFinder {
|
||||||
|
|
||||||
ThemeVo activation();
|
Mono<ThemeVo> activation();
|
||||||
|
|
||||||
ThemeVo getByName(String themeName);
|
Mono<ThemeVo> getByName(String themeName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,8 @@ import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
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.core.extension.Category;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
@ -34,24 +36,22 @@ public class CategoryFinderImpl implements CategoryFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CategoryVo getByName(String name) {
|
public Mono<CategoryVo> getByName(String name) {
|
||||||
return client.fetch(Category.class, name)
|
return client.fetch(Category.class, name)
|
||||||
.map(CategoryVo::from)
|
.map(CategoryVo::from);
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CategoryVo> getByNames(List<String> names) {
|
public Flux<CategoryVo> getByNames(List<String> names) {
|
||||||
if (names == null) {
|
if (names == null) {
|
||||||
return List.of();
|
return Flux.empty();
|
||||||
}
|
}
|
||||||
return names.stream().map(this::getByName)
|
return Flux.fromIterable(names)
|
||||||
.filter(Objects::nonNull)
|
.flatMap(this::getByName);
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<CategoryVo> list(Integer page, Integer size) {
|
public Mono<ListResult<CategoryVo>> list(Integer page, Integer size) {
|
||||||
return client.list(Category.class, null,
|
return client.list(Category.class, null,
|
||||||
defaultComparator(), pageNullSafe(page), sizeNullSafe(size))
|
defaultComparator(), pageNullSafe(page), sizeNullSafe(size))
|
||||||
.map(list -> {
|
.map(list -> {
|
||||||
|
@ -61,38 +61,39 @@ public class CategoryFinderImpl implements CategoryFinder {
|
||||||
return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(),
|
return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(),
|
||||||
categoryVos);
|
categoryVos);
|
||||||
})
|
})
|
||||||
.block();
|
.defaultIfEmpty(new ListResult<>(page, size, 0L, List.of()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CategoryVo> listAll() {
|
public Flux<CategoryVo> listAll() {
|
||||||
return client.list(Category.class, null, defaultComparator())
|
return client.list(Category.class, null, defaultComparator())
|
||||||
.map(CategoryVo::from)
|
.map(CategoryVo::from);
|
||||||
.collectList()
|
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<CategoryTreeVo> listAsTree() {
|
public Flux<CategoryTreeVo> listAsTree() {
|
||||||
List<CategoryVo> categoryVos = listAll();
|
return listAll()
|
||||||
Map<String, CategoryTreeVo> nameIdentityMap = categoryVos.stream()
|
.collectList()
|
||||||
.map(CategoryTreeVo::from)
|
.flatMapIterable(categoryVos -> {
|
||||||
.collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(),
|
Map<String, CategoryTreeVo> nameIdentityMap = categoryVos.stream()
|
||||||
Function.identity()));
|
.map(CategoryTreeVo::from)
|
||||||
|
.collect(Collectors.toMap(categoryVo -> categoryVo.getMetadata().getName(),
|
||||||
|
Function.identity()));
|
||||||
|
|
||||||
nameIdentityMap.forEach((name, value) -> {
|
nameIdentityMap.forEach((name, value) -> {
|
||||||
List<String> children = value.getSpec().getChildren();
|
List<String> children = value.getSpec().getChildren();
|
||||||
if (children == null) {
|
if (children == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
for (String child : children) {
|
for (String child : children) {
|
||||||
CategoryTreeVo childNode = nameIdentityMap.get(child);
|
CategoryTreeVo childNode = nameIdentityMap.get(child);
|
||||||
if (childNode != null) {
|
if (childNode != null) {
|
||||||
childNode.setParentName(name);
|
childNode.setParentName(name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return listToTree(nameIdentityMap.values());
|
return listToTree(nameIdentityMap.values());
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<CategoryTreeVo> listToTree(Collection<CategoryTreeVo> list) {
|
static List<CategoryTreeVo> listToTree(Collection<CategoryTreeVo> list) {
|
||||||
|
|
|
@ -2,6 +2,7 @@ package run.halo.app.theme.finders.impl;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
|
@ -37,14 +38,13 @@ public class CommentFinderImpl implements CommentFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CommentVo getByName(String name) {
|
public Mono<CommentVo> getByName(String name) {
|
||||||
return client.fetch(Comment.class, name)
|
return client.fetch(Comment.class, name)
|
||||||
.flatMap(this::toCommentVo)
|
.flatMap(this::toCommentVo);
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<CommentVo> list(Ref ref, Integer page, Integer size) {
|
public Mono<ListResult<CommentVo>> list(Ref ref, Integer page, Integer size) {
|
||||||
return client.list(Comment.class, fixedPredicate(ref),
|
return client.list(Comment.class, fixedPredicate(ref),
|
||||||
defaultComparator(),
|
defaultComparator(),
|
||||||
pageNullSafe(page), sizeNullSafe(size))
|
pageNullSafe(page), sizeNullSafe(size))
|
||||||
|
@ -55,11 +55,11 @@ public class CommentFinderImpl implements CommentFinder {
|
||||||
commentVos)
|
commentVos)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.block();
|
.defaultIfEmpty(new ListResult<>(page, size, 0L, List.of()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<ReplyVo> listReply(String commentName, Integer page, Integer size) {
|
public Mono<ListResult<ReplyVo>> listReply(String commentName, Integer page, Integer size) {
|
||||||
Comparator<Reply> comparator =
|
Comparator<Reply> comparator =
|
||||||
Comparator.comparing(reply -> reply.getMetadata().getCreationTimestamp());
|
Comparator.comparing(reply -> reply.getMetadata().getCreationTimestamp());
|
||||||
return client.list(Reply.class,
|
return client.list(Reply.class,
|
||||||
|
@ -73,7 +73,7 @@ public class CommentFinderImpl implements CommentFinder {
|
||||||
.map(replyVos -> new ListResult<>(list.getPage(), list.getSize(), list.getTotal(),
|
.map(replyVos -> new ListResult<>(list.getPage(), list.getSize(), list.getTotal(),
|
||||||
replyVos))
|
replyVos))
|
||||||
)
|
)
|
||||||
.block();
|
.defaultIfEmpty(new ListResult<>(page, size, 0L, List.of()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<CommentVo> toCommentVo(Comment comment) {
|
private Mono<CommentVo> toCommentVo(Comment comment) {
|
||||||
|
@ -81,6 +81,7 @@ public class CommentFinderImpl implements CommentFinder {
|
||||||
return Mono.just(CommentVo.from(comment))
|
return Mono.just(CommentVo.from(comment))
|
||||||
.flatMap(commentVo -> getOwnerInfo(owner)
|
.flatMap(commentVo -> getOwnerInfo(owner)
|
||||||
.map(commentVo::withOwner)
|
.map(commentVo::withOwner)
|
||||||
|
.defaultIfEmpty(commentVo)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -88,6 +89,7 @@ public class CommentFinderImpl implements CommentFinder {
|
||||||
return Mono.just(ReplyVo.from(reply))
|
return Mono.just(ReplyVo.from(reply))
|
||||||
.flatMap(replyVo -> getOwnerInfo(reply.getSpec().getOwner())
|
.flatMap(replyVo -> getOwnerInfo(reply.getSpec().getOwner())
|
||||||
.map(replyVo::withOwner)
|
.map(replyVo::withOwner)
|
||||||
|
.defaultIfEmpty(replyVo)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,7 +99,7 @@ public class CommentFinderImpl implements CommentFinder {
|
||||||
}
|
}
|
||||||
return client.fetch(User.class, owner.getName())
|
return client.fetch(User.class, owner.getName())
|
||||||
.map(OwnerInfo::from)
|
.map(OwnerInfo::from)
|
||||||
.switchIfEmpty(Mono.just(OwnerInfo.ghostUser()));
|
.defaultIfEmpty(OwnerInfo.ghostUser());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Predicate<Comment> fixedPredicate(Ref ref) {
|
private Predicate<Comment> fixedPredicate(Ref ref) {
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
package run.halo.app.theme.finders.impl;
|
package run.halo.app.theme.finders.impl;
|
||||||
|
|
||||||
import java.util.List;
|
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.core.extension.User;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
import run.halo.app.theme.finders.ContributorFinder;
|
import run.halo.app.theme.finders.ContributorFinder;
|
||||||
|
@ -24,20 +25,17 @@ public class ContributorFinderImpl implements ContributorFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Contributor getContributor(String name) {
|
public Mono<Contributor> getContributor(String name) {
|
||||||
return client.fetch(User.class, name)
|
return client.fetch(User.class, name)
|
||||||
.map(Contributor::from)
|
.map(Contributor::from);
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<Contributor> getContributors(List<String> names) {
|
public Flux<Contributor> getContributors(List<String> names) {
|
||||||
if (names == null) {
|
if (names == null) {
|
||||||
return List.of();
|
return Flux.empty();
|
||||||
}
|
}
|
||||||
return names.stream()
|
return Flux.fromIterable(names)
|
||||||
.map(this::getContributor)
|
.flatMap(this::getContributor);
|
||||||
.filter(Objects::nonNull)
|
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,9 +10,10 @@ import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.comparator.Comparators;
|
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.Menu;
|
||||||
import run.halo.app.core.extension.MenuItem;
|
import run.halo.app.core.extension.MenuItem;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
@ -37,56 +38,58 @@ public class MenuFinderImpl implements MenuFinder {
|
||||||
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MenuVo getByName(String name) {
|
public Mono<MenuVo> getByName(String name) {
|
||||||
return listAsTree().stream()
|
return listAsTree()
|
||||||
.filter(menu -> menu.getMetadata().getName().equals(name))
|
.filter(menu -> menu.getMetadata().getName().equals(name))
|
||||||
.findAny()
|
.next();
|
||||||
.orElse(null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public MenuVo getPrimary() {
|
public Mono<MenuVo> getPrimary() {
|
||||||
List<MenuVo> menuVos = listAsTree();
|
return listAsTree().collectList()
|
||||||
if (CollectionUtils.isEmpty(menuVos)) {
|
.flatMap(menuVos -> {
|
||||||
return null;
|
if (CollectionUtils.isEmpty(menuVos)) {
|
||||||
}
|
return Mono.empty();
|
||||||
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<MenuVo> listAll() {
|
|
||||||
return client.list(Menu.class, null, null)
|
|
||||||
.map(MenuVo::from)
|
|
||||||
.collectList()
|
|
||||||
.block();
|
|
||||||
}
|
|
||||||
|
|
||||||
List<MenuVo> listAsTree() {
|
|
||||||
Collection<MenuItemVo> menuItemVos = populateParentName(listAllMenuItem());
|
|
||||||
List<MenuItemVo> treeList = listToTree(menuItemVos);
|
|
||||||
Map<String, MenuItemVo> nameItemRootNodeMap = treeList.stream()
|
|
||||||
.collect(Collectors.toMap(item -> item.getMetadata().getName(), Function.identity()));
|
|
||||||
|
|
||||||
return listAll().stream()
|
|
||||||
.map(menuVo -> {
|
|
||||||
LinkedHashSet<String> menuItemNames = menuVo.getSpec().getMenuItems();
|
|
||||||
if (menuItemNames == null) {
|
|
||||||
return menuVo.withMenuItems(List.of());
|
|
||||||
}
|
}
|
||||||
List<MenuItemVo> menuItems = menuItemNames.stream()
|
return environmentFetcher.fetch(SystemSetting.Menu.GROUP, SystemSetting.Menu.class)
|
||||||
.map(nameItemRootNodeMap::get)
|
.map(SystemSetting.Menu::getPrimary)
|
||||||
.filter(Objects::nonNull)
|
.map(primaryConfig -> menuVos.stream()
|
||||||
.sorted(defaultTreeNodeComparator())
|
.filter(menuVo -> menuVo.getMetadata().getName().equals(primaryConfig))
|
||||||
.toList();
|
.findAny()
|
||||||
return menuVo.withMenuItems(menuItems);
|
.orElse(menuVos.get(0))
|
||||||
})
|
)
|
||||||
.toList();
|
.defaultIfEmpty(menuVos.get(0));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
Flux<MenuVo> listAll() {
|
||||||
|
return client.list(Menu.class, null, null)
|
||||||
|
.map(MenuVo::from);
|
||||||
|
}
|
||||||
|
|
||||||
|
Flux<MenuVo> listAsTree() {
|
||||||
|
return listAllMenuItem()
|
||||||
|
.collectList()
|
||||||
|
.map(MenuFinderImpl::populateParentName)
|
||||||
|
.flatMapMany(menuItemVos -> {
|
||||||
|
List<MenuItemVo> treeList = listToTree(menuItemVos);
|
||||||
|
Map<String, MenuItemVo> nameItemRootNodeMap = treeList.stream()
|
||||||
|
.collect(Collectors.toMap(item -> item.getMetadata().getName(),
|
||||||
|
Function.identity()));
|
||||||
|
return listAll()
|
||||||
|
.map(menuVo -> {
|
||||||
|
LinkedHashSet<String> menuItemNames = menuVo.getSpec().getMenuItems();
|
||||||
|
if (menuItemNames == null) {
|
||||||
|
return menuVo.withMenuItems(List.of());
|
||||||
|
}
|
||||||
|
List<MenuItemVo> menuItems = menuItemNames.stream()
|
||||||
|
.map(nameItemRootNodeMap::get)
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.sorted(defaultTreeNodeComparator())
|
||||||
|
.toList();
|
||||||
|
return menuVo.withMenuItems(menuItems);
|
||||||
|
});
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static List<MenuItemVo> listToTree(Collection<MenuItemVo> list) {
|
static List<MenuItemVo> listToTree(Collection<MenuItemVo> list) {
|
||||||
|
@ -109,11 +112,9 @@ public class MenuFinderImpl implements MenuFinder {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
List<MenuItemVo> listAllMenuItem() {
|
Flux<MenuItemVo> listAllMenuItem() {
|
||||||
return client.list(MenuItem.class, null, null)
|
return client.list(MenuItem.class, null, null)
|
||||||
.map(MenuItemVo::from)
|
.map(MenuItemVo::from);
|
||||||
.collectList()
|
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Comparator<MenuItemVo> defaultTreeNodeComparator() {
|
static Comparator<MenuItemVo> defaultTreeNodeComparator() {
|
||||||
|
|
|
@ -15,7 +15,10 @@ import org.apache.commons.lang3.ObjectUtils;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.apache.commons.lang3.tuple.Pair;
|
import org.apache.commons.lang3.tuple.Pair;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
import org.springframework.util.comparator.Comparators;
|
import org.springframework.util.comparator.Comparators;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.util.function.Tuple2;
|
import reactor.util.function.Tuple2;
|
||||||
import run.halo.app.content.ContentService;
|
import run.halo.app.content.ContentService;
|
||||||
import run.halo.app.core.extension.Counter;
|
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.Finder;
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
import run.halo.app.theme.finders.PostFinder;
|
||||||
import run.halo.app.theme.finders.TagFinder;
|
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.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.NavigationPostVo;
|
||||||
import run.halo.app.theme.finders.vo.PostArchiveVo;
|
import run.halo.app.theme.finders.vo.PostArchiveVo;
|
||||||
import run.halo.app.theme.finders.vo.PostArchiveYearMonthVo;
|
import run.halo.app.theme.finders.vo.PostArchiveYearMonthVo;
|
||||||
import run.halo.app.theme.finders.vo.PostVo;
|
import run.halo.app.theme.finders.vo.PostVo;
|
||||||
import run.halo.app.theme.finders.vo.StatsVo;
|
import run.halo.app.theme.finders.vo.StatsVo;
|
||||||
import run.halo.app.theme.finders.vo.TagVo;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A finder for {@link Post}.
|
* A finder for {@link Post}.
|
||||||
|
@ -50,8 +51,8 @@ import run.halo.app.theme.finders.vo.TagVo;
|
||||||
public class PostFinderImpl implements PostFinder {
|
public class PostFinderImpl implements PostFinder {
|
||||||
|
|
||||||
public static final Predicate<Post> FIXED_PREDICATE = post -> post.isPublished()
|
public static final Predicate<Post> FIXED_PREDICATE = post -> post.isPublished()
|
||||||
&& Objects.equals(false, post.getSpec().getDeleted())
|
&& Objects.equals(false, post.getSpec().getDeleted())
|
||||||
&& Post.VisibleEnum.PUBLIC.equals(post.getSpec().getVisible());
|
&& Post.VisibleEnum.PUBLIC.equals(post.getSpec().getVisible());
|
||||||
private final ReactiveExtensionClient client;
|
private final ReactiveExtensionClient client;
|
||||||
|
|
||||||
private final ContentService contentService;
|
private final ContentService contentService;
|
||||||
|
@ -78,53 +79,49 @@ public class PostFinderImpl implements PostFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public PostVo getByName(String postName) {
|
public Mono<PostVo> getByName(String postName) {
|
||||||
Post post = client.fetch(Post.class, postName)
|
return client.fetch(Post.class, postName)
|
||||||
.block();
|
.flatMap(this::getListedPostVo)
|
||||||
if (post == null) {
|
.map(PostVo::from)
|
||||||
return null;
|
.flatMap(postVo -> content(postName)
|
||||||
}
|
.doOnNext(postVo::setContent)
|
||||||
PostVo postVo = getPostVo(post);
|
.thenReturn(postVo)
|
||||||
postVo.setContent(content(postName));
|
);
|
||||||
return postVo;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContentVo content(String postName) {
|
public Mono<ContentVo> content(String postName) {
|
||||||
return client.fetch(Post.class, postName)
|
return client.fetch(Post.class, postName)
|
||||||
.map(post -> post.getSpec().getReleaseSnapshot())
|
.map(post -> post.getSpec().getReleaseSnapshot())
|
||||||
.flatMap(contentService::getContent)
|
.flatMap(contentService::getContent)
|
||||||
.map(wrapper -> ContentVo.builder().content(wrapper.getContent())
|
.map(wrapper -> ContentVo.builder().content(wrapper.getContent())
|
||||||
.raw(wrapper.getRaw()).build())
|
.raw(wrapper.getRaw()).build());
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public NavigationPostVo cursor(String currentName) {
|
public Mono<NavigationPostVo> cursor(String currentName) {
|
||||||
// TODO Optimize the post names query here
|
// TODO Optimize the post names query here
|
||||||
List<String> postNames = client.list(Post.class, FIXED_PREDICATE, defaultComparator())
|
return client.list(Post.class, FIXED_PREDICATE, defaultComparator())
|
||||||
.map(post -> post.getMetadata().getName())
|
.map(post -> post.getMetadata().getName())
|
||||||
.collectList()
|
.collectList()
|
||||||
.block();
|
.flatMap(postNames -> Mono.just(NavigationPostVo.builder())
|
||||||
if (postNames == null) {
|
.flatMap(builder -> getByName(currentName)
|
||||||
return NavigationPostVo.empty();
|
.doOnNext(builder::current)
|
||||||
}
|
.thenReturn(builder)
|
||||||
|
)
|
||||||
NavigationPostVo.NavigationPostVoBuilder builder = NavigationPostVo.builder()
|
.flatMap(builder -> {
|
||||||
.current(getByName(currentName));
|
Pair<String, String> previousNextPair =
|
||||||
|
postPreviousNextPair(postNames, currentName);
|
||||||
Pair<String, String> previousNextPair = postPreviousNextPair(postNames, currentName);
|
String previousPostName = previousNextPair.getLeft();
|
||||||
String previousPostName = previousNextPair.getLeft();
|
String nextPostName = previousNextPair.getRight();
|
||||||
String nextPostName = previousNextPair.getRight();
|
return getByName(previousPostName)
|
||||||
|
.doOnNext(builder::previous)
|
||||||
if (previousPostName != null) {
|
.then(getByName(nextPostName))
|
||||||
builder.previous(getByName(previousPostName));
|
.doOnNext(builder::next)
|
||||||
}
|
.thenReturn(builder);
|
||||||
|
})
|
||||||
if (nextPostName != null) {
|
.map(NavigationPostVo.NavigationPostVoBuilder::build))
|
||||||
builder.next(getByName(nextPostName));
|
.defaultIfEmpty(NavigationPostVo.empty());
|
||||||
}
|
|
||||||
return builder.build();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static Pair<String, String> postPreviousNextPair(List<String> postNames,
|
static Pair<String, String> postPreviousNextPair(List<String> postNames,
|
||||||
|
@ -201,36 +198,37 @@ public class PostFinderImpl implements PostFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<PostVo> list(Integer page, Integer size) {
|
public Mono<ListResult<ListedPostVo>> list(Integer page, Integer size) {
|
||||||
return listPost(page, size, null, defaultComparator());
|
return listPost(page, size, null, defaultComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<PostVo> listByCategory(Integer page, Integer size, String categoryName) {
|
public Mono<ListResult<ListedPostVo>> listByCategory(Integer page, Integer size,
|
||||||
|
String categoryName) {
|
||||||
return listPost(page, size,
|
return listPost(page, size,
|
||||||
post -> contains(post.getSpec().getCategories(), categoryName), defaultComparator());
|
post -> contains(post.getSpec().getCategories(), categoryName), defaultComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<PostVo> listByTag(Integer page, Integer size, String tag) {
|
public Mono<ListResult<ListedPostVo>> listByTag(Integer page, Integer size, String tag) {
|
||||||
return listPost(page, size,
|
return listPost(page, size,
|
||||||
post -> contains(post.getSpec().getTags(), tag), defaultComparator());
|
post -> contains(post.getSpec().getTags(), tag), defaultComparator());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<PostArchiveVo> archives(Integer page, Integer size) {
|
public Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size) {
|
||||||
return archives(page, size, null, null);
|
return archives(page, size, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<PostArchiveVo> archives(Integer page, Integer size, String year) {
|
public Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size, String year) {
|
||||||
return archives(page, size, year, null);
|
return archives(page, size, year, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<PostArchiveVo> archives(Integer page, Integer size, String year,
|
public Mono<ListResult<PostArchiveVo>> archives(Integer page, Integer size, String year,
|
||||||
String month) {
|
String month) {
|
||||||
ListResult<PostVo> list = listPost(page, size, post -> {
|
return listPost(page, size, post -> {
|
||||||
Map<String, String> labels = post.getMetadata().getLabels();
|
Map<String, String> labels = post.getMetadata().getLabels();
|
||||||
if (labels == null) {
|
if (labels == null) {
|
||||||
return false;
|
return false;
|
||||||
|
@ -240,34 +238,37 @@ public class PostFinderImpl implements PostFinder {
|
||||||
boolean monthMatch = StringUtils.isBlank(month)
|
boolean monthMatch = StringUtils.isBlank(month)
|
||||||
|| month.equals(labels.get(Post.ARCHIVE_MONTH_LABEL));
|
|| month.equals(labels.get(Post.ARCHIVE_MONTH_LABEL));
|
||||||
return yearMatch && monthMatch;
|
return yearMatch && monthMatch;
|
||||||
}, archiveComparator());
|
}, archiveComparator())
|
||||||
|
.map(list -> {
|
||||||
Map<String, List<PostVo>> yearPosts = list.get()
|
Map<String, List<ListedPostVo>> yearPosts = list.get()
|
||||||
.collect(Collectors.groupingBy(
|
|
||||||
post -> HaloUtils.getYearText(post.getSpec().getPublishTime())));
|
|
||||||
List<PostArchiveVo> postArchives =
|
|
||||||
yearPosts.entrySet().stream().map(entry -> {
|
|
||||||
String key = entry.getKey();
|
|
||||||
// archives by month
|
|
||||||
Map<String, List<PostVo>> monthPosts = entry.getValue().stream()
|
|
||||||
.collect(Collectors.groupingBy(
|
.collect(Collectors.groupingBy(
|
||||||
post -> HaloUtils.getMonthText(post.getSpec().getPublishTime())));
|
post -> HaloUtils.getYearText(post.getSpec().getPublishTime())));
|
||||||
// convert to archive year month value objects
|
List<PostArchiveVo> postArchives =
|
||||||
List<PostArchiveYearMonthVo> monthArchives = monthPosts.entrySet()
|
yearPosts.entrySet().stream().map(entry -> {
|
||||||
.stream()
|
String key = entry.getKey();
|
||||||
.sorted(Map.Entry.comparingByKey())
|
// archives by month
|
||||||
.map(monthEntry -> PostArchiveYearMonthVo.builder()
|
Map<String, List<ListedPostVo>> monthPosts = entry.getValue().stream()
|
||||||
.posts(monthEntry.getValue())
|
.collect(Collectors.groupingBy(
|
||||||
.month(monthEntry.getKey())
|
post -> HaloUtils.getMonthText(post.getSpec().getPublishTime())));
|
||||||
.build()
|
// convert to archive year month value objects
|
||||||
)
|
List<PostArchiveYearMonthVo> monthArchives = monthPosts.entrySet()
|
||||||
.toList();
|
.stream()
|
||||||
return PostArchiveVo.builder()
|
.sorted(Map.Entry.comparingByKey())
|
||||||
.year(String.valueOf(key))
|
.map(monthEntry -> PostArchiveYearMonthVo.builder()
|
||||||
.months(monthArchives)
|
.posts(monthEntry.getValue())
|
||||||
.build();
|
.month(monthEntry.getKey())
|
||||||
}).toList();
|
.build()
|
||||||
return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), postArchives);
|
)
|
||||||
|
.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<String> c, String key) {
|
private boolean contains(List<String> c, String key) {
|
||||||
|
@ -277,24 +278,29 @@ public class PostFinderImpl implements PostFinder {
|
||||||
return c.contains(key);
|
return c.contains(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ListResult<PostVo> listPost(Integer page, Integer size, Predicate<Post> postPredicate,
|
private Mono<ListResult<ListedPostVo>> listPost(Integer page, Integer size,
|
||||||
|
Predicate<Post> postPredicate,
|
||||||
Comparator<Post> comparator) {
|
Comparator<Post> comparator) {
|
||||||
Predicate<Post> predicate = FIXED_PREDICATE
|
Predicate<Post> predicate = FIXED_PREDICATE
|
||||||
.and(postPredicate == null ? post -> true : postPredicate);
|
.and(postPredicate == null ? post -> true : postPredicate);
|
||||||
ListResult<Post> list = client.list(Post.class, predicate,
|
return client.list(Post.class, predicate,
|
||||||
comparator, pageNullSafe(page), sizeNullSafe(size))
|
comparator, pageNullSafe(page), sizeNullSafe(size))
|
||||||
.block();
|
.flatMap(list -> Flux.fromStream(list.get())
|
||||||
if (list == null) {
|
.flatMap(post -> getListedPostVo(post)
|
||||||
return new ListResult<>(List.of());
|
.map(postVo -> {
|
||||||
}
|
populateStats(postVo);
|
||||||
List<PostVo> postVos = list.get()
|
return postVo;
|
||||||
.map(this::getPostVo)
|
})
|
||||||
.peek(this::populateStats)
|
)
|
||||||
.toList();
|
.collectList()
|
||||||
return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), postVos);
|
.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 <T extends ListedPostVo> void populateStats(T postVo) {
|
||||||
Counter counter =
|
Counter counter =
|
||||||
counterService.getByName(MeterUtils.nameOf(Post.class, postVo.getMetadata()
|
counterService.getByName(MeterUtils.nameOf(Post.class, postVo.getMetadata()
|
||||||
.getName()));
|
.getName()));
|
||||||
|
@ -306,18 +312,45 @@ public class PostFinderImpl implements PostFinder {
|
||||||
postVo.setStats(statsVo);
|
postVo.setStats(statsVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PostVo getPostVo(@NonNull Post post) {
|
private Mono<ListedPostVo> getListedPostVo(@NonNull Post post) {
|
||||||
List<TagVo> tags = tagFinder.getByNames(post.getSpec().getTags());
|
ListedPostVo postVo = ListedPostVo.from(post);
|
||||||
List<CategoryVo> categoryVos = categoryFinder.getByNames(post.getSpec().getCategories());
|
postVo.setCategories(List.of());
|
||||||
List<Contributor> contributors =
|
postVo.setTags(List.of());
|
||||||
contributorFinder.getContributors(post.getStatus().getContributors());
|
postVo.setContributors(List.of());
|
||||||
PostVo postVo = PostVo.from(post);
|
|
||||||
postVo.setCategories(categoryVos);
|
|
||||||
postVo.setTags(tags);
|
|
||||||
postVo.setContributors(contributors);
|
|
||||||
postVo.setOwner(contributorFinder.getContributor(post.getSpec().getOwner()));
|
|
||||||
populateStats(postVo);
|
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<String> 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<String> 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<Post> defaultComparator() {
|
static Comparator<Post> defaultComparator() {
|
||||||
|
|
|
@ -7,6 +7,9 @@ import java.util.Objects;
|
||||||
import java.util.function.Function;
|
import java.util.function.Function;
|
||||||
import java.util.function.Predicate;
|
import java.util.function.Predicate;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
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.content.ContentService;
|
||||||
import run.halo.app.core.extension.Counter;
|
import run.halo.app.core.extension.Counter;
|
||||||
import run.halo.app.core.extension.Post;
|
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.Finder;
|
||||||
import run.halo.app.theme.finders.SinglePageFinder;
|
import run.halo.app.theme.finders.SinglePageFinder;
|
||||||
import run.halo.app.theme.finders.vo.ContentVo;
|
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.SinglePageVo;
|
||||||
import run.halo.app.theme.finders.vo.StatsVo;
|
import run.halo.app.theme.finders.vo.StatsVo;
|
||||||
|
|
||||||
|
@ -53,54 +56,56 @@ public class SinglePageFinderImpl implements SinglePageFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SinglePageVo getByName(String pageName) {
|
public Mono<SinglePageVo> getByName(String pageName) {
|
||||||
SinglePage page = client.fetch(SinglePage.class, pageName)
|
return client.fetch(SinglePage.class, pageName)
|
||||||
.block();
|
.map(page -> {
|
||||||
if (page == null) {
|
SinglePageVo pageVo = SinglePageVo.from(page);
|
||||||
return null;
|
pageVo.setContributors(List.of());
|
||||||
}
|
pageVo.setContent(ContentVo.empty());
|
||||||
List<Contributor> contributors =
|
populateStats(pageVo);
|
||||||
contributorFinder.getContributors(page.getStatus().getContributors());
|
return pageVo;
|
||||||
SinglePageVo pageVo = SinglePageVo.from(page);
|
})
|
||||||
pageVo.setContributors(contributors);
|
.flatMap(this::populateContributors)
|
||||||
pageVo.setContent(content(pageName));
|
.flatMap(page -> content(pageName)
|
||||||
pageVo.setOwner(contributorFinder.getContributor(page.getSpec().getOwner()));
|
.doOnNext(page::setContent)
|
||||||
populateStats(pageVo);
|
.thenReturn(page)
|
||||||
return pageVo;
|
)
|
||||||
|
.flatMap(page -> contributorFinder.getContributor(page.getSpec().getOwner())
|
||||||
|
.doOnNext(page::setOwner)
|
||||||
|
.thenReturn(page)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ContentVo content(String pageName) {
|
public Mono<ContentVo> content(String pageName) {
|
||||||
return client.fetch(SinglePage.class, pageName)
|
return client.fetch(SinglePage.class, pageName)
|
||||||
.map(page -> page.getSpec().getReleaseSnapshot())
|
.map(page -> page.getSpec().getReleaseSnapshot())
|
||||||
.flatMap(contentService::getContent)
|
.flatMap(contentService::getContent)
|
||||||
.map(wrapper -> ContentVo.builder().content(wrapper.getContent())
|
.map(wrapper -> ContentVo.builder().content(wrapper.getContent())
|
||||||
.raw(wrapper.getRaw()).build())
|
.raw(wrapper.getRaw()).build());
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<SinglePageVo> list(Integer page, Integer size) {
|
public Mono<ListResult<ListedSinglePageVo>> list(Integer page, Integer size) {
|
||||||
ListResult<SinglePage> list = client.list(SinglePage.class, FIXED_PREDICATE,
|
return client.list(SinglePage.class, FIXED_PREDICATE,
|
||||||
defaultComparator(), pageNullSafe(page), sizeNullSafe(size))
|
defaultComparator(), pageNullSafe(page), sizeNullSafe(size))
|
||||||
.block();
|
.flatMap(list -> Flux.fromStream(list.get())
|
||||||
if (list == null) {
|
.map(singlePage -> {
|
||||||
return new ListResult<>(0, 0, 0, List.of());
|
ListedSinglePageVo pageVo = ListedSinglePageVo.from(singlePage);
|
||||||
}
|
pageVo.setContributors(List.of());
|
||||||
List<SinglePageVo> pageVos = list.get()
|
populateStats(pageVo);
|
||||||
.map(sp -> {
|
return pageVo;
|
||||||
List<Contributor> contributors =
|
})
|
||||||
contributorFinder.getContributors(sp.getStatus().getContributors());
|
.flatMap(this::populateContributors)
|
||||||
SinglePageVo pageVo = SinglePageVo.from(sp);
|
.collectList()
|
||||||
pageVo.setContributors(contributors);
|
.map(pageVos -> new ListResult<>(list.getPage(), list.getSize(), list.getTotal(),
|
||||||
populateStats(pageVo);
|
pageVos)
|
||||||
return pageVo;
|
)
|
||||||
})
|
)
|
||||||
.toList();
|
.defaultIfEmpty(new ListResult<>(0, 0, 0, List.of()));
|
||||||
return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), pageVos);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void populateStats(SinglePageVo pageVo) {
|
<T extends ListedSinglePageVo> void populateStats(T pageVo) {
|
||||||
String name = pageVo.getMetadata().getName();
|
String name = pageVo.getMetadata().getName();
|
||||||
Counter counter =
|
Counter counter =
|
||||||
counterService.getByName(MeterUtils.nameOf(SinglePage.class, name));
|
counterService.getByName(MeterUtils.nameOf(SinglePage.class, name));
|
||||||
|
@ -112,6 +117,17 @@ public class SinglePageFinderImpl implements SinglePageFinder {
|
||||||
pageVo.setStats(statsVo);
|
pageVo.setStats(statsVo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
<T extends ListedSinglePageVo> Mono<T> populateContributors(T pageVo) {
|
||||||
|
List<String> names = pageVo.getStatus().getContributors();
|
||||||
|
if (CollectionUtils.isEmpty(names)) {
|
||||||
|
return Mono.just(pageVo);
|
||||||
|
}
|
||||||
|
return contributorFinder.getContributors(names)
|
||||||
|
.collectList()
|
||||||
|
.doOnNext(pageVo::setContributors)
|
||||||
|
.thenReturn(pageVo);
|
||||||
|
}
|
||||||
|
|
||||||
static Comparator<SinglePage> defaultComparator() {
|
static Comparator<SinglePage> defaultComparator() {
|
||||||
Function<SinglePage, Boolean> pinned =
|
Function<SinglePage, Boolean> pinned =
|
||||||
page -> Objects.requireNonNullElse(page.getSpec().getPinned(), false);
|
page -> Objects.requireNonNullElse(page.getSpec().getPinned(), false);
|
||||||
|
|
|
@ -22,7 +22,7 @@ public class SiteStatsFinderImpl implements SiteStatsFinder {
|
||||||
private final ReactiveExtensionClient client;
|
private final ReactiveExtensionClient client;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public SiteStatsVo getStats() {
|
public Mono<SiteStatsVo> getStats() {
|
||||||
return client.list(Counter.class, null, null)
|
return client.list(Counter.class, null, null)
|
||||||
.reduce(SiteStatsVo.empty(), (stats, counter) -> {
|
.reduce(SiteStatsVo.empty(), (stats, counter) -> {
|
||||||
stats.setVisit(stats.getVisit() + counter.getVisit());
|
stats.setVisit(stats.getVisit() + counter.getVisit());
|
||||||
|
@ -36,8 +36,7 @@ public class SiteStatsFinderImpl implements SiteStatsFinder {
|
||||||
)
|
)
|
||||||
.flatMap(siteStatsVo -> categoryCount()
|
.flatMap(siteStatsVo -> categoryCount()
|
||||||
.doOnNext(siteStatsVo::setCategory)
|
.doOnNext(siteStatsVo::setCategory)
|
||||||
.thenReturn(siteStatsVo))
|
.thenReturn(siteStatsVo));
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<Integer> postCount() {
|
Mono<Integer> postCount() {
|
||||||
|
|
|
@ -2,9 +2,10 @@ package run.halo.app.theme.finders.impl;
|
||||||
|
|
||||||
import java.util.Comparator;
|
import java.util.Comparator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import org.apache.commons.lang3.ObjectUtils;
|
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.core.extension.Tag;
|
||||||
import run.halo.app.extension.ListResult;
|
import run.halo.app.extension.ListResult;
|
||||||
import run.halo.app.extension.ReactiveExtensionClient;
|
import run.halo.app.extension.ReactiveExtensionClient;
|
||||||
|
@ -31,21 +32,19 @@ public class TagFinderImpl implements TagFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TagVo getByName(String name) {
|
public Mono<TagVo> getByName(String name) {
|
||||||
return client.fetch(Tag.class, name)
|
return client.fetch(Tag.class, name)
|
||||||
.map(TagVo::from)
|
.map(TagVo::from);
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TagVo> getByNames(List<String> names) {
|
public Flux<TagVo> getByNames(List<String> names) {
|
||||||
return names.stream().map(this::getByName)
|
return Flux.fromIterable(names)
|
||||||
.filter(Objects::nonNull)
|
.flatMap(this::getByName);
|
||||||
.toList();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ListResult<TagVo> list(Integer page, Integer size) {
|
public Mono<ListResult<TagVo>> list(Integer page, Integer size) {
|
||||||
return client.list(Tag.class, null,
|
return client.list(Tag.class, null,
|
||||||
DEFAULT_COMPARATOR.reversed(), pageNullSafe(page), sizeNullSafe(size))
|
DEFAULT_COMPARATOR.reversed(), pageNullSafe(page), sizeNullSafe(size))
|
||||||
.map(list -> {
|
.map(list -> {
|
||||||
|
@ -54,16 +53,14 @@ public class TagFinderImpl implements TagFinder {
|
||||||
.collect(Collectors.toList());
|
.collect(Collectors.toList());
|
||||||
return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), tagVos);
|
return new ListResult<>(list.getPage(), list.getSize(), list.getTotal(), tagVos);
|
||||||
})
|
})
|
||||||
.block();
|
.defaultIfEmpty(new ListResult<>(page, size, 0L, List.of()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<TagVo> listAll() {
|
public Flux<TagVo> listAll() {
|
||||||
return client.list(Tag.class, null,
|
return client.list(Tag.class, null,
|
||||||
DEFAULT_COMPARATOR.reversed())
|
DEFAULT_COMPARATOR.reversed())
|
||||||
.map(TagVo::from)
|
.map(TagVo::from);
|
||||||
.collectList()
|
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int pageNullSafe(Integer page) {
|
int pageNullSafe(Integer page) {
|
||||||
|
|
|
@ -34,19 +34,17 @@ public class ThemeFinderImpl implements ThemeFinder {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ThemeVo activation() {
|
public Mono<ThemeVo> activation() {
|
||||||
return environmentFetcher.fetch(SystemSetting.Theme.GROUP, SystemSetting.Theme.class)
|
return environmentFetcher.fetch(SystemSetting.Theme.GROUP, SystemSetting.Theme.class)
|
||||||
.map(SystemSetting.Theme::getActive)
|
.map(SystemSetting.Theme::getActive)
|
||||||
.flatMap(themeName -> client.fetch(Theme.class, themeName))
|
.flatMap(themeName -> client.fetch(Theme.class, themeName))
|
||||||
.flatMap(theme -> themeWithConfig(ThemeVo.from(theme)))
|
.flatMap(theme -> themeWithConfig(ThemeVo.from(theme)));
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ThemeVo getByName(String themeName) {
|
public Mono<ThemeVo> getByName(String themeName) {
|
||||||
return client.fetch(Theme.class, themeName)
|
return client.fetch(Theme.class, themeName)
|
||||||
.flatMap(theme -> themeWithConfig(ThemeVo.from(theme)))
|
.flatMap(theme -> themeWithConfig(ThemeVo.from(theme)));
|
||||||
.block();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ThemeVo> themeWithConfig(ThemeVo themeVo) {
|
private Mono<ThemeVo> themeWithConfig(ThemeVo themeVo) {
|
||||||
|
@ -63,6 +61,6 @@ public class ThemeFinderImpl implements ThemeFinder {
|
||||||
JsonNode configJson = JsonUtils.mapToObject(config, JsonNode.class);
|
JsonNode configJson = JsonUtils.mapToObject(config, JsonNode.class);
|
||||||
return themeVo.withConfig(configJson);
|
return themeVo.withConfig(configJson);
|
||||||
})
|
})
|
||||||
.switchIfEmpty(Mono.just(themeVo));
|
.defaultIfEmpty(themeVo);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,4 +19,14 @@ public class ContentVo {
|
||||||
String raw;
|
String raw;
|
||||||
|
|
||||||
String content;
|
String content;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Empty content object.
|
||||||
|
*/
|
||||||
|
public static ContentVo empty() {
|
||||||
|
return ContentVo.builder()
|
||||||
|
.raw("")
|
||||||
|
.content("")
|
||||||
|
.build();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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<CategoryVo> categories;
|
||||||
|
|
||||||
|
private List<TagVo> tags;
|
||||||
|
|
||||||
|
private List<Contributor> 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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<Contributor> 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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,5 +16,5 @@ public class PostArchiveYearMonthVo {
|
||||||
|
|
||||||
String month;
|
String month;
|
||||||
|
|
||||||
List<PostVo> posts;
|
List<ListedPostVo> posts;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package run.halo.app.theme.finders.vo;
|
package run.halo.app.theme.finders.vo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import run.halo.app.core.extension.Post;
|
import run.halo.app.core.extension.Post;
|
||||||
import run.halo.app.extension.MetadataOperator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A value object for {@link Post}.
|
* A value object for {@link Post}.
|
||||||
|
@ -16,29 +15,13 @@ import run.halo.app.extension.MetadataOperator;
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@SuperBuilder
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class PostVo {
|
public class PostVo extends ListedPostVo {
|
||||||
|
|
||||||
private MetadataOperator metadata;
|
|
||||||
|
|
||||||
private Post.PostSpec spec;
|
|
||||||
|
|
||||||
private Post.PostStatus status;
|
|
||||||
|
|
||||||
private ContentVo content;
|
private ContentVo content;
|
||||||
|
|
||||||
private List<CategoryVo> categories;
|
|
||||||
|
|
||||||
private List<TagVo> tags;
|
|
||||||
|
|
||||||
private List<Contributor> contributors;
|
|
||||||
|
|
||||||
private Contributor owner;
|
|
||||||
|
|
||||||
private StatsVo stats;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert {@link Post} to {@link PostVo}.
|
* Convert {@link Post} to {@link PostVo}.
|
||||||
*
|
*
|
||||||
|
@ -59,4 +42,21 @@ public class PostVo {
|
||||||
.content(new ContentVo(null, null))
|
.content(new ContentVo(null, null))
|
||||||
.build();
|
.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();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
package run.halo.app.theme.finders.vo;
|
package run.halo.app.theme.finders.vo;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import lombok.Builder;
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import run.halo.app.core.extension.SinglePage;
|
import run.halo.app.core.extension.SinglePage;
|
||||||
import run.halo.app.extension.MetadataOperator;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A value object for {@link SinglePage}.
|
* A value object for {@link SinglePage}.
|
||||||
|
@ -16,25 +15,13 @@ import run.halo.app.extension.MetadataOperator;
|
||||||
* @since 2.0.0
|
* @since 2.0.0
|
||||||
*/
|
*/
|
||||||
@Data
|
@Data
|
||||||
@Builder
|
@SuperBuilder
|
||||||
@ToString
|
@ToString
|
||||||
@EqualsAndHashCode
|
@EqualsAndHashCode(callSuper = true)
|
||||||
public class SinglePageVo {
|
public class SinglePageVo extends ListedSinglePageVo {
|
||||||
|
|
||||||
private MetadataOperator metadata;
|
|
||||||
|
|
||||||
private SinglePage.SinglePageSpec spec;
|
|
||||||
|
|
||||||
private SinglePage.SinglePageStatus status;
|
|
||||||
|
|
||||||
private ContentVo content;
|
private ContentVo content;
|
||||||
|
|
||||||
private StatsVo stats;
|
|
||||||
|
|
||||||
private List<Contributor> contributors;
|
|
||||||
|
|
||||||
private Contributor owner;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Convert {@link SinglePage} to {@link SinglePageVo}.
|
* Convert {@link SinglePage} to {@link SinglePageVo}.
|
||||||
*
|
*
|
||||||
|
|
|
@ -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.ServerRequest;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import reactor.core.publisher.Mono;
|
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.SystemConfigurableEnvironmentFetcher;
|
||||||
import run.halo.app.infra.utils.PathUtils;
|
import run.halo.app.infra.utils.PathUtils;
|
||||||
import run.halo.app.theme.DefaultTemplateEnum;
|
import run.halo.app.theme.DefaultTemplateEnum;
|
||||||
|
@ -47,7 +45,7 @@ public class ArchivesRouteStrategy implements ListPageRouteHandlerStrategy {
|
||||||
String path = request.path();
|
String path = request.path();
|
||||||
return environmentFetcher.fetchPost()
|
return environmentFetcher.fetchPost()
|
||||||
.map(postSetting -> defaultIfNull(postSetting.getArchivePageSize(), DEFAULT_PAGE_SIZE))
|
.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<PostArchiveVo>()
|
.map(list -> new UrlContextListResult.Builder<PostArchiveVo>()
|
||||||
.listResult(list)
|
.listResult(list)
|
||||||
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
||||||
|
@ -55,11 +53,6 @@ public class ArchivesRouteStrategy implements ListPageRouteHandlerStrategy {
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
Mono<ListResult<PostArchiveVo>> 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) {
|
private String pathVariable(ServerRequest request, String name) {
|
||||||
Map<String, String> pathVariables = request.pathVariables();
|
Map<String, String> pathVariables = request.pathVariables();
|
||||||
if (pathVariables.containsKey(name)) {
|
if (pathVariables.containsKey(name)) {
|
||||||
|
|
|
@ -7,11 +7,8 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
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.DefaultTemplateEnum;
|
||||||
import run.halo.app.theme.finders.CategoryFinder;
|
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
|
* 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 {
|
public class CategoriesRouteStrategy implements ListPageRouteHandlerStrategy {
|
||||||
private final CategoryFinder categoryFinder;
|
private final CategoryFinder categoryFinder;
|
||||||
|
|
||||||
private Mono<List<CategoryTreeVo>> categories() {
|
|
||||||
return Mono.defer(() -> Mono.just(categoryFinder.listAsTree()))
|
|
||||||
.publishOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HandlerFunction<ServerResponse> getHandler() {
|
public HandlerFunction<ServerResponse> getHandler() {
|
||||||
return request -> ServerResponse.ok()
|
return request -> ServerResponse.ok()
|
||||||
.render(DefaultTemplateEnum.CATEGORIES.getValue(),
|
.render(DefaultTemplateEnum.CATEGORIES.getValue(),
|
||||||
Map.of("categories", categories(),
|
Map.of("categories", categoryFinder.listAsTree(),
|
||||||
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.CATEGORIES.getValue()));
|
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.CATEGORIES.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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.ServerRequest;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.core.scheduler.Schedulers;
|
|
||||||
import run.halo.app.core.extension.Category;
|
import run.halo.app.core.extension.Category;
|
||||||
import run.halo.app.extension.GroupVersionKind;
|
import run.halo.app.extension.GroupVersionKind;
|
||||||
import run.halo.app.extension.ListResult;
|
|
||||||
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
|
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
|
||||||
import run.halo.app.infra.SystemSetting;
|
import run.halo.app.infra.SystemSetting;
|
||||||
import run.halo.app.theme.DefaultTemplateEnum;
|
import run.halo.app.theme.DefaultTemplateEnum;
|
||||||
import run.halo.app.theme.finders.CategoryFinder;
|
import run.halo.app.theme.finders.CategoryFinder;
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
import run.halo.app.theme.finders.PostFinder;
|
||||||
import run.halo.app.theme.finders.vo.CategoryVo;
|
import run.halo.app.theme.finders.vo.ListedPostVo;
|
||||||
import run.halo.app.theme.finders.vo.PostVo;
|
|
||||||
import run.halo.app.theme.router.PageUrlUtils;
|
import run.halo.app.theme.router.PageUrlUtils;
|
||||||
import run.halo.app.theme.router.UrlContextListResult;
|
import run.halo.app.theme.router.UrlContextListResult;
|
||||||
import run.halo.app.theme.router.ViewNameResolver;
|
import run.halo.app.theme.router.ViewNameResolver;
|
||||||
|
@ -46,29 +43,20 @@ public class CategoryRouteStrategy implements DetailsPageRouteHandlerStrategy {
|
||||||
|
|
||||||
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
||||||
|
|
||||||
private Mono<UrlContextListResult<PostVo>> postListByCategoryName(String name,
|
private Mono<UrlContextListResult<ListedPostVo>> postListByCategoryName(String name,
|
||||||
ServerRequest request) {
|
ServerRequest request) {
|
||||||
String path = request.path();
|
String path = request.path();
|
||||||
return environmentFetcher.fetchPost()
|
return environmentFetcher.fetchPost()
|
||||||
.map(post -> defaultIfNull(post.getCategoryPageSize(), ModelConst.DEFAULT_PAGE_SIZE))
|
.map(post -> defaultIfNull(post.getCategoryPageSize(), ModelConst.DEFAULT_PAGE_SIZE))
|
||||||
.flatMap(pageSize -> listPostsByCategory(pageNum(request), pageSize, name))
|
.flatMap(
|
||||||
.map(list -> new UrlContextListResult.Builder<PostVo>()
|
pageSize -> postFinder.listByCategory(pageNum(request), pageSize, name))
|
||||||
|
.map(list -> new UrlContextListResult.Builder<ListedPostVo>()
|
||||||
.listResult(list)
|
.listResult(list)
|
||||||
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
||||||
.prevUrl(PageUrlUtils.prevPageUrl(path))
|
.prevUrl(PageUrlUtils.prevPageUrl(path))
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<CategoryVo> categoryByName(String name) {
|
|
||||||
return Mono.fromCallable(() -> categoryFinder.getByName(name))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mono<ListResult<PostVo>> listPostsByCategory(int page, int size, String categoryName) {
|
|
||||||
return Mono.fromCallable(() -> postFinder.listByCategory(page, size, categoryName))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HandlerFunction<ServerResponse> getHandler(SystemSetting.ThemeRouteRules routeRules,
|
public HandlerFunction<ServerResponse> getHandler(SystemSetting.ThemeRouteRules routeRules,
|
||||||
String name) {
|
String name) {
|
||||||
|
@ -78,7 +66,7 @@ public class CategoryRouteStrategy implements DetailsPageRouteHandlerStrategy {
|
||||||
model.put("posts", postListByCategoryName(name, request));
|
model.put("posts", postListByCategoryName(name, request));
|
||||||
|
|
||||||
model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.CATEGORY.getValue());
|
model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.CATEGORY.getValue());
|
||||||
return categoryByName(name).flatMap(categoryVo -> {
|
return categoryFinder.getByName(name).flatMap(categoryVo -> {
|
||||||
model.put("category", categoryVo);
|
model.put("category", categoryVo);
|
||||||
String template = categoryVo.getSpec().getTemplate();
|
String template = categoryVo.getSpec().getTemplate();
|
||||||
return viewNameResolver.resolveViewNameOrDefault(request, template,
|
return viewNameResolver.resolveViewNameOrDefault(request, template,
|
||||||
|
|
|
@ -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.ServerRequest;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import reactor.core.publisher.Mono;
|
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.SystemConfigurableEnvironmentFetcher;
|
||||||
import run.halo.app.theme.DefaultTemplateEnum;
|
import run.halo.app.theme.DefaultTemplateEnum;
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
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.PageUrlUtils;
|
||||||
import run.halo.app.theme.router.UrlContextListResult;
|
import run.halo.app.theme.router.UrlContextListResult;
|
||||||
|
|
||||||
|
@ -36,23 +34,18 @@ public class IndexRouteStrategy implements ListPageRouteHandlerStrategy {
|
||||||
private final PostFinder postFinder;
|
private final PostFinder postFinder;
|
||||||
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
||||||
|
|
||||||
private Mono<UrlContextListResult<PostVo>> postList(ServerRequest request) {
|
private Mono<UrlContextListResult<ListedPostVo>> postList(ServerRequest request) {
|
||||||
String path = request.path();
|
String path = request.path();
|
||||||
return environmentFetcher.fetchPost()
|
return environmentFetcher.fetchPost()
|
||||||
.map(p -> defaultIfNull(p.getPostPageSize(), DEFAULT_PAGE_SIZE))
|
.map(p -> defaultIfNull(p.getPostPageSize(), DEFAULT_PAGE_SIZE))
|
||||||
.flatMap(pageSize -> listPost(pageNum(request), pageSize))
|
.flatMap(pageSize -> postFinder.list(pageNum(request), pageSize))
|
||||||
.map(list -> new UrlContextListResult.Builder<PostVo>()
|
.map(list -> new UrlContextListResult.Builder<ListedPostVo>()
|
||||||
.listResult(list)
|
.listResult(list)
|
||||||
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
||||||
.prevUrl(PageUrlUtils.prevPageUrl(path))
|
.prevUrl(PageUrlUtils.prevPageUrl(path))
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ListResult<PostVo>> listPost(int page, int size) {
|
|
||||||
return Mono.fromCallable(() -> postFinder.list(page, size))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HandlerFunction<ServerResponse> getHandler() {
|
public HandlerFunction<ServerResponse> getHandler() {
|
||||||
return request -> ServerResponse.ok()
|
return request -> ServerResponse.ok()
|
||||||
|
|
|
@ -8,15 +8,12 @@ import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import org.springframework.web.util.pattern.PathPattern;
|
import org.springframework.web.util.pattern.PathPattern;
|
||||||
import org.springframework.web.util.pattern.PathPatternParser;
|
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.core.extension.Post;
|
||||||
import run.halo.app.extension.GVK;
|
import run.halo.app.extension.GVK;
|
||||||
import run.halo.app.extension.GroupVersionKind;
|
import run.halo.app.extension.GroupVersionKind;
|
||||||
import run.halo.app.infra.SystemSetting;
|
import run.halo.app.infra.SystemSetting;
|
||||||
import run.halo.app.theme.DefaultTemplateEnum;
|
import run.halo.app.theme.DefaultTemplateEnum;
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
import run.halo.app.theme.finders.PostFinder;
|
||||||
import run.halo.app.theme.finders.vo.PostVo;
|
|
||||||
import run.halo.app.theme.router.ViewNameResolver;
|
import run.halo.app.theme.router.ViewNameResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -57,7 +54,7 @@ public class PostRouteStrategy implements DetailsPageRouteHandlerStrategy {
|
||||||
model.put("plural", gvk.plural());
|
model.put("plural", gvk.plural());
|
||||||
// used by TemplateGlobalHeadProcessor and PostTemplateHeadProcessor
|
// used by TemplateGlobalHeadProcessor and PostTemplateHeadProcessor
|
||||||
model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.POST.getValue());
|
model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.POST.getValue());
|
||||||
return postByName(name)
|
return postFinder.getByName(name)
|
||||||
.flatMap(postVo -> {
|
.flatMap(postVo -> {
|
||||||
model.put("post", postVo);
|
model.put("post", postVo);
|
||||||
String template = postVo.getSpec().getTemplate();
|
String template = postVo.getSpec().getTemplate();
|
||||||
|
@ -72,9 +69,4 @@ public class PostRouteStrategy implements DetailsPageRouteHandlerStrategy {
|
||||||
public boolean supports(GroupVersionKind gvk) {
|
public boolean supports(GroupVersionKind gvk) {
|
||||||
return groupVersionKind.equals(gvk);
|
return groupVersionKind.equals(gvk);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<PostVo> postByName(String name) {
|
|
||||||
return Mono.fromCallable(() -> postFinder.getByName(name))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,15 +5,12 @@ import java.util.Map;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
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.core.extension.SinglePage;
|
||||||
import run.halo.app.extension.GVK;
|
import run.halo.app.extension.GVK;
|
||||||
import run.halo.app.extension.GroupVersionKind;
|
import run.halo.app.extension.GroupVersionKind;
|
||||||
import run.halo.app.infra.SystemSetting;
|
import run.halo.app.infra.SystemSetting;
|
||||||
import run.halo.app.theme.DefaultTemplateEnum;
|
import run.halo.app.theme.DefaultTemplateEnum;
|
||||||
import run.halo.app.theme.finders.SinglePageFinder;
|
import run.halo.app.theme.finders.SinglePageFinder;
|
||||||
import run.halo.app.theme.finders.vo.SinglePageVo;
|
|
||||||
import run.halo.app.theme.router.ViewNameResolver;
|
import run.halo.app.theme.router.ViewNameResolver;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -40,11 +37,6 @@ public class SinglePageRouteStrategy implements DetailsPageRouteHandlerStrategy
|
||||||
return annotation.plural();
|
return annotation.plural();
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<SinglePageVo> singlePageByName(String name) {
|
|
||||||
return Mono.fromCallable(() -> singlePageFinder.getByName(name))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HandlerFunction<ServerResponse> getHandler(SystemSetting.ThemeRouteRules routeRules,
|
public HandlerFunction<ServerResponse> getHandler(SystemSetting.ThemeRouteRules routeRules,
|
||||||
String name) {
|
String name) {
|
||||||
|
@ -54,7 +46,7 @@ public class SinglePageRouteStrategy implements DetailsPageRouteHandlerStrategy
|
||||||
model.put("plural", getPlural());
|
model.put("plural", getPlural());
|
||||||
model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.SINGLE_PAGE.getValue());
|
model.put(ModelConst.TEMPLATE_ID, DefaultTemplateEnum.SINGLE_PAGE.getValue());
|
||||||
|
|
||||||
return singlePageByName(name).flatMap(singlePageVo -> {
|
return singlePageFinder.getByName(name).flatMap(singlePageVo -> {
|
||||||
model.put("singlePage", singlePageVo);
|
model.put("singlePage", singlePageVo);
|
||||||
String template = singlePageVo.getSpec().getTemplate();
|
String template = singlePageVo.getSpec().getTemplate();
|
||||||
return viewNameResolver.resolveViewNameOrDefault(request, template,
|
return viewNameResolver.resolveViewNameOrDefault(request, template,
|
||||||
|
|
|
@ -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.ServerRequest;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import reactor.core.scheduler.Schedulers;
|
|
||||||
import run.halo.app.core.extension.Tag;
|
import run.halo.app.core.extension.Tag;
|
||||||
import run.halo.app.extension.GroupVersionKind;
|
import run.halo.app.extension.GroupVersionKind;
|
||||||
import run.halo.app.extension.ListResult;
|
|
||||||
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
|
import run.halo.app.infra.SystemConfigurableEnvironmentFetcher;
|
||||||
import run.halo.app.infra.SystemSetting;
|
import run.halo.app.infra.SystemSetting;
|
||||||
import run.halo.app.theme.DefaultTemplateEnum;
|
import run.halo.app.theme.DefaultTemplateEnum;
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
import run.halo.app.theme.finders.PostFinder;
|
||||||
import run.halo.app.theme.finders.TagFinder;
|
import run.halo.app.theme.finders.TagFinder;
|
||||||
import run.halo.app.theme.finders.vo.PostVo;
|
import run.halo.app.theme.finders.vo.ListedPostVo;
|
||||||
import run.halo.app.theme.finders.vo.TagVo;
|
|
||||||
import run.halo.app.theme.router.PageUrlUtils;
|
import run.halo.app.theme.router.PageUrlUtils;
|
||||||
import run.halo.app.theme.router.UrlContextListResult;
|
import run.halo.app.theme.router.UrlContextListResult;
|
||||||
|
|
||||||
|
@ -43,28 +40,18 @@ public class TagRouteStrategy implements DetailsPageRouteHandlerStrategy {
|
||||||
|
|
||||||
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
private final SystemConfigurableEnvironmentFetcher environmentFetcher;
|
||||||
|
|
||||||
private Mono<UrlContextListResult<PostVo>> postList(ServerRequest request, String name) {
|
private Mono<UrlContextListResult<ListedPostVo>> postList(ServerRequest request, String name) {
|
||||||
String path = request.path();
|
String path = request.path();
|
||||||
return environmentFetcher.fetchPost()
|
return environmentFetcher.fetchPost()
|
||||||
.map(p -> defaultIfNull(p.getTagPageSize(), ModelConst.DEFAULT_PAGE_SIZE))
|
.map(p -> defaultIfNull(p.getTagPageSize(), ModelConst.DEFAULT_PAGE_SIZE))
|
||||||
.flatMap(pageSize -> listPostByTag(pageNum(request), pageSize, name))
|
.flatMap(pageSize -> postFinder.listByTag(pageNum(request), pageSize, name))
|
||||||
.map(list -> new UrlContextListResult.Builder<PostVo>()
|
.map(list -> new UrlContextListResult.Builder<ListedPostVo>()
|
||||||
.listResult(list)
|
.listResult(list)
|
||||||
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
.nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list)))
|
||||||
.prevUrl(PageUrlUtils.prevPageUrl(path))
|
.prevUrl(PageUrlUtils.prevPageUrl(path))
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<ListResult<PostVo>> listPostByTag(int page, int size, String name) {
|
|
||||||
return Mono.fromCallable(() -> postFinder.listByTag(page, size, name))
|
|
||||||
.subscribeOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
private Mono<TagVo> tagByName(String name) {
|
|
||||||
return Mono.defer(() -> Mono.just(tagFinder.getByName(name)))
|
|
||||||
.publishOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HandlerFunction<ServerResponse> getHandler(SystemSetting.ThemeRouteRules routeRules,
|
public HandlerFunction<ServerResponse> getHandler(SystemSetting.ThemeRouteRules routeRules,
|
||||||
String name) {
|
String name) {
|
||||||
|
@ -72,7 +59,7 @@ public class TagRouteStrategy implements DetailsPageRouteHandlerStrategy {
|
||||||
.render(DefaultTemplateEnum.TAG.getValue(),
|
.render(DefaultTemplateEnum.TAG.getValue(),
|
||||||
Map.of("name", name,
|
Map.of("name", name,
|
||||||
"posts", postList(request, name),
|
"posts", postList(request, name),
|
||||||
"tag", tagByName(name),
|
"tag", tagFinder.getByName(name),
|
||||||
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.TAG.getValue()
|
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.TAG.getValue()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -6,11 +6,8 @@ import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.web.reactive.function.server.HandlerFunction;
|
import org.springframework.web.reactive.function.server.HandlerFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
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.DefaultTemplateEnum;
|
||||||
import run.halo.app.theme.finders.TagFinder;
|
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
|
* The {@link TagsRouteStrategy} for generate {@link HandlerFunction} specific to the template
|
||||||
|
@ -28,16 +25,11 @@ public class TagsRouteStrategy implements ListPageRouteHandlerStrategy {
|
||||||
this.tagFinder = tagFinder;
|
this.tagFinder = tagFinder;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Mono<List<TagVo>> tags() {
|
|
||||||
return Mono.defer(() -> Mono.just(tagFinder.listAll()))
|
|
||||||
.publishOn(Schedulers.boundedElastic());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public HandlerFunction<ServerResponse> getHandler() {
|
public HandlerFunction<ServerResponse> getHandler() {
|
||||||
return request -> ServerResponse.ok()
|
return request -> ServerResponse.ok()
|
||||||
.render(DefaultTemplateEnum.TAGS.getValue(),
|
.render(DefaultTemplateEnum.TAGS.getValue(),
|
||||||
Map.of("tags", tags(),
|
Map.of("tags", tagFinder.listAll(),
|
||||||
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.TAGS.getValue()
|
ModelConst.TEMPLATE_ID, DefaultTemplateEnum.TAGS.getValue()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
|
@ -142,7 +142,7 @@ class HaloProcessorDialectTest {
|
||||||
PostVo postVo = PostVo.builder()
|
PostVo postVo = PostVo.builder()
|
||||||
.spec(postSpec)
|
.spec(postSpec)
|
||||||
.metadata(metadata).build();
|
.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();
|
SystemSetting.Basic basic = new SystemSetting.Basic();
|
||||||
basic.setFavicon(null);
|
basic.setFavicon(null);
|
||||||
|
|
|
@ -60,7 +60,7 @@ class CommentFinderEndpointTest {
|
||||||
@Test
|
@Test
|
||||||
void listComments() {
|
void listComments() {
|
||||||
when(commentFinder.list(any(), anyInt(), anyInt()))
|
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 ref = new Ref();
|
||||||
ref.setGroup("content.halo.run");
|
ref.setGroup("content.halo.run");
|
||||||
|
@ -104,15 +104,13 @@ class CommentFinderEndpointTest {
|
||||||
@Test
|
@Test
|
||||||
void listCommentReplies() {
|
void listCommentReplies() {
|
||||||
when(commentFinder.listReply(any(), anyInt(), anyInt()))
|
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()
|
webTestClient.get()
|
||||||
.uri(uriBuilder -> {
|
.uri(uriBuilder -> uriBuilder.path("/comments/test-comment/reply")
|
||||||
return uriBuilder.path("/comments/test-comment/reply")
|
.queryParam("page", 2)
|
||||||
.queryParam("page", 2)
|
.queryParam("size", 20)
|
||||||
.queryParam("size", 20)
|
.build())
|
||||||
.build();
|
|
||||||
})
|
|
||||||
.exchange()
|
.exchange()
|
||||||
.expectStatus()
|
.expectStatus()
|
||||||
.isOk();
|
.isOk();
|
||||||
|
|
|
@ -51,7 +51,7 @@ class CategoryFinderImplTest {
|
||||||
void getByName() throws JSONException {
|
void getByName() throws JSONException {
|
||||||
when(client.fetch(eq(Category.class), eq("hello")))
|
when(client.fetch(eq(Category.class), eq("hello")))
|
||||||
.thenReturn(Mono.just(category()));
|
.thenReturn(Mono.just(category()));
|
||||||
CategoryVo categoryVo = categoryFinder.getByName("hello");
|
CategoryVo categoryVo = categoryFinder.getByName("hello").block();
|
||||||
categoryVo.getMetadata().setCreationTimestamp(null);
|
categoryVo.getMetadata().setCreationTimestamp(null);
|
||||||
JSONAssert.assertEquals("""
|
JSONAssert.assertEquals("""
|
||||||
{
|
{
|
||||||
|
@ -87,7 +87,7 @@ class CategoryFinderImplTest {
|
||||||
.toList());
|
.toList());
|
||||||
when(client.list(eq(Category.class), eq(null), any(), anyInt(), anyInt()))
|
when(client.list(eq(Category.class), eq(null), any(), anyInt(), anyInt()))
|
||||||
.thenReturn(Mono.just(categories));
|
.thenReturn(Mono.just(categories));
|
||||||
ListResult<CategoryVo> list = categoryFinder.list(1, 10);
|
ListResult<CategoryVo> list = categoryFinder.list(1, 10).block();
|
||||||
assertThat(list.getItems()).hasSize(3);
|
assertThat(list.getItems()).hasSize(3);
|
||||||
assertThat(list.get().map(categoryVo -> categoryVo.getMetadata().getName()).toList())
|
assertThat(list.get().map(categoryVo -> categoryVo.getMetadata().getName()).toList())
|
||||||
.isEqualTo(List.of("c3", "c2", "hello"));
|
.isEqualTo(List.of("c3", "c2", "hello"));
|
||||||
|
@ -97,7 +97,7 @@ class CategoryFinderImplTest {
|
||||||
void listAsTree() {
|
void listAsTree() {
|
||||||
when(client.list(eq(Category.class), eq(null), any()))
|
when(client.list(eq(Category.class), eq(null), any()))
|
||||||
.thenReturn(Flux.fromIterable(categoriesForTree()));
|
.thenReturn(Flux.fromIterable(categoriesForTree()));
|
||||||
List<CategoryTreeVo> treeVos = categoryFinder.listAsTree();
|
List<CategoryTreeVo> treeVos = categoryFinder.listAsTree().collectList().block();
|
||||||
assertThat(treeVos).hasSize(1);
|
assertThat(treeVos).hasSize(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -110,7 +110,7 @@ class CategoryFinderImplTest {
|
||||||
void listAsTreeMore() {
|
void listAsTreeMore() {
|
||||||
when(client.list(eq(Category.class), eq(null), any()))
|
when(client.list(eq(Category.class), eq(null), any()))
|
||||||
.thenReturn(Flux.fromIterable(moreCategories()));
|
.thenReturn(Flux.fromIterable(moreCategories()));
|
||||||
List<CategoryTreeVo> treeVos = categoryFinder.listAsTree();
|
List<CategoryTreeVo> treeVos = categoryFinder.listAsTree().collectList().block();
|
||||||
String s = visualizeTree(treeVos);
|
String s = visualizeTree(treeVos);
|
||||||
assertThat(s).isEqualTo("""
|
assertThat(s).isEqualTo("""
|
||||||
全部 (5)
|
全部 (5)
|
||||||
|
|
|
@ -45,7 +45,7 @@ class MenuFinderImplTest {
|
||||||
Mockito.when(client.list(eq(MenuItem.class), eq(null), any()))
|
Mockito.when(client.list(eq(MenuItem.class), eq(null), any()))
|
||||||
.thenReturn(Flux.fromIterable(tuple.getT2()));
|
.thenReturn(Flux.fromIterable(tuple.getT2()));
|
||||||
|
|
||||||
List<MenuVo> menuVos = menuFinder.listAsTree();
|
List<MenuVo> menuVos = menuFinder.listAsTree().collectList().block();
|
||||||
assertThat(visualizeTree(menuVos)).isEqualTo("""
|
assertThat(visualizeTree(menuVos)).isEqualTo("""
|
||||||
D
|
D
|
||||||
└── E
|
└── E
|
||||||
|
|
|
@ -18,6 +18,7 @@ import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
import org.mockito.Mock;
|
import org.mockito.Mock;
|
||||||
import org.mockito.junit.jupiter.MockitoExtension;
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.content.ContentService;
|
import run.halo.app.content.ContentService;
|
||||||
import run.halo.app.content.ContentWrapper;
|
import run.halo.app.content.ContentWrapper;
|
||||||
|
@ -78,7 +79,7 @@ class PostFinderImplTest {
|
||||||
.thenReturn(Mono.just(post));
|
.thenReturn(Mono.just(post));
|
||||||
when(contentService.getContent(post.getSpec().getReleaseSnapshot()))
|
when(contentService.getContent(post.getSpec().getReleaseSnapshot()))
|
||||||
.thenReturn(Mono.just(contentWrapper));
|
.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.getContent()).isEqualTo(contentWrapper.getContent());
|
||||||
assertThat(content.getRaw()).isEqualTo(contentWrapper.getRaw());
|
assertThat(content.getRaw()).isEqualTo(contentWrapper.getRaw());
|
||||||
}
|
}
|
||||||
|
@ -108,7 +109,12 @@ class PostFinderImplTest {
|
||||||
ListResult<Post> listResult = new ListResult<>(1, 10, 3, postsForArchives());
|
ListResult<Post> listResult = new ListResult<>(1, 10, 3, postsForArchives());
|
||||||
when(client.list(eq(Post.class), any(), any(), anyInt(), anyInt()))
|
when(client.list(eq(Post.class), any(), any(), anyInt(), anyInt()))
|
||||||
.thenReturn(Mono.just(listResult));
|
.thenReturn(Mono.just(listResult));
|
||||||
ListResult<PostArchiveVo> archives = postFinder.archives(1, 10);
|
when(contributorFinder.getContributor(any())).thenReturn(Mono.empty());
|
||||||
|
when(contributorFinder.getContributors(any())).thenReturn(Flux.empty());
|
||||||
|
|
||||||
|
ListResult<PostArchiveVo> archives = postFinder.archives(1, 10).block();
|
||||||
|
assertThat(archives).isNotNull();
|
||||||
|
|
||||||
List<PostArchiveVo> items = archives.getItems();
|
List<PostArchiveVo> items = archives.getItems();
|
||||||
assertThat(items.size()).isEqualTo(2);
|
assertThat(items.size()).isEqualTo(2);
|
||||||
assertThat(items.get(0).getYear()).isEqualTo("2022");
|
assertThat(items.get(0).getYear()).isEqualTo("2022");
|
||||||
|
|
|
@ -47,7 +47,7 @@ class TagFinderImplTest {
|
||||||
void getByName() throws JSONException {
|
void getByName() throws JSONException {
|
||||||
when(client.fetch(eq(Tag.class), eq("t1")))
|
when(client.fetch(eq(Tag.class), eq("t1")))
|
||||||
.thenReturn(Mono.just(tag(1)));
|
.thenReturn(Mono.just(tag(1)));
|
||||||
TagVo tagVo = tagFinder.getByName("t1");
|
TagVo tagVo = tagFinder.getByName("t1").block();
|
||||||
tagVo.getMetadata().setCreationTimestamp(null);
|
tagVo.getMetadata().setCreationTimestamp(null);
|
||||||
JSONAssert.assertEquals("""
|
JSONAssert.assertEquals("""
|
||||||
{
|
{
|
||||||
|
@ -82,7 +82,7 @@ class TagFinderImplTest {
|
||||||
tags().stream().sorted(TagFinderImpl.DEFAULT_COMPARATOR.reversed()).toList()
|
tags().stream().sorted(TagFinderImpl.DEFAULT_COMPARATOR.reversed()).toList()
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
List<TagVo> tags = tagFinder.listAll();
|
List<TagVo> tags = tagFinder.listAll().collectList().block();
|
||||||
assertThat(tags).hasSize(3);
|
assertThat(tags).hasSize(3);
|
||||||
assertThat(tags.stream()
|
assertThat(tags.stream()
|
||||||
.map(tag -> tag.getMetadata().getName())
|
.map(tag -> tag.getMetadata().getName())
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package run.halo.app.theme.router.strategy;
|
package run.halo.app.theme.router.strategy;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
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.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
import run.halo.app.theme.finders.PostFinder;
|
||||||
import run.halo.app.theme.router.UrlContextListResult;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link ArchivesRouteStrategy}.
|
* Tests for {@link ArchivesRouteStrategy}.
|
||||||
|
@ -31,12 +27,6 @@ class ArchivesRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private ArchivesRouteStrategy archivesRouteStrategy;
|
private ArchivesRouteStrategy archivesRouteStrategy;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() {
|
|
||||||
lenient().when(postFinder.list(any(), any())).thenReturn(
|
|
||||||
new UrlContextListResult<>(1, 10, 1, List.of(), null, null));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getRouteFunctionWhenDefaultPattern() {
|
void getRouteFunctionWhenDefaultPattern() {
|
||||||
HandlerFunction<ServerResponse> handler = archivesRouteStrategy.getHandler();
|
HandlerFunction<ServerResponse> handler = archivesRouteStrategy.getHandler();
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package run.halo.app.theme.router.strategy;
|
package run.halo.app.theme.router.strategy;
|
||||||
|
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
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.HandlerFunction;
|
||||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
import run.halo.app.theme.finders.CategoryFinder;
|
import run.halo.app.theme.finders.CategoryFinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -29,12 +30,6 @@ class CategoriesRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private CategoriesRouteStrategy categoriesRouteStrategy;
|
private CategoriesRouteStrategy categoriesRouteStrategy;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() {
|
|
||||||
lenient().when(categoryFinder.listAsTree())
|
|
||||||
.thenReturn(List.of());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getRouteFunction() {
|
void getRouteFunction() {
|
||||||
HandlerFunction<ServerResponse> handler = categoriesRouteStrategy.getHandler();
|
HandlerFunction<ServerResponse> handler = categoriesRouteStrategy.getHandler();
|
||||||
|
@ -47,6 +42,7 @@ class CategoriesRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
permalinkHttpGetRouter.insert(routerPath, handler);
|
permalinkHttpGetRouter.insert(routerPath, handler);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
when(categoryFinder.listAsTree()).thenReturn(Flux.empty());
|
||||||
client.get()
|
client.get()
|
||||||
.uri("/categories-test")
|
.uri("/categories-test")
|
||||||
.exchange()
|
.exchange()
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package run.halo.app.theme.router.strategy;
|
package run.halo.app.theme.router.strategy;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
@ -14,7 +12,7 @@ import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
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.CategoryFinder;
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
import run.halo.app.theme.finders.PostFinder;
|
||||||
|
|
||||||
|
@ -36,12 +34,6 @@ class CategoryRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private CategoryRouteStrategy categoryRouteStrategy;
|
private CategoryRouteStrategy categoryRouteStrategy;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() {
|
|
||||||
lenient().when(postFinder.listByCategory(anyInt(), anyInt(), any()))
|
|
||||||
.thenReturn(new ListResult<>(1, 10, 0, List.of()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getRouteFunction() {
|
void getRouteFunction() {
|
||||||
RouterFunction<ServerResponse> routeFunction = getRouterFunction();
|
RouterFunction<ServerResponse> routeFunction = getRouterFunction();
|
||||||
|
@ -52,6 +44,8 @@ class CategoryRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
permalinkHttpGetRouter.insert("/categories-test/category-slug-2",
|
permalinkHttpGetRouter.insert("/categories-test/category-slug-2",
|
||||||
categoryRouteStrategy.getHandler(null, "category-slug-2"));
|
categoryRouteStrategy.getHandler(null, "category-slug-2"));
|
||||||
|
|
||||||
|
when(categoryFinder.getByName(any())).thenReturn(Mono.empty());
|
||||||
|
|
||||||
// /{prefix}/{slug}
|
// /{prefix}/{slug}
|
||||||
client.get()
|
client.get()
|
||||||
.uri("/categories-test/category-slug-1")
|
.uri("/categories-test/category-slug-1")
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package run.halo.app.theme.router.strategy;
|
package run.halo.app.theme.router.strategy;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
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.HandlerFunction;
|
||||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import run.halo.app.extension.ListResult;
|
|
||||||
import run.halo.app.theme.finders.PostFinder;
|
import run.halo.app.theme.finders.PostFinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,12 +27,6 @@ class IndexRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private IndexRouteStrategy indexRouteStrategy;
|
private IndexRouteStrategy indexRouteStrategy;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() {
|
|
||||||
lenient().when(postFinder.list(anyInt(), anyInt()))
|
|
||||||
.thenReturn(new ListResult<>(1, 10, 0, List.of()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getRouteFunction() {
|
void getRouteFunction() {
|
||||||
HandlerFunction<ServerResponse> handler = indexRouteStrategy.getHandler();
|
HandlerFunction<ServerResponse> handler = indexRouteStrategy.getHandler();
|
||||||
|
|
|
@ -42,7 +42,8 @@ class PostRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
lenient().when(viewNameResolver.resolveViewNameOrDefault(any(), any(), any()))
|
lenient().when(viewNameResolver.resolveViewNameOrDefault(any(), any(), any()))
|
||||||
.thenReturn(Mono.just(DefaultTemplateEnum.POST.getValue()));
|
.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
|
@Test
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
package run.halo.app.theme.router.strategy;
|
package run.halo.app.theme.router.strategy;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
import static run.halo.app.theme.DefaultTemplateEnum.SINGLE_PAGE;
|
import static run.halo.app.theme.DefaultTemplateEnum.SINGLE_PAGE;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InjectMocks;
|
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.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
import reactor.core.publisher.Mono;
|
import reactor.core.publisher.Mono;
|
||||||
import run.halo.app.extension.ListResult;
|
|
||||||
import run.halo.app.theme.finders.SinglePageFinder;
|
import run.halo.app.theme.finders.SinglePageFinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,8 +33,6 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setUp() {
|
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()))
|
lenient().when(viewResolver.resolveViewName(eq(SINGLE_PAGE.getValue()), any()))
|
||||||
.thenReturn(Mono.just(new EmptyView()));
|
.thenReturn(Mono.just(new EmptyView()));
|
||||||
}
|
}
|
||||||
|
@ -53,6 +49,7 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
void shouldResponse200IfPermalinkFound() {
|
void shouldResponse200IfPermalinkFound() {
|
||||||
permalinkHttpGetRouter.insert("/fake-slug",
|
permalinkHttpGetRouter.insert("/fake-slug",
|
||||||
strategy.getHandler(getThemeRouteRules(), "fake-name"));
|
strategy.getHandler(getThemeRouteRules(), "fake-name"));
|
||||||
|
when(singlePageFinder.getByName(any())).thenReturn(Mono.empty());
|
||||||
createClient().get()
|
createClient().get()
|
||||||
.uri("/fake-slug")
|
.uri("/fake-slug")
|
||||||
.exchange()
|
.exchange()
|
||||||
|
@ -64,6 +61,8 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
void shouldResponse200IfSlugNameContainsSpecialChars() {
|
void shouldResponse200IfSlugNameContainsSpecialChars() {
|
||||||
permalinkHttpGetRouter.insert("/fake / slug",
|
permalinkHttpGetRouter.insert("/fake / slug",
|
||||||
strategy.getHandler(getThemeRouteRules(), "fake-name"));
|
strategy.getHandler(getThemeRouteRules(), "fake-name"));
|
||||||
|
|
||||||
|
when(singlePageFinder.getByName(any())).thenReturn(Mono.empty());
|
||||||
createClient().get()
|
createClient().get()
|
||||||
.uri("/fake / slug")
|
.uri("/fake / slug")
|
||||||
.exchange()
|
.exchange()
|
||||||
|
@ -74,6 +73,9 @@ class SinglePageRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
void shouldResponse200IfSlugNameContainsChineseChars() {
|
void shouldResponse200IfSlugNameContainsChineseChars() {
|
||||||
permalinkHttpGetRouter.insert("/中文",
|
permalinkHttpGetRouter.insert("/中文",
|
||||||
strategy.getHandler(getThemeRouteRules(), "fake-name"));
|
strategy.getHandler(getThemeRouteRules(), "fake-name"));
|
||||||
|
|
||||||
|
when(singlePageFinder.getByName(any())).thenReturn(Mono.empty());
|
||||||
|
|
||||||
createClient().get()
|
createClient().get()
|
||||||
.uri("/中文")
|
.uri("/中文")
|
||||||
.exchange()
|
.exchange()
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package run.halo.app.theme.router.strategy;
|
package run.halo.app.theme.router.strategy;
|
||||||
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.anyInt;
|
import static org.mockito.Mockito.when;
|
||||||
import static org.mockito.Mockito.lenient;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.junit.jupiter.api.extension.ExtendWith;
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
import org.mockito.InjectMocks;
|
import org.mockito.InjectMocks;
|
||||||
|
@ -14,8 +12,9 @@ import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.test.web.reactive.server.WebTestClient;
|
import org.springframework.test.web.reactive.server.WebTestClient;
|
||||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
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.PostFinder;
|
||||||
|
import run.halo.app.theme.finders.TagFinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests for {@link TagRouteStrategy}.
|
* Tests for {@link TagRouteStrategy}.
|
||||||
|
@ -28,16 +27,12 @@ class TagRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private PostFinder postFinder;
|
private PostFinder postFinder;
|
||||||
|
@Mock
|
||||||
|
private TagFinder tagFinder;
|
||||||
|
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private TagRouteStrategy tagRouteStrategy;
|
private TagRouteStrategy tagRouteStrategy;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() {
|
|
||||||
lenient().when(postFinder.listByTag(anyInt(), anyInt(), any()))
|
|
||||||
.thenReturn(new ListResult<>(1, 10, 0, List.of()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getRouteFunction() {
|
void getRouteFunction() {
|
||||||
RouterFunction<ServerResponse> routeFunction = getRouterFunction();
|
RouterFunction<ServerResponse> routeFunction = getRouterFunction();
|
||||||
|
@ -45,6 +40,7 @@ class TagRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
|
|
||||||
permalinkHttpGetRouter.insert("/tags-test/fake-slug",
|
permalinkHttpGetRouter.insert("/tags-test/fake-slug",
|
||||||
tagRouteStrategy.getHandler(getThemeRouteRules(), "fake-name"));
|
tagRouteStrategy.getHandler(getThemeRouteRules(), "fake-name"));
|
||||||
|
when(tagFinder.getByName(any())).thenReturn(Mono.empty());
|
||||||
|
|
||||||
client.get()
|
client.get()
|
||||||
.uri("/tags-test/fake-slug")
|
.uri("/tags-test/fake-slug")
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
package run.halo.app.theme.router.strategy;
|
package run.halo.app.theme.router.strategy;
|
||||||
|
|
||||||
import static org.mockito.Mockito.lenient;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import org.junit.jupiter.api.Test;
|
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.HandlerFunction;
|
||||||
import org.springframework.web.reactive.function.server.RouterFunction;
|
import org.springframework.web.reactive.function.server.RouterFunction;
|
||||||
import org.springframework.web.reactive.function.server.ServerResponse;
|
import org.springframework.web.reactive.function.server.ServerResponse;
|
||||||
|
import reactor.core.publisher.Flux;
|
||||||
import run.halo.app.theme.finders.TagFinder;
|
import run.halo.app.theme.finders.TagFinder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -30,11 +31,6 @@ class TagsRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
@InjectMocks
|
@InjectMocks
|
||||||
private TagsRouteStrategy tagsRouteStrategy;
|
private TagsRouteStrategy tagsRouteStrategy;
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setUp() {
|
|
||||||
lenient().when(tagFinder.listAll()).thenReturn(List.of());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getRouteFunction() {
|
void getRouteFunction() {
|
||||||
RouterFunction<ServerResponse> routeFunction = getRouterFunction();
|
RouterFunction<ServerResponse> routeFunction = getRouterFunction();
|
||||||
|
@ -45,6 +41,7 @@ class TagsRouteStrategyTest extends RouterStrategyTestSuite {
|
||||||
for (String routerPath : routerPaths) {
|
for (String routerPath : routerPaths) {
|
||||||
permalinkHttpGetRouter.insert(routerPath, handler);
|
permalinkHttpGetRouter.insert(routerPath, handler);
|
||||||
}
|
}
|
||||||
|
when(tagFinder.listAll()).thenReturn(Flux.empty());
|
||||||
|
|
||||||
client.get()
|
client.get()
|
||||||
.uri("/tags-test")
|
.uri("/tags-test")
|
||||||
|
|
Loading…
Reference in New Issue