diff --git a/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java index dc1a1410e..5ce1b7ec7 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/PostFinderImpl.java @@ -66,7 +66,9 @@ public class PostFinderImpl implements PostFinder { if (post == null) { return null; } - return getPostVo(post); + PostVo postVo = getPostVo(post); + postVo.setContent(content(postName)); + return postVo; } @Override diff --git a/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java b/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java index 35b4631ca..315efef03 100644 --- a/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java +++ b/src/main/java/run/halo/app/theme/finders/impl/SinglePageFinderImpl.java @@ -57,6 +57,7 @@ public class SinglePageFinderImpl implements SinglePageFinder { contributorFinder.getContributors(page.getStatus().getContributors()); SinglePageVo pageVo = SinglePageVo.from(page); pageVo.setContributors(contributors); + pageVo.setContent(content(pageName)); return pageVo; } diff --git a/src/main/java/run/halo/app/theme/finders/vo/BaseCategoryVo.java b/src/main/java/run/halo/app/theme/finders/vo/BaseCategoryVo.java index cf0295600..397418482 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/BaseCategoryVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/BaseCategoryVo.java @@ -2,6 +2,7 @@ package run.halo.app.theme.finders.vo; import java.util.List; import lombok.Getter; +import lombok.ToString; import lombok.experimental.SuperBuilder; /** @@ -11,6 +12,7 @@ import lombok.experimental.SuperBuilder; * @since 2.0.0 */ @Getter +@ToString @SuperBuilder public class BaseCategoryVo { String name; diff --git a/src/main/java/run/halo/app/theme/finders/vo/CategoryTreeVo.java b/src/main/java/run/halo/app/theme/finders/vo/CategoryTreeVo.java index 2421c48e0..bf593d6d4 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/CategoryTreeVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/CategoryTreeVo.java @@ -3,6 +3,7 @@ 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.Category; @@ -15,6 +16,7 @@ import run.halo.app.core.extension.Category; */ @Data @SuperBuilder +@ToString(callSuper = true) @EqualsAndHashCode(callSuper = true) public class CategoryTreeVo extends BaseCategoryVo { diff --git a/src/main/java/run/halo/app/theme/finders/vo/PostVo.java b/src/main/java/run/halo/app/theme/finders/vo/PostVo.java index 7b3f1f5ee..119fda588 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/PostVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/PostVo.java @@ -18,6 +18,8 @@ import run.halo.app.core.extension.Post; @EqualsAndHashCode(callSuper = true) public class PostVo extends BasePostVo { + ContentVo content; + List categories; List tags; @@ -53,6 +55,7 @@ public class PostVo extends BasePostVo { .permalink(postStatus.getPermalink()) .excerpt(postStatus.getExcerpt()) .contributors(List.of()) + .content(new ContentVo(null, null)) .build(); } } diff --git a/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java b/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java index 8db7a5860..96c32404d 100644 --- a/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java +++ b/src/main/java/run/halo/app/theme/finders/vo/SinglePageVo.java @@ -20,6 +20,8 @@ import run.halo.app.core.extension.SinglePage; @EqualsAndHashCode(callSuper = true) public class SinglePageVo extends BasePostVo { + ContentVo content; + /** * Convert {@link SinglePage} to {@link SinglePageVo}. * @@ -49,6 +51,7 @@ public class SinglePageVo extends BasePostVo { .permalink(pageStatus.getPermalink()) .excerpt(pageStatus.getExcerpt()) .contributors(List.of()) + .content(new ContentVo(null, null)) .build(); } } diff --git a/src/main/java/run/halo/app/theme/router/TemplateRouteManager.java b/src/main/java/run/halo/app/theme/router/TemplateRouteManager.java index 0cf1eb969..4939e171b 100644 --- a/src/main/java/run/halo/app/theme/router/TemplateRouteManager.java +++ b/src/main/java/run/halo/app/theme/router/TemplateRouteManager.java @@ -4,6 +4,7 @@ import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; import org.springframework.boot.context.event.ApplicationReadyEvent; +import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationListener; import org.springframework.lang.NonNull; import org.springframework.stereotype.Component; @@ -35,13 +36,13 @@ public class TemplateRouteManager implements ApplicationListener> routerFunctionMap = new HashMap<>(); - private final PermalinkIndexer permalinkIndexer; private final PermalinkPatternProvider permalinkPatternProvider; + private final ApplicationContext applicationContext; - public TemplateRouteManager(PermalinkIndexer permalinkIndexer, - PermalinkPatternProvider permalinkPatternProvider) { - this.permalinkIndexer = permalinkIndexer; + public TemplateRouteManager(PermalinkPatternProvider permalinkPatternProvider, + ApplicationContext applicationContext) { this.permalinkPatternProvider = permalinkPatternProvider; + this.applicationContext = applicationContext; } public Map> getRouterFunctionMap() { @@ -85,6 +86,9 @@ public class TemplateRouteManager implements ApplicationListener routeFunction = templateRouterStrategy(templateName) .getRouteFunction(templateName, pattern); + if (routeFunction == null) { + throw new IllegalStateException("Router function must not be null"); + } writeLock.lock(); try { routerFunctionMap.put(templateName, routeFunction); @@ -106,15 +110,16 @@ public class TemplateRouteManager implements ApplicationListener new IndexRouteStrategy(); - case POST -> new PostRouteStrategy(permalinkIndexer); - case ARCHIVES -> new ArchivesRouteStrategy(); - case TAGS -> new TagsRouteStrategy(); - case TAG -> new TagRouteStrategy(permalinkIndexer); - case CATEGORIES -> new CategoriesRouteStrategy(); - case CATEGORY -> new CategoryRouteStrategy(permalinkIndexer); - case SINGLE_PAGE -> new SinglePageRouteStrategy(permalinkIndexer); + case INDEX -> applicationContext.getBean(IndexRouteStrategy.class); + case POST -> applicationContext.getBean(PostRouteStrategy.class); + case ARCHIVES -> applicationContext.getBean(ArchivesRouteStrategy.class); + case TAGS -> applicationContext.getBean(TagsRouteStrategy.class); + case TAG -> applicationContext.getBean(TagRouteStrategy.class); + case CATEGORIES -> applicationContext.getBean(CategoriesRouteStrategy.class); + case CATEGORY -> applicationContext.getBean(CategoryRouteStrategy.class); + case SINGLE_PAGE -> applicationContext.getBean(SinglePageRouteStrategy.class); }; } diff --git a/src/main/java/run/halo/app/theme/router/TemplateRouterStrategy.java b/src/main/java/run/halo/app/theme/router/TemplateRouterStrategy.java index a92ca71e9..efa4534c4 100644 --- a/src/main/java/run/halo/app/theme/router/TemplateRouterStrategy.java +++ b/src/main/java/run/halo/app/theme/router/TemplateRouterStrategy.java @@ -1,7 +1,13 @@ package run.halo.app.theme.router; +import org.apache.commons.lang3.ArrayUtils; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.math.NumberUtils; import org.springframework.web.reactive.function.server.RouterFunction; +import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; +import run.halo.app.extension.ListResult; +import run.halo.app.infra.utils.PathUtils; /** * The {@link TemplateRouterStrategy} for generate {@link RouterFunction} specific to the template. @@ -13,4 +19,86 @@ import org.springframework.web.reactive.function.server.ServerResponse; public interface TemplateRouterStrategy { RouterFunction getRouteFunction(String template, String pattern); + + class PageUrlUtils { + public static final String PAGE_PART = "page"; + + public static int pageNum(ServerRequest request) { + String pageNum = request.pathVariables().get(PageUrlUtils.PAGE_PART); + return NumberUtils.toInt(pageNum, 1); + } + + public static long totalPage(ListResult list) { + return (list.getTotal() - 1) / list.getSize() + 1; + } + + /** + * Gets next page url with path. + * + * @param path request path + * @return request path with next page part + */ + public static String nextPageUrl(String path, long total) { + String[] segments = StringUtils.split(path, "/"); + long defaultPage = Math.min(2, Math.max(total, 1)); + if (segments.length > 1) { + String pagePart = segments[segments.length - 2]; + if (PAGE_PART.equals(pagePart)) { + int pageNumIndex = segments.length - 1; + String pageNum = segments[pageNumIndex]; + segments[pageNumIndex] = toNextPage(pageNum, total); + return PathUtils.combinePath(segments); + } + return appendPagePart(PathUtils.combinePath(segments), defaultPage); + } + return appendPagePart(PathUtils.combinePath(segments), defaultPage); + } + + /** + * Gets previous page url with path. + * + * @param path request path + * @return request path with previous page part + */ + public static String prevPageUrl(String path) { + String[] segments = StringUtils.split(path, "/"); + if (segments.length > 1) { + String pagePart = segments[segments.length - 2]; + if (PAGE_PART.equals(pagePart)) { + int pageNumIndex = segments.length - 1; + String pageNum = segments[pageNumIndex]; + int prevPage = toPrevPage(pageNum); + segments[pageNumIndex] = String.valueOf(prevPage); + if (prevPage == 1) { + segments = ArrayUtils.subarray(segments, 0, pageNumIndex - 1); + } + if (segments.length == 0) { + return "/"; + } + return PathUtils.combinePath(segments); + } + } + return StringUtils.defaultString(path, "/"); + } + + private static String appendPagePart(String path, long page) { + return PathUtils.combinePath(path, PAGE_PART, String.valueOf(page)); + } + + private static String toNextPage(String pageStr, long total) { + long page = Math.min(parseInt(pageStr) + 1, Math.max(total, 1)); + return String.valueOf(page); + } + + private static int toPrevPage(String pageStr) { + return Math.max(parseInt(pageStr) - 1, 1); + } + + private static int parseInt(String pageStr) { + if (!NumberUtils.isParsable(pageStr)) { + throw new IllegalArgumentException("Page number must be a number"); + } + return NumberUtils.toInt(pageStr, 1); + } + } } diff --git a/src/main/java/run/halo/app/theme/router/UrlContextListResult.java b/src/main/java/run/halo/app/theme/router/UrlContextListResult.java new file mode 100644 index 000000000..4b7efccc7 --- /dev/null +++ b/src/main/java/run/halo/app/theme/router/UrlContextListResult.java @@ -0,0 +1,84 @@ +package run.halo.app.theme.router; + +import java.util.List; +import lombok.Getter; +import lombok.ToString; +import run.halo.app.extension.ListResult; + +/** + * Page wrapper with next and previous url. + * + * @param the type of the list item. + * @author guqing + * @since 2.0.0 + */ +@Getter +@ToString(callSuper = true) +public class UrlContextListResult extends ListResult { + private final String nextUrl; + private final String prevUrl; + + public UrlContextListResult(int page, int size, long total, List items, String nextUrl, + String prevUrl) { + super(page, size, total, items); + this.nextUrl = nextUrl; + this.prevUrl = prevUrl; + } + + public static class Builder { + private int page; + private int size; + private long total; + private List items; + private String nextUrl; + private String prevUrl; + + public Builder page(int page) { + this.page = page; + return this; + } + + public Builder size(int size) { + this.size = size; + return this; + } + + public Builder total(long total) { + this.total = total; + return this; + } + + public Builder items(List items) { + this.items = items; + return this; + } + + public Builder nextUrl(String nextUrl) { + this.nextUrl = nextUrl; + return this; + } + + public Builder prevUrl(String prevUrl) { + this.prevUrl = prevUrl; + return this; + } + + /** + * Assign value with list result. + * + * @param listResult list result + * @return builder + */ + public Builder listResult(ListResult listResult) { + this.page = listResult.getPage(); + this.size = listResult.getSize(); + this.total = listResult.getTotal(); + this.items = listResult.getItems(); + return this; + } + + public UrlContextListResult build() { + return new UrlContextListResult<>(page, size, total, items, nextUrl, prevUrl); + } + } +} diff --git a/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java index 2421f317a..e28f80372 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategy.java @@ -2,14 +2,24 @@ package run.halo.app.theme.router.strategy; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.pageNum; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.totalPage; +import java.util.Map; import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.infra.utils.PathUtils; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.finders.vo.PostVo; import run.halo.app.theme.router.TemplateRouterStrategy; +import run.halo.app.theme.router.UrlContextListResult; /** * The {@link ArchivesRouteStrategy} for generate {@link RouterFunction} specific to the template @@ -18,7 +28,13 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class ArchivesRouteStrategy implements TemplateRouterStrategy { + private final PostFinder postFinder; + + public ArchivesRouteStrategy(PostFinder postFinder) { + this.postFinder = postFinder; + } @Override public RouterFunction getRouteFunction(String template, String prefix) { @@ -29,6 +45,18 @@ public class ArchivesRouteStrategy implements TemplateRouterStrategy { .or(GET(PathUtils.combinePath(prefix, "/{year}/{month}/page/{page}"))) .and(accept(MediaType.TEXT_HTML)), request -> ServerResponse.ok() - .render(DefaultTemplateEnum.ARCHIVES.getValue())); + .render(DefaultTemplateEnum.ARCHIVES.getValue(), + Map.of("posts", postList(request)))); + } + + private Mono> postList(ServerRequest request) { + String path = request.path(); + return Mono.defer(() -> Mono.just(postFinder.list(pageNum(request), 10))) + .publishOn(Schedulers.boundedElastic()) + .map(list -> new UrlContextListResult.Builder() + .listResult(list) + .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) + .prevUrl(PageUrlUtils.prevPageUrl(path)) + .build()); } } diff --git a/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java index b921ee609..8e9f4dc81 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategy.java @@ -3,12 +3,19 @@ package run.halo.app.theme.router.strategy; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import java.util.List; +import java.util.Map; import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.infra.utils.PathUtils; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.CategoryFinder; +import run.halo.app.theme.finders.vo.CategoryTreeVo; import run.halo.app.theme.router.TemplateRouterStrategy; /** @@ -18,7 +25,13 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class CategoriesRouteStrategy implements TemplateRouterStrategy { + private final CategoryFinder categoryFinder; + + public CategoriesRouteStrategy(CategoryFinder categoryFinder) { + this.categoryFinder = categoryFinder; + } @Override public RouterFunction getRouteFunction(String template, String prefix) { @@ -26,6 +39,12 @@ public class CategoriesRouteStrategy implements TemplateRouterStrategy { .route(GET(PathUtils.combinePath(prefix)) .and(accept(MediaType.TEXT_HTML)), request -> ServerResponse.ok() - .render(DefaultTemplateEnum.CATEGORIES.getValue())); + .render(DefaultTemplateEnum.CATEGORIES.getValue(), + Map.of("categories", categories()))); + } + + private Mono> categories() { + return Mono.defer(() -> Mono.just(categoryFinder.listAsTree())) + .publishOn(Schedulers.boundedElastic()); } } diff --git a/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java index 03acb073c..4b3848127 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/CategoryRouteStrategy.java @@ -2,19 +2,30 @@ package run.halo.app.theme.router.strategy; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.pageNum; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.totalPage; import java.util.List; import java.util.Map; import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.Category; import run.halo.app.extension.GroupVersionKind; import run.halo.app.infra.utils.PathUtils; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.CategoryFinder; +import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.finders.vo.CategoryVo; +import run.halo.app.theme.finders.vo.PostVo; import run.halo.app.theme.router.PermalinkIndexer; import run.halo.app.theme.router.TemplateRouterStrategy; +import run.halo.app.theme.router.UrlContextListResult; /** * The {@link CategoryRouteStrategy} for generate {@link RouterFunction} specific to the template @@ -23,12 +34,19 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class CategoryRouteStrategy implements TemplateRouterStrategy { private final PermalinkIndexer permalinkIndexer; + private final PostFinder postFinder; - public CategoryRouteStrategy(PermalinkIndexer permalinkIndexer) { + private final CategoryFinder categoryFinder; + + public CategoryRouteStrategy(PermalinkIndexer permalinkIndexer, PostFinder postFinder, + CategoryFinder categoryFinder) { this.permalinkIndexer = permalinkIndexer; + this.postFinder = postFinder; + this.categoryFinder = categoryFinder; } @Override @@ -47,7 +65,26 @@ public class CategoryRouteStrategy implements TemplateRouterStrategy { String categoryName = permalinkIndexer.getNameBySlug(gvk, slug); return ServerResponse.ok() .render(DefaultTemplateEnum.CATEGORY.getValue(), - Map.of("name", categoryName)); + Map.of("name", categoryName, + "posts", postListByCategoryName(categoryName, request), + "category", categoryByName(categoryName))); }); } + + private Mono> postListByCategoryName(String name, + ServerRequest request) { + String path = request.path(); + return Mono.defer(() -> Mono.just(postFinder.listByCategory(pageNum(request), 10, name))) + .publishOn(Schedulers.boundedElastic()) + .map(list -> new UrlContextListResult.Builder() + .listResult(list) + .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) + .prevUrl(PageUrlUtils.prevPageUrl(path)) + .build()); + } + + private Mono categoryByName(String name) { + return Mono.defer(() -> Mono.just(categoryFinder.getByName(name))) + .publishOn(Schedulers.boundedElastic()); + } } diff --git a/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java index d2e6ce4d2..dbf5e7ebf 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/IndexRouteStrategy.java @@ -2,13 +2,23 @@ package run.halo.app.theme.router.strategy; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.pageNum; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.totalPage; +import java.util.Map; import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.finders.vo.PostVo; import run.halo.app.theme.router.TemplateRouterStrategy; +import run.halo.app.theme.router.UrlContextListResult; /** * The {@link IndexRouteStrategy} for generate {@link RouterFunction} specific to the template @@ -17,14 +27,33 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class IndexRouteStrategy implements TemplateRouterStrategy { + private final PostFinder postFinder; + + public IndexRouteStrategy(PostFinder postFinder) { + this.postFinder = postFinder; + } + @Override public RouterFunction getRouteFunction(String template, String pattern) { return RouterFunctions .route(GET("/").or(GET("/page/{page}")) .and(accept(MediaType.TEXT_HTML)), request -> ServerResponse.ok() - .render(DefaultTemplateEnum.INDEX.getValue())); + .render(DefaultTemplateEnum.INDEX.getValue(), + Map.of("posts", postList(request)))); + } + + private Mono> postList(ServerRequest request) { + String path = request.path(); + return Mono.defer(() -> Mono.just(postFinder.list(pageNum(request), 10))) + .publishOn(Schedulers.boundedElastic()) + .map(list -> new UrlContextListResult.Builder() + .listResult(list) + .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) + .prevUrl(PageUrlUtils.prevPageUrl(path)) + .build()); } } diff --git a/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java index 54f096bed..45740b500 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/PostRouteStrategy.java @@ -10,6 +10,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; import org.springframework.http.MediaType; import org.springframework.http.server.PathContainer; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RequestPredicate; import org.springframework.web.reactive.function.server.RequestPredicates; import org.springframework.web.reactive.function.server.RouterFunction; @@ -17,10 +18,14 @@ import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.util.pattern.PathPattern; import org.springframework.web.util.pattern.PathPatternParser; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.content.permalinks.ExtensionLocator; import run.halo.app.core.extension.Post; import run.halo.app.extension.GroupVersionKind; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.finders.vo.PostVo; import run.halo.app.theme.router.PermalinkIndexer; import run.halo.app.theme.router.TemplateRouterStrategy; @@ -31,11 +36,14 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class PostRouteStrategy implements TemplateRouterStrategy { private final PermalinkIndexer permalinkIndexer; + private final PostFinder postFinder; - public PostRouteStrategy(PermalinkIndexer permalinkIndexer) { + public PostRouteStrategy(PermalinkIndexer permalinkIndexer, PostFinder postFinder) { this.permalinkIndexer = permalinkIndexer; + this.postFinder = postFinder; } @Override @@ -86,17 +94,23 @@ public class PostRouteStrategy implements TemplateRouterStrategy { PathPattern parse = PathPatternParser.defaultInstance.parse(pattern); PathPattern.PathMatchInfo pathMatchInfo = parse.matchAndExtract(PathContainer.parsePath(request.path())); - Map uriVariables = new HashMap<>(); - uriVariables.put(PostRequestParamPredicate.NAME_PARAM, + Map model = new HashMap<>(); + model.put(PostRequestParamPredicate.NAME_PARAM, extensionLocator.name()); if (pathMatchInfo != null) { - uriVariables.putAll(pathMatchInfo.getUriVariables()); + model.putAll(pathMatchInfo.getUriVariables()); } + model.put("post", postByName(extensionLocator.name())); return ServerResponse.ok() - .render(DefaultTemplateEnum.POST.getValue(), uriVariables); + .render(DefaultTemplateEnum.POST.getValue(), model); }); } + private Mono postByName(String name) { + return Mono.defer(() -> Mono.just(postFinder.getByName(name))) + .publishOn(Schedulers.boundedElastic()); + } + class PostRequestParamPredicate { static final String NAME_PARAM = "name"; static final String SLUG_PARAM = "slug"; diff --git a/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java index ca574cba6..2f402e2f5 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategy.java @@ -7,14 +7,19 @@ import java.util.Map; import java.util.Objects; import org.apache.commons.lang3.StringUtils; import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RequestPredicate; import org.springframework.web.reactive.function.server.RequestPredicates; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.SinglePage; import run.halo.app.extension.GroupVersionKind; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.SinglePageFinder; +import run.halo.app.theme.finders.vo.SinglePageVo; import run.halo.app.theme.router.PermalinkIndexer; import run.halo.app.theme.router.TemplateRouterStrategy; @@ -25,12 +30,16 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class SinglePageRouteStrategy implements TemplateRouterStrategy { private final PermalinkIndexer permalinkIndexer; + private final SinglePageFinder singlePageFinder; - public SinglePageRouteStrategy(PermalinkIndexer permalinkIndexer) { + public SinglePageRouteStrategy(PermalinkIndexer permalinkIndexer, + SinglePageFinder singlePageFinder) { this.permalinkIndexer = permalinkIndexer; + this.singlePageFinder = singlePageFinder; } @Override @@ -53,7 +62,14 @@ public class SinglePageRouteStrategy implements TemplateRouterStrategy { return ServerResponse.notFound().build(); } return ServerResponse.ok() - .render(DefaultTemplateEnum.SINGLE_PAGE.getValue(), Map.of("name", name)); + .render(DefaultTemplateEnum.SINGLE_PAGE.getValue(), + Map.of("name", name, + "singlePage", singlePageByName(name))); }); } + + private Mono singlePageByName(String name) { + return Mono.defer(() -> Mono.just(singlePageFinder.getByName(name))) + .publishOn(Schedulers.boundedElastic()); + } } diff --git a/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java index 09e47f35a..837210ac2 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/TagRouteStrategy.java @@ -2,19 +2,30 @@ package run.halo.app.theme.router.strategy; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.pageNum; +import static run.halo.app.theme.router.TemplateRouterStrategy.PageUrlUtils.totalPage; import java.util.List; import java.util.Map; import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; +import org.springframework.web.reactive.function.server.ServerRequest; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.core.extension.Tag; import run.halo.app.extension.GroupVersionKind; import run.halo.app.infra.utils.PathUtils; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.finders.TagFinder; +import run.halo.app.theme.finders.vo.PostVo; +import run.halo.app.theme.finders.vo.TagVo; import run.halo.app.theme.router.PermalinkIndexer; import run.halo.app.theme.router.TemplateRouterStrategy; +import run.halo.app.theme.router.UrlContextListResult; /** * The {@link TagRouteStrategy} for generate {@link RouterFunction} specific to the template @@ -23,12 +34,19 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class TagRouteStrategy implements TemplateRouterStrategy { private final PermalinkIndexer permalinkIndexer; + private final PostFinder postFinder; - public TagRouteStrategy(PermalinkIndexer permalinkIndexer) { + private final TagFinder tagFinder; + + public TagRouteStrategy(PermalinkIndexer permalinkIndexer, PostFinder postFinder, + TagFinder tagFinder) { this.permalinkIndexer = permalinkIndexer; + this.postFinder = postFinder; + this.tagFinder = tagFinder; } @Override @@ -46,7 +64,27 @@ public class TagRouteStrategy implements TemplateRouterStrategy { } String name = permalinkIndexer.getNameBySlug(gvk, slug); return ServerResponse.ok() - .render(DefaultTemplateEnum.TAG.getValue(), Map.of("name", name)); + .render(DefaultTemplateEnum.TAG.getValue(), + Map.of("name", name, + "posts", postList(request, name), + "tag", tagByName(name)) + ); }); } + + private Mono> postList(ServerRequest request, String name) { + String path = request.path(); + return Mono.defer(() -> Mono.just(postFinder.listByTag(pageNum(request), 10, name))) + .publishOn(Schedulers.boundedElastic()) + .map(list -> new UrlContextListResult.Builder() + .listResult(list) + .nextUrl(PageUrlUtils.nextPageUrl(path, totalPage(list))) + .prevUrl(PageUrlUtils.prevPageUrl(path)) + .build()); + } + + private Mono tagByName(String name) { + return Mono.defer(() -> Mono.just(tagFinder.getByName(name))) + .publishOn(Schedulers.boundedElastic()); + } } diff --git a/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java b/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java index dcd3dc5e4..0ab563448 100644 --- a/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java +++ b/src/main/java/run/halo/app/theme/router/strategy/TagsRouteStrategy.java @@ -3,12 +3,19 @@ package run.halo.app.theme.router.strategy; import static org.springframework.web.reactive.function.server.RequestPredicates.GET; import static org.springframework.web.reactive.function.server.RequestPredicates.accept; +import java.util.List; +import java.util.Map; import org.springframework.http.MediaType; +import org.springframework.stereotype.Component; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.RouterFunctions; import org.springframework.web.reactive.function.server.ServerResponse; +import reactor.core.publisher.Mono; +import reactor.core.scheduler.Schedulers; import run.halo.app.infra.utils.PathUtils; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.TagFinder; +import run.halo.app.theme.finders.vo.TagVo; import run.halo.app.theme.router.TemplateRouterStrategy; /** @@ -18,8 +25,15 @@ import run.halo.app.theme.router.TemplateRouterStrategy; * @author guqing * @since 2.0.0 */ +@Component public class TagsRouteStrategy implements TemplateRouterStrategy { + private final TagFinder tagFinder; + + public TagsRouteStrategy(TagFinder tagFinder) { + this.tagFinder = tagFinder; + } + @Override public RouterFunction getRouteFunction(String template, String prefix) { String pattern = PathUtils.combinePath(prefix); @@ -27,6 +41,13 @@ public class TagsRouteStrategy implements TemplateRouterStrategy { .route(GET(pattern) .and(accept(MediaType.TEXT_HTML)), request -> ServerResponse.ok() - .render(DefaultTemplateEnum.TAGS.getValue())); + .render(DefaultTemplateEnum.TAGS.getValue(), + Map.of("tags", tags())) + ); + } + + private Mono> tags() { + return Mono.defer(() -> Mono.just(tagFinder.listAll())) + .publishOn(Schedulers.boundedElastic()); } } diff --git a/src/test/java/run/halo/app/theme/router/TemplateRouteManagerTest.java b/src/test/java/run/halo/app/theme/router/TemplateRouteManagerTest.java index 319a910a6..83e9318f7 100644 --- a/src/test/java/run/halo/app/theme/router/TemplateRouteManagerTest.java +++ b/src/test/java/run/halo/app/theme/router/TemplateRouteManagerTest.java @@ -1,6 +1,7 @@ package run.halo.app.theme.router; import static org.assertj.core.api.Assertions.assertThat; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import java.util.Map; @@ -8,10 +9,14 @@ import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.context.ApplicationContext; import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.TagFinder; +import run.halo.app.theme.router.strategy.TagsRouteStrategy; /** * Tests for {@link TemplateRouteManager}. @@ -26,16 +31,22 @@ class TemplateRouteManagerTest { private PermalinkPatternProvider permalinkPatternProvider; @Mock - private PermalinkIndexer permalinkIndexer; + private ApplicationContext applicationContext; private TemplateRouteManager templateRouteManager; @BeforeEach void setUp() { - templateRouteManager = new TemplateRouteManager(permalinkIndexer, permalinkPatternProvider); + templateRouteManager = new TemplateRouteManager(permalinkPatternProvider, + applicationContext); when(permalinkPatternProvider.getPattern(DefaultTemplateEnum.TAGS)) .thenReturn("/tags"); + + TagFinder tagFinder = Mockito.mock(TagFinder.class); + when(applicationContext.getBean(eq(TagsRouteStrategy.class))) + .thenReturn(new TagsRouteStrategy(tagFinder)); + templateRouteManager.register(DefaultTemplateEnum.TAGS.getValue()); } diff --git a/src/test/java/run/halo/app/theme/router/TemplateRouterStrategyTest.java b/src/test/java/run/halo/app/theme/router/TemplateRouterStrategyTest.java new file mode 100644 index 000000000..90a624f7d --- /dev/null +++ b/src/test/java/run/halo/app/theme/router/TemplateRouterStrategyTest.java @@ -0,0 +1,68 @@ +package run.halo.app.theme.router; + +import static org.assertj.core.api.Assertions.assertThat; + +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +/** + * Tests for {@link TemplateRouterStrategy}. + * + * @author guqing + * @since 2.0.0 + */ +class TemplateRouterStrategyTest { + + @Nested + class PageUrlUtils { + static String s = "/tags"; + static String s1 = "/tags/page/1"; + static String s2 = "/tags/page/2"; + static String s3 = "/tags/y/m/page/2"; + static String s4 = "/tags/y/m"; + static String s5 = "/tags/y/m/page/3"; + + @Test + void nextPageUrl() { + long totalPage = 10; + assertThat(TemplateRouterStrategy.PageUrlUtils.nextPageUrl(s, totalPage)) + .isEqualTo("/tags/page/2"); + assertThat(TemplateRouterStrategy.PageUrlUtils.nextPageUrl(s2, totalPage)) + .isEqualTo("/tags/page/3"); + assertThat(TemplateRouterStrategy.PageUrlUtils.nextPageUrl(s3, totalPage)) + .isEqualTo("/tags/y/m/page/3"); + assertThat(TemplateRouterStrategy.PageUrlUtils.nextPageUrl(s4, totalPage)) + .isEqualTo("/tags/y/m/page/2"); + assertThat(TemplateRouterStrategy.PageUrlUtils.nextPageUrl(s5, totalPage)) + .isEqualTo("/tags/y/m/page/4"); + + // The number of pages does not exceed the total number of pages + totalPage = 1; + assertThat(TemplateRouterStrategy.PageUrlUtils.nextPageUrl("/tags/page/1", totalPage)) + .isEqualTo("/tags/page/1"); + + totalPage = 0; + assertThat(TemplateRouterStrategy.PageUrlUtils.nextPageUrl("/tags", totalPage)) + .isEqualTo("/tags/page/1"); + } + + @Test + void prevPageUrl() { + assertThat(TemplateRouterStrategy.PageUrlUtils.prevPageUrl(s)) + .isEqualTo("/tags"); + assertThat(TemplateRouterStrategy.PageUrlUtils.prevPageUrl(s1)) + .isEqualTo("/tags"); + assertThat(TemplateRouterStrategy.PageUrlUtils.prevPageUrl(s2)) + .isEqualTo("/tags"); + assertThat(TemplateRouterStrategy.PageUrlUtils.prevPageUrl(s3)) + .isEqualTo("/tags/y/m"); + assertThat(TemplateRouterStrategy.PageUrlUtils.prevPageUrl(s4)) + .isEqualTo("/tags/y/m"); + assertThat(TemplateRouterStrategy.PageUrlUtils.prevPageUrl(s5)) + .isEqualTo("/tags/y/m/page/2"); + + assertThat(TemplateRouterStrategy.PageUrlUtils.prevPageUrl("/page/2")) + .isEqualTo("/"); + } + } +} \ No newline at end of file diff --git a/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java index 06c5d5a27..bb20fa1ba 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/ArchivesRouteStrategyTest.java @@ -2,11 +2,14 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -17,6 +20,8 @@ import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.router.UrlContextListResult; /** * Tests for {@link ArchivesRouteStrategy}. @@ -29,12 +34,16 @@ class ArchivesRouteStrategyTest { @Mock private ViewResolver viewResolver; + @Mock + private PostFinder postFinder; + @InjectMocks private ArchivesRouteStrategy archivesRouteStrategy; @BeforeEach void setUp() { - archivesRouteStrategy = new ArchivesRouteStrategy(); + lenient().when(postFinder.list(any(), any())).thenReturn( + new UrlContextListResult<>(1, 10, 1, List.of(), null, null)); } @Test diff --git a/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java index 523732609..c9ee375b2 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/CategoriesRouteStrategyTest.java @@ -2,11 +2,14 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -17,6 +20,7 @@ import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.CategoryFinder; /** * Tests for {@link CategoriesRouteStrategy}. @@ -29,11 +33,16 @@ class CategoriesRouteStrategyTest { @Mock private ViewResolver viewResolver; + @Mock + private CategoryFinder categoryFinder; + + @InjectMocks private CategoriesRouteStrategy categoriesRouteStrategy; @BeforeEach void setUp() { - categoriesRouteStrategy = new CategoriesRouteStrategy(); + lenient().when(categoryFinder.listAsTree()) + .thenReturn(List.of()); } @Test diff --git a/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java index f4eb196df..af30cc862 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/CategoryRouteStrategyTest.java @@ -1,13 +1,16 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -17,7 +20,9 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; +import run.halo.app.extension.ListResult; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.router.PermalinkIndexer; /** @@ -34,17 +39,23 @@ class CategoryRouteStrategyTest { @Mock private ViewResolver viewResolver; + @Mock + private PostFinder postFinder; + + @InjectMocks private CategoryRouteStrategy categoryRouteStrategy; @BeforeEach void setUp() { - categoryRouteStrategy = new CategoryRouteStrategy(permalinkIndexer); when(permalinkIndexer.getSlugs(any())) .thenReturn(List.of("category-slug-1", "category-slug-2")); when(permalinkIndexer.getNameBySlug(any(), eq("category-slug-1"))) .thenReturn("category-name-1"); when(permalinkIndexer.getNameBySlug(any(), eq("category-slug-2"))) .thenReturn("category-name-2"); + + lenient().when(postFinder.listByCategory(anyInt(), anyInt(), any())) + .thenReturn(new ListResult<>(1, 10, 0, List.of())); } @Test diff --git a/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java index 43513d3ea..2aa20f2b1 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/IndexRouteStrategyTest.java @@ -1,12 +1,16 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -16,7 +20,9 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; +import run.halo.app.extension.ListResult; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; /** * Tests for {@link IndexRouteStrategy}. @@ -29,11 +35,16 @@ class IndexRouteStrategyTest { @Mock private ViewResolver viewResolver; + @Mock + private PostFinder postFinder; + + @InjectMocks private IndexRouteStrategy indexRouteStrategy; @BeforeEach void setUp() { - indexRouteStrategy = new IndexRouteStrategy(); + lenient().when(postFinder.list(anyInt(), anyInt())) + .thenReturn(new ListResult<>(1, 10, 0, List.of())); } @Test diff --git a/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java index 46789e400..161bb0ca9 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/PostRouteStrategyTest.java @@ -9,6 +9,7 @@ import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -18,10 +19,13 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; +import run.halo.app.content.TestPost; import run.halo.app.content.permalinks.ExtensionLocator; import run.halo.app.core.extension.Post; import run.halo.app.extension.GroupVersionKind; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; +import run.halo.app.theme.finders.vo.PostVo; import run.halo.app.theme.router.PermalinkIndexer; /** @@ -39,11 +43,15 @@ class PostRouteStrategyTest { @Mock private PermalinkIndexer permalinkIndexer; + @Mock + private PostFinder postFinder; + + @InjectMocks private PostRouteStrategy postRouteStrategy; @BeforeEach void setUp() { - postRouteStrategy = new PostRouteStrategy(permalinkIndexer); + lenient().when(postFinder.getByName(any())).thenReturn(PostVo.from(TestPost.postV1())); } @Test diff --git a/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java index 8f578e988..56ea75aed 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/SinglePageRouteStrategyTest.java @@ -1,13 +1,16 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -17,7 +20,9 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; +import run.halo.app.extension.ListResult; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.SinglePageFinder; import run.halo.app.theme.router.PermalinkIndexer; /** @@ -35,11 +40,16 @@ class SinglePageRouteStrategyTest { @Mock private ViewResolver viewResolver; + @Mock + private SinglePageFinder singlePageFinder; + + @InjectMocks private SinglePageRouteStrategy strategy; @BeforeEach void setUp() { - strategy = new SinglePageRouteStrategy(permalinkIndexer); + lenient().when(singlePageFinder.list(anyInt(), anyInt())) + .thenReturn(new ListResult<>(1, 10, 0, List.of())); when(permalinkIndexer.getPermalinks(any())) .thenReturn(List.of("/fake-slug")); when(permalinkIndexer.getNameBySlug(any(), eq("fake-slug"))) diff --git a/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java index c9dbbc872..6a8bf6b72 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/TagRouteStrategyTest.java @@ -1,13 +1,16 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -17,7 +20,9 @@ import org.springframework.web.reactive.function.server.RouterFunction; import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; +import run.halo.app.extension.ListResult; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.PostFinder; import run.halo.app.theme.router.PermalinkIndexer; /** @@ -31,15 +36,18 @@ class TagRouteStrategyTest { @Mock private PermalinkIndexer permalinkIndexer; - + @Mock + private PostFinder postFinder; @Mock private ViewResolver viewResolver; + @InjectMocks private TagRouteStrategy tagRouteStrategy; @BeforeEach void setUp() { - tagRouteStrategy = new TagRouteStrategy(permalinkIndexer); + lenient().when(postFinder.listByTag(anyInt(), anyInt(), any())) + .thenReturn(new ListResult<>(1, 10, 0, List.of())); when(permalinkIndexer.getSlugs(any())) .thenReturn(List.of("fake-slug")); when(permalinkIndexer.getNameBySlug(any(), eq("fake-slug"))) diff --git a/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java b/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java index 05e2db2f2..ff19b62c8 100644 --- a/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java +++ b/src/test/java/run/halo/app/theme/router/strategy/TagsRouteStrategyTest.java @@ -2,11 +2,14 @@ package run.halo.app.theme.router.strategy; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.when; +import java.util.List; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.HttpStatus; @@ -17,6 +20,7 @@ import org.springframework.web.reactive.function.server.ServerResponse; import org.springframework.web.reactive.result.view.ViewResolver; import reactor.core.publisher.Mono; import run.halo.app.theme.DefaultTemplateEnum; +import run.halo.app.theme.finders.TagFinder; /** * Tests for {@link TagsRouteStrategy}. @@ -30,11 +34,15 @@ class TagsRouteStrategyTest { @Mock private ViewResolver viewResolver; + @Mock + private TagFinder tagFinder; + + @InjectMocks private TagsRouteStrategy tagsRouteStrategy; @BeforeEach void setUp() { - tagsRouteStrategy = new TagsRouteStrategy(); + lenient().when(tagFinder.listAll()).thenReturn(List.of()); } @Test