From c224b68fbcf1d3996154c4af9b9abf61b27ebbdb Mon Sep 17 00:00:00 2001 From: Ryan Wang Date: Mon, 24 Feb 2020 23:42:54 +0800 Subject: [PATCH] feat: supports setting the post path type and path suffix. (#563) * feat: build full path for category and tag. * feat: build full path for post. * feat: build full path for sheet. * feat: build full path for post. * feat: change post url for rss sitemap pages. * feat: support set links/photos/journal page prefix. * feat: support set internal sheet's title. * refactor: build full path method. * refactor: archives post full path. * feat: support nextPageFullPath and prePageFullPath variable in pageable pages. * Update CommentEventListener.java * feat: make rss formats more standard. * feat: add some useful freemarker variable. * feat: add some useful freemarker variable. * feat: add some useful freemarker variable. * refactor: preview post and password post. --- .../controller/admin/api/PostController.java | 23 +- .../controller/admin/api/SheetController.java | 17 +- .../content/ContentArchiveController.java | 69 ------ .../content/ContentContentController.java | 117 +++++++--- .../content/ContentJournalController.java | 86 -------- .../content/ContentSearchController.java | 38 ++++ .../content/ContentSheetController.java | 77 ------- .../content/model/CategoryModel.java | 24 +- .../content/model/JournalModel.java | 87 ++++++++ .../controller/content/model/PhotoModel.java | 81 +++++++ .../controller/content/model/PostModel.java | 42 +++- .../controller/content/model/SheetModel.java | 11 +- .../controller/content/model/TagModel.java | 24 +- .../freemarker/tag/CategoryTagDirective.java | 5 +- .../core/freemarker/tag/PostTagDirective.java | 13 +- .../core/freemarker/tag/TagTagDirective.java | 5 +- .../comment/CommentEventListener.java | 37 ++-- .../FreemarkerConfigAwareListener.java | 30 ++- .../model/properties/PermalinkProperties.java | 18 ++ .../app/model/properties/PropertyEnum.java | 1 + .../app/model/properties/SheetProperties.java | 62 ++++++ .../run/halo/app/service/OptionService.java | 64 ++++++ .../halo/app/service/PostCommentService.java | 5 - .../run/halo/app/service/PostService.java | 9 + .../app/service/impl/AdminServiceImpl.java | 1 + .../service/impl/AttachmentServiceImpl.java | 3 +- .../app/service/impl/CategoryServiceImpl.java | 25 ++- .../app/service/impl/OptionServiceImpl.java | 45 ++++ .../service/impl/PostCategoryServiceImpl.java | 22 +- .../service/impl/PostCommentServiceImpl.java | 64 +++++- .../app/service/impl/PostServiceImpl.java | 207 +++++++++++++----- .../app/service/impl/PostTagServiceImpl.java | 22 +- .../service/impl/SheetCommentServiceImpl.java | 30 ++- .../app/service/impl/SheetServiceImpl.java | 67 +++++- .../halo/app/service/impl/TagServiceImpl.java | 25 ++- .../templates/common/error/error.ftl | 4 +- .../common/mail_template/mail_reply.ftl | 6 +- .../common/template/post_password.ftl | 4 +- .../resources/templates/common/web/atom.ftl | 63 +++--- .../resources/templates/common/web/readme.ftl | 10 +- .../resources/templates/common/web/robots.ftl | 4 +- .../resources/templates/common/web/rss.ftl | 17 +- .../templates/common/web/sitemap_html.ftl | 22 +- .../templates/common/web/sitemap_xml.ftl | 2 +- 44 files changed, 1109 insertions(+), 479 deletions(-) delete mode 100644 src/main/java/run/halo/app/controller/content/ContentArchiveController.java delete mode 100644 src/main/java/run/halo/app/controller/content/ContentJournalController.java delete mode 100644 src/main/java/run/halo/app/controller/content/ContentSheetController.java create mode 100644 src/main/java/run/halo/app/controller/content/model/JournalModel.java create mode 100644 src/main/java/run/halo/app/controller/content/model/PhotoModel.java create mode 100644 src/main/java/run/halo/app/model/properties/SheetProperties.java diff --git a/src/main/java/run/halo/app/controller/admin/api/PostController.java b/src/main/java/run/halo/app/controller/admin/api/PostController.java index b8027d9a7..3fca601b8 100644 --- a/src/main/java/run/halo/app/controller/admin/api/PostController.java +++ b/src/main/java/run/halo/app/controller/admin/api/PostController.java @@ -11,6 +11,7 @@ import run.halo.app.model.dto.post.BasePostDetailDTO; import run.halo.app.model.dto.post.BasePostMinimalDTO; import run.halo.app.model.dto.post.BasePostSimpleDTO; import run.halo.app.model.entity.Post; +import run.halo.app.model.enums.PostPermalinkType; import run.halo.app.model.enums.PostStatus; import run.halo.app.model.params.PostContentParam; import run.halo.app.model.params.PostParam; @@ -166,12 +167,32 @@ public class PostController { public String preview(@PathVariable("postId") Integer postId) throws UnsupportedEncodingException { Post post = postService.getById(postId); + post.setUrl(URLEncoder.encode(post.getUrl(), StandardCharsets.UTF_8.name())); + + BasePostMinimalDTO postMinimalDTO = postService.convertToMinimal(post); + String token = IdUtil.simpleUUID(); // cache preview token cacheStore.putAny(token, token, 10, TimeUnit.MINUTES); + StringBuilder previewUrl = new StringBuilder(); + + if (!optionService.isEnabledAbsolutePath()) { + previewUrl.append(optionService.getBlogBaseUrl()); + } + + previewUrl.append(postMinimalDTO.getFullPath()); + + if (optionService.getPostPermalinkType().equals(PostPermalinkType.ID)) { + previewUrl.append("&token=") + .append(token); + } else { + previewUrl.append("?token=") + .append(token); + } + // build preview post url and return - return String.format("%s/archives/%s?token=%s", optionService.getBlogBaseUrl(), URLEncoder.encode(post.getUrl(), StandardCharsets.UTF_8.name()), token); + return previewUrl.toString(); } } diff --git a/src/main/java/run/halo/app/controller/admin/api/SheetController.java b/src/main/java/run/halo/app/controller/admin/api/SheetController.java index 1a8733a84..83647639d 100644 --- a/src/main/java/run/halo/app/controller/admin/api/SheetController.java +++ b/src/main/java/run/halo/app/controller/admin/api/SheetController.java @@ -8,6 +8,7 @@ import org.springframework.data.web.PageableDefault; import org.springframework.web.bind.annotation.*; import run.halo.app.cache.StringCacheStore; import run.halo.app.model.dto.InternalSheetDTO; +import run.halo.app.model.dto.post.BasePostMinimalDTO; import run.halo.app.model.entity.Sheet; import run.halo.app.model.enums.PostStatus; import run.halo.app.model.params.SheetParam; @@ -119,12 +120,26 @@ public class SheetController { public String preview(@PathVariable("sheetId") Integer sheetId) throws UnsupportedEncodingException { Sheet sheet = sheetService.getById(sheetId); + sheet.setUrl(URLEncoder.encode(sheet.getUrl(), StandardCharsets.UTF_8.name())); + + BasePostMinimalDTO sheetMinimalDTO = sheetService.convertToMinimal(sheet); + String token = IdUtil.simpleUUID(); // cache preview token cacheStore.putAny(token, token, 10, TimeUnit.MINUTES); + StringBuilder previewUrl = new StringBuilder(); + + if (!optionService.isEnabledAbsolutePath()) { + previewUrl.append(optionService.getBlogBaseUrl()); + } + + previewUrl.append(sheetMinimalDTO.getFullPath()) + .append("?token=") + .append(token); + // build preview post url and return - return String.format("%s/s/%s?token=%s", optionService.getBlogBaseUrl(), URLEncoder.encode(sheet.getUrl(), StandardCharsets.UTF_8.name()), token); + return previewUrl.toString(); } } diff --git a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java deleted file mode 100644 index e734ffbf8..000000000 --- a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java +++ /dev/null @@ -1,69 +0,0 @@ -package run.halo.app.controller.content; - -import cn.hutool.core.util.IdUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.*; -import run.halo.app.cache.StringCacheStore; -import run.halo.app.cache.lock.CacheLock; -import run.halo.app.model.entity.Post; -import run.halo.app.model.enums.PostStatus; -import run.halo.app.service.OptionService; -import run.halo.app.service.PostService; - -import java.util.concurrent.TimeUnit; - -/** - * Blog archive page controller - * - * @author ryanwang - * @author guqing - * @author evanwang - * @date 2019-03-17 - */ -@Slf4j -@Controller -@RequestMapping(value = "/archives") -public class ContentArchiveController { - - private final PostService postService; - - private final OptionService optionService; - - private final StringCacheStore cacheStore; - - - public ContentArchiveController(PostService postService, - OptionService optionService, - StringCacheStore cacheStore) { - this.postService = postService; - this.optionService = optionService; - this.cacheStore = cacheStore; - } - - @GetMapping(value = "{url:.*}/password") - public String password(@PathVariable("url") String url, - Model model) { - model.addAttribute("url", url); - return "common/template/post_password"; - } - - @PostMapping(value = "{url:.*}/password") - @CacheLock(traceRequest = true, expired = 2) - public String password(@PathVariable("url") String url, - @RequestParam(value = "password") String password) { - Post post = postService.getBy(PostStatus.INTIMATE, url); - - if (password.equals(post.getPassword())) { - String token = IdUtil.simpleUUID(); - cacheStore.putAny(token, token, 10, TimeUnit.SECONDS); - - String redirect = String.format("%s/archives/%s?token=%s", optionService.getBlogBaseUrl(), post.getUrl(), token); - return "redirect:" + redirect; - } else { - String redirect = String.format("%s/archives/%s/password", optionService.getBlogBaseUrl(), post.getUrl()); - return "redirect:" + redirect; - } - } -} diff --git a/src/main/java/run/halo/app/controller/content/ContentContentController.java b/src/main/java/run/halo/app/controller/content/ContentContentController.java index 83615753a..befa4e2ed 100644 --- a/src/main/java/run/halo/app/controller/content/ContentContentController.java +++ b/src/main/java/run/halo/app/controller/content/ContentContentController.java @@ -1,24 +1,28 @@ package run.halo.app.controller.content; +import cn.hutool.core.util.IdUtil; import lombok.extern.slf4j.Slf4j; import org.springframework.stereotype.Controller; import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import org.springframework.web.bind.annotation.RequestParam; -import run.halo.app.controller.content.model.CategoryModel; -import run.halo.app.controller.content.model.PostModel; -import run.halo.app.controller.content.model.SheetModel; -import run.halo.app.controller.content.model.TagModel; +import org.springframework.web.bind.annotation.*; +import run.halo.app.cache.StringCacheStore; +import run.halo.app.cache.lock.CacheLock; +import run.halo.app.controller.content.model.*; import run.halo.app.exception.NotFoundException; +import run.halo.app.model.dto.post.BasePostMinimalDTO; import run.halo.app.model.entity.Post; import run.halo.app.model.entity.Sheet; import run.halo.app.model.enums.PostPermalinkType; -import run.halo.app.model.properties.PermalinkProperties; +import run.halo.app.model.enums.PostStatus; import run.halo.app.service.OptionService; import run.halo.app.service.PostService; import run.halo.app.service.SheetService; +import run.halo.app.service.ThemeService; + +import java.io.UnsupportedEncodingException; +import java.net.URLEncoder; +import java.nio.charset.StandardCharsets; +import java.util.concurrent.TimeUnit; /** * @author ryanwang @@ -37,41 +41,60 @@ public class ContentContentController { private final TagModel tagModel; + private final JournalModel journalModel; + + private final PhotoModel photoModel; + private final OptionService optionService; private final PostService postService; private final SheetService sheetService; + private final ThemeService themeService; + + private final StringCacheStore cacheStore; + public ContentContentController(PostModel postModel, SheetModel sheetModel, CategoryModel categoryModel, TagModel tagModel, + JournalModel journalModel, + PhotoModel photoModel, OptionService optionService, PostService postService, - SheetService sheetService) { + SheetService sheetService, + ThemeService themeService, + StringCacheStore cacheStore) { this.postModel = postModel; this.sheetModel = sheetModel; this.categoryModel = categoryModel; this.tagModel = tagModel; + this.journalModel = journalModel; + this.photoModel = photoModel; this.optionService = optionService; this.postService = postService; this.sheetService = sheetService; + this.themeService = themeService; + this.cacheStore = cacheStore; } @GetMapping("{prefix}") public String content(@PathVariable("prefix") String prefix, Model model) { - String archivesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, PermalinkProperties.ARCHIVES_PREFIX.defaultValue()); - String categoriesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.CATEGORIES_PREFIX, String.class, PermalinkProperties.CATEGORIES_PREFIX.defaultValue()); - String tagsPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.TAGS_PREFIX, String.class, PermalinkProperties.TAGS_PREFIX.defaultValue()); - - if (archivesPrefix.equals(prefix)) { + if (optionService.getArchivesPrefix().equals(prefix)) { return postModel.list(1, model, "is_archives", "archives"); - } else if (categoriesPrefix.equals(prefix)) { + } else if (optionService.getCategoriesPrefix().equals(prefix)) { return categoryModel.list(model); - } else if (tagsPrefix.equals(prefix)) { + } else if (optionService.getTagsPrefix().equals(prefix)) { return tagModel.list(model); + } else if (optionService.getJournalsPrefix().equals(prefix)) { + return journalModel.list(1, model); + } else if (optionService.getPhotosPrefix().equals(prefix)) { + return photoModel.list(1, model); + } else if (optionService.getLinksPrefix().equals(prefix)) { + model.addAttribute("is_links", true); + return themeService.render("links"); } else { throw new NotFoundException("Not Found"); } @@ -81,9 +104,12 @@ public class ContentContentController { public String content(@PathVariable("prefix") String prefix, @PathVariable(value = "page") Integer page, Model model) { - String archivesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, PermalinkProperties.ARCHIVES_PREFIX.defaultValue()); - if (archivesPrefix.equals(prefix)) { + if (optionService.getArchivesPrefix().equals(prefix)) { return postModel.list(page, model, "is_archives", "archives"); + } else if (optionService.getJournalsPrefix().equals(prefix)) { + return journalModel.list(page, model); + } else if (optionService.getPhotosPrefix().equals(prefix)) { + return photoModel.list(page, model); } else { throw new NotFoundException("Not Found"); } @@ -95,20 +121,16 @@ public class ContentContentController { @RequestParam(value = "token", required = false) String token, Model model) { PostPermalinkType postPermalinkType = optionService.getPostPermalinkType(); - String archivesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, PermalinkProperties.ARCHIVES_PREFIX.defaultValue()); - String sheetPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.SHEET_PREFIX, String.class, PermalinkProperties.SHEET_PREFIX.defaultValue()); - String categoriesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.CATEGORIES_PREFIX, String.class, PermalinkProperties.CATEGORIES_PREFIX.defaultValue()); - String tagsPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.TAGS_PREFIX, String.class, PermalinkProperties.TAGS_PREFIX.defaultValue()); - if (postPermalinkType.equals(PostPermalinkType.DEFAULT) && archivesPrefix.equals(prefix)) { + if (postPermalinkType.equals(PostPermalinkType.DEFAULT) && optionService.getArchivesPrefix().equals(prefix)) { Post post = postService.getByUrl(url); return postModel.content(post, token, model); - } else if (sheetPrefix.equals(prefix)) { + } else if (optionService.getSheetPrefix().equals(prefix)) { Sheet sheet = sheetService.getByUrl(url); return sheetModel.content(sheet, token, model); - } else if (categoriesPrefix.equals(prefix)) { + } else if (optionService.getCategoriesPrefix().equals(prefix)) { return categoryModel.listPost(model, url, 1); - } else if (tagsPrefix.equals(prefix)) { + } else if (optionService.getTagsPrefix().equals(prefix)) { return tagModel.listPost(model, url, 1); } else { throw new NotFoundException("Not Found"); @@ -120,12 +142,9 @@ public class ContentContentController { @PathVariable("url") String url, @PathVariable("page") Integer page, Model model) { - String categoriesPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.CATEGORIES_PREFIX, String.class, PermalinkProperties.CATEGORIES_PREFIX.defaultValue()); - String tagsPrefix = optionService.getByPropertyOrDefault(PermalinkProperties.TAGS_PREFIX, String.class, PermalinkProperties.TAGS_PREFIX.defaultValue()); - - if (categoriesPrefix.equals(prefix)) { + if (optionService.getCategoriesPrefix().equals(prefix)) { return categoryModel.listPost(model, url, page); - } else if (tagsPrefix.equals(prefix)) { + } else if (optionService.getTagsPrefix().equals(prefix)) { return tagModel.listPost(model, url, page); } else { throw new NotFoundException("Not Found"); @@ -162,4 +181,38 @@ public class ContentContentController { throw new NotFoundException("Not Found"); } } + + @PostMapping(value = "archives/{url:.*}/password") + @CacheLock(traceRequest = true, expired = 2) + public String password(@PathVariable("url") String url, + @RequestParam(value = "password") String password) throws UnsupportedEncodingException { + Post post = postService.getBy(PostStatus.INTIMATE, url); + + post.setUrl(URLEncoder.encode(post.getUrl(), StandardCharsets.UTF_8.name())); + + BasePostMinimalDTO postMinimalDTO = postService.convertToMinimal(post); + + StringBuilder redirectUrl = new StringBuilder(); + + if (!optionService.isEnabledAbsolutePath()) { + redirectUrl.append(optionService.getBlogBaseUrl()); + } + + redirectUrl.append(postMinimalDTO.getFullPath()); + + if (password.equals(post.getPassword())) { + String token = IdUtil.simpleUUID(); + cacheStore.putAny(token, token, 10, TimeUnit.SECONDS); + + if (optionService.getPostPermalinkType().equals(PostPermalinkType.ID)) { + redirectUrl.append("&token=") + .append(token); + } else { + redirectUrl.append("?token=") + .append(token); + } + } + + return "redirect:" + redirectUrl; + } } diff --git a/src/main/java/run/halo/app/controller/content/ContentJournalController.java b/src/main/java/run/halo/app/controller/content/ContentJournalController.java deleted file mode 100644 index da8d428f3..000000000 --- a/src/main/java/run/halo/app/controller/content/ContentJournalController.java +++ /dev/null @@ -1,86 +0,0 @@ -package run.halo.app.controller.content; - -import cn.hutool.core.util.PageUtil; -import lombok.extern.slf4j.Slf4j; -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.data.web.SortDefault; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestMapping; -import run.halo.app.model.entity.Journal; -import run.halo.app.model.enums.JournalType; -import run.halo.app.service.JournalService; -import run.halo.app.service.OptionService; -import run.halo.app.service.ThemeService; - -import static org.springframework.data.domain.Sort.Direction.DESC; - -/** - * Blog journal page controller - * - * @author ryanwang - * @date 2019-05-04 - */ -@Slf4j -@Controller -@RequestMapping(value = "/journals") -public class ContentJournalController { - - private final JournalService journalService; - - private final OptionService optionService; - - private final ThemeService themeService; - - public ContentJournalController(JournalService journalService, - OptionService optionService, - ThemeService themeService) { - this.journalService = journalService; - this.optionService = optionService; - this.themeService = themeService; - } - - /** - * Render journal page. - * - * @param model model - * @return template path: themes/{theme}/journals.ftl - */ - @GetMapping - public String journals(Model model) { - return this.journals(model, 1, Sort.by(DESC, "createTime")); - } - - - /** - * Render journal page. - * - * @param model model - * @param page current page number - * @return template path: themes/{theme}/journals.ftl - */ - @GetMapping(value = "page/{page}") - public String journals(Model model, - @PathVariable(value = "page") Integer page, - @SortDefault(sort = "createTime", direction = DESC) Sort sort) { - log.debug("Requested journal page, sort info: [{}]", sort); - - int pageSize = optionService.getPostPageSize(); - - Pageable pageable = PageRequest.of(page >= 1 ? page - 1 : page, pageSize, sort); - - Page journals = journalService.pageBy(JournalType.PUBLIC, pageable); - - int[] rainbow = PageUtil.rainbow(page, journals.getTotalPages(), 3); - - model.addAttribute("is_journals", true); - model.addAttribute("journals", journalService.convertToCmtCountDto(journals)); - model.addAttribute("rainbow", rainbow); - return themeService.render("journals"); - } -} diff --git a/src/main/java/run/halo/app/controller/content/ContentSearchController.java b/src/main/java/run/halo/app/controller/content/ContentSearchController.java index f8d4506d2..f1f7fd876 100644 --- a/src/main/java/run/halo/app/controller/content/ContentSearchController.java +++ b/src/main/java/run/halo/app/controller/content/ContentSearchController.java @@ -73,11 +73,49 @@ public class ContentSearchController { final Page posts = postService.convertToListVo(postPage); + // TODO remove this variable final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3); + + // Next page and previous page url. + StringBuilder nextPageFullPath = new StringBuilder(); + StringBuilder prePageFullPath = new StringBuilder(); + + if (optionService.isEnabledAbsolutePath()) { + nextPageFullPath.append(optionService.getBlogBaseUrl()) + .append("/"); + prePageFullPath.append(optionService.getBlogBaseUrl()) + .append("/"); + } else { + nextPageFullPath.append("/"); + prePageFullPath.append("/"); + } + + nextPageFullPath.append("search"); + prePageFullPath.append("search"); + + nextPageFullPath.append("/page/") + .append(posts.getNumber() + 2) + .append(optionService.getPathSuffix()) + .append("?keyword=") + .append(keyword); + + if (posts.getNumber() == 1) { + prePageFullPath.append("?keyword=") + .append(keyword); + } else { + prePageFullPath.append("/page/") + .append(posts.getNumber()) + .append(optionService.getPathSuffix()) + .append("?keyword=") + .append(keyword); + } + model.addAttribute("is_search", true); model.addAttribute("keyword", keyword); model.addAttribute("posts", posts); model.addAttribute("rainbow", rainbow); + model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); + model.addAttribute("prePageFullPath", prePageFullPath.toString()); return themeService.render("search"); } } diff --git a/src/main/java/run/halo/app/controller/content/ContentSheetController.java b/src/main/java/run/halo/app/controller/content/ContentSheetController.java deleted file mode 100644 index cca6dc329..000000000 --- a/src/main/java/run/halo/app/controller/content/ContentSheetController.java +++ /dev/null @@ -1,77 +0,0 @@ -package run.halo.app.controller.content; - -import org.springframework.data.domain.Page; -import org.springframework.data.domain.PageRequest; -import org.springframework.data.domain.Pageable; -import org.springframework.data.domain.Sort; -import org.springframework.stereotype.Controller; -import org.springframework.ui.Model; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.PathVariable; -import org.springframework.web.bind.annotation.RequestParam; -import run.halo.app.model.dto.PhotoDTO; -import run.halo.app.service.PhotoService; -import run.halo.app.service.ThemeService; - -import static org.springframework.data.domain.Sort.Direction.DESC; - -/** - * Content sheet controller. - * - * @author ryanwang - * @author evanwang - * @date 2019-03-21 - */ -@Controller -public class ContentSheetController { - - - private final ThemeService themeService; - - private final PhotoService photoService; - - public ContentSheetController(ThemeService themeService, - PhotoService photoService) { - this.themeService = themeService; - this.photoService = photoService; - } - - /** - * Render photo page - * - * @return template path: themes/{theme}/photos.ftl - */ - @GetMapping(value = "/photos") - public String photos(Model model, - @RequestParam(value = "size", required = false, defaultValue = "10") Integer size) { - return photos(model, 1, size); - } - - /** - * Render photo page - * - * @param model model - * @param page current page - * @param size current page size - * @return template path: themes/{theme}/photos.ftl - */ - @GetMapping(value = "/photos/page/{page}") - public String photos(Model model, - @PathVariable(value = "page") Integer page, - @RequestParam(value = "size", required = false, defaultValue = "10") Integer size) { - Pageable pageable = PageRequest.of(page >= 1 ? page - 1 : page, size, Sort.by(DESC, "createTime")); - Page photos = photoService.pageBy(pageable); - model.addAttribute("photos", photos); - return themeService.render("photos"); - } - - /** - * Render links page - * - * @return template path: themes/{theme}/links.ftl - */ - @GetMapping(value = "/links") - public String links() { - return themeService.render("links"); - } -} diff --git a/src/main/java/run/halo/app/controller/content/model/CategoryModel.java b/src/main/java/run/halo/app/controller/content/model/CategoryModel.java index ecc5aedf4..4f9517079 100644 --- a/src/main/java/run/halo/app/controller/content/model/CategoryModel.java +++ b/src/main/java/run/halo/app/controller/content/model/CategoryModel.java @@ -7,6 +7,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; import org.springframework.ui.Model; +import run.halo.app.model.dto.CategoryDTO; import run.halo.app.model.entity.Category; import run.halo.app.model.entity.Post; import run.halo.app.model.enums.PostStatus; @@ -50,16 +51,37 @@ public class CategoryModel { public String listPost(Model model, String slugName, Integer page) { // Get category by slug name final Category category = categoryService.getBySlugNameOfNonNull(slugName); + CategoryDTO categoryDTO = categoryService.convertTo(category); final Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), Sort.by(DESC, "createTime")); Page postPage = postCategoryService.pagePostBy(category.getId(), PostStatus.PUBLISHED, pageable); Page posts = postService.convertToListVo(postPage); + + // TODO remove this variable final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3); + // Next page and previous page url. + StringBuilder nextPageFullPath = new StringBuilder(categoryDTO.getFullPath()); + StringBuilder prePageFullPath = new StringBuilder(categoryDTO.getFullPath()); + + nextPageFullPath.append("/page/") + .append(posts.getNumber() + 2) + .append(optionService.getPathSuffix()); + + if (posts.getNumber() == 1) { + prePageFullPath.append("/"); + } else { + prePageFullPath.append("/page/") + .append(posts.getNumber()) + .append(optionService.getPathSuffix()); + } + model.addAttribute("is_category", true); model.addAttribute("posts", posts); model.addAttribute("rainbow", rainbow); - model.addAttribute("category", category); + model.addAttribute("category", categoryDTO); + model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); + model.addAttribute("prePageFullPath", prePageFullPath.toString()); return themeService.render("category"); } } diff --git a/src/main/java/run/halo/app/controller/content/model/JournalModel.java b/src/main/java/run/halo/app/controller/content/model/JournalModel.java new file mode 100644 index 000000000..229753ea5 --- /dev/null +++ b/src/main/java/run/halo/app/controller/content/model/JournalModel.java @@ -0,0 +1,87 @@ +package run.halo.app.controller.content.model; + +import cn.hutool.core.util.PageUtil; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; +import org.springframework.ui.Model; +import run.halo.app.model.entity.Journal; +import run.halo.app.model.enums.JournalType; +import run.halo.app.model.properties.SheetProperties; +import run.halo.app.service.JournalService; +import run.halo.app.service.OptionService; +import run.halo.app.service.ThemeService; + +import static org.springframework.data.domain.Sort.Direction.DESC; + +/** + * @author ryanwang + * @date 2020-02-11 + */ +@Component +public class JournalModel { + + private final JournalService journalService; + + private final OptionService optionService; + + private final ThemeService themeService; + + public JournalModel(JournalService journalService, + OptionService optionService, + ThemeService themeService) { + this.journalService = journalService; + this.optionService = optionService; + this.themeService = themeService; + } + + public String list(Integer page, Model model) { + + int pageSize = optionService.getByPropertyOrDefault(SheetProperties.JOURNALS_PAGE_SIZE, Integer.class, Integer.parseInt(SheetProperties.JOURNALS_PAGE_SIZE.defaultValue())); + + Pageable pageable = PageRequest.of(page >= 1 ? page - 1 : page, pageSize, Sort.by(DESC, "createTime")); + + Page journals = journalService.pageBy(JournalType.PUBLIC, pageable); + + // TODO remove this variable + int[] rainbow = PageUtil.rainbow(page, journals.getTotalPages(), 3); + + // Next page and previous page url. + StringBuilder nextPageFullPath = new StringBuilder(); + StringBuilder prePageFullPath = new StringBuilder(); + + if (optionService.isEnabledAbsolutePath()) { + nextPageFullPath.append(optionService.getBlogBaseUrl()) + .append("/"); + prePageFullPath.append(optionService.getBlogBaseUrl()) + .append("/"); + } else { + nextPageFullPath.append("/"); + prePageFullPath.append("/"); + } + + nextPageFullPath.append(optionService.getJournalsPrefix()); + prePageFullPath.append(optionService.getJournalsPrefix()); + + nextPageFullPath.append("/page/") + .append(journals.getNumber() + 2) + .append(optionService.getPathSuffix()); + + if (journals.getNumber() == 1) { + prePageFullPath.append("/"); + } else { + prePageFullPath.append("/page/") + .append(journals.getNumber()) + .append(optionService.getPathSuffix()); + } + + model.addAttribute("is_journals", true); + model.addAttribute("journals", journalService.convertToCmtCountDto(journals)); + model.addAttribute("rainbow", rainbow); + model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); + model.addAttribute("prePageFullPath", prePageFullPath.toString()); + return themeService.render("journals"); + } +} diff --git a/src/main/java/run/halo/app/controller/content/model/PhotoModel.java b/src/main/java/run/halo/app/controller/content/model/PhotoModel.java new file mode 100644 index 000000000..cdeea40cd --- /dev/null +++ b/src/main/java/run/halo/app/controller/content/model/PhotoModel.java @@ -0,0 +1,81 @@ +package run.halo.app.controller.content.model; + +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.stereotype.Component; +import org.springframework.ui.Model; +import run.halo.app.model.dto.PhotoDTO; +import run.halo.app.model.properties.SheetProperties; +import run.halo.app.service.OptionService; +import run.halo.app.service.PhotoService; +import run.halo.app.service.ThemeService; + +import static org.springframework.data.domain.Sort.Direction.DESC; + +/** + * @author ryanwang + * @date 2020-02-11 + */ +@Component +public class PhotoModel { + + private final PhotoService photoService; + + private final ThemeService themeService; + + private final OptionService optionService; + + public PhotoModel(PhotoService photoService, + ThemeService themeService, + OptionService optionService) { + this.photoService = photoService; + this.themeService = themeService; + this.optionService = optionService; + } + + public String list(Integer page, Model model) { + + int pageSize = optionService.getByPropertyOrDefault(SheetProperties.PHOTOS_PAGE_SIZE, Integer.class, Integer.parseInt(SheetProperties.PHOTOS_PAGE_SIZE.defaultValue())); + + Pageable pageable = PageRequest.of(page >= 1 ? page - 1 : page, pageSize, Sort.by(DESC, "createTime")); + + Page photos = photoService.pageBy(pageable); + + // Next page and previous page url. + StringBuilder nextPageFullPath = new StringBuilder(); + StringBuilder prePageFullPath = new StringBuilder(); + + if (optionService.isEnabledAbsolutePath()) { + nextPageFullPath.append(optionService.getBlogBaseUrl()) + .append("/"); + prePageFullPath.append(optionService.getBlogBaseUrl()) + .append("/"); + } else { + nextPageFullPath.append("/"); + prePageFullPath.append("/"); + } + + nextPageFullPath.append(optionService.getPhotosPrefix()); + prePageFullPath.append(optionService.getPhotosPrefix()); + + nextPageFullPath.append("/page/") + .append(photos.getNumber() + 2) + .append(optionService.getPathSuffix()); + + if (photos.getNumber() == 1) { + prePageFullPath.append("/"); + } else { + prePageFullPath.append("/page/") + .append(photos.getNumber()) + .append(optionService.getPathSuffix()); + } + + model.addAttribute("is_photos", true); + model.addAttribute("photos", photos); + model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); + model.addAttribute("prePageFullPath", prePageFullPath.toString()); + return themeService.render("photos"); + } +} diff --git a/src/main/java/run/halo/app/controller/content/model/PostModel.java b/src/main/java/run/halo/app/controller/content/model/PostModel.java index 8848a49dd..f56b9e4a4 100644 --- a/src/main/java/run/halo/app/controller/content/model/PostModel.java +++ b/src/main/java/run/halo/app/controller/content/model/PostModel.java @@ -72,26 +72,26 @@ public class PostModel { public String content(Post post, String token, Model model) { if (post.getStatus().equals(PostStatus.INTIMATE) && StringUtils.isEmpty(token)) { - String redirect = String - .format("%s/archives/%s/password", optionService.getBlogBaseUrl(), - post.getUrl()); - return "redirect:" + redirect; + model.addAttribute("url", post.getUrl()); + return "common/template/post_password"; } - if (!StringUtils.isEmpty(token)) { + if (StringUtils.isEmpty(token)) { + post = postService.getBy(PostStatus.PUBLISHED, post.getUrl()); + } else { // verify token - String cachedToken = cacheStore.getAny(token, String.class) - .orElseThrow(() -> new ForbiddenException("您没有该文章的访问权限")); + String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该文章的访问权限")); if (!cachedToken.equals(token)) { throw new ForbiddenException("您没有该文章的访问权限"); } post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent())); } + postService.publishVisitEvent(post.getId()); AdjacentPostVO adjacentPostVO = postService.getAdjacentPosts(post); - adjacentPostVO.getOptionalPrePost().ifPresent(prePost -> model.addAttribute("prePost", prePost)); - adjacentPostVO.getOptionalNextPost().ifPresent(nextPost -> model.addAttribute("nextPost", nextPost)); + adjacentPostVO.getOptionalPrePost().ifPresent(prePost -> model.addAttribute("prePost", postService.convertToDetailVo(prePost))); + adjacentPostVO.getOptionalNextPost().ifPresent(nextPost -> model.addAttribute("nextPost", postService.convertToDetailVo(nextPost))); List categories = postCategoryService.listCategoriesBy(post.getId()); List tags = postTagService.listTagsBy(post.getId()); @@ -122,12 +122,36 @@ public class PostModel { Page postPage = postService.pageBy(PostStatus.PUBLISHED, pageable); Page posts = postService.convertToListVo(postPage); + // TODO remove this variable int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3); + // Next page and previous page url. + StringBuilder nextPageFullPath = new StringBuilder(); + StringBuilder prePageFullPath = new StringBuilder(); + + if (optionService.isEnabledAbsolutePath()) { + nextPageFullPath.append(optionService.getBlogBaseUrl()); + prePageFullPath.append(optionService.getBlogBaseUrl()); + } + + nextPageFullPath.append("/page/") + .append(posts.getNumber() + 2) + .append(optionService.getPathSuffix()); + + if (posts.getNumber() == 1) { + prePageFullPath.append("/"); + } else { + prePageFullPath.append("/page/") + .append(posts.getNumber()) + .append(optionService.getPathSuffix()); + } + model.addAttribute(decide, true); model.addAttribute("posts", posts); model.addAttribute("rainbow", rainbow); model.addAttribute("pageRainbow", rainbow); + model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); + model.addAttribute("prePageFullPath", prePageFullPath.toString()); return themeService.render(template); } } diff --git a/src/main/java/run/halo/app/controller/content/model/SheetModel.java b/src/main/java/run/halo/app/controller/content/model/SheetModel.java index 7e0203e81..f87561582 100644 --- a/src/main/java/run/halo/app/controller/content/model/SheetModel.java +++ b/src/main/java/run/halo/app/controller/content/model/SheetModel.java @@ -7,6 +7,7 @@ import org.springframework.ui.Model; import run.halo.app.cache.StringCacheStore; import run.halo.app.exception.ForbiddenException; import run.halo.app.model.entity.Sheet; +import run.halo.app.model.enums.PostStatus; import run.halo.app.model.support.HaloConst; import run.halo.app.model.vo.SheetDetailVO; import run.halo.app.service.SheetService; @@ -35,17 +36,19 @@ public class SheetModel { } public String content(Sheet sheet, String token, Model model) { - if (!StringUtils.isEmpty(token)) { - // render markdown to html when preview sheet - sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent())); + if (StringUtils.isEmpty(token)) { + sheet = sheetService.getBy(PostStatus.PUBLISHED, sheet.getUrl()); + } else { // verify token String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该页面的访问权限")); - if (!cachedToken.equals(token)) { throw new ForbiddenException("您没有该页面的访问权限"); } + // render markdown to html when preview sheet + sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent())); } + sheetService.publishVisitEvent(sheet.getId()); SheetDetailVO sheetDetailVO = sheetService.convertToDetailVo(sheet); diff --git a/src/main/java/run/halo/app/controller/content/model/TagModel.java b/src/main/java/run/halo/app/controller/content/model/TagModel.java index ae34ba2f5..3e40680f2 100644 --- a/src/main/java/run/halo/app/controller/content/model/TagModel.java +++ b/src/main/java/run/halo/app/controller/content/model/TagModel.java @@ -7,6 +7,7 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; import org.springframework.ui.Model; +import run.halo.app.model.dto.TagDTO; import run.halo.app.model.entity.Post; import run.halo.app.model.entity.Tag; import run.halo.app.model.enums.PostStatus; @@ -50,16 +51,37 @@ public class TagModel { public String listPost(Model model, String slugName, Integer page) { // Get tag by slug name final Tag tag = tagService.getBySlugNameOfNonNull(slugName); + TagDTO tagDTO = tagService.convertTo(tag); final Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), Sort.by(DESC, "createTime")); Page postPage = postTagService.pagePostsBy(tag.getId(), PostStatus.PUBLISHED, pageable); Page posts = postService.convertToListVo(postPage); + + // TODO remove this variable final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3); + // Next page and previous page url. + StringBuilder nextPageFullPath = new StringBuilder(tagDTO.getFullPath()); + StringBuilder prePageFullPath = new StringBuilder(tagDTO.getFullPath()); + + nextPageFullPath.append("/page/") + .append(posts.getNumber() + 2) + .append(optionService.getPathSuffix()); + + if (posts.getNumber() == 1) { + prePageFullPath.append("/"); + } else { + prePageFullPath.append("/page/") + .append(posts.getNumber()) + .append(optionService.getPathSuffix()); + } + model.addAttribute("is_tag", true); model.addAttribute("posts", posts); model.addAttribute("rainbow", rainbow); - model.addAttribute("tag", tag); + model.addAttribute("tag", tagDTO); + model.addAttribute("nextPageFullPath", nextPageFullPath.toString()); + model.addAttribute("prePageFullPath", prePageFullPath.toString()); return themeService.render("tag"); } } diff --git a/src/main/java/run/halo/app/core/freemarker/tag/CategoryTagDirective.java b/src/main/java/run/halo/app/core/freemarker/tag/CategoryTagDirective.java index e23bf7236..9fc7be408 100644 --- a/src/main/java/run/halo/app/core/freemarker/tag/CategoryTagDirective.java +++ b/src/main/java/run/halo/app/core/freemarker/tag/CategoryTagDirective.java @@ -4,11 +4,13 @@ import freemarker.core.Environment; import freemarker.template.*; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; +import run.halo.app.model.entity.Category; import run.halo.app.model.support.HaloConst; import run.halo.app.service.CategoryService; import run.halo.app.service.PostCategoryService; import java.io.IOException; +import java.util.List; import java.util.Map; import static org.springframework.data.domain.Sort.Direction.DESC; @@ -44,7 +46,8 @@ public class CategoryTagDirective implements TemplateDirectiveModel { break; case "listByPostId": Integer postId = Integer.parseInt(params.get("postId").toString()); - env.setVariable("categories", builder.build().wrap(postCategoryService.listCategoriesBy(postId))); + List categories = postCategoryService.listCategoriesBy(postId); + env.setVariable("categories", builder.build().wrap(categoryService.convertTo(categories))); break; case "count": env.setVariable("count", builder.build().wrap(categoryService.count())); diff --git a/src/main/java/run/halo/app/core/freemarker/tag/PostTagDirective.java b/src/main/java/run/halo/app/core/freemarker/tag/PostTagDirective.java index 69b2c448e..4e15f8a25 100644 --- a/src/main/java/run/halo/app/core/freemarker/tag/PostTagDirective.java +++ b/src/main/java/run/halo/app/core/freemarker/tag/PostTagDirective.java @@ -3,6 +3,7 @@ package run.halo.app.core.freemarker.tag; import freemarker.core.Environment; import freemarker.template.*; import org.springframework.stereotype.Component; +import run.halo.app.model.entity.Post; import run.halo.app.model.enums.PostStatus; import run.halo.app.model.support.HaloConst; import run.halo.app.service.PostCategoryService; @@ -10,6 +11,7 @@ import run.halo.app.service.PostService; import run.halo.app.service.PostTagService; import java.io.IOException; +import java.util.List; import java.util.Map; /** @@ -45,7 +47,8 @@ public class PostTagDirective implements TemplateDirectiveModel { switch (method) { case "latest": int top = Integer.parseInt(params.get("top").toString()); - env.setVariable("posts", builder.build().wrap(postService.listLatest(top))); + List posts = postService.listLatest(top); + env.setVariable("posts", builder.build().wrap(postService.convertToListVo(posts))); break; case "count": env.setVariable("count", builder.build().wrap(postService.countByStatus(PostStatus.PUBLISHED))); @@ -62,19 +65,19 @@ public class PostTagDirective implements TemplateDirectiveModel { break; case "listByCategoryId": Integer categoryId = Integer.parseInt(params.get("categoryId").toString()); - env.setVariable("posts", builder.build().wrap(postCategoryService.listPostBy(categoryId, PostStatus.PUBLISHED))); + env.setVariable("posts", builder.build().wrap(postService.convertToListVo(postCategoryService.listPostBy(categoryId, PostStatus.PUBLISHED)))); break; case "listByCategorySlug": String categorySlug = params.get("categorySlug").toString(); - env.setVariable("posts", builder.build().wrap(postCategoryService.listPostBy(categorySlug, PostStatus.PUBLISHED))); + env.setVariable("posts", builder.build().wrap(postService.convertToListVo(postCategoryService.listPostBy(categorySlug, PostStatus.PUBLISHED)))); break; case "listByTagId": Integer tagId = Integer.parseInt(params.get("tagId").toString()); - env.setVariable("posts", builder.build().wrap(postTagService.listPostsBy(tagId, PostStatus.PUBLISHED))); + env.setVariable("posts", builder.build().wrap(postService.convertToListVo(postTagService.listPostsBy(tagId, PostStatus.PUBLISHED)))); break; case "listByTagSlug": String tagSlug = params.get("tagSlug").toString(); - env.setVariable("posts", builder.build().wrap(postTagService.listPostsBy(tagSlug, PostStatus.PUBLISHED))); + env.setVariable("posts", builder.build().wrap(postService.convertToListVo(postTagService.listPostsBy(tagSlug, PostStatus.PUBLISHED)))); break; default: break; diff --git a/src/main/java/run/halo/app/core/freemarker/tag/TagTagDirective.java b/src/main/java/run/halo/app/core/freemarker/tag/TagTagDirective.java index 132e92022..0fba322fe 100644 --- a/src/main/java/run/halo/app/core/freemarker/tag/TagTagDirective.java +++ b/src/main/java/run/halo/app/core/freemarker/tag/TagTagDirective.java @@ -4,11 +4,13 @@ import freemarker.core.Environment; import freemarker.template.*; import org.springframework.data.domain.Sort; import org.springframework.stereotype.Component; +import run.halo.app.model.entity.Tag; import run.halo.app.model.support.HaloConst; import run.halo.app.service.PostTagService; import run.halo.app.service.TagService; import java.io.IOException; +import java.util.List; import java.util.Map; import static org.springframework.data.domain.Sort.Direction.DESC; @@ -44,7 +46,8 @@ public class TagTagDirective implements TemplateDirectiveModel { break; case "listByPostId": Integer postId = Integer.parseInt(params.get("postId").toString()); - env.setVariable("tags", builder.build().wrap(postTagService.listTagsBy(postId))); + List tags = postTagService.listTagsBy(postId); + env.setVariable("tags", builder.build().wrap(tagService.convertTo(tags))); break; case "count": env.setVariable("count", builder.build().wrap(tagService.count())); diff --git a/src/main/java/run/halo/app/listener/comment/CommentEventListener.java b/src/main/java/run/halo/app/listener/comment/CommentEventListener.java index f154ef737..b24bf0d75 100644 --- a/src/main/java/run/halo/app/listener/comment/CommentEventListener.java +++ b/src/main/java/run/halo/app/listener/comment/CommentEventListener.java @@ -10,6 +10,7 @@ import org.springframework.stereotype.Component; import run.halo.app.event.comment.CommentNewEvent; import run.halo.app.event.comment.CommentReplyEvent; import run.halo.app.exception.ServiceException; +import run.halo.app.model.dto.post.BasePostMinimalDTO; import run.halo.app.mail.MailService; import run.halo.app.model.entity.*; import run.halo.app.model.properties.CommentProperties; @@ -87,12 +88,9 @@ public class CommentEventListener { log.debug("Got post comment: [{}]", postComment); - Post post = postService.getById(postComment.getPostId()); + BasePostMinimalDTO post = postService.convertToMinimal(postService.getById(postComment.getPostId())); - StrBuilder url = new StrBuilder(optionService.getBlogBaseUrl()) - .append("/archives/") - .append(post.getUrl()); - data.put("url", url.toString()); + data.put("url", post.getFullPath()); data.put("page", post.getTitle()); data.put("author", postComment.getAuthor()); data.put("content", postComment.getContent()); @@ -106,12 +104,9 @@ public class CommentEventListener { log.debug("Got sheet comment: [{}]", sheetComment); - Sheet sheet = sheetService.getById(sheetComment.getPostId()); + BasePostMinimalDTO sheet = sheetService.convertToMinimal(sheetService.getById(sheetComment.getPostId())); - StrBuilder url = new StrBuilder(optionService.getBlogBaseUrl()) - .append("/s/") - .append(sheet.getUrl()); - data.put("url", url.toString()); + data.put("url", sheet.getFullPath()); data.put("page", sheet.getTitle()); data.put("author", sheetComment.getAuthor()); data.put("content", sheetComment.getContent()); @@ -127,7 +122,8 @@ public class CommentEventListener { Journal journal = journalService.getById(journalComment.getPostId()); StrBuilder url = new StrBuilder(optionService.getBlogBaseUrl()) - .append("/journals"); + .append("/") + .append(optionService.getJournalsPrefix()); data.put("url", url.toString()); data.put("page", journal.getCreateTime()); data.put("author", journalComment.getAuthor()); @@ -180,13 +176,9 @@ public class CommentEventListener { baseAuthorEmail = baseComment.getEmail(); - Post post = postService.getById(postComment.getPostId()); + BasePostMinimalDTO post = postService.convertToMinimal(postService.getById(postComment.getPostId())); - StrBuilder url = new StrBuilder(optionService.getBlogBaseUrl()) - .append("/archives/") - .append(post.getUrl()); - - data.put("url", url); + data.put("url", post.getFullPath()); data.put("page", post.getTitle()); data.put("baseAuthor", baseComment.getAuthor()); data.put("baseContent", baseComment.getContent()); @@ -214,13 +206,9 @@ public class CommentEventListener { baseAuthorEmail = baseComment.getEmail(); - Sheet sheet = sheetService.getById(sheetComment.getPostId()); + BasePostMinimalDTO sheet = sheetService.convertToMinimal(sheetService.getById(sheetComment.getPostId())); - StrBuilder url = new StrBuilder(optionService.getBlogBaseUrl()) - .append("/s/") - .append(sheet.getUrl()); - - data.put("url", url); + data.put("url", sheet.getFullPath()); data.put("page", sheet.getTitle()); data.put("baseAuthor", baseComment.getAuthor()); data.put("baseContent", baseComment.getContent()); @@ -250,7 +238,8 @@ public class CommentEventListener { Journal journal = journalService.getById(journalComment.getPostId()); StrBuilder url = new StrBuilder(optionService.getBlogBaseUrl()) - .append("/journals"); + .append("/") + .append(optionService.getJournalsPrefix()); data.put("url", url); data.put("page", journal.getContent()); data.put("baseAuthor", baseComment.getAuthor()); diff --git a/src/main/java/run/halo/app/listener/freemarker/FreemarkerConfigAwareListener.java b/src/main/java/run/halo/app/listener/freemarker/FreemarkerConfigAwareListener.java index 2738876e0..146fa37ed 100644 --- a/src/main/java/run/halo/app/listener/freemarker/FreemarkerConfigAwareListener.java +++ b/src/main/java/run/halo/app/listener/freemarker/FreemarkerConfigAwareListener.java @@ -13,7 +13,8 @@ import run.halo.app.event.theme.ThemeActivatedEvent; import run.halo.app.event.theme.ThemeUpdatedEvent; import run.halo.app.event.user.UserUpdatedEvent; import run.halo.app.handler.theme.config.support.ThemeProperty; -import run.halo.app.model.properties.OtherProperties; +import run.halo.app.model.properties.BlogProperties; +import run.halo.app.model.properties.SeoProperties; import run.halo.app.model.support.HaloConst; import run.halo.app.service.OptionService; import run.halo.app.service.ThemeService; @@ -99,9 +100,30 @@ public class FreemarkerConfigAwareListener { } private void loadOptionsConfig() throws TemplateModelException { + + String context = optionService.isEnabledAbsolutePath() ? optionService.getBlogBaseUrl() + "/" : "/"; + configuration.setSharedVariable("options", optionService.listOptions()); - configuration.setSharedVariable("context", optionService.getBlogBaseUrl()); + configuration.setSharedVariable("context", context); configuration.setSharedVariable("version", HaloConst.HALO_VERSION); + + configuration.setSharedVariable("blog_title", optionService.getBlogTitle()); + configuration.setSharedVariable("blog_url", optionService.getBlogBaseUrl()); + configuration.setSharedVariable("blog_logo", optionService.getByPropertyOrDefault(BlogProperties.BLOG_LOGO, String.class, BlogProperties.BLOG_LOGO.defaultValue())); + configuration.setSharedVariable("seo_keywords", optionService.getByPropertyOrDefault(SeoProperties.KEYWORDS, String.class, SeoProperties.KEYWORDS.defaultValue())); + configuration.setSharedVariable("seo_description", optionService.getByPropertyOrDefault(SeoProperties.DESCRIPTION, String.class, SeoProperties.DESCRIPTION.defaultValue())); + + configuration.setSharedVariable("rss_url", optionService.getBlogBaseUrl() + "/rss.xml"); + configuration.setSharedVariable("atom_url", optionService.getBlogBaseUrl() + "/atom.xml"); + configuration.setSharedVariable("sitemap_xml_url", optionService.getBlogBaseUrl() + "/sitemap.xml"); + configuration.setSharedVariable("sitemap_html_url", optionService.getBlogBaseUrl() + "/sitemap.html"); + configuration.setSharedVariable("links_url", context + optionService.getLinksPrefix()); + configuration.setSharedVariable("photos_url", context + optionService.getPhotosPrefix()); + configuration.setSharedVariable("journals_url", context + optionService.getJournalsPrefix()); + configuration.setSharedVariable("archives_url", context + optionService.getArchivesPrefix()); + configuration.setSharedVariable("categories_url", context + optionService.getCategoriesPrefix()); + configuration.setSharedVariable("tags_url", context + optionService.getTagsPrefix()); + log.debug("Loaded options"); } @@ -110,9 +132,7 @@ public class FreemarkerConfigAwareListener { // Get current activated theme. ThemeProperty activatedTheme = themeService.getActivatedTheme(); - Boolean enabledAbsolutePath = optionService.getByPropertyOrDefault(OtherProperties.GLOBAL_ABSOLUTE_PATH_ENABLED, Boolean.class, true); - - String themeBasePath = (enabledAbsolutePath ? optionService.getBlogBaseUrl() : "") + "/themes/" + activatedTheme.getFolderName(); + String themeBasePath = (optionService.isEnabledAbsolutePath() ? optionService.getBlogBaseUrl() : "") + "/themes/" + activatedTheme.getFolderName(); configuration.setSharedVariable("theme", activatedTheme); diff --git a/src/main/java/run/halo/app/model/properties/PermalinkProperties.java b/src/main/java/run/halo/app/model/properties/PermalinkProperties.java index 5745566f7..1cb036736 100644 --- a/src/main/java/run/halo/app/model/properties/PermalinkProperties.java +++ b/src/main/java/run/halo/app/model/properties/PermalinkProperties.java @@ -39,6 +39,24 @@ public enum PermalinkProperties implements PropertyEnum { */ SHEET_PREFIX("sheet_prefix", String.class, "s"), + /** + * Links page prefix + * default is links + */ + LINKS_PREFIX("links_prefix", String.class, "links"), + + /** + * Photos page prefix + * default is photos + */ + PHOTOS_PREFIX("photos_prefix", String.class, "photos"), + + /** + * Journals page prefix + * default is journals + */ + JOURNALS_PREFIX("journals_prefix", String.class, "journals"), + /** * Path suffix * such as: .html or .jsp diff --git a/src/main/java/run/halo/app/model/properties/PropertyEnum.java b/src/main/java/run/halo/app/model/properties/PropertyEnum.java index c04bc4a49..1416d7221 100644 --- a/src/main/java/run/halo/app/model/properties/PropertyEnum.java +++ b/src/main/java/run/halo/app/model/properties/PropertyEnum.java @@ -185,6 +185,7 @@ public interface PropertyEnum extends ValueEnum { propertyEnumClasses.add(EmailProperties.class); propertyEnumClasses.add(OtherProperties.class); propertyEnumClasses.add(PostProperties.class); + propertyEnumClasses.add(SheetProperties.class); propertyEnumClasses.add(PrimaryProperties.class); propertyEnumClasses.add(QiniuOssProperties.class); propertyEnumClasses.add(SeoProperties.class); diff --git a/src/main/java/run/halo/app/model/properties/SheetProperties.java b/src/main/java/run/halo/app/model/properties/SheetProperties.java new file mode 100644 index 000000000..055a6c7b4 --- /dev/null +++ b/src/main/java/run/halo/app/model/properties/SheetProperties.java @@ -0,0 +1,62 @@ +package run.halo.app.model.properties; + +/** + * Sheet properties. + * + * @author ryanwang + * @date 2020-02-11 + */ +public enum SheetProperties implements PropertyEnum { + + /** + * Links page title. + */ + LINKS_TITLE("links_title", String.class, "友情链接"), + + /** + * Photos page title. + */ + PHOTOS_TITLE("photos_title", String.class, "图库"), + + /** + * Photos page size. + */ + PHOTOS_PAGE_SIZE("photos_page_size", Integer.class, "10"), + + /** + * Journals page title. + */ + JOURNALS_TITLE("journals_title", String.class, "日志"), + + /** + * Journals page size. + */ + JOURNALS_PAGE_SIZE("journals_page_size", Integer.class, "10"); + + private final String value; + + private final Class type; + + private final String defaultValue; + + SheetProperties(String value, Class type, String defaultValue) { + this.value = value; + this.type = type; + this.defaultValue = defaultValue; + } + + @Override + public String getValue() { + return value; + } + + @Override + public Class getType() { + return type; + } + + @Override + public String defaultValue() { + return defaultValue; + } +} diff --git a/src/main/java/run/halo/app/service/OptionService.java b/src/main/java/run/halo/app/service/OptionService.java index bdee3f9aa..af8cb5bc2 100755 --- a/src/main/java/run/halo/app/service/OptionService.java +++ b/src/main/java/run/halo/app/service/OptionService.java @@ -26,6 +26,7 @@ import java.util.Optional; * Option service interface. * * @author johnniang + * @author ryanwang * @date 2019-03-14 */ public interface OptionService extends CrudService { @@ -358,6 +359,69 @@ public interface OptionService extends CrudService { */ PostPermalinkType getPostPermalinkType(); + /** + * Get sheet custom prefix. + * + * @return sheet prefix. + */ + String getSheetPrefix(); + + /** + * Get links page custom prefix. + * + * @return links page prefix. + */ + String getLinksPrefix(); + + /** + * Get photos page custom prefix. + * + * @return photos page prefix. + */ + String getPhotosPrefix(); + + /** + * Get journals page custom prefix. + * + * @return journals page prefix. + */ + String getJournalsPrefix(); + + /** + * Get archives custom prefix. + * + * @return archives prefix. + */ + String getArchivesPrefix(); + + /** + * Get categories custom prefix. + * + * @return categories prefix. + */ + String getCategoriesPrefix(); + + /** + * Get tags custom prefix. + * + * @return tags prefix. + */ + String getTagsPrefix(); + + /** + * Get custom path suffix. + * + * @return path suffix. + */ + String getPathSuffix(); + + /** + * Is enabled absolute path. + * + * @return true or false. + */ + Boolean isEnabledAbsolutePath(); + /** * Replace option url in batch. * diff --git a/src/main/java/run/halo/app/service/PostCommentService.java b/src/main/java/run/halo/app/service/PostCommentService.java index 91bd9665b..c266b5729 100644 --- a/src/main/java/run/halo/app/service/PostCommentService.java +++ b/src/main/java/run/halo/app/service/PostCommentService.java @@ -1,11 +1,9 @@ package run.halo.app.service; import org.springframework.data.domain.Page; -import org.springframework.data.domain.Pageable; import org.springframework.lang.NonNull; import org.springframework.lang.Nullable; import run.halo.app.model.entity.PostComment; -import run.halo.app.model.params.CommentQuery; import run.halo.app.model.vo.PostCommentWithPostVO; import run.halo.app.service.base.BaseCommentService; @@ -47,9 +45,6 @@ public interface PostCommentService extends BaseCommentService { @NonNull List convertToWithPostVo(@Nullable List postComments); - @NonNull - Page pageTreeBy(@NonNull CommentQuery commentQuery, @NonNull Pageable pageable); - /** * Validate CommentBlackList Status */ diff --git a/src/main/java/run/halo/app/service/PostService.java b/src/main/java/run/halo/app/service/PostService.java index 5217eb19d..801055046 100755 --- a/src/main/java/run/halo/app/service/PostService.java +++ b/src/main/java/run/halo/app/service/PostService.java @@ -213,6 +213,15 @@ public interface PostService extends BasePostService { @NonNull Page convertToListVo(@NonNull Page postPage); + /** + * Converts to a list of post list vo. + * + * @param posts post must not be null + * @return a list of post list vo + */ + @NonNull + List convertToListVo(@NonNull List posts); + /** * Converts to a page of detail vo. * diff --git a/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java b/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java index d62f12fef..81f3bfce5 100644 --- a/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java @@ -131,6 +131,7 @@ public class AdminServiceImpl implements AdminService { this.mode = mode; } + @Override public AuthToken authenticate(LoginParam loginParam) { Assert.notNull(loginParam, "Login param must not be null"); diff --git a/src/main/java/run/halo/app/service/impl/AttachmentServiceImpl.java b/src/main/java/run/halo/app/service/impl/AttachmentServiceImpl.java index 5703fe71e..09dd6f9ad 100644 --- a/src/main/java/run/halo/app/service/impl/AttachmentServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/AttachmentServiceImpl.java @@ -18,7 +18,6 @@ import run.halo.app.model.entity.Attachment; import run.halo.app.model.enums.AttachmentType; import run.halo.app.model.params.AttachmentQuery; import run.halo.app.model.properties.AttachmentProperties; -import run.halo.app.model.properties.OtherProperties; import run.halo.app.model.support.UploadResult; import run.halo.app.repository.AttachmentRepository; import run.halo.app.service.AttachmentService; @@ -158,7 +157,7 @@ public class AttachmentServiceImpl extends AbstractCrudService private final PostCategoryService postCategoryService; + private final OptionService optionService; + public CategoryServiceImpl(CategoryRepository categoryRepository, - PostCategoryService postCategoryService) { + PostCategoryService postCategoryService, + OptionService optionService) { super(categoryRepository); this.categoryRepository = categoryRepository; this.postCategoryService = postCategoryService; + this.optionService = optionService; } @Override @@ -188,7 +193,23 @@ public class CategoryServiceImpl extends AbstractCrudService public CategoryDTO convertTo(Category category) { Assert.notNull(category, "Category must not be null"); - return new CategoryDTO().convertFrom(category); + CategoryDTO categoryDTO = new CategoryDTO().convertFrom(category); + + StringBuilder fullPath = new StringBuilder(); + + if (optionService.isEnabledAbsolutePath()) { + fullPath.append(optionService.getBlogBaseUrl()); + } + + fullPath.append("/") + .append(optionService.getCategoriesPrefix()) + .append("/") + .append(category.getSlugName()) + .append(optionService.getPathSuffix()); + + categoryDTO.setFullPath(fullPath.toString()); + + return categoryDTO; } @Override diff --git a/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java b/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java index 801f639bc..2ade3bb0b 100644 --- a/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/OptionServiceImpl.java @@ -472,6 +472,51 @@ public class OptionServiceImpl extends AbstractCrudService impl return getEnumByPropertyOrDefault(PermalinkProperties.POST_PERMALINK_TYPE, PostPermalinkType.class, PostPermalinkType.DEFAULT); } + @Override + public String getSheetPrefix() { + return getByPropertyOrDefault(PermalinkProperties.SHEET_PREFIX, String.class, PermalinkProperties.SHEET_PREFIX.defaultValue()); + } + + @Override + public String getLinksPrefix() { + return getByPropertyOrDefault(PermalinkProperties.LINKS_PREFIX, String.class, PermalinkProperties.LINKS_PREFIX.defaultValue()); + } + + @Override + public String getPhotosPrefix() { + return getByPropertyOrDefault(PermalinkProperties.PHOTOS_PREFIX, String.class, PermalinkProperties.PHOTOS_PREFIX.defaultValue()); + } + + @Override + public String getJournalsPrefix() { + return getByPropertyOrDefault(PermalinkProperties.JOURNALS_PREFIX, String.class, PermalinkProperties.JOURNALS_PREFIX.defaultValue()); + } + + @Override + public String getArchivesPrefix() { + return getByPropertyOrDefault(PermalinkProperties.ARCHIVES_PREFIX, String.class, PermalinkProperties.ARCHIVES_PREFIX.defaultValue()); + } + + @Override + public String getCategoriesPrefix() { + return getByPropertyOrDefault(PermalinkProperties.CATEGORIES_PREFIX, String.class, PermalinkProperties.CATEGORIES_PREFIX.defaultValue()); + } + + @Override + public String getTagsPrefix() { + return getByPropertyOrDefault(PermalinkProperties.TAGS_PREFIX, String.class, PermalinkProperties.TAGS_PREFIX.defaultValue()); + } + + @Override + public String getPathSuffix() { + return getByPropertyOrDefault(PermalinkProperties.PATH_SUFFIX, String.class, PermalinkProperties.PATH_SUFFIX.defaultValue()); + } + + @Override + public Boolean isEnabledAbsolutePath() { + return getByPropertyOrDefault(OtherProperties.GLOBAL_ABSOLUTE_PATH_ENABLED, Boolean.class, true); + } + @Override public List replaceUrl(String oldUrl, String newUrl) { List