Fix migration logical bug

pull/146/head
johnniang 2019-05-01 21:45:40 +08:00
parent f2b9fc768d
commit 4c8d38ae07
6 changed files with 126 additions and 39 deletions

View File

@ -3,9 +3,8 @@ package run.halo.app.model.entity;
import lombok.Data; import lombok.Data;
import lombok.EqualsAndHashCode; import lombok.EqualsAndHashCode;
import lombok.ToString; import lombok.ToString;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.enums.CommentStatus;
import run.halo.app.utils.ServiceUtils;
import javax.persistence.*; import javax.persistence.*;
@ -102,7 +101,11 @@ public class BaseComment extends BaseEntity {
public void prePersist() { public void prePersist() {
super.prePersist(); super.prePersist();
if (parentId == null || parentId < 0) { if (ServiceUtils.isEmptyId(id)) {
id = null;
}
if (ServiceUtils.isEmptyId(parentId)) {
parentId = 0L; parentId = 0L;
} }

View File

@ -46,4 +46,5 @@ public interface BaseRepository<DOMAIN, ID> extends JpaRepository<DOMAIN, ID> {
* @return number of rows affected * @return number of rows affected
*/ */
long deleteByIdIn(@NonNull Iterable<ID> ids); long deleteByIdIn(@NonNull Iterable<ID> ids);
} }

View File

@ -10,6 +10,7 @@ import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository; import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.repository.support.PageableExecutionUtils; import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.Assert; import org.springframework.util.Assert;
import javax.persistence.EntityManager; import javax.persistence.EntityManager;
@ -97,6 +98,7 @@ public class BaseRepositoryImpl<DOMAIN, ID> extends SimpleJpaRepository<DOMAIN,
* @return number of rows affected * @return number of rows affected
*/ */
@Override @Override
@Transactional
public long deleteByIdIn(Iterable<ID> ids) { public long deleteByIdIn(Iterable<ID> ids) {
log.debug("Customized deleteByIdIn method was invoked"); log.debug("Customized deleteByIdIn method was invoked");

View File

@ -13,6 +13,7 @@ import run.halo.app.model.vo.BaseCommentVO;
import run.halo.app.model.vo.BaseCommentWithParentVO; import run.halo.app.model.vo.BaseCommentWithParentVO;
import java.util.Collection; import java.util.Collection;
import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -163,6 +164,15 @@ public interface BaseCommentService<COMMENT extends BaseComment> extends CrudSer
@NonNull @NonNull
Page<BaseCommentDTO> convertTo(@NonNull Page<COMMENT> commentPage); Page<BaseCommentDTO> convertTo(@NonNull Page<COMMENT> commentPage);
/**
* Converts to base comment vo tree.
*
* @param comments comments list could be null
* @param comparator comment comparator could be null
* @return a comment vo tree
*/
List<BaseCommentVO> convertToVo(@Nullable List<COMMENT> comments, @Nullable Comparator<BaseCommentVO> comparator);
/** /**
* Target must exist. * Target must exist.
* *

View File

@ -219,9 +219,17 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
// Set some default values // Set some default values
comment.setIpAddress(ServletUtils.getRequestIp()); if (comment.getIpAddress() == null) {
comment.setUserAgent(ServletUtils.getHeaderIgnoreCase(HttpHeaders.USER_AGENT)); comment.setIpAddress(ServletUtils.getRequestIp());
comment.setGavatarMd5(DigestUtils.md5Hex(comment.getEmail())); }
if (comment.getUserAgent() == null) {
comment.setUserAgent(ServletUtils.getHeaderIgnoreCase(HttpHeaders.USER_AGENT));
}
if (comment.getGavatarMd5() == null) {
comment.setGavatarMd5(DigestUtils.md5Hex(comment.getEmail()));
}
if (authentication != null) { if (authentication != null) {
// Comment of blogger // Comment of blogger
@ -368,15 +376,8 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
}; };
} }
/**
* Converts to base comment vo tree.
*
* @param comments comments list could be null
* @param comparator comment comparator could be null
* @return a comment vo tree
*/
@NonNull @NonNull
protected List<BaseCommentVO> convertToVo(@Nullable List<COMMENT> comments, @Nullable Comparator<BaseCommentVO> comparator) { public List<BaseCommentVO> convertToVo(@Nullable List<COMMENT> comments, @Nullable Comparator<BaseCommentVO> comparator) {
if (CollectionUtils.isEmpty(comments)) { if (CollectionUtils.isEmpty(comments)) {
return Collections.emptyList(); return Collections.emptyList();
} }
@ -408,32 +409,24 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
return; return;
} }
List<COMMENT> children = new LinkedList<>(); // Get children
List<COMMENT> children = comments.stream()
.filter(comment -> Objects.equals(parentComment.getId(), comment.getParentId()))
.collect(Collectors.toList());
comments.forEach(comment -> { // Add children
if (parentComment.getId().equals(comment.getParentId())) { children.forEach(comment -> {
// Stage the child comment // Convert to comment vo
children.add(comment); BaseCommentVO commentVO = new BaseCommentVO().convertFrom(comment);
// Convert to comment vo if (parentComment.getChildren() == null) {
BaseCommentVO commentVO = new BaseCommentVO().convertFrom(comment); parentComment.setChildren(new LinkedList<>());
// Add additional content
if (commentVO.getParentId() > 0) {
// TODO Provide an optional additional content
commentVO.setContent(String.format(COMMENT_TEMPLATE, parentComment.getId(), parentComment.getAuthor(), commentVO.getContent()));
}
// Init children container
if (parentComment.getChildren() == null) {
parentComment.setChildren(new LinkedList<>());
}
parentComment.getChildren().add(commentVO);
} }
parentComment.getChildren().add(commentVO);
}); });
// Remove all children // Remove children
comments.removeAll(children); comments.removeAll(children);
if (!CollectionUtils.isEmpty(parentComment.getChildren())) { if (!CollectionUtils.isEmpty(parentComment.getChildren())) {

View File

@ -7,6 +7,7 @@ import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable; import org.springframework.lang.Nullable;
import org.springframework.scheduling.annotation.Async; import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils; import org.springframework.util.FileCopyUtils;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import run.halo.app.exception.ServiceException; import run.halo.app.exception.ServiceException;
@ -14,9 +15,12 @@ import run.halo.app.model.entity.*;
import run.halo.app.model.enums.AttachmentType; import run.halo.app.model.enums.AttachmentType;
import run.halo.app.model.enums.CommentStatus; import run.halo.app.model.enums.CommentStatus;
import run.halo.app.model.enums.PostStatus; import run.halo.app.model.enums.PostStatus;
import run.halo.app.repository.PostCommentRepository;
import run.halo.app.repository.SheetCommentRepository;
import run.halo.app.service.*; import run.halo.app.service.*;
import run.halo.app.utils.BeanUtils; import run.halo.app.utils.BeanUtils;
import run.halo.app.utils.JsonUtils; import run.halo.app.utils.JsonUtils;
import run.halo.app.utils.ServiceUtils;
import java.io.IOException; import java.io.IOException;
import java.io.InputStreamReader; import java.io.InputStreamReader;
@ -49,8 +53,12 @@ public class RecoveryServiceImpl implements RecoveryService {
private final PostCommentService postCommentService; private final PostCommentService postCommentService;
private final PostCommentRepository postCommentRepository;
private final SheetCommentService sheetCommentService; private final SheetCommentService sheetCommentService;
private final SheetCommentRepository sheetCommentRepository;
private final SheetService sheetService; private final SheetService sheetService;
private final PhotoService photoService; private final PhotoService photoService;
@ -62,7 +70,9 @@ public class RecoveryServiceImpl implements RecoveryService {
CategoryService categoryService, CategoryService categoryService,
TagService tagService, TagService tagService,
PostCommentService postCommentService, PostCommentService postCommentService,
PostCommentRepository postCommentRepository,
SheetCommentService sheetCommentService, SheetCommentService sheetCommentService,
SheetCommentRepository sheetCommentRepository,
SheetService sheetService, SheetService sheetService,
PhotoService photoService) { PhotoService photoService) {
this.attachmentService = attachmentService; this.attachmentService = attachmentService;
@ -72,7 +82,9 @@ public class RecoveryServiceImpl implements RecoveryService {
this.categoryService = categoryService; this.categoryService = categoryService;
this.tagService = tagService; this.tagService = tagService;
this.postCommentService = postCommentService; this.postCommentService = postCommentService;
this.postCommentRepository = postCommentRepository;
this.sheetCommentService = sheetCommentService; this.sheetCommentService = sheetCommentService;
this.sheetCommentRepository = sheetCommentRepository;
this.sheetService = sheetService; this.sheetService = sheetService;
this.photoService = photoService; this.photoService = photoService;
} }
@ -203,7 +215,7 @@ public class RecoveryServiceImpl implements RecoveryService {
Post createdPost = postService.createOrUpdateBy(post); Post createdPost = postService.createOrUpdateBy(post);
Object commentsObject = postMap.get("comments"); Object commentsObject = postMap.get("comments");
// TODO Handle comments // Handle comments
List<BaseComment> baseComments = handleComment(commentsObject, createdPost.getId()); List<BaseComment> baseComments = handleComment(commentsObject, createdPost.getId());
List<PostComment> postComments = baseComments.stream() List<PostComment> postComments = baseComments.stream()
@ -211,9 +223,11 @@ public class RecoveryServiceImpl implements RecoveryService {
.collect(Collectors.toList()); .collect(Collectors.toList());
try { try {
// Build virtual comment
PostComment virtualPostComment = new PostComment();
virtualPostComment.setId(0L);
// Create comments // Create comments
// TODO Don't use createInBatch method createPostCommentRecursively(virtualPostComment, postComments);
List<PostComment> createdPostComments = postCommentService.createInBatch(postComments);
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to create post comments for post with id " + createdPost.getId(), e); log.warn("Failed to create post comments for post with id " + createdPost.getId(), e);
// Ignore this exception // Ignore this exception
@ -239,7 +253,11 @@ public class RecoveryServiceImpl implements RecoveryService {
// Create comments // Create comments
try { try {
sheetCommentService.createInBatch(sheetComments); // Build virtual comment
SheetComment virtualSheetComment = new SheetComment();
virtualSheetComment.setId(0L);
// Create comments
createSheetCommentRecursively(virtualSheetComment, sheetComments);
} catch (Exception e) { } catch (Exception e) {
log.warn("Failed to create sheet comments for sheet with id " + createdSheet.getId(), e); log.warn("Failed to create sheet comments for sheet with id " + createdSheet.getId(), e);
// Ignore this exception // Ignore this exception
@ -248,6 +266,62 @@ public class RecoveryServiceImpl implements RecoveryService {
return createdSheet; return createdSheet;
} }
private void createPostCommentRecursively(@NonNull final PostComment parentComment, List<PostComment> postComments) {
Long oldParentId = parentComment.getId();
// Create parent
if (!ServiceUtils.isEmptyId(parentComment.getId())) {
PostComment createdComment = postCommentRepository.save(parentComment);
log.debug("Created post comment: [{}]", createdComment);
parentComment.setId(createdComment.getId());
}
if (CollectionUtils.isEmpty(postComments)) {
return;
}
// Get all children
List<PostComment> children = postComments.stream()
.filter(postComment -> Objects.equals(oldParentId, postComment.getParentId()))
.collect(Collectors.toList());
// Set parent id again
children.forEach(postComment -> postComment.setParentId(parentComment.getId()));
// Remove children
postComments.removeAll(children);
// Create children recursively
children.forEach(childComment -> createPostCommentRecursively(childComment, postComments));
}
private void createSheetCommentRecursively(@NonNull final SheetComment parentComment, List<SheetComment> sheetComments) {
Long oldParentId = parentComment.getId();
// Create parent
if (!ServiceUtils.isEmptyId(parentComment.getId())) {
SheetComment createComment = sheetCommentRepository.save(parentComment);
parentComment.setId(createComment.getId());
}
if (CollectionUtils.isEmpty(sheetComments)) {
return;
}
// Get all children
List<SheetComment> children = sheetComments.stream()
.filter(sheetComment -> Objects.equals(oldParentId, sheetComment.getParentId()))
.collect(Collectors.toList());
// Set parent id again
children.forEach(postComment -> postComment.setParentId(parentComment.getId()));
// Remove children
sheetComments.removeAll(children);
// Create children recursively
children.forEach(childComment -> createSheetCommentRecursively(childComment, sheetComments));
}
private List<BaseComment> handleComment(@Nullable Object commentsObject, @NonNull Integer postId) { private List<BaseComment> handleComment(@Nullable Object commentsObject, @NonNull Integer postId) {
Assert.notNull(postId, "Post id must not be null"); Assert.notNull(postId, "Post id must not be null");
@ -279,6 +353,10 @@ public class RecoveryServiceImpl implements RecoveryService {
baseComment.setPostId(postId); baseComment.setPostId(postId);
baseComment.setParentId(getLongOrDefault(commentMap.getOrDefault("commentParent", "").toString(), 0L)); baseComment.setParentId(getLongOrDefault(commentMap.getOrDefault("commentParent", "").toString(), 0L));
// Set create date
Long createTimestamp = getLongOrDefault(commentMap.getOrDefault("createDate", "").toString(), System.currentTimeMillis());
baseComment.setCreateTime(new Date(createTimestamp));
Integer commentStatus = getIntegerOrDefault(commentMap.getOrDefault("commentStatus", "").toString(), 1); Integer commentStatus = getIntegerOrDefault(commentMap.getOrDefault("commentStatus", "").toString(), 1);
if (commentStatus == 0) { if (commentStatus == 0) {
baseComment.setStatus(CommentStatus.PUBLISHED); baseComment.setStatus(CommentStatus.PUBLISHED);