mirror of https://github.com/halo-dev/halo
Complete TagController#createTag api
parent
45661ca36a
commit
72a0e5e255
1
pom.xml
1
pom.xml
|
@ -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>
|
||||
|
|
|
@ -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;
|
||||
|
||||
}
|
|
@ -7,7 +7,6 @@ import org.hibernate.annotations.SQLDelete;
|
|||
import org.hibernate.annotations.Where;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.time.Instant;
|
||||
|
||||
/**
|
||||
* Attachment entity
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -62,4 +62,5 @@ public interface PostTagRepository extends BaseRepository<PostTag, Integer> {
|
|||
*/
|
||||
@NonNull
|
||||
List<PostTag> findAllByPostIdIn(@NonNull Iterable<Integer> postIds);
|
||||
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 {
|
||||
|
||||
|
@ -31,4 +34,20 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
|
|||
public void remove(Integer id) {
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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"));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue