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 7115c479d..245b53f8f 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 @@ -150,9 +150,9 @@ public class PostController { cacheStore.putAny("preview-post-token-" + postId, token, 10, TimeUnit.MINUTES); // build preview post url - String url = String.format("%s/archives/%s?preview=true&token=%s", optionService.getBlogBaseUrl(), post.getUrl(), token); + String redirect = String.format("%s/archives/%s?preview=true&token=%s", optionService.getBlogBaseUrl(), post.getUrl(), token); // redirect to preview url - response.sendRedirect(url); + response.sendRedirect(redirect); } } 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 13e0e5782..8a3330a17 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 @@ -123,9 +123,9 @@ public class SheetController { cacheStore.putAny("preview-sheet-token-" + sheetId, token, 10, TimeUnit.MINUTES); // build preview sheet url - String url = String.format("%s/s/%s?preview=true&token=%s", optionService.getBlogBaseUrl(), sheet.getUrl(), token); + String redirect = String.format("%s/s/%s?preview=true&token=%s", optionService.getBlogBaseUrl(), sheet.getUrl(), token); // redirect to preview url - response.sendRedirect(url); + response.sendRedirect(redirect); } } diff --git a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java index 2824ca41f..80a2c4231 100644 --- a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java +++ b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java @@ -1,6 +1,8 @@ package run.halo.app.controller.content; +import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.PageUtil; +import cn.hutool.crypto.digest.BCrypt; import lombok.extern.slf4j.Slf4j; import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; @@ -9,11 +11,9 @@ 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 org.springframework.web.bind.annotation.RequestParam; +import org.springframework.web.bind.annotation.*; import run.halo.app.cache.StringCacheStore; +import run.halo.app.cache.lock.CacheLock; import run.halo.app.exception.ForbiddenException; import run.halo.app.model.entity.Category; import run.halo.app.model.entity.Post; @@ -111,10 +111,19 @@ public class ContentArchiveController { @GetMapping("{url}") public String post(@PathVariable("url") String url, @RequestParam(value = "preview", required = false, defaultValue = "false") boolean preview, + @RequestParam(value = "intimate", required = false, defaultValue = "false") boolean intimate, @RequestParam(value = "token", required = false) String token, Model model) { - Post post = postService.getBy(preview ? PostStatus.DRAFT : PostStatus.PUBLISHED, url); + Post post; + if (preview) { + post = postService.getBy(PostStatus.DRAFT, url); + } else if (intimate) { + post = postService.getBy(PostStatus.INTIMATE, url); + } else { + post = postService.getBy(PostStatus.PUBLISHED, url); + } + // if this is a preview url. if (preview) { // render markdown to html when preview post post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent())); @@ -127,6 +136,15 @@ public class ContentArchiveController { } } + // if this is a intimate url. + if (intimate) { + // verify token + String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该文章的访问权限")); + if (!cachedToken.equals(token)) { + throw new ForbiddenException("您没有该文章的访问权限"); + } + } + postService.getNextPost(post.getCreateTime()).ifPresent(nextPost -> model.addAttribute("nextPost", nextPost)); postService.getPrePost(post.getCreateTime()).ifPresent(prePost -> model.addAttribute("prePost", prePost)); @@ -145,4 +163,37 @@ public class ContentArchiveController { return themeService.render("post"); } + + @GetMapping(value = "{url}/password") + public String password(@PathVariable("url") String url, + Model model) { + Post post = postService.getBy(PostStatus.INTIMATE, url); + if (null == post) { + throw new ForbiddenException("没有查询到该文章信息"); + } + + model.addAttribute("url", url); + return "common/template/post_password"; + } + + @PostMapping(value = "{url}/password") + @CacheLock + public String password(@PathVariable("url") String url, + @RequestParam(value = "password") String password) { + Post post = postService.getBy(PostStatus.INTIMATE, url); + if (null == post) { + throw new ForbiddenException("没有查询到该文章信息"); + } + + if (BCrypt.checkpw(password, post.getPassword())) { + String token = IdUtil.simpleUUID(); + cacheStore.putAny(token, token, 10, TimeUnit.SECONDS); + + String redirect = String.format("%s/archives/%s?intimate=true&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/model/dto/post/BasePostSimpleDTO.java b/src/main/java/run/halo/app/model/dto/post/BasePostSimpleDTO.java index 2f7e9afe9..793bdabb4 100644 --- a/src/main/java/run/halo/app/model/dto/post/BasePostSimpleDTO.java +++ b/src/main/java/run/halo/app/model/dto/post/BasePostSimpleDTO.java @@ -23,6 +23,8 @@ public class BasePostSimpleDTO extends BasePostMinimalDTO { private Boolean disallowComment; + private String password; + private String template; private Integer topPriority = 0; diff --git a/src/main/java/run/halo/app/model/enums/JournalType.java b/src/main/java/run/halo/app/model/enums/JournalType.java index 2b4b4ff28..97386238b 100644 --- a/src/main/java/run/halo/app/model/enums/JournalType.java +++ b/src/main/java/run/halo/app/model/enums/JournalType.java @@ -13,9 +13,9 @@ public enum JournalType implements ValueEnum { PUBLIC(1), /** - * Private type. + * Intimate type. */ - PRIVATE(0); + INTIMATE(0); private final int value; diff --git a/src/main/java/run/halo/app/model/enums/PostStatus.java b/src/main/java/run/halo/app/model/enums/PostStatus.java index fedd6ecff..9e5b4e3f6 100644 --- a/src/main/java/run/halo/app/model/enums/PostStatus.java +++ b/src/main/java/run/halo/app/model/enums/PostStatus.java @@ -20,7 +20,12 @@ public enum PostStatus implements ValueEnum { /** * Recycle status. */ - RECYCLE(2); + RECYCLE(2), + + /** + * Intimate status + */ + INTIMATE(3); private final int value; diff --git a/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java b/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java index b3389d63d..1e5d2c178 100644 --- a/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/BasePostServiceImpl.java @@ -217,6 +217,11 @@ public abstract class BasePostServiceImpl extends Abstrac post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent())); } + // if password is not empty,change status to intimate + if (StringUtils.isNotEmpty(post.getPassword()) && post.getStatus() != PostStatus.DRAFT) { + post.setStatus(PostStatus.INTIMATE); + } + // Create or update post if (ServiceUtils.isEmptyId(post.getId())) { // The sheet will be created diff --git a/src/main/resources/templates/common/template/post_password.ftl b/src/main/resources/templates/common/template/post_password.ftl new file mode 100644 index 000000000..2aeac0316 --- /dev/null +++ b/src/main/resources/templates/common/template/post_password.ftl @@ -0,0 +1,169 @@ + + + + + + + + 私密文章访问 - ${options.blog_title!} + + + +
+
+
+ + + + + +
+
+ +
+
+
+ + \ No newline at end of file