mirror of https://github.com/halo-dev/halo
refactor: refactor post preview and private post view.
parent
e6497f97ad
commit
f5d957edc1
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
|
|
|
@ -24,7 +24,7 @@ public class StaticFile implements Comparator<StaticFile> {
|
|||
|
||||
private Boolean isFile;
|
||||
|
||||
private String mediaType;
|
||||
private String mimeType;
|
||||
|
||||
private Long createTime;
|
||||
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue