mirror of https://github.com/halo-dev/halo
Add base post services
parent
afdf94b898
commit
bd2eebf1cd
|
@ -113,8 +113,10 @@ public class AdminController {
|
|||
adminService.updateApplicationConfig(content);
|
||||
}
|
||||
|
||||
@PostMapping("/spring/restart")
|
||||
@PostMapping(value = {"halo/restart", "spring/restart"})
|
||||
@ApiOperation("Restart halo server")
|
||||
public void restartApplication() {
|
||||
Application.restart();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -88,5 +88,4 @@ public class MainController {
|
|||
response.sendRedirect(favicon);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -67,8 +67,6 @@ public class CommonController extends AbstractErrorController {
|
|||
*/
|
||||
@GetMapping
|
||||
public String handleError(HttpServletRequest request, HttpServletResponse response, Model model) {
|
||||
HttpStatus status = getStatus(request);
|
||||
|
||||
log.error("Request URL: [{}], URI: [{}], Request Method: [{}], IP: [{}]",
|
||||
request.getRequestURL(),
|
||||
request.getRequestURI(),
|
||||
|
@ -82,6 +80,8 @@ public class CommonController extends AbstractErrorController {
|
|||
|
||||
log.debug("Error detail: [{}]", errorDetail);
|
||||
|
||||
HttpStatus status = getStatus(request);
|
||||
|
||||
if (status.equals(HttpStatus.INTERNAL_SERVER_ERROR)) {
|
||||
return contentInternalError();
|
||||
} else if (status.equals(HttpStatus.NOT_FOUND)) {
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
package run.halo.app.event.post;
|
||||
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
|
||||
/**
|
||||
* Post visit event.
|
||||
*
|
||||
|
@ -14,7 +18,8 @@ public class PostVisitEvent extends AbstractVisitEvent {
|
|||
* @param source the object on which the event initially occurred (never {@code null})
|
||||
* @param postId post id must not be null
|
||||
*/
|
||||
public PostVisitEvent(Object source, Integer postId) {
|
||||
public PostVisitEvent(Object source, @NonNull Integer postId) {
|
||||
super(source, postId);
|
||||
Assert.isTrue(!ServiceUtils.isEmptyId(postId), "Post id must not be empty");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@ import org.springframework.context.ApplicationListener;
|
|||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.core.Ordered;
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.ResourceUtils;
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.model.properties.PrimaryProperties;
|
||||
|
@ -15,6 +17,7 @@ import run.halo.app.service.ThemeService;
|
|||
import run.halo.app.service.UserService;
|
||||
import run.halo.app.utils.FileUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.*;
|
||||
import java.util.Collections;
|
||||
|
@ -76,8 +79,9 @@ public class StartedListener implements ApplicationListener<ApplicationStartedEv
|
|||
Path source;
|
||||
|
||||
if ("jar".equalsIgnoreCase(themeUri.getScheme())) {
|
||||
|
||||
// Create new file system for jar
|
||||
FileSystem fileSystem = FileSystems.newFileSystem(themeUri, Collections.emptyMap());
|
||||
FileSystem fileSystem = getFileSystem(themeUri);
|
||||
source = fileSystem.getPath("/BOOT-INF/classes/" + ThemeService.THEME_FOLDER);
|
||||
} else {
|
||||
source = Paths.get(themeUri);
|
||||
|
@ -98,4 +102,18 @@ public class StartedListener implements ApplicationListener<ApplicationStartedEv
|
|||
}
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private FileSystem getFileSystem(@NonNull URI uri) throws IOException {
|
||||
Assert.notNull(uri, "Uri must not be null");
|
||||
|
||||
FileSystem fileSystem;
|
||||
|
||||
try {
|
||||
fileSystem = FileSystems.getFileSystem(uri);
|
||||
} catch (FileSystemNotFoundException e) {
|
||||
fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
|
||||
}
|
||||
|
||||
return fileSystem;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
package run.halo.app.model.params;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Post content param.
|
||||
*
|
||||
* @author johnniang
|
||||
*/
|
||||
@Data
|
||||
public class PostContentParam {
|
||||
private String content;
|
||||
}
|
|
@ -142,4 +142,22 @@ public interface BasePostRepository<POST extends BasePost> extends BaseRepositor
|
|||
@Query("update BasePost p set p.likes = p.likes + :likes where p.id = :postId")
|
||||
int updateLikes(@Param("likes") long likes, @Param("postId") @NonNull Integer postId);
|
||||
|
||||
/**
|
||||
* Updates post original content/
|
||||
*
|
||||
* @param content content could be blank but disallow to be null
|
||||
* @param postId post id must not be null
|
||||
* @return updated rows
|
||||
*/
|
||||
@Modifying
|
||||
@Query("update BasePost p set p.originalContent = :content where p.id = :postId")
|
||||
int updateOriginalContent(@Param("content") @NonNull String content, @Param("postId") @NonNull Integer postId);
|
||||
|
||||
@Modifying
|
||||
@Query("update BasePost p set p.status = :status where p.id = :postId")
|
||||
int updateStatus(@Param("status") @NonNull PostStatus status, @Param("postId") @NonNull Integer postId);
|
||||
|
||||
@Modifying
|
||||
@Query("update BasePost p set p.formatContent = :formatContent where p.id = :postId")
|
||||
int updateFormatContent(@Param("formatContent") @NonNull String formatContent, @Param("postId") @NonNull Integer postId);
|
||||
}
|
||||
|
|
|
@ -8,6 +8,7 @@ import run.halo.app.model.dto.post.BasePostDetailDTO;
|
|||
import run.halo.app.model.dto.post.BasePostMinimalDTO;
|
||||
import run.halo.app.model.dto.post.BasePostSimpleDTO;
|
||||
import run.halo.app.model.entity.BasePost;
|
||||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
|
||||
import java.util.Date;
|
||||
|
@ -215,4 +216,24 @@ public interface BasePostService<POST extends BasePost> extends CrudService<POST
|
|||
|
||||
@NonNull
|
||||
BasePostDetailDTO convertToDetail(@NonNull POST post);
|
||||
|
||||
/**
|
||||
* Updates draft content.
|
||||
*
|
||||
* @param content draft content could be blank
|
||||
* @param postId post id must not be null
|
||||
* @return updated post
|
||||
*/
|
||||
@NonNull
|
||||
POST updateDraftContent(@Nullable String content, @NonNull Integer postId);
|
||||
|
||||
/**
|
||||
* Updates post status.
|
||||
*
|
||||
* @param status post status must not be null
|
||||
* @param postId post id must not be null
|
||||
* @return updated post
|
||||
*/
|
||||
@NonNull
|
||||
POST updateStatus(@NonNull PostStatus status, @NonNull Integer postId);
|
||||
}
|
||||
|
|
|
@ -112,14 +112,7 @@ public abstract class BaseMetaServiceImpl<META extends BaseMeta> extends Abstrac
|
|||
|
||||
@Override
|
||||
public Map<String, Object> convertToMap(List<META> metas) {
|
||||
if (CollectionUtils.isEmpty(metas)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
metas.forEach(meta -> result.put(meta.getKey(), meta.getValue()));
|
||||
|
||||
return result;
|
||||
return ServiceUtils.convertToMap(metas, META::getKey, META::getValue);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.springframework.util.CollectionUtils;
|
|||
import run.halo.app.exception.AlreadyExistsException;
|
||||
import run.halo.app.exception.BadRequestException;
|
||||
import run.halo.app.exception.NotFoundException;
|
||||
import run.halo.app.exception.ServiceException;
|
||||
import run.halo.app.model.dto.post.BasePostDetailDTO;
|
||||
import run.halo.app.model.dto.post.BasePostMinimalDTO;
|
||||
import run.halo.app.model.dto.post.BasePostSimpleDTO;
|
||||
|
@ -320,6 +321,65 @@ public abstract class BasePostServiceImpl<POST extends BasePost> extends Abstrac
|
|||
return new BasePostDetailDTO().convertFrom(post);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public POST updateDraftContent(String content, Integer postId) {
|
||||
Assert.isTrue(!ServiceUtils.isEmptyId(postId), "Post id must not be empty");
|
||||
|
||||
if (content == null) {
|
||||
content = "";
|
||||
}
|
||||
|
||||
POST post = getById(postId);
|
||||
|
||||
if (!StringUtils.equals(content, post.getOriginalContent())) {
|
||||
// If content is different with database, then update database
|
||||
int updatedRows = basePostRepository.updateOriginalContent(content, postId);
|
||||
if (updatedRows != 1) {
|
||||
throw new ServiceException("Failed to update original content of post with id " + postId);
|
||||
}
|
||||
// Set the content
|
||||
post.setOriginalContent(content);
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public POST updateStatus(PostStatus status, Integer postId) {
|
||||
Assert.notNull(status, "Post status must not be null");
|
||||
Assert.isTrue(!ServiceUtils.isEmptyId(postId), "Post id must not be empty");
|
||||
|
||||
// Get post
|
||||
POST post = getById(postId);
|
||||
|
||||
if (!status.equals(post.getStatus())) {
|
||||
// Update post
|
||||
int updatedRows = basePostRepository.updateStatus(status, postId);
|
||||
if (updatedRows != 1) {
|
||||
throw new ServiceException("Failed to update post status of post with id " + postId);
|
||||
}
|
||||
|
||||
post.setStatus(status);
|
||||
}
|
||||
|
||||
// Sync content
|
||||
if (PostStatus.PUBLISHED.equals(status)) {
|
||||
// If publish this post, then convert the formatted content
|
||||
String formatContent = MarkdownUtils.renderHtml(post.getOriginalContent());
|
||||
int updatedRows = basePostRepository.updateFormatContent(formatContent, postId);
|
||||
|
||||
if (updatedRows != 1) {
|
||||
throw new ServiceException("Failed to update post format content of post with id " + postId);
|
||||
}
|
||||
|
||||
post.setFormatContent(formatContent);
|
||||
}
|
||||
|
||||
return post;
|
||||
}
|
||||
|
||||
@Override
|
||||
public POST create(POST post) {
|
||||
// Check title
|
||||
|
|
|
@ -67,7 +67,7 @@ public class MarkdownUtils {
|
|||
/**
|
||||
* Render Markdown content
|
||||
*
|
||||
* @param content content
|
||||
* @param markdown content
|
||||
* @return String
|
||||
*/
|
||||
public static String renderHtml(String markdown) {
|
||||
|
@ -108,7 +108,7 @@ public class MarkdownUtils {
|
|||
/**
|
||||
* Get front-matter
|
||||
*
|
||||
* @param content content
|
||||
* @param markdown markdown
|
||||
* @return Map
|
||||
*/
|
||||
public static Map<String, List<String>> getFrontMatter(String markdown) {
|
||||
|
|
|
@ -99,8 +99,9 @@ public class ServiceUtils {
|
|||
* @return a map which key from list data and value is data
|
||||
*/
|
||||
@NonNull
|
||||
public static <ID, D, V> Map<ID, V> convertToMap(Collection<D> list, Function<D, ID> keyFunction, Function<D, V> valueFunction) {
|
||||
Assert.notNull(keyFunction, "mapping function must not be null");
|
||||
public static <ID, D, V> Map<ID, V> convertToMap(@Nullable Collection<D> list, @NonNull Function<D, ID> keyFunction, @NonNull Function<D, V> valueFunction) {
|
||||
Assert.notNull(keyFunction, "Key function must not be null");
|
||||
Assert.notNull(valueFunction, "Value function must not be null");
|
||||
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return Collections.emptyMap();
|
||||
|
|
|
@ -14,10 +14,10 @@ spring:
|
|||
type: com.zaxxer.hikari.HikariDataSource
|
||||
|
||||
# H2 Database 配置
|
||||
driver-class-name: org.h2.Driver
|
||||
url: jdbc:h2:file:~/halo-test/db/halo
|
||||
username: admin
|
||||
password: 123456
|
||||
# driver-class-name: org.h2.Driver
|
||||
# url: jdbc:h2:file:~/halo-test/db/halo
|
||||
# username: admin
|
||||
# password: 123456
|
||||
|
||||
# MySQL 配置
|
||||
# driver-class-name: com.mysql.cj.jdbc.Driver
|
||||
|
|
|
@ -7,13 +7,14 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.ActiveProfiles;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@ActiveProfiles("dev")
|
||||
@ActiveProfiles("test")
|
||||
public class PostServiceImplTest {
|
||||
|
||||
String standardMdContent = "---\n" +
|
||||
private String standardMdContent = "---\n" +
|
||||
"title: springfox-swagger2配置成功但无法访问/swagger-ui.html\n" +
|
||||
"tags:\n" +
|
||||
" - spring boot\n" +
|
||||
|
@ -26,7 +27,7 @@ public class PostServiceImplTest {
|
|||
"\n" +
|
||||
"在前后端分离项目中,通常需要用到 API 文档,springfox 开发的 **[SpringFox](https://github.com/springfox/springfox)** 可以实现自动化 json API 文档。";
|
||||
|
||||
String nonStandardMdContent = "---\n" +
|
||||
private String nonStandardMdContent = "---\n" +
|
||||
"title: Basic concepts of JPA\n" +
|
||||
"date: 2018-08-03 11:57:00\n" +
|
||||
"tags: ['spring', 'jpa', 'database', 'concept']\n" +
|
||||
|
@ -45,6 +46,7 @@ public class PostServiceImplTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
@Transactional
|
||||
public void markdownImportTest() {
|
||||
postService.importMarkdown(standardMdContent, "standard");
|
||||
postService.importMarkdown(nonStandardMdContent, "nonStandard");
|
||||
|
|
Loading…
Reference in New Issue