Complete TagController#createTag api

pull/137/head
johnniang 2019-03-20 23:28:44 +08:00
parent 45661ca36a
commit 72a0e5e255
12 changed files with 216 additions and 8 deletions

View File

@ -49,6 +49,7 @@
<thumbnailator.version>0.4.8</thumbnailator.version>
<commonmark.version>0.12.1</commonmark.version>
<commons-lang3.version>3.8.1</commons-lang3.version>
<slugify.version>2.3</slugify.version>
</properties>
<dependencies>

View File

@ -0,0 +1,16 @@
package cc.ryanc.halo.model.dto;
import lombok.Data;
/**
* Tag with post count output dto.
*
* @author johnniang
* @date 3/20/19
*/
@Data
public class TagWithCountOutputDTO extends TagOutputDTO {
private Long postCount;
}

View File

@ -7,7 +7,6 @@ import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;
import javax.persistence.*;
import java.time.Instant;
/**
* Attachment entity

View File

@ -0,0 +1,36 @@
package cc.ryanc.halo.model.params;
import cc.ryanc.halo.model.dto.base.InputConverter;
import cc.ryanc.halo.model.entity.Tag;
import cc.ryanc.halo.utils.SlugUtils;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
/**
* Tag param.
*
* @author johnniang
* @date 3/20/19
*/
@Data
public class TagParam implements InputConverter<Tag> {
@NotBlank(message = "Tag name must not be blank")
@Size(max = 255, message = "Length of tag name must not be more than {max}")
private String name;
@Size(max = 255, message = "Length of tag slug name must not be more than {max}")
private String slugName;
@Override
public Tag convertTo() {
if (StringUtils.isBlank(slugName)) {
// Handle slug name
slugName = SlugUtils.slugify(name);
}
return InputConverter.super.convertTo();
}
}

View File

@ -62,4 +62,5 @@ public interface PostTagRepository extends BaseRepository<PostTag, Integer> {
*/
@NonNull
List<PostTag> findAllByPostIdIn(@NonNull Iterable<Integer> postIds);
}

View File

@ -2,6 +2,7 @@ package cc.ryanc.halo.repository;
import cc.ryanc.halo.model.entity.Tag;
import cc.ryanc.halo.repository.base.BaseRepository;
import org.springframework.lang.NonNull;
/**
* Tag repository.
@ -10,4 +11,12 @@ import cc.ryanc.halo.repository.base.BaseRepository;
*/
public interface TagRepository extends BaseRepository<Tag, Integer> {
/**
* Count by name or slug name.
*
* @param name tag name must not be null
* @param slugName tag slug name must not be null
* @return tag count
*/
long countByNameOrSlugName(@NonNull String name, @NonNull String slugName);
}

View File

@ -1,9 +1,11 @@
package cc.ryanc.halo.service;
import cc.ryanc.halo.model.dto.TagWithCountOutputDTO;
import cc.ryanc.halo.model.entity.Post;
import cc.ryanc.halo.model.entity.PostTag;
import cc.ryanc.halo.model.entity.Tag;
import cc.ryanc.halo.service.base.CrudService;
import org.springframework.data.domain.Sort;
import org.springframework.lang.NonNull;
import java.util.Collection;
@ -25,10 +27,19 @@ public interface PostTagService extends CrudService<PostTag, Integer> {
* @return a list of tag
*/
@NonNull
List<Tag> listTagBy(@NonNull Integer postId);
List<Tag> listTagsBy(@NonNull Integer postId);
/**
* Lists tag list map by post id.
* List tag with post count output dtos.
*
* @param sort sort info
* @return a list of tag with post count output dto
*/
@NonNull
List<TagWithCountOutputDTO> listTagWithCountDtos(@NonNull Sort sort);
/**
* Lists tags list map by post id.
*
* @param postIds post id collection
* @return tag map (key: postId, value: a list of tags)
@ -37,12 +48,12 @@ public interface PostTagService extends CrudService<PostTag, Integer> {
Map<Integer, List<Tag>> listTagListMapBy(Collection<Integer> postIds);
/**
* Lists post by tag id.
* Lists posts by tag id.
*
* @param tagId tag id must not be null
* @return a list of post
*/
@NonNull
List<Post> listPostBy(@NonNull Integer tagId);
List<Post> listPostsBy(@NonNull Integer tagId);
}

View File

@ -1,5 +1,6 @@
package cc.ryanc.halo.service.impl;
import cc.ryanc.halo.model.dto.TagWithCountOutputDTO;
import cc.ryanc.halo.model.entity.Post;
import cc.ryanc.halo.model.entity.PostTag;
import cc.ryanc.halo.model.entity.Tag;
@ -9,11 +10,13 @@ import cc.ryanc.halo.repository.TagRepository;
import cc.ryanc.halo.service.PostTagService;
import cc.ryanc.halo.service.base.AbstractCrudService;
import cc.ryanc.halo.utils.ServiceUtils;
import org.springframework.data.domain.Sort;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import java.util.*;
import java.util.stream.Collectors;
/**
* Post tag service implementation.
@ -40,7 +43,7 @@ public class PostTagServiceImpl extends AbstractCrudService<PostTag, Integer> im
}
@Override
public List<Tag> listTagBy(Integer postId) {
public List<Tag> listTagsBy(Integer postId) {
Assert.notNull(postId, "Post id must not be null");
// Find all tag ids
@ -49,6 +52,21 @@ public class PostTagServiceImpl extends AbstractCrudService<PostTag, Integer> im
return tagRepository.findAllById(tagIds);
}
@Override
public List<TagWithCountOutputDTO> listTagWithCountDtos(Sort sort) {
Assert.notNull(sort, "Sort info must not be null");
// Find all tags
List<Tag> tags = tagRepository.findAll(sort);
// Find post count
return tags.stream().map(tag -> {
TagWithCountOutputDTO tagOutputDTO = new TagWithCountOutputDTO().convertFrom(tag);
return tagOutputDTO;
}).collect(Collectors.toList());
}
@Override
public Map<Integer, List<Tag>> listTagListMapBy(Collection<Integer> postIds) {
if (CollectionUtils.isEmpty(postIds)) {
@ -78,7 +96,7 @@ public class PostTagServiceImpl extends AbstractCrudService<PostTag, Integer> im
@Override
public List<Post> listPostBy(Integer tagId) {
public List<Post> listPostsBy(Integer tagId) {
Assert.notNull(tagId, "Tag id must not be null");
// Find all post ids

View File

@ -1,9 +1,11 @@
package cc.ryanc.halo.service.impl;
import cc.ryanc.halo.exception.AlreadyExistsException;
import cc.ryanc.halo.model.entity.Tag;
import cc.ryanc.halo.repository.TagRepository;
import cc.ryanc.halo.service.TagService;
import cc.ryanc.halo.service.base.AbstractCrudService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
/**
@ -12,6 +14,7 @@ import org.springframework.stereotype.Service;
* @author : RYAN0UP
* @date : 2019-03-14
*/
@Slf4j
@Service
public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements TagService {
@ -29,6 +32,22 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
*/
@Override
public void remove(Integer id) {
// TODO 删除标签,以及对应的文章关系
// TODO 删除标签,以及对应的文章关系
}
@Override
public Tag create(Tag tag) {
// Check if the tag is exist
long count = tagRepository.countByNameOrSlugName(tag.getName(), tag.getSlugName());
log.debug("Tag count: [{}]", count);
if (count > 0) {
// If the tag has exist already
throw new AlreadyExistsException("The tag has already exist").setErrorData(tag);
}
// Get tag name
return super.create(tag);
}
}

View File

@ -0,0 +1,29 @@
package cc.ryanc.halo.utils;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import java.text.Normalizer;
import java.util.Locale;
import java.util.regex.Pattern;
/**
* Slugify utilities.
*
* @author johnniang
* @date 3/20/19
*/
public class SlugUtils {
private static final Pattern NON_LATIN = Pattern.compile("[^\\w-]");
private static final Pattern WHITESPACE = Pattern.compile("[\\s]");
public static String slugify(@NonNull String input) {
Assert.hasText(input, "Input string must not be blank");
String withoutWhitespace = WHITESPACE.matcher(input).replaceAll("-");
String normalized = Normalizer.normalize(withoutWhitespace, Normalizer.Form.NFKD);
String slug = NON_LATIN.matcher(normalized).replaceAll("");
return slug.toLowerCase(Locale.ENGLISH);
}
}

View File

@ -0,0 +1,48 @@
package cc.ryanc.halo.web.controller.admin.api;
import cc.ryanc.halo.model.dto.TagOutputDTO;
import cc.ryanc.halo.model.entity.Tag;
import cc.ryanc.halo.model.params.TagParam;
import cc.ryanc.halo.service.TagService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;
import java.util.List;
/**
* Tag controller.
*
* @author johnniang
* @date 3/20/19
*/
@Slf4j
@RestController
@RequestMapping("/admin/api/tags")
public class TagController {
private final TagService tagService;
public TagController(TagService tagService) {
this.tagService = tagService;
}
@GetMapping
public List<TagOutputDTO> listTags(@SortDefault(sort = "updateTime", direction = Sort.Direction.DESC) Sort sort) {
return null;
}
@PostMapping
public TagOutputDTO createTag(@Valid @RequestBody TagParam tagParam) {
// Convert to tag
Tag tag = tagParam.convertTo();
log.debug("Tag to be created: [{}]", tag);
// Create and convert
return new TagOutputDTO().convertFrom(tagService.create(tag));
}
}

View File

@ -0,0 +1,21 @@
package cc.ryanc.halo.utils;
import org.junit.Assert;
import org.junit.Test;
import static org.hamcrest.Matchers.equalTo;
import static org.junit.Assert.*;
/**
* @author johnniang
* @date 3/20/19
*/
public class SlugUtilsTest {
@Test
public void makeSlugTest() {
String slugResult = SlugUtils.slugify("Hello World");
Assert.assertThat(slugResult, equalTo("hello-world"));
}
}