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.OptionService;
import javax.servlet.http.HttpServletResponse;
import javax.validation.Valid;
/**
@ -124,4 +125,10 @@ public class AdminController {
public BaseResponse<String> getLogFiles(@RequestParam("lines") Long 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 javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -156,15 +159,15 @@ public class PostController {
@GetMapping(value = {"preview/{postId:\\d+}", "{postId:\\d+}/preview"})
@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);
String token = IdUtil.simpleUUID();
// 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
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 javax.validation.Valid;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;
@ -111,15 +114,15 @@ public class SheetController {
}
@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);
String token = IdUtil.simpleUUID();
// 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
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.PageUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
@ -13,7 +14,6 @@ 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.exception.BadRequestException;
import run.halo.app.exception.ForbiddenException;
import run.halo.app.exception.NotFoundException;
import run.halo.app.model.entity.Category;
@ -122,41 +122,26 @@ 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,
@RequestParam(value = "cp", defaultValue = "1") Integer cp,
@SortDefault(sort = "createTime", direction = DESC) Sort sort,
Model model) {
Post post;
if (preview) {
post = postService.getByUrl(url);
} else if (intimate) {
post = postService.getBy(PostStatus.INTIMATE, url);
} else {
Post post = postService.getByUrl(url);
if (post.getStatus().equals(PostStatus.INTIMATE) && StringUtils.isEmpty(token)) {
String redirect = String.format("%s/archives/%s/password", optionService.getBlogBaseUrl(), post.getUrl());
return "redirect:" + redirect;
}
if (StringUtils.isEmpty(token)) {
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()));
// 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) {
} else {
// verify token
String cachedToken = cacheStore.getAny(token, String.class).orElseThrow(() -> new ForbiddenException("您没有该文章的访问权限"));
if (!cachedToken.equals(token)) {
throw new ForbiddenException("您没有该文章的访问权限");
}
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
}
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("comments", comments);
if (preview) {
// refresh timeUnit
cacheStore.putAny("preview-post-token-" + post.getId(), token, 10, TimeUnit.MINUTES);
}
return themeService.render("post");
}
@ -201,14 +181,14 @@ public class ContentArchiveController {
@RequestParam(value = "password") String password) {
Post post = postService.getBy(PostStatus.INTIMATE, url);
if (null == post) {
throw new ForbiddenException("没有查询到该文章信息");
throw new NotFoundException("查询不到该文章的信息").setErrorData(url);
}
if (password.equals(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);
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());

View File

@ -1,5 +1,6 @@
package run.halo.app.controller.content;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
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.utils.MarkdownUtils;
import java.util.concurrent.TimeUnit;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
@ -110,39 +109,35 @@ public class ContentSheetController {
*/
@GetMapping(value = "/s/{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 = "cp", defaultValue = "1") Integer cp,
@SortDefault(sort = "createTime", direction = DESC) Sort sort,
Model model) {
Sheet sheet = sheetService.getBy(preview ? PostStatus.DRAFT : PostStatus.PUBLISHED, url);
if (preview) {
// render markdown to html when preview post
Sheet sheet = sheetService.getByUrl(url);
if (StringUtils.isEmpty(token)) {
sheet = sheetService.getBy(PostStatus.PUBLISHED, url);
} else {
// render markdown to html when preview sheet
sheet.setFormatContent(MarkdownUtils.renderHtml(sheet.getOriginalContent()));
// 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)) {
throw new ForbiddenException("该页面的预览链接不存在或已过期");
throw new ForbiddenException("您没有该页面的访问权限");
}
}
Page<BaseCommentVO> comments = sheetCommentService.pageVosBy(sheet.getId(), PageRequest.of(cp, optionService.getCommentPageSize(), sort));
// sheet and post all can use
model.addAttribute("sheet", sheetService.convertToDetail(sheet));
model.addAttribute("post", sheetService.convertToDetail(sheet));
model.addAttribute("is_sheet", true);
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)) {
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 String mediaType;
private String mimeType;
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.security.token.AuthToken;
import javax.servlet.http.HttpServletResponse;
/**
* Admin service interface.
*
@ -98,7 +100,7 @@ public interface AdminService {
*
* @param content new content
*/
void updateApplicationConfig(String content);
void updateApplicationConfig(@NonNull String content);
/**
* Get halo logs content.
@ -106,5 +108,12 @@ public interface AdminService {
* @param lines lines
* @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;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.file.FileReader;
import cn.hutool.core.lang.Validator;
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.HaloUtils;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;
@ -457,6 +461,8 @@ public class AdminServiceImpl implements AdminService {
@Override
public void updateApplicationConfig(String content) {
Assert.notNull(content, "Content must not be null");
Path path = Paths.get(haloProperties.getWorkDir(), APPLICATION_CONFIG_NAME);
try {
Files.write(path, content.getBytes(StandardCharsets.UTF_8));
@ -467,6 +473,7 @@ public class AdminServiceImpl implements AdminService {
@Override
public String getLogFiles(Long lines) {
Assert.notNull(lines, "Lines must not be null");
File file = new File(haloProperties.getWorkDir(), LOG_PATH);
@ -517,4 +524,29 @@ public class AdminServiceImpl implements AdminService {
}
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.utils.FileUtils;
import javax.activation.MimetypesFileTypeMap;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@ -34,8 +35,9 @@ public class StaticStorageServiceImpl implements StaticStorageService {
private final HaloProperties haloProperties;
public StaticStorageServiceImpl(HaloProperties haloProperties) {
public StaticStorageServiceImpl(HaloProperties haloProperties) throws IOException {
staticDir = Paths.get(haloProperties.getWorkDir(), STATIC_FOLDER);
FileUtils.createIfAbsent(staticDir);
this.haloProperties = haloProperties;
}
@ -66,6 +68,7 @@ public class StaticStorageServiceImpl implements StaticStorageService {
} catch (IOException e) {
e.printStackTrace();
}
staticFile.setMimeType(MimetypesFileTypeMap.getDefaultFileTypeMap().getContentType(path.toFile()));
if (Files.isDirectory(path)) {
staticFile.setChildren(listStaticFileTree(path));
}