mirror of https://github.com/halo-dev/halo
✨ 支持文章加密
parent
bba2e3a7e0
commit
3818be62e3
|
@ -1,7 +1,6 @@
|
|||
package cc.ryanc.halo.model.domain;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
@ -130,6 +129,11 @@ public class Post implements Serializable {
|
|||
*/
|
||||
private Integer allowComment = 0;
|
||||
|
||||
/**
|
||||
* 文章访问密码
|
||||
*/
|
||||
private String postPassword;
|
||||
|
||||
/**
|
||||
* 指定渲染模板
|
||||
*/
|
||||
|
|
|
@ -149,7 +149,7 @@ public class PostServiceImpl implements PostService {
|
|||
*/
|
||||
@Override
|
||||
public Page<Post> searchPosts(String keyword, String postType, Integer postStatus, Pageable pageable) {
|
||||
return postRepository.findByPostTypeAndPostStatusAndPostTitleLikeOrPostTypeAndPostStatusAndPostContentLike(
|
||||
Page<Post> posts = postRepository.findByPostTypeAndPostStatusAndPostTitleLikeOrPostTypeAndPostStatusAndPostContentLike(
|
||||
postType,
|
||||
postStatus,
|
||||
"%" + keyword + "%",
|
||||
|
@ -158,6 +158,12 @@ public class PostServiceImpl implements PostService {
|
|||
"%" + keyword + "%",
|
||||
pageable
|
||||
);
|
||||
for (Post post : posts.getContent()) {
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostSummary("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -170,7 +176,13 @@ public class PostServiceImpl implements PostService {
|
|||
*/
|
||||
@Override
|
||||
public Page<Post> findPostByStatus(Integer status, String postType, Pageable pageable) {
|
||||
return postRepository.findPostsByPostStatusAndPostType(status, postType, pageable);
|
||||
Page<Post> posts = postRepository.findPostsByPostStatusAndPostType(status, postType, pageable);
|
||||
for (Post post : posts.getContent()) {
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostSummary("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -182,7 +194,13 @@ public class PostServiceImpl implements PostService {
|
|||
@Override
|
||||
@Cacheable(value = POSTS_CACHE_NAME, key = "'posts_page_'+#pageable.pageNumber")
|
||||
public Page<Post> findPostByStatus(Pageable pageable) {
|
||||
return postRepository.findPostsByPostStatusAndPostType(PostStatusEnum.PUBLISHED.getCode(), PostTypeEnum.POST_TYPE_POST.getDesc(), pageable);
|
||||
Page<Post> posts = postRepository.findPostsByPostStatusAndPostType(PostStatusEnum.PUBLISHED.getCode(), PostTypeEnum.POST_TYPE_POST.getDesc(), pageable);
|
||||
for (Post post : posts.getContent()) {
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostSummary("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -367,7 +385,13 @@ public class PostServiceImpl implements PostService {
|
|||
*/
|
||||
@Override
|
||||
public Page<Post> findPostByYearAndMonth(String year, String month, Pageable pageable) {
|
||||
return postRepository.findPostByYearAndMonth(year, month, null);
|
||||
Page<Post> posts = postRepository.findPostByYearAndMonth(year, month, null);
|
||||
for (Post post : posts.getContent()) {
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostSummary("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -381,7 +405,13 @@ public class PostServiceImpl implements PostService {
|
|||
@Override
|
||||
@CachePut(value = POSTS_CACHE_NAME, key = "'posts_category_'+#category.cateId+'_'+#pageable.pageNumber")
|
||||
public Page<Post> findPostByCategories(Category category, Pageable pageable) {
|
||||
return postRepository.findPostByCategoriesAndPostStatus(category, PostStatusEnum.PUBLISHED.getCode(), pageable);
|
||||
Page<Post> posts = postRepository.findPostByCategoriesAndPostStatus(category, PostStatusEnum.PUBLISHED.getCode(), pageable);
|
||||
for (Post post : posts.getContent()) {
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostSummary("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -395,7 +425,13 @@ public class PostServiceImpl implements PostService {
|
|||
@Override
|
||||
@CachePut(value = POSTS_CACHE_NAME, key = "'posts_tag_'+#tag.tagId+'_'+#pageable.pageNumber")
|
||||
public Page<Post> findPostsByTags(Tag tag, Pageable pageable) {
|
||||
return postRepository.findPostsByTagsAndPostStatus(tag, PostStatusEnum.PUBLISHED.getCode(), pageable);
|
||||
Page<Post> posts = postRepository.findPostsByTagsAndPostStatus(tag, PostStatusEnum.PUBLISHED.getCode(), pageable);
|
||||
for (Post post : posts.getContent()) {
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostSummary("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return posts;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -18,6 +18,7 @@ import cc.ryanc.halo.web.controller.core.BaseController;
|
|||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.propertyeditors.CustomDateEditor;
|
||||
|
@ -186,6 +187,9 @@ public class PostController extends BaseController {
|
|||
post.setUser(user);
|
||||
post = postService.buildCategoriesAndTags(post, cateList, tagList);
|
||||
post.setPostUrl(urlFilter(post.getPostUrl()));
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostPassword(SecureUtil.md5(post.getPostPassword()));
|
||||
}
|
||||
//当没有选择文章缩略图的时候,自动分配一张内置的缩略图
|
||||
if (StrUtil.equals(post.getPostThumbnail(), BlogPropertiesEnum.DEFAULT_THUMBNAIL.getProp())) {
|
||||
post.setPostThumbnail("/static/halo-frontend/images/thumbnail/thumbnail-" + RandomUtil.randomInt(1, 10) + ".jpg");
|
||||
|
@ -223,6 +227,9 @@ public class PostController extends BaseController {
|
|||
post.setPostDate(new Date());
|
||||
}
|
||||
post = postService.buildCategoriesAndTags(post, cateList, tagList);
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
post.setPostPassword(SecureUtil.md5(post.getPostPassword()));
|
||||
}
|
||||
//当没有选择文章缩略图的时候,自动分配一张内置的缩略图
|
||||
if (StrUtil.equals(post.getPostThumbnail(), BlogPropertiesEnum.DEFAULT_THUMBNAIL.getProp())) {
|
||||
post.setPostThumbnail("/static/halo-frontend/images/thumbnail/thumbnail-" + RandomUtil.randomInt(1, 10) + ".jpg");
|
||||
|
|
|
@ -13,19 +13,22 @@ import cc.ryanc.halo.web.controller.core.BaseController;
|
|||
import cn.hutool.core.collection.CollUtil;
|
||||
import cn.hutool.core.util.PageUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import cn.hutool.extra.servlet.ServletUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.servlet.http.Cookie;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
@ -43,9 +46,9 @@ import java.util.List;
|
|||
@RequestMapping(value = "/archives")
|
||||
public class FrontArchiveController extends BaseController {
|
||||
|
||||
private static final String POSTS_CACHE_NAME = "posts";
|
||||
@Autowired
|
||||
private PostService postService;
|
||||
|
||||
@Autowired
|
||||
private CommentService commentService;
|
||||
|
||||
|
@ -53,7 +56,6 @@ public class FrontArchiveController extends BaseController {
|
|||
* 文章归档
|
||||
*
|
||||
* @param model model
|
||||
*
|
||||
* @return 模板路径
|
||||
*/
|
||||
@GetMapping
|
||||
|
@ -66,7 +68,6 @@ public class FrontArchiveController extends BaseController {
|
|||
*
|
||||
* @param model model
|
||||
* @param page page 当前页码
|
||||
*
|
||||
* @return 模板路径/themes/{theme}/archives
|
||||
*/
|
||||
@GetMapping(value = "page/{page}")
|
||||
|
@ -91,7 +92,6 @@ public class FrontArchiveController extends BaseController {
|
|||
* @param model model
|
||||
* @param year year 年份
|
||||
* @param month month 月份
|
||||
*
|
||||
* @return 模板路径/themes/{theme}/archives
|
||||
*/
|
||||
@GetMapping(value = "{year}/{month}")
|
||||
|
@ -112,12 +112,12 @@ public class FrontArchiveController extends BaseController {
|
|||
*
|
||||
* @param postUrl 文章路径名
|
||||
* @param model model
|
||||
*
|
||||
* @return 模板路径/themes/{theme}/post
|
||||
*/
|
||||
@GetMapping(value = "{postUrl}")
|
||||
public String getPost(@PathVariable String postUrl,
|
||||
@RequestParam(value = "cp", defaultValue = "1") Integer cp,
|
||||
HttpServletRequest request,
|
||||
Model model) {
|
||||
final Post post = postService.findByPostUrl(postUrl, PostTypeEnum.POST_TYPE_POST.getDesc());
|
||||
if (null == post || !post.getPostStatus().equals(PostStatusEnum.PUBLISHED.getCode())) {
|
||||
|
@ -161,12 +161,44 @@ public class FrontArchiveController extends BaseController {
|
|||
final ListPage<Comment> commentsPage = new ListPage<Comment>(CommentUtil.getComments(comments), cp, size);
|
||||
final int[] rainbow = PageUtil.rainbow(cp, commentsPage.getTotalPage(), 3);
|
||||
model.addAttribute("is_post", true);
|
||||
model.addAttribute("post", post);
|
||||
model.addAttribute("comments", commentsPage);
|
||||
model.addAttribute("commentsCount", comments.size());
|
||||
model.addAttribute("rainbow", rainbow);
|
||||
model.addAttribute("tagWords", CollUtil.join(tagWords, ","));
|
||||
postService.cacheViews(post.getPostId());
|
||||
|
||||
//判断文章是否有加密
|
||||
if (StrUtil.isNotEmpty(post.getPostPassword())) {
|
||||
Cookie cookie = ServletUtil.getCookie(request, "halo-post-password-" + post.getPostId());
|
||||
if (null == cookie) {
|
||||
post.setPostSummary("该文章为加密文章");
|
||||
post.setPostContent("<form id=\"postPasswordForm\" method=\"post\" action=\"/archives/verifyPostPassword\"><p>该文章为加密文章,输入正确的密码即可访问。</p><input type=\"hidden\" id=\"postId\" name=\"postId\" value=\"" + post.getPostId() + "\"> <input type=\"password\" id=\"postPassword\" name=\"postPassword\"> <input type=\"submit\" id=\"passwordSubmit\" value=\"提交\"></form>");
|
||||
}
|
||||
}
|
||||
model.addAttribute("post", post);
|
||||
return this.render("post");
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证文章密码
|
||||
*
|
||||
* @param postId postId
|
||||
* @param postPassword postPassword
|
||||
* @param response response
|
||||
* @return String
|
||||
*/
|
||||
@PostMapping(value = "/verifyPostPassword")
|
||||
@CacheEvict(value = POSTS_CACHE_NAME, allEntries = true, beforeInvocation = true)
|
||||
public String verifyPostPassword(@RequestParam(value = "postId") Long postId,
|
||||
@RequestParam(value = "postPassword") String postPassword,
|
||||
HttpServletResponse response) {
|
||||
final Post post = postService.findByPostId(postId, PostTypeEnum.POST_TYPE_POST.getDesc());
|
||||
if (null == post) {
|
||||
return this.renderNotFound();
|
||||
}
|
||||
if (SecureUtil.md5(postPassword).equals(post.getPostPassword())) {
|
||||
ServletUtil.addCookie(response, "halo-post-password-" + post.getPostId(), SecureUtil.md5(postPassword));
|
||||
}
|
||||
return "redirect:/archives/" + post.getPostUrl();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -48,6 +48,11 @@ public class FrontOthersController {
|
|||
final Pageable pageable = PageRequest.of(0, Integer.parseInt(rssPosts), sort);
|
||||
final Page<Post> postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), pageable);
|
||||
final List<Post> posts = postsPage.getContent();
|
||||
for (Post post : posts) {
|
||||
if(StrUtil.isNotEmpty(post.getPostPassword())){
|
||||
post.setPostContent("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return postService.buildRss(posts);
|
||||
}
|
||||
|
||||
|
@ -64,6 +69,11 @@ public class FrontOthersController {
|
|||
final Pageable pageable = PageRequest.of(0, 999, sort);
|
||||
final Page<Post> postsPage = postService.findPostByStatus(0, PostTypeEnum.POST_TYPE_POST.getDesc(), pageable);
|
||||
final List<Post> posts = postsPage.getContent();
|
||||
for (Post post : posts) {
|
||||
if(StrUtil.isNotEmpty(post.getPostPassword())){
|
||||
post.setPostContent("该文章为加密文章");
|
||||
}
|
||||
}
|
||||
return postService.buildSiteMap(posts);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -67,6 +67,10 @@
|
|||
<option value="0" <#if (post.allowComment!)==0>selected</#if>><@spring.message code='common.select.no' /></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="postPassword" class="control-label">文章密码:</label>
|
||||
<input type="password" class="form-control" id="postPassword" name="postPassword" value="${post.postPassword!}">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="postDate" class="control-label">发布时间:</label>
|
||||
<input type="text" class="form-control" id="postDate" name="postDate" value="${post.postDate!?string('yyyy-MM-dd HH:mm')}">
|
||||
|
@ -297,7 +301,8 @@
|
|||
'cateList' : cateList.toString(),
|
||||
'tagList' : $('#tagList').tagEditor('getTags')[0].tags.toString(),
|
||||
'allowComment' : $('#allowComment').val(),
|
||||
'postDate' : $("#postDate").val()
|
||||
'postDate' : $("#postDate").val(),
|
||||
'postPassword' : $("#postPassword").val()
|
||||
},function (data) {
|
||||
if(data.code === 1){
|
||||
//清除自动保存的内容
|
||||
|
|
|
@ -65,6 +65,10 @@
|
|||
<option value="0"><@spring.message code='common.select.no' /></option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="postPassword" class="control-label">文章密码:</label>
|
||||
<input type="password" class="form-control" id="postPassword" name="postPassword">
|
||||
</div>
|
||||
</div>
|
||||
<div class="box-footer">
|
||||
<button onclick="push(1)" class="btn btn-default btn-sm "><@spring.message code='admin.editor.save-draft' /></button>
|
||||
|
@ -273,7 +277,8 @@
|
|||
'postThumbnail': $('#selectImg').attr('src'),
|
||||
'cateList' : cateList.toString(),
|
||||
'tagList' : $('#tagList').tagEditor('getTags')[0].tags.toString(),
|
||||
'allowComment' : $('#allowComment').val()
|
||||
'allowComment' : $('#allowComment').val(),
|
||||
'postPassword' : $("#postPassword").val()
|
||||
},function (data) {
|
||||
if(data.code === 1){
|
||||
//清除自动保存的内容
|
||||
|
|
Loading…
Reference in New Issue