diff --git a/src/main/java/cc/ryanc/halo/model/params/PostParam.java b/src/main/java/cc/ryanc/halo/model/params/PostParam.java index 518be8df6..dc25a43d4 100644 --- a/src/main/java/cc/ryanc/halo/model/params/PostParam.java +++ b/src/main/java/cc/ryanc/halo/model/params/PostParam.java @@ -66,8 +66,28 @@ public class PostParam implements InputConverter { Post post = InputConverter.super.convertTo(); // Crypt password - post.setPassword(BCrypt.hashpw(password, BCrypt.gensalt())); + if (StringUtils.isNotBlank(password)) { + post.setPassword(BCrypt.hashpw(password, BCrypt.gensalt())); + } return post; } + + @Override + public void update(Post post) { + if (StringUtils.isBlank(url)) { + url = HaloUtils.normalizeUrl(title); + } else { + url = HaloUtils.normalizeUrl(url); + } + + url = HaloUtils.initializeUrlIfBlank(url); + + InputConverter.super.update(post); + + // Crypt password + if (StringUtils.isNotBlank(password)) { + post.setPassword(BCrypt.hashpw(password, BCrypt.gensalt())); + } + } } diff --git a/src/main/java/cc/ryanc/halo/service/PostCategoryService.java b/src/main/java/cc/ryanc/halo/service/PostCategoryService.java index 4b232f4e1..0fddc67d8 100644 --- a/src/main/java/cc/ryanc/halo/service/PostCategoryService.java +++ b/src/main/java/cc/ryanc/halo/service/PostCategoryService.java @@ -47,12 +47,12 @@ public interface PostCategoryService extends CrudService List listPostBy(@NonNull Integer categoryId); /** - * Creates post categories by post id and category id set. + * Merges or creates post categories by post id and category id set if absent. * * @param postId post id must not be null * @param categoryIds category id set * @return a list of post category */ @NonNull - List createBy(@NonNull Integer postId, Set categoryIds); + List mergeOrCreateByIfAbsent(@NonNull Integer postId, Set categoryIds); } diff --git a/src/main/java/cc/ryanc/halo/service/PostService.java b/src/main/java/cc/ryanc/halo/service/PostService.java index 3a10edf3b..d1caa68cb 100755 --- a/src/main/java/cc/ryanc/halo/service/PostService.java +++ b/src/main/java/cc/ryanc/halo/service/PostService.java @@ -126,6 +126,18 @@ public interface PostService extends CrudService { @Transactional Post createBy(@NonNull Post post, Set tagIds, Set categoryIds); + /** + * Updates post by post, tag id set and category id set. + * + * @param postToUpdate post to update must not be null + * @param tagIds tag id set + * @param categoryIds category id set + * @return updated post + */ + @NonNull + @Transactional + Post updateBy(@NonNull Post postToUpdate, Set tagIds, Set categoryIds); + /** * Get post by url. * diff --git a/src/main/java/cc/ryanc/halo/service/PostTagService.java b/src/main/java/cc/ryanc/halo/service/PostTagService.java index ed481f4a7..1736ec7e2 100644 --- a/src/main/java/cc/ryanc/halo/service/PostTagService.java +++ b/src/main/java/cc/ryanc/halo/service/PostTagService.java @@ -58,12 +58,12 @@ public interface PostTagService extends CrudService { List listPostsBy(@NonNull Integer tagId); /** - * Creates post tags by post id and tag id set. + * Merges or creates post tags by post id and tag id set if absent. * * @param postId post id must not be null * @param tagIds tag id set * @return a list of post tag */ @NonNull - List createBy(@NonNull Integer postId, Set tagIds); + List mergeOrCreateByIfAbsent(@NonNull Integer postId, Set tagIds); } diff --git a/src/main/java/cc/ryanc/halo/service/impl/PostCategoryServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/PostCategoryServiceImpl.java index ed03ab8cc..90017515f 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/PostCategoryServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/PostCategoryServiceImpl.java @@ -88,7 +88,7 @@ public class PostCategoryServiceImpl extends AbstractCrudService createBy(Integer postId, Set categoryIds) { + public List mergeOrCreateByIfAbsent(Integer postId, Set categoryIds) { Assert.notNull(postId, "Post id must not be null"); if (CollectionUtils.isEmpty(categoryIds)) { @@ -96,17 +96,41 @@ public class PostCategoryServiceImpl extends AbstractCrudService postCategories = categoryIds.stream().map(categoryId -> { + List postCategoriesStaging = categoryIds.stream().map(categoryId -> { PostCategory postCategory = new PostCategory(); postCategory.setPostId(postId); postCategory.setCategoryId(categoryId); return postCategory; - }).collect(Collectors.toSet()); + }).collect(Collectors.toList()); - // List all post categories and remove them - postCategories.removeAll(postCategoryRepository.findAllByPostId(postId)); + List postCategoriesToCreate = new LinkedList<>(); + List postCategoriesToRemove = new LinkedList<>(); + + // Find all exist post categories + List postCategories = postCategoryRepository.findAllByPostId(postId); + + postCategories.forEach(postCategory -> { + if (!postCategoriesStaging.contains(postCategory)) { + postCategoriesToRemove.add(postCategory); + } + }); + + postCategoriesStaging.forEach(postCategoryStaging -> { + if (!postCategories.contains(postCategoryStaging)) { + postCategoriesToCreate.add(postCategoryStaging); + } + }); + + // Remove post categories + removeAll(postCategoriesToRemove); + + // Remove all post categories need to remove + postCategories.removeAll(postCategoriesToRemove); + + // Add all created post categories + postCategories.addAll(createInBatch(postCategoriesToCreate)); // Create them - return createInBatch(postCategories); + return postCategories; } } diff --git a/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java index cb32c724c..06b05f206 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/PostServiceImpl.java @@ -20,12 +20,14 @@ import org.springframework.data.domain.Page; import org.springframework.data.domain.PageRequest; import org.springframework.data.domain.Pageable; import org.springframework.data.domain.Sort; +import org.springframework.lang.NonNull; import org.springframework.stereotype.Service; import org.springframework.util.Assert; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; /** @@ -166,10 +168,20 @@ public class PostServiceImpl extends AbstractCrudService implemen } @Override - public Post createBy(Post post, Set tagIds, Set categoryIds) { - Assert.notNull(post, "Post param must not be null"); + public Post createBy(Post postToCreate, Set tagIds, Set categoryIds) { + return createOrUpdate(postToCreate, tagIds, categoryIds, this::create); + } - // TODO Check url + @Override + public Post updateBy(Post postToUpdate, Set tagIds, Set categoryIds) { + return createOrUpdate(postToUpdate, tagIds, categoryIds, this::update); + } + + private Post createOrUpdate(@NonNull Post post, Set tagIds, Set categoryIds, @NonNull Function postOperation) { + Assert.notNull(post, "Post param must not be null"); + Assert.notNull(postOperation, "Post operation must not be null"); + + // Check url long count = postRepository.countByUrl(post.getUrl()); if (count > 0) { @@ -179,10 +191,8 @@ public class PostServiceImpl extends AbstractCrudService implemen // Render content post.setFormatContent(MarkdownUtils.renderMarkdown(post.getOriginalContent())); - // TODO Handle thumbnail - - // Create post - create(post); + // Update post + post = postOperation.apply(post); // List all tags List tags = tagService.listAllByIds(tagIds); @@ -191,12 +201,12 @@ public class PostServiceImpl extends AbstractCrudService implemen List categories = categoryService.listAllByIds(categoryIds); // Create post tags - List postTags = postTagService.createBy(post.getId(), ServiceUtils.fetchProperty(tags, Tag::getId)); + List postTags = postTagService.mergeOrCreateByIfAbsent(post.getId(), ServiceUtils.fetchProperty(tags, Tag::getId)); log.debug("Created post tags: [{}]", postTags); // Create post categories - List postCategories = postCategoryService.createBy(post.getId(), ServiceUtils.fetchProperty(categories, Category::getId)); + List postCategories = postCategoryService.mergeOrCreateByIfAbsent(post.getId(), ServiceUtils.fetchProperty(categories, Category::getId)); log.debug("Created post categories: [{}]", postCategories); @@ -212,6 +222,6 @@ public class PostServiceImpl extends AbstractCrudService implemen */ @Override public Post getByUrl(String url, PostType type) { - return postRepository.getByUrlAndType(url, type).orElseThrow(()->new NotFoundException("The post does not exist").setErrorData(url)); + return postRepository.getByUrlAndType(url, type).orElseThrow(() -> new NotFoundException("The post does not exist").setErrorData(url)); } } diff --git a/src/main/java/cc/ryanc/halo/service/impl/PostTagServiceImpl.java b/src/main/java/cc/ryanc/halo/service/impl/PostTagServiceImpl.java index 8d6f8590e..e72a96fcd 100644 --- a/src/main/java/cc/ryanc/halo/service/impl/PostTagServiceImpl.java +++ b/src/main/java/cc/ryanc/halo/service/impl/PostTagServiceImpl.java @@ -104,7 +104,7 @@ public class PostTagServiceImpl extends AbstractCrudService im } @Override - public List createBy(Integer postId, Set tagIds) { + public List mergeOrCreateByIfAbsent(Integer postId, Set tagIds) { Assert.notNull(postId, "Post id must not be null"); if (CollectionUtils.isEmpty(tagIds)) { @@ -112,18 +112,41 @@ public class PostTagServiceImpl extends AbstractCrudService im } // Create post tags - Set postTags = tagIds.stream().map(tagId -> { + List postTagsStaging = tagIds.stream().map(tagId -> { // Build post tag PostTag postTag = new PostTag(); postTag.setPostId(postId); postTag.setTagId(tagId); return postTag; - }).collect(Collectors.toSet()); + }).collect(Collectors.toList()); - // Get post tag exist and remove them - postTags.removeAll(postTagRepository.findAllByPostId(postId)); + List postTagsToRemove = new LinkedList<>(); + List postTagsToCreate = new LinkedList<>(); - // Create in batch - return createInBatch(postTags); + List postTags = postTagRepository.findAllByPostId(postId); + + postTags.forEach(postTag -> { + if (!postTagsStaging.contains(postTag)) { + postTagsToRemove.add(postTag); + } + }); + + postTagsStaging.forEach(postTagStaging -> { + if (!postTags.contains(postTagStaging)) { + postTagsToCreate.add(postTagStaging); + } + }); + + // Remove post tags + removeAll(postTagsToRemove); + + // Remove all post tags need to remove + postTags.removeAll(postTagsToRemove); + + // Add all created post tags + postTags.addAll(createInBatch(postTagsToCreate)); + + // Return post tags + return postTags; } } diff --git a/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java b/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java index c5f8309af..69ebe91bf 100644 --- a/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java +++ b/src/main/java/cc/ryanc/halo/web/controller/admin/api/PostController.java @@ -7,7 +7,7 @@ import cc.ryanc.halo.model.entity.Post; import cc.ryanc.halo.model.enums.PostStatus; import cc.ryanc.halo.model.enums.PostType; import cc.ryanc.halo.model.params.PostParam; -import cc.ryanc.halo.service.*; +import cc.ryanc.halo.service.PostService; import io.swagger.annotations.ApiOperation; import org.springframework.data.domain.Page; import org.springframework.data.domain.Pageable; @@ -53,7 +53,22 @@ public class PostController { // Convert to Post post = postParam.convertTo(); - return new PostDetailOutputDTO().convertFrom(postService.createBy(post, postParam.getTagIds(), postParam.getCategoryIds())); + Post createdPost = postService.createBy(post, postParam.getTagIds(), postParam.getCategoryIds()); + + return new PostDetailOutputDTO().convertFrom(createdPost); + } + + @PutMapping("{postId:\\d+}") + public PostDetailOutputDTO updateBy(@Valid @RequestBody PostParam postParam, + @PathVariable("postId") Integer postId) { + // Get the post info + Post postToUpdate = postService.getById(postId); + + postParam.update(postToUpdate); + + Post updatedPost = postService.updateBy(postToUpdate, postParam.getTagIds(), postParam.getCategoryIds()); + + return new PostDetailOutputDTO().convertFrom(updatedPost); } }