Support preview post and sheet.

pull/296/head
ruibaby 2019-09-05 21:29:10 +08:00
parent 042e5af43d
commit 73b1e606b9
5 changed files with 188 additions and 4 deletions

View File

@ -1,5 +1,6 @@
package run.halo.app.controller.admin.api;
import cn.hutool.core.util.IdUtil;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
@ -8,6 +9,7 @@ import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.*;
import run.halo.app.cache.StringCacheStore;
import run.halo.app.model.dto.post.BasePostMinimalDTO;
import run.halo.app.model.dto.post.BasePostSimpleDTO;
import run.halo.app.model.entity.Post;
@ -16,10 +18,14 @@ import run.halo.app.model.params.PostParam;
import run.halo.app.model.params.PostQuery;
import run.halo.app.model.vo.PostDetailVO;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostService;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.springframework.data.domain.Sort.Direction.DESC;
@ -36,8 +42,16 @@ public class PostController {
private final PostService postService;
public PostController(PostService postService) {
private final StringCacheStore cacheStore;
private final OptionService optionService;
public PostController(PostService postService,
StringCacheStore cacheStore,
OptionService optionService) {
this.postService = postService;
this.cacheStore = cacheStore;
this.optionService = optionService;
}
@GetMapping
@ -125,4 +139,20 @@ public class PostController {
postService.removeById(postId);
}
@GetMapping("preview/{postId:\\d+}")
public void preview(@PathVariable("postId") Integer postId,
HttpServletResponse response) throws IOException {
Post post = postService.getById(postId);
String token = IdUtil.simpleUUID();
// cache preview token
cacheStore.putAny("preview-post-token-" + postId, token, 10, TimeUnit.MINUTES);
// build preview post url
String url = String.format("%s/preview/post/%s?token=%s", optionService.getBlogBaseUrl(), post.getUrl(), token);
// redirect to preview url
response.sendRedirect(url);
}
}

View File

@ -1,20 +1,26 @@
package run.halo.app.controller.admin.api;
import cn.hutool.core.util.IdUtil;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
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.BasePostDetailDTO;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.params.SheetParam;
import run.halo.app.model.vo.SheetListVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.SheetService;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;
import static org.springframework.data.domain.Sort.Direction.DESC;
@ -31,8 +37,16 @@ public class SheetController {
private final SheetService sheetService;
public SheetController(SheetService sheetService) {
private final StringCacheStore cacheStore;
private final OptionService optionService;
public SheetController(SheetService sheetService,
StringCacheStore cacheStore,
OptionService optionService) {
this.sheetService = sheetService;
this.cacheStore = cacheStore;
this.optionService = optionService;
}
@GetMapping("{sheetId:\\d+}")
@ -97,4 +111,21 @@ public class SheetController {
Sheet sheet = sheetService.removeById(sheetId);
return sheetService.convertToDetail(sheet);
}
@GetMapping("preview/{sheetId:\\d+}")
public void preview(@PathVariable("sheetId") Integer sheetId,
HttpServletResponse response) throws IOException {
Sheet sheet = sheetService.getById(sheetId);
String token = IdUtil.simpleUUID();
// cache preview token
cacheStore.putAny("preview-sheet-token-" + sheetId, token, 10, TimeUnit.MINUTES);
// build preview sheet url
String url = String.format("%s/preview/s/%s?token=%s", optionService.getBlogBaseUrl(), sheet.getUrl(), token);
// redirect to preview url
response.sendRedirect(url);
}
}

View File

@ -0,0 +1,116 @@
package run.halo.app.controller.content;
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.cache.StringCacheStore;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Post;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.entity.Tag;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.support.HaloConst;
import run.halo.app.service.*;
import run.halo.app.utils.MarkdownUtils;
import java.util.List;
import java.util.concurrent.TimeUnit;
/**
* Post and sheet preview controller.
*
* @author ryanwang
* @date : 2019-09-05
*/
@Slf4j
@Controller
@RequestMapping(value = "/preview")
public class ContentPreviewController {
private final PostService postService;
private final ThemeService themeService;
private final PostCategoryService postCategoryService;
private final PostTagService postTagService;
private final SheetService sheetService;
private final StringCacheStore cacheStore;
public ContentPreviewController(PostService postService,
ThemeService themeService,
PostCategoryService postCategoryService,
PostTagService postTagService,
SheetService sheetService,
StringCacheStore cacheStore) {
this.postService = postService;
this.themeService = themeService;
this.postCategoryService = postCategoryService;
this.postTagService = postTagService;
this.sheetService = sheetService;
this.cacheStore = cacheStore;
}
@GetMapping(value = "post/{url}")
public String post(@PathVariable("url") String url,
@RequestParam(value = "token") String token,
Model model) {
Post post = postService.getBy(PostStatus.DRAFT, url);
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
// verify token
String cachedToken = cacheStore.getAny("preview-post-token-" + post.getId(), String.class).orElseThrow(() -> new ForbiddenException("该文章的预览链接不存在或已过期"));
if (!cachedToken.equals(token)) {
throw new ForbiddenException("该文章的预览链接不存在或已过期");
}
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
List<Tag> tags = postTagService.listTagsBy(post.getId());
model.addAttribute("is_post", true);
model.addAttribute("post", post);
model.addAttribute("categories", categories);
model.addAttribute("tags", tags);
// refresh timeUnit
cacheStore.putAny("preview-post-token-" + post.getId(), token, 10, TimeUnit.MINUTES);
return themeService.render("post");
}
@GetMapping(value = "s/{url}")
public String sheet(@PathVariable("url") String url,
@RequestParam(value = "token") String token,
Model model) {
Sheet sheet = sheetService.getBy(PostStatus.DRAFT, url);
sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent()));
// verify token
String cachedToken = cacheStore.getAny("preview-sheet-token-" + sheet.getId(), String.class).orElseThrow(() -> new ForbiddenException("该页面的预览链接不存在或已过期"));
if (!cachedToken.equals(token)) {
throw new ForbiddenException("该页面的预览链接不存在或已过期");
}
// sheet and post all can use
model.addAttribute("sheet", sheetService.convertToDetail(sheet));
model.addAttribute("post", sheetService.convertToDetail(sheet));
model.addAttribute("is_sheet", true);
if (themeService.templateExists(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate() + HaloConst.SUFFIX_FTL)) {
return themeService.render(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate());
}
return themeService.render("sheet");
}
}

View File

@ -10,9 +10,10 @@ import javax.persistence.*;
import java.util.Date;
/**
* Post entity.
* Post base entity.
*
* @author johnniang
* @author ryanwang
*/
@Data
@Entity(name = "BasePost")
@ -168,6 +169,10 @@ public class BasePost extends BaseEntity {
if (likes == null || likes < 0) {
likes = 0L;
}
if (formatContent == null) {
formatContent = "";
}
}
}

View File

@ -213,7 +213,9 @@ public abstract class BasePostServiceImpl<POST extends BasePost> extends Abstrac
Assert.notNull(post, "Post must not be null");
// Render content
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
if (post.getStatus() == PostStatus.PUBLISHED) {
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
}
// Create or update post
if (ServiceUtils.isEmptyId(post.getId())) {