mirror of https://github.com/halo-dev/halo
feat: add api for markdown export (#1199)
* add API for markdown-export * add front-matter support * optimize fileName for markdown-export * fornt-matter与正文中间增加换行符pull/1220/head
parent
276aea4bdd
commit
8ba115ffb6
|
@ -58,6 +58,11 @@ public class HaloProperties {
|
||||||
*/
|
*/
|
||||||
private String backupDir = ensureSuffix(TEMP_DIR, FILE_SEPARATOR) + "halo-backup" + FILE_SEPARATOR;
|
private String backupDir = ensureSuffix(TEMP_DIR, FILE_SEPARATOR) + "halo-backup" + FILE_SEPARATOR;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Halo backup markdown directory.(Not recommended to modify this config);
|
||||||
|
*/
|
||||||
|
private String backupMarkdownDir = ensureSuffix(TEMP_DIR, FILE_SEPARATOR) + "halo-backup-markdown" + FILE_SEPARATOR;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Halo data export directory.
|
* Halo data export directory.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -12,6 +12,7 @@ import run.halo.app.annotation.DisableOnCondition;
|
||||||
import run.halo.app.config.properties.HaloProperties;
|
import run.halo.app.config.properties.HaloProperties;
|
||||||
import run.halo.app.model.dto.BackupDTO;
|
import run.halo.app.model.dto.BackupDTO;
|
||||||
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
||||||
|
import run.halo.app.model.params.PostMarkdownParam;
|
||||||
import run.halo.app.service.BackupService;
|
import run.halo.app.service.BackupService;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
@ -23,6 +24,7 @@ import java.util.List;
|
||||||
*
|
*
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author Raremaa
|
||||||
* @date 2019-04-26
|
* @date 2019-04-26
|
||||||
*/
|
*/
|
||||||
@RestController
|
@RestController
|
||||||
|
@ -34,8 +36,7 @@ public class BackupController {
|
||||||
|
|
||||||
private final HaloProperties haloProperties;
|
private final HaloProperties haloProperties;
|
||||||
|
|
||||||
public BackupController(BackupService backupService,
|
public BackupController(BackupService backupService, HaloProperties haloProperties) {
|
||||||
HaloProperties haloProperties) {
|
|
||||||
this.backupService = backupService;
|
this.backupService = backupService;
|
||||||
this.haloProperties = haloProperties;
|
this.haloProperties = haloProperties;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +85,7 @@ public class BackupController {
|
||||||
backupService.deleteWorkDirBackup(filename);
|
backupService.deleteWorkDirBackup(filename);
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping("markdown")
|
@PostMapping("markdown/import")
|
||||||
@ApiOperation("Imports markdown")
|
@ApiOperation("Imports markdown")
|
||||||
public BasePostDetailDTO backupMarkdowns(@RequestPart("file") MultipartFile file) throws IOException {
|
public BasePostDetailDTO backupMarkdowns(@RequestPart("file") MultipartFile file) throws IOException {
|
||||||
return backupService.importMarkdown(file);
|
return backupService.importMarkdown(file);
|
||||||
|
@ -132,4 +133,50 @@ public class BackupController {
|
||||||
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + exportDataResource.getFilename() + "\"")
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + exportDataResource.getFilename() + "\"")
|
||||||
.body(exportDataResource);
|
.body(exportDataResource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("markdown/export")
|
||||||
|
@ApiOperation("Exports markdowns")
|
||||||
|
@DisableOnCondition
|
||||||
|
public BackupDTO exportMarkdowns(@RequestBody PostMarkdownParam postMarkdownParam) throws IOException {
|
||||||
|
return backupService.exportMarkdowns(postMarkdownParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("markdown/export")
|
||||||
|
@ApiOperation("Gets all markdown backups")
|
||||||
|
public List<BackupDTO> listMarkdowns() {
|
||||||
|
return backupService.listMarkdowns();
|
||||||
|
}
|
||||||
|
|
||||||
|
@DeleteMapping("markdown/export")
|
||||||
|
@ApiOperation("Deletes a markdown backup")
|
||||||
|
@DisableOnCondition
|
||||||
|
public void deleteMarkdown(@RequestParam("filename") String filename) {
|
||||||
|
backupService.deleteMarkdown(filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping("markdown/export/{fileName:.+}")
|
||||||
|
@ApiOperation("Downloads a work markdown backup file")
|
||||||
|
@DisableOnCondition
|
||||||
|
public ResponseEntity<Resource> downloadMarkdown(@PathVariable("fileName") String fileName, HttpServletRequest request) {
|
||||||
|
log.info("Try to download markdown backup file: [{}]", fileName);
|
||||||
|
|
||||||
|
// Load file as resource
|
||||||
|
Resource backupResource = backupService.loadFileAsResource(haloProperties.getBackupMarkdownDir(), fileName);
|
||||||
|
|
||||||
|
String contentType = MediaType.APPLICATION_OCTET_STREAM_VALUE;
|
||||||
|
// Try to determine file's content type
|
||||||
|
try {
|
||||||
|
contentType = request.getServletContext().getMimeType(backupResource.getFile().getAbsolutePath());
|
||||||
|
} catch (IOException e) {
|
||||||
|
log.warn("Could not determine file type", e);
|
||||||
|
// Ignore this error
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResponseEntity.ok()
|
||||||
|
.contentType(MediaType.parseMediaType(contentType))
|
||||||
|
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + backupResource.getFilename() + "\"")
|
||||||
|
.body(backupResource);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,17 @@
|
||||||
|
package run.halo.app.model.params;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Raremaa
|
||||||
|
* @date 2020/12/25 11:22 上午
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class PostMarkdownParam {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* true if need frontMatter
|
||||||
|
* default false
|
||||||
|
*/
|
||||||
|
private Boolean needFrontMatter;
|
||||||
|
}
|
|
@ -36,6 +36,11 @@ public class HaloConst {
|
||||||
*/
|
*/
|
||||||
public final static String HALO_BACKUP_PREFIX = "halo-backup-";
|
public final static String HALO_BACKUP_PREFIX = "halo-backup-";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Halo backup markdown prefix.
|
||||||
|
*/
|
||||||
|
public final static String HALO_BACKUP_MARKDOWN_PREFIX = "halo-backup-markdown-";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Halo data export prefix.
|
* Halo data export prefix.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
package run.halo.app.model.vo;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Markdown export VO
|
||||||
|
*
|
||||||
|
* @author Raremaa
|
||||||
|
* @date 2020/12/25 9:14 上午
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@ToString
|
||||||
|
public class PostMarkdownVO {
|
||||||
|
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
private String slug;
|
||||||
|
|
||||||
|
private String originalContent;
|
||||||
|
|
||||||
|
private String frontMatter;
|
||||||
|
}
|
|
@ -5,6 +5,7 @@ import org.springframework.lang.NonNull;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
import run.halo.app.model.dto.BackupDTO;
|
import run.halo.app.model.dto.BackupDTO;
|
||||||
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
||||||
|
import run.halo.app.model.params.PostMarkdownParam;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -91,4 +92,29 @@ public interface BackupService {
|
||||||
* @throws IOException throws IOException
|
* @throws IOException throws IOException
|
||||||
*/
|
*/
|
||||||
void importData(MultipartFile file) throws IOException;
|
void importData(MultipartFile file) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export Markdown content
|
||||||
|
*
|
||||||
|
* @param postMarkdownParam param
|
||||||
|
* @return backup dto.
|
||||||
|
* @throws IOException throws IOException
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
BackupDTO exportMarkdowns(PostMarkdownParam postMarkdownParam) throws IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* list Markdown backups
|
||||||
|
*
|
||||||
|
* @return backup list
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<BackupDTO> listMarkdowns();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* delete a markdown backup
|
||||||
|
*
|
||||||
|
* @param fileName
|
||||||
|
*/
|
||||||
|
void deleteMarkdown(@NonNull String fileName);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,10 +8,7 @@ import run.halo.app.model.entity.Post;
|
||||||
import run.halo.app.model.entity.PostMeta;
|
import run.halo.app.model.entity.PostMeta;
|
||||||
import run.halo.app.model.enums.PostStatus;
|
import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.params.PostQuery;
|
import run.halo.app.model.params.PostQuery;
|
||||||
import run.halo.app.model.vo.ArchiveMonthVO;
|
import run.halo.app.model.vo.*;
|
||||||
import run.halo.app.model.vo.ArchiveYearVO;
|
|
||||||
import run.halo.app.model.vo.PostDetailVO;
|
|
||||||
import run.halo.app.model.vo.PostListVO;
|
|
||||||
import run.halo.app.service.base.BasePostService;
|
import run.halo.app.service.base.BasePostService;
|
||||||
|
|
||||||
import javax.validation.constraints.NotNull;
|
import javax.validation.constraints.NotNull;
|
||||||
|
@ -112,8 +109,8 @@ public interface PostService extends BasePostService<Post> {
|
||||||
/**
|
/**
|
||||||
* Gets post by post year and slug.
|
* Gets post by post year and slug.
|
||||||
*
|
*
|
||||||
* @param year post create year.
|
* @param year post create year.
|
||||||
* @param slug post slug.
|
* @param slug post slug.
|
||||||
* @return post info
|
* @return post info
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
|
@ -276,4 +273,12 @@ public interface PostService extends BasePostService<Post> {
|
||||||
@NotNull
|
@NotNull
|
||||||
Sort getPostDefaultSort();
|
Sort getPostDefaultSort();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists PostMarkdown vo
|
||||||
|
*
|
||||||
|
* @return a list of PostMarkdown vo
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
List<PostMarkdownVO> listPostMarkdowns();
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,10 +23,13 @@ import run.halo.app.event.options.OptionUpdatedEvent;
|
||||||
import run.halo.app.event.theme.ThemeUpdatedEvent;
|
import run.halo.app.event.theme.ThemeUpdatedEvent;
|
||||||
import run.halo.app.exception.NotFoundException;
|
import run.halo.app.exception.NotFoundException;
|
||||||
import run.halo.app.exception.ServiceException;
|
import run.halo.app.exception.ServiceException;
|
||||||
|
import run.halo.app.handler.file.FileHandler;
|
||||||
import run.halo.app.model.dto.BackupDTO;
|
import run.halo.app.model.dto.BackupDTO;
|
||||||
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
||||||
import run.halo.app.model.entity.*;
|
import run.halo.app.model.entity.*;
|
||||||
|
import run.halo.app.model.params.PostMarkdownParam;
|
||||||
import run.halo.app.model.support.HaloConst;
|
import run.halo.app.model.support.HaloConst;
|
||||||
|
import run.halo.app.model.vo.PostMarkdownVO;
|
||||||
import run.halo.app.security.service.OneTimeTokenService;
|
import run.halo.app.security.service.OneTimeTokenService;
|
||||||
import run.halo.app.service.*;
|
import run.halo.app.service.*;
|
||||||
import run.halo.app.utils.DateTimeUtils;
|
import run.halo.app.utils.DateTimeUtils;
|
||||||
|
@ -45,12 +48,14 @@ import java.time.LocalDateTime;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
import java.util.zip.ZipOutputStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Backup service implementation.
|
* Backup service implementation.
|
||||||
*
|
*
|
||||||
* @author johnniang
|
* @author johnniang
|
||||||
* @author ryanwang
|
* @author ryanwang
|
||||||
|
* @author Raremaa
|
||||||
* @date 2019-04-26
|
* @date 2019-04-26
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
|
@ -59,10 +64,14 @@ public class BackupServiceImpl implements BackupService {
|
||||||
|
|
||||||
private static final String BACKUP_RESOURCE_BASE_URI = "/api/admin/backups/work-dir";
|
private static final String BACKUP_RESOURCE_BASE_URI = "/api/admin/backups/work-dir";
|
||||||
|
|
||||||
|
private static final String DATA_EXPORT_MARKDOWN_BASE_URI = "/api/admin/backups/markdown/export";
|
||||||
|
|
||||||
private static final String DATA_EXPORT_BASE_URI = "/api/admin/backups/data";
|
private static final String DATA_EXPORT_BASE_URI = "/api/admin/backups/data";
|
||||||
|
|
||||||
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
private static final String LINE_SEPARATOR = System.getProperty("line.separator");
|
||||||
|
|
||||||
|
private final static String UPLOAD_SUB_DIR = "upload/";
|
||||||
|
|
||||||
private static final Type MAP_TYPE = new TypeToken<Map<String, ?>>() {
|
private static final Type MAP_TYPE = new TypeToken<Map<String, ?>>() {
|
||||||
}.getType();
|
}.getType();
|
||||||
|
|
||||||
|
@ -429,6 +438,121 @@ public class BackupServiceImpl implements BackupService {
|
||||||
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
|
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BackupDTO exportMarkdowns(PostMarkdownParam postMarkdownParam) throws IOException {
|
||||||
|
// Query all Post data
|
||||||
|
List<PostMarkdownVO> postMarkdownList = postService.listPostMarkdowns();
|
||||||
|
Assert.notEmpty(postMarkdownList, "当前无文章可以导出");
|
||||||
|
|
||||||
|
// Write files to the temporary directory
|
||||||
|
String markdownFileTempPathName = haloProperties.getBackupMarkdownDir() + IdUtil.simpleUUID().hashCode();
|
||||||
|
for (int i = 0; i < postMarkdownList.size(); i++) {
|
||||||
|
PostMarkdownVO postMarkdownVO = postMarkdownList.get(i);
|
||||||
|
StringBuilder content = new StringBuilder();
|
||||||
|
Boolean needFrontMatter = Optional.ofNullable(postMarkdownParam.getNeedFrontMatter()).orElse(false);
|
||||||
|
if (needFrontMatter) {
|
||||||
|
// Add front-matter
|
||||||
|
content.append(postMarkdownVO.getFrontMatter()).append("\n");
|
||||||
|
}
|
||||||
|
content.append(postMarkdownVO.getOriginalContent());
|
||||||
|
try {
|
||||||
|
String markdownFileName = postMarkdownVO.getTitle() + "-" + postMarkdownVO.getSlug() + ".md";
|
||||||
|
Path markdownFilePath = Paths.get(markdownFileTempPathName, markdownFileName);
|
||||||
|
if (!Files.exists(markdownFilePath.getParent())) {
|
||||||
|
Files.createDirectories(markdownFilePath.getParent());
|
||||||
|
}
|
||||||
|
Path markdownDataPath = Files.createFile(markdownFilePath);
|
||||||
|
FileWriter fileWriter = new FileWriter(markdownDataPath.toFile(), CharsetUtil.UTF_8);
|
||||||
|
fileWriter.write(content.toString());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException("导出数据失败", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ZipOutputStream markdownZipOut = null;
|
||||||
|
// Zip file
|
||||||
|
try {
|
||||||
|
// Create zip path
|
||||||
|
String markdownZipFileName = HaloConst.HALO_BACKUP_MARKDOWN_PREFIX +
|
||||||
|
DateTimeUtils.format(LocalDateTime.now(), DateTimeUtils.HORIZONTAL_LINE_DATETIME_FORMATTER) +
|
||||||
|
IdUtil.simpleUUID().hashCode() + ".zip";
|
||||||
|
|
||||||
|
// Create zip file
|
||||||
|
Path markdownZipFilePath = Paths.get(haloProperties.getBackupMarkdownDir(), markdownZipFileName);
|
||||||
|
if (!Files.exists(markdownZipFilePath.getParent())) {
|
||||||
|
Files.createDirectories(markdownZipFilePath.getParent());
|
||||||
|
}
|
||||||
|
Path markdownZipPath = Files.createFile(markdownZipFilePath);
|
||||||
|
|
||||||
|
markdownZipOut = new ZipOutputStream(Files.newOutputStream(markdownZipPath));
|
||||||
|
|
||||||
|
// Zip temporary directory
|
||||||
|
Path markdownFileTempPath = Paths.get(markdownFileTempPathName);
|
||||||
|
run.halo.app.utils.FileUtils.zip(markdownFileTempPath, markdownZipOut);
|
||||||
|
|
||||||
|
// Zip upload sub-directory
|
||||||
|
String uploadPathName = FileHandler.normalizeDirectory(haloProperties.getWorkDir()) + UPLOAD_SUB_DIR;
|
||||||
|
Path uploadPath = Paths.get(uploadPathName);
|
||||||
|
if (Files.exists(uploadPath)) {
|
||||||
|
run.halo.app.utils.FileUtils.zip(uploadPath, markdownZipOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove files in the temporary directory
|
||||||
|
run.halo.app.utils.FileUtils.deleteFolder(markdownFileTempPath);
|
||||||
|
|
||||||
|
// Build backup dto
|
||||||
|
return buildBackupDto(DATA_EXPORT_MARKDOWN_BASE_URI, markdownZipPath);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException("Failed to export markdowns", e);
|
||||||
|
} finally {
|
||||||
|
if (markdownZipOut != null) {
|
||||||
|
markdownZipOut.close();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<BackupDTO> listMarkdowns() {
|
||||||
|
// Ensure the parent folder exist
|
||||||
|
Path backupParentPath = Paths.get(haloProperties.getBackupMarkdownDir());
|
||||||
|
if (Files.notExists(backupParentPath)) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Build backup dto
|
||||||
|
try (Stream<Path> subPathStream = Files.list(backupParentPath)) {
|
||||||
|
return subPathStream
|
||||||
|
.filter(backupPath -> StringUtils.startsWithIgnoreCase(backupPath.getFileName().toString(), HaloConst.HALO_BACKUP_MARKDOWN_PREFIX))
|
||||||
|
.map(backupPath -> buildBackupDto(DATA_EXPORT_MARKDOWN_BASE_URI, backupPath))
|
||||||
|
.sorted(Comparator.comparingLong(BackupDTO::getUpdateTime).reversed())
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException("Failed to fetch backups", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void deleteMarkdown(String fileName) {
|
||||||
|
Assert.hasText(fileName, "File name must not be blank");
|
||||||
|
|
||||||
|
Path backupRootPath = Paths.get(haloProperties.getBackupMarkdownDir());
|
||||||
|
|
||||||
|
// Get backup path
|
||||||
|
Path backupPath = backupRootPath.resolve(fileName);
|
||||||
|
|
||||||
|
// Check directory traversal
|
||||||
|
run.halo.app.utils.FileUtils.checkDirectoryTraversal(backupRootPath, backupPath);
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Delete backup file
|
||||||
|
Files.delete(backupPath);
|
||||||
|
} catch (NoSuchFileException e) {
|
||||||
|
throw new NotFoundException("The file " + fileName + " was not found", e);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new ServiceException("Failed to delete backup", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Builds backup dto.
|
* Builds backup dto.
|
||||||
*
|
*
|
||||||
|
|
|
@ -27,10 +27,7 @@ import run.halo.app.model.enums.PostStatus;
|
||||||
import run.halo.app.model.params.PostParam;
|
import run.halo.app.model.params.PostParam;
|
||||||
import run.halo.app.model.params.PostQuery;
|
import run.halo.app.model.params.PostQuery;
|
||||||
import run.halo.app.model.properties.PostProperties;
|
import run.halo.app.model.properties.PostProperties;
|
||||||
import run.halo.app.model.vo.ArchiveMonthVO;
|
import run.halo.app.model.vo.*;
|
||||||
import run.halo.app.model.vo.ArchiveYearVO;
|
|
||||||
import run.halo.app.model.vo.PostDetailVO;
|
|
||||||
import run.halo.app.model.vo.PostListVO;
|
|
||||||
import run.halo.app.repository.PostRepository;
|
import run.halo.app.repository.PostRepository;
|
||||||
import run.halo.app.repository.base.BasePostRepository;
|
import run.halo.app.repository.base.BasePostRepository;
|
||||||
import run.halo.app.service.*;
|
import run.halo.app.service.*;
|
||||||
|
@ -57,6 +54,7 @@ import static run.halo.app.model.support.HaloConst.URL_SEPARATOR;
|
||||||
* @author guqing
|
* @author guqing
|
||||||
* @author evanwang
|
* @author evanwang
|
||||||
* @author coor.top
|
* @author coor.top
|
||||||
|
* @author Raremaa
|
||||||
* @date 2019-03-14
|
* @date 2019-03-14
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@ -819,6 +817,64 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
||||||
return Sort.by(DESC, "topPriority").and(Sort.by(DESC, indexSort).and(Sort.by(DESC, "id")));
|
return Sort.by(DESC, "topPriority").and(Sort.by(DESC, indexSort).and(Sort.by(DESC, "id")));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<PostMarkdownVO> listPostMarkdowns() {
|
||||||
|
List<Post> allPostList = listAll();
|
||||||
|
List<PostMarkdownVO> result = new ArrayList(allPostList.size());
|
||||||
|
for (int i = 0; i < allPostList.size(); i++) {
|
||||||
|
Post post = allPostList.get(i);
|
||||||
|
result.add(convertToPostMarkdownVo(post));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
private PostMarkdownVO convertToPostMarkdownVo(Post post) {
|
||||||
|
PostMarkdownVO postMarkdownVO = new PostMarkdownVO();
|
||||||
|
|
||||||
|
StringBuilder frontMatter = new StringBuilder("---\n");
|
||||||
|
frontMatter.append("title: ").append(post.getTitle()).append("\n");
|
||||||
|
frontMatter.append("date: ").append(post.getCreateTime()).append("\n");
|
||||||
|
frontMatter.append("updated: ").append(post.getUpdateTime()).append("\n");
|
||||||
|
|
||||||
|
//set fullPath
|
||||||
|
frontMatter.append("url: ").append(buildFullPath(post)).append("\n");
|
||||||
|
|
||||||
|
//set category
|
||||||
|
List<Category> categories = postCategoryService.listCategoriesBy(post.getId());
|
||||||
|
StringBuilder categoryContent = new StringBuilder();
|
||||||
|
for (int i = 0; i < categories.size(); i++) {
|
||||||
|
Category category = categories.get(i);
|
||||||
|
String categoryName = category.getName();
|
||||||
|
if (i == 0) {
|
||||||
|
categoryContent.append(categoryName);
|
||||||
|
} else {
|
||||||
|
categoryContent.append(" | ").append(categoryName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frontMatter.append("categories: ").append(categoryContent.toString()).append("\n");
|
||||||
|
|
||||||
|
//set tags
|
||||||
|
List<Tag> tags = postTagService.listTagsBy(post.getId());
|
||||||
|
StringBuilder tagContent = new StringBuilder();
|
||||||
|
for (int i = 0; i < tags.size(); i++) {
|
||||||
|
Tag tag = tags.get(i);
|
||||||
|
String tagName = tag.getName();
|
||||||
|
if (i == 0) {
|
||||||
|
tagContent.append(tagName);
|
||||||
|
} else {
|
||||||
|
tagContent.append(" | ").append(tagName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
frontMatter.append("tags: ").append(tagContent.toString()).append("\n");
|
||||||
|
|
||||||
|
frontMatter.append("---\n");
|
||||||
|
postMarkdownVO.setFrontMatter(frontMatter.toString());
|
||||||
|
postMarkdownVO.setOriginalContent(post.getOriginalContent());
|
||||||
|
postMarkdownVO.setTitle(post.getTitle());
|
||||||
|
postMarkdownVO.setSlug(post.getSlug());
|
||||||
|
return postMarkdownVO;
|
||||||
|
}
|
||||||
|
|
||||||
private String buildFullPath(Post post) {
|
private String buildFullPath(Post post) {
|
||||||
|
|
||||||
PostPermalinkType permalinkType = optionService.getPostPermalinkType();
|
PostPermalinkType permalinkType = optionService.getPostPermalinkType();
|
||||||
|
|
|
@ -36,7 +36,7 @@ class PostServiceImplTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void getContent() {
|
void getContent() {
|
||||||
String exportMarkdown = postService.exportMarkdown(18);
|
String exportMarkdown = postService.exportMarkdown(1);
|
||||||
log.debug(exportMarkdown);
|
log.debug(exportMarkdown);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue