refactor: refactor post preview and private post view.

pull/435/head
ruibaby 2019-12-19 17:49:07 +08:00
parent e6497f97ad
commit f5d957edc1
9 changed files with 89 additions and 57 deletions

View File

@ -16,6 +16,7 @@ import run.halo.app.security.token.AuthToken;
import run.halo.app.service.AdminService; import run.halo.app.service.AdminService;
import run.halo.app.service.OptionService; import run.halo.app.service.OptionService;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid; import javax.validation.Valid;
/** /**
@ -124,4 +125,10 @@ public class AdminController {
public BaseResponse<String> getLogFiles(@RequestParam("lines") Long lines) { public BaseResponse<String> getLogFiles(@RequestParam("lines") Long lines) {
return BaseResponse.ok(HttpStatus.OK.getReasonPhrase(), adminService.getLogFiles(lines)); return BaseResponse.ok(HttpStatus.OK.getReasonPhrase(), adminService.getLogFiles(lines));
} }
@GetMapping(value = "halo/logfile/download")
@ApiOperation("Download halo log file.")
public void downloadLogFiles(@RequestParam("lines") Long lines, HttpServletResponse response) {
adminService.downloadLogFiles(lines, response);
}
} }

View File

@ -20,6 +20,9 @@ import run.halo.app.service.OptionService;
import run.halo.app.service.PostService; import run.halo.app.service.PostService;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -156,15 +159,15 @@ public class PostController {
@GetMapping(value = {"preview/{postId:\\d+}", "{postId:\\d+}/preview"}) @GetMapping(value = {"preview/{postId:\\d+}", "{postId:\\d+}/preview"})
@ApiOperation("Get preview link") @ApiOperation("Get preview link")
public String preview(@PathVariable("postId") Integer postId) { public String preview(@PathVariable("postId") Integer postId) throws UnsupportedEncodingException {
Post post = postService.getById(postId); Post post = postService.getById(postId);
String token = IdUtil.simpleUUID(); String token = IdUtil.simpleUUID();
// cache preview token // cache preview token
cacheStore.putAny("preview-post-token-" + postId, token, 10, TimeUnit.MINUTES); cacheStore.putAny(token, token, 10, TimeUnit.MINUTES);
// build preview post url and return // build preview post url and return
return String.format("%s/archives/%s?preview=true&token=%s", optionService.getBlogBaseUrl(), post.getUrl(), token); return String.format("%s/archives/%s?token=%s", optionService.getBlogBaseUrl(), URLEncoder.encode(post.getUrl(), StandardCharsets.UTF_8.name()), token);
} }
} }

View File

@ -17,6 +17,9 @@ import run.halo.app.service.OptionService;
import run.halo.app.service.SheetService; import run.halo.app.service.SheetService;
import javax.validation.Valid; import javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List; import java.util.List;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@ -111,15 +114,15 @@ public class SheetController {
} }
@GetMapping("preview/{sheetId:\\d+}") @GetMapping("preview/{sheetId:\\d+}")
public String preview(@PathVariable("sheetId") Integer sheetId) { public String preview(@PathVariable("sheetId") Integer sheetId) throws UnsupportedEncodingException {
Sheet sheet = sheetService.getById(sheetId); Sheet sheet = sheetService.getById(sheetId);
String token = IdUtil.simpleUUID(); String token = IdUtil.simpleUUID();
// cache preview token // cache preview token
cacheStore.putAny("preview-sheet-token-" + sheetId, token, 10, TimeUnit.MINUTES); cacheStore.putAny(token, token, 10, TimeUnit.MINUTES);
// build preview post url and return // build preview post url and return
return String.format("%s/s/%s?preview=true&token=%s", optionService.getBlogBaseUrl(), sheet.getUrl(), token); return String.format("%s/s/%s?token=%s", optionService.getBlogBaseUrl(), URLEncoder.encode(sheet.getUrl(), StandardCharsets.UTF_8.name()), token);
} }
} }

View File

@ -3,6 +3,7 @@ package run.halo.app.controller.content;
import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.PageUtil; import cn.hutool.core.util.PageUtil;
import lombok.extern.slf4j.Slf4j; import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -13,7 +14,6 @@ import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.*; import org.springframework.web.bind.annotation.*;
import run.halo.app.cache.StringCacheStore; import run.halo.app.cache.StringCacheStore;
import run.halo.app.cache.lock.CacheLock; import run.halo.app.cache.lock.CacheLock;
import run.halo.app.exception.BadRequestException;
import run.halo.app.exception.ForbiddenException; import run.halo.app.exception.ForbiddenException;
import run.halo.app.exception.NotFoundException; import run.halo.app.exception.NotFoundException;
import run.halo.app.model.entity.Category; import run.halo.app.model.entity.Category;
@ -122,41 +122,26 @@ public class ContentArchiveController {
*/ */
@GetMapping("{url}") @GetMapping("{url}")
public String post(@PathVariable("url") String 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, @RequestParam(value = "token", required = false) String token,
@RequestParam(value = "cp", defaultValue = "1") Integer cp, @RequestParam(value = "cp", defaultValue = "1") Integer cp,
@SortDefault(sort = "createTime", direction = DESC) Sort sort, @SortDefault(sort = "createTime", direction = DESC) Sort sort,
Model model) { Model model) {
Post post; Post post = postService.getByUrl(url);
if (preview) {
post = postService.getByUrl(url); if (post.getStatus().equals(PostStatus.INTIMATE) && StringUtils.isEmpty(token)) {
} else if (intimate) { String redirect = String.format("%s/archives/%s/password", optionService.getBlogBaseUrl(), post.getUrl());
post = postService.getBy(PostStatus.INTIMATE, url); return "redirect:" + redirect;
} else { }
if (StringUtils.isEmpty(token)) {
post = postService.getBy(PostStatus.PUBLISHED, url); post = postService.getBy(PostStatus.PUBLISHED, url);
} } else {
// if this is a preview url.
if (preview) {
// render markdown to html when preview post
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
// verify token
String cachedToken = cacheStore.getAny("preview-post-token-" + post.getId(), String.class).orElseThrow(() -> new NotFoundException("该文章的预览链接不存在或已过期"));
if (!cachedToken.equals(token)) {
throw new BadRequestException("预览 Token 错误");
}
}
// if this is a intimate url.
if (intimate) {
// verify token // 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)) { if (!cachedToken.equals(token)) {
throw new ForbiddenException("您没有该文章的访问权限"); throw new ForbiddenException("您没有该文章的访问权限");
} }
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
} }
postService.getNextPost(post.getCreateTime()).ifPresent(nextPost -> model.addAttribute("nextPost", nextPost)); postService.getNextPost(post.getCreateTime()).ifPresent(nextPost -> model.addAttribute("nextPost", nextPost));
@ -175,11 +160,6 @@ public class ContentArchiveController {
model.addAttribute("metas", postMetaService.convertToMap(metas)); model.addAttribute("metas", postMetaService.convertToMap(metas));
model.addAttribute("comments", comments); model.addAttribute("comments", comments);
if (preview) {
// refresh timeUnit
cacheStore.putAny("preview-post-token-" + post.getId(), token, 10, TimeUnit.MINUTES);
}
return themeService.render("post"); return themeService.render("post");
} }
@ -201,14 +181,14 @@ public class ContentArchiveController {
@RequestParam(value = "password") String password) { @RequestParam(value = "password") String password) {
Post post = postService.getBy(PostStatus.INTIMATE, url); Post post = postService.getBy(PostStatus.INTIMATE, url);
if (null == post) { if (null == post) {
throw new ForbiddenException("没有查询到该文章信息"); throw new NotFoundException("查询不到该文章的信息").setErrorData(url);
} }
if (password.equals(post.getPassword())) { if (password.equals(post.getPassword())) {
String token = IdUtil.simpleUUID(); String token = IdUtil.simpleUUID();
cacheStore.putAny(token, token, 10, TimeUnit.SECONDS); cacheStore.putAny(token, token, 10, TimeUnit.SECONDS);
String redirect = String.format("%s/archives/%s?intimate=true&token=%s", optionService.getBlogBaseUrl(), post.getUrl(), token); String redirect = String.format("%s/archives/%s?token=%s", optionService.getBlogBaseUrl(), post.getUrl(), token);
return "redirect:" + redirect; return "redirect:" + redirect;
} else { } else {
String redirect = String.format("%s/archives/%s/password", optionService.getBlogBaseUrl(), post.getUrl()); String redirect = String.format("%s/archives/%s/password", optionService.getBlogBaseUrl(), post.getUrl());

View File

@ -1,5 +1,6 @@
package run.halo.app.controller.content; package run.halo.app.controller.content;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page; import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Pageable;
@ -20,8 +21,6 @@ import run.halo.app.model.vo.BaseCommentVO;
import run.halo.app.service.*; import run.halo.app.service.*;
import run.halo.app.utils.MarkdownUtils; import run.halo.app.utils.MarkdownUtils;
import java.util.concurrent.TimeUnit;
import static org.springframework.data.domain.Sort.Direction.DESC; import static org.springframework.data.domain.Sort.Direction.DESC;
/** /**
@ -110,39 +109,35 @@ public class ContentSheetController {
*/ */
@GetMapping(value = "/s/{url}") @GetMapping(value = "/s/{url}")
public String sheet(@PathVariable(value = "url") String url, public String sheet(@PathVariable(value = "url") String url,
@RequestParam(value = "preview", required = false, defaultValue = "false") boolean preview,
@RequestParam(value = "token", required = false) String token, @RequestParam(value = "token", required = false) String token,
@RequestParam(value = "cp", defaultValue = "1") Integer cp, @RequestParam(value = "cp", defaultValue = "1") Integer cp,
@SortDefault(sort = "createTime", direction = DESC) Sort sort, @SortDefault(sort = "createTime", direction = DESC) Sort sort,
Model model) { Model model) {
Sheet sheet = sheetService.getBy(preview ? PostStatus.DRAFT : PostStatus.PUBLISHED, url);
if (preview) { Sheet sheet = sheetService.getByUrl(url);
// render markdown to html when preview post
if (StringUtils.isEmpty(token)) {
sheet = sheetService.getBy(PostStatus.PUBLISHED, url);
} else {
// render markdown to html when preview sheet
sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent())); sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent()));
// verify token // verify token
String cachedToken = cacheStore.getAny("preview-sheet-token-" + sheet.getId(), String.class).orElseThrow(() -> new ForbiddenException("该页面的预览链接不存在或已过期")); String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该页面的访问权限"));
if (!cachedToken.equals(token)) { if (!cachedToken.equals(token)) {
throw new ForbiddenException("该页面的预览链接不存在或已过期"); throw new ForbiddenException("您没有该页面的访问权限");
} }
} }
Page<BaseCommentVO> comments = sheetCommentService.pageVosBy(sheet.getId(), PageRequest.of(cp, optionService.getCommentPageSize(), sort)); Page<BaseCommentVO> comments = sheetCommentService.pageVosBy(sheet.getId(), PageRequest.of(cp, optionService.getCommentPageSize(), sort));
// sheet and post all can use // sheet and post all can use
model.addAttribute("sheet", sheetService.convertToDetail(sheet)); model.addAttribute("sheet", sheetService.convertToDetail(sheet));
model.addAttribute("post", sheetService.convertToDetail(sheet)); model.addAttribute("post", sheetService.convertToDetail(sheet));
model.addAttribute("is_sheet", true); model.addAttribute("is_sheet", true);
model.addAttribute("comments", comments); model.addAttribute("comments", comments);
if (preview) {
// refresh timeUnit
cacheStore.putAny("preview-sheet-token-" + sheet.getId(), token, 10, TimeUnit.MINUTES);
}
if (themeService.templateExists(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate() + HaloConst.SUFFIX_FTL)) { if (themeService.templateExists(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate() + HaloConst.SUFFIX_FTL)) {
return themeService.render(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate()); return themeService.render(ThemeService.CUSTOM_SHEET_PREFIX + sheet.getTemplate());
} }

View File

@ -24,7 +24,7 @@ public class StaticFile implements Comparator<StaticFile> {
private Boolean isFile; private Boolean isFile;
private String mediaType; private String mimeType;
private Long createTime; private Long createTime;

View File

@ -7,6 +7,8 @@ import run.halo.app.model.params.LoginParam;
import run.halo.app.model.params.ResetPasswordParam; import run.halo.app.model.params.ResetPasswordParam;
import run.halo.app.security.token.AuthToken; import run.halo.app.security.token.AuthToken;
import javax.servlet.http.HttpServletResponse;
/** /**
* Admin service interface. * Admin service interface.
* *
@ -98,7 +100,7 @@ public interface AdminService {
* *
* @param content new content * @param content new content
*/ */
void updateApplicationConfig(String content); void updateApplicationConfig(@NonNull String content);
/** /**
* Get halo logs content. * Get halo logs content.
@ -106,5 +108,12 @@ public interface AdminService {
* @param lines lines * @param lines lines
* @return logs content. * @return logs content.
*/ */
String getLogFiles(Long lines); String getLogFiles(@NonNull Long lines);
/**
* Download halo log file.
*
* @param lines lines.
*/
void downloadLogFiles(@NonNull Long lines, @NonNull HttpServletResponse response);
} }

View File

@ -1,5 +1,6 @@
package run.halo.app.service.impl; package run.halo.app.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileReader; import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.lang.Validator; import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.RandomUtil; import cn.hutool.core.util.RandomUtil;
@ -37,6 +38,9 @@ import run.halo.app.service.*;
import run.halo.app.utils.FileUtils; import run.halo.app.utils.FileUtils;
import run.halo.app.utils.HaloUtils; import run.halo.app.utils.HaloUtils;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File; import java.io.File;
import java.io.IOException; import java.io.IOException;
import java.io.RandomAccessFile; import java.io.RandomAccessFile;
@ -457,6 +461,8 @@ public class AdminServiceImpl implements AdminService {
@Override @Override
public void updateApplicationConfig(String content) { public void updateApplicationConfig(String content) {
Assert.notNull(content, "Content must not be null");
Path path = Paths.get(haloProperties.getWorkDir(), APPLICATION_CONFIG_NAME); Path path = Paths.get(haloProperties.getWorkDir(), APPLICATION_CONFIG_NAME);
try { try {
Files.write(path, content.getBytes(StandardCharsets.UTF_8)); Files.write(path, content.getBytes(StandardCharsets.UTF_8));
@ -467,6 +473,7 @@ public class AdminServiceImpl implements AdminService {
@Override @Override
public String getLogFiles(Long lines) { public String getLogFiles(Long lines) {
Assert.notNull(lines, "Lines must not be null");
File file = new File(haloProperties.getWorkDir(), LOG_PATH); File file = new File(haloProperties.getWorkDir(), LOG_PATH);
@ -517,4 +524,29 @@ public class AdminServiceImpl implements AdminService {
} }
return result.toString(); return result.toString();
} }
@Override
public void downloadLogFiles(Long lines, HttpServletResponse response) {
Assert.notNull(lines, "Lines must not be null");
Assert.notNull(response, "HttpServletResponse must not be null");
String logFiles = getLogFiles(lines);
String fileName = "halo-log-" +
DateUtil.format(DateUtil.date(), "yyyy-MM-dd-HH-mm-ss") +
".log";
response.setContentType("application/force-download");
response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
ServletOutputStream outputStream;
BufferedOutputStream bufferedOutputStream;
try {
outputStream = response.getOutputStream();
bufferedOutputStream = new BufferedOutputStream(outputStream);
bufferedOutputStream.write(logFiles.getBytes(StandardCharsets.UTF_8));
bufferedOutputStream.flush();
bufferedOutputStream.close();
outputStream.close();
} catch (IOException e) {
throw new ServiceException("日志下载失败", e);
}
}
} }

View File

@ -13,6 +13,7 @@ import run.halo.app.model.support.StaticFile;
import run.halo.app.service.StaticStorageService; import run.halo.app.service.StaticStorageService;
import run.halo.app.utils.FileUtils; import run.halo.app.utils.FileUtils;
import javax.activation.MimetypesFileTypeMap;
import java.io.IOException; import java.io.IOException;
import java.nio.file.Files; import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
@ -34,8 +35,9 @@ public class StaticStorageServiceImpl implements StaticStorageService {
private final HaloProperties haloProperties; private final HaloProperties haloProperties;
public StaticStorageServiceImpl(HaloProperties haloProperties) { public StaticStorageServiceImpl(HaloProperties haloProperties) throws IOException {
staticDir = Paths.get(haloProperties.getWorkDir(), STATIC_FOLDER); staticDir = Paths.get(haloProperties.getWorkDir(), STATIC_FOLDER);
FileUtils.createIfAbsent(staticDir);
this.haloProperties = haloProperties; this.haloProperties = haloProperties;
} }
@ -66,6 +68,7 @@ public class StaticStorageServiceImpl implements StaticStorageService {
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
} }
staticFile.setMimeType(MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(path.toFile()));
if (Files.isDirectory(path)) { if (Files.isDirectory(path)) {
staticFile.setChildren(listStaticFileTree(path)); staticFile.setChildren(listStaticFileTree(path));
} }