refactor: move logic to application level
This commit is contained in:
parent
49cac729f1
commit
36e33e7730
7
src/main/java/io/spring/Util.java
Normal file
7
src/main/java/io/spring/Util.java
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
package io.spring;
|
||||||
|
|
||||||
|
public class Util {
|
||||||
|
public static boolean isEmpty(String value) {
|
||||||
|
return value == null || value.isEmpty();
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,17 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
|
||||||
import io.spring.api.exception.NoAuthorizationException;
|
import io.spring.api.exception.NoAuthorizationException;
|
||||||
import io.spring.api.exception.ResourceNotFoundException;
|
import io.spring.api.exception.ResourceNotFoundException;
|
||||||
import io.spring.core.service.AuthorizationService;
|
|
||||||
import io.spring.application.data.ArticleData;
|
|
||||||
import io.spring.application.ArticleQueryService;
|
import io.spring.application.ArticleQueryService;
|
||||||
|
import io.spring.application.article.ArticleCommandService;
|
||||||
|
import io.spring.application.article.UpdateArticleParam;
|
||||||
|
import io.spring.application.data.ArticleData;
|
||||||
import io.spring.core.article.ArticleRepository;
|
import io.spring.core.article.ArticleRepository;
|
||||||
|
import io.spring.core.service.AuthorizationService;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
import lombok.Getter;
|
import java.util.HashMap;
|
||||||
import lombok.NoArgsConstructor;
|
import java.util.Map;
|
||||||
|
import javax.validation.Valid;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
@ -21,71 +23,72 @@ import org.springframework.web.bind.annotation.RequestBody;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import javax.validation.Valid;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(path = "/articles/{slug}")
|
@RequestMapping(path = "/articles/{slug}")
|
||||||
public class ArticleApi {
|
public class ArticleApi {
|
||||||
private ArticleQueryService articleQueryService;
|
private ArticleQueryService articleQueryService;
|
||||||
private ArticleRepository articleRepository;
|
private ArticleRepository articleRepository;
|
||||||
|
private ArticleCommandService articleCommandService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ArticleApi(ArticleQueryService articleQueryService, ArticleRepository articleRepository) {
|
public ArticleApi(
|
||||||
this.articleQueryService = articleQueryService;
|
ArticleQueryService articleQueryService,
|
||||||
this.articleRepository = articleRepository;
|
ArticleRepository articleRepository,
|
||||||
}
|
ArticleCommandService articleCommandService) {
|
||||||
|
this.articleQueryService = articleQueryService;
|
||||||
|
this.articleRepository = articleRepository;
|
||||||
|
this.articleCommandService = articleCommandService;
|
||||||
|
}
|
||||||
|
|
||||||
@GetMapping
|
@GetMapping
|
||||||
public ResponseEntity<?> article(@PathVariable("slug") String slug,
|
public ResponseEntity<?> article(
|
||||||
@AuthenticationPrincipal User user) {
|
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||||
return articleQueryService.findBySlug(slug, user)
|
return articleQueryService
|
||||||
.map(articleData -> ResponseEntity.ok(articleResponse(articleData)))
|
.findBySlug(slug, user)
|
||||||
.orElseThrow(ResourceNotFoundException::new);
|
.map(articleData -> ResponseEntity.ok(articleResponse(articleData)))
|
||||||
}
|
.orElseThrow(ResourceNotFoundException::new);
|
||||||
|
}
|
||||||
|
|
||||||
@PutMapping
|
@PutMapping
|
||||||
public ResponseEntity<?> updateArticle(@PathVariable("slug") String slug,
|
public ResponseEntity<?> updateArticle(
|
||||||
@AuthenticationPrincipal User user,
|
@PathVariable("slug") String slug,
|
||||||
@Valid @RequestBody UpdateArticleParam updateArticleParam) {
|
@AuthenticationPrincipal User user,
|
||||||
return articleRepository.findBySlug(slug).map(article -> {
|
@Valid @RequestBody UpdateArticleParam updateArticleParam) {
|
||||||
if (!AuthorizationService.canWriteArticle(user, article)) {
|
return articleRepository
|
||||||
|
.findBySlug(slug)
|
||||||
|
.map(
|
||||||
|
article -> {
|
||||||
|
if (!AuthorizationService.canWriteArticle(user, article)) {
|
||||||
throw new NoAuthorizationException();
|
throw new NoAuthorizationException();
|
||||||
}
|
}
|
||||||
article.update(
|
articleCommandService.updateArticle(article, updateArticleParam);
|
||||||
updateArticleParam.getTitle(),
|
return ResponseEntity.ok(
|
||||||
updateArticleParam.getDescription(),
|
articleResponse(articleQueryService.findBySlug(slug, user).get()));
|
||||||
updateArticleParam.getBody());
|
})
|
||||||
articleRepository.save(article);
|
.orElseThrow(ResourceNotFoundException::new);
|
||||||
return ResponseEntity.ok(articleResponse(articleQueryService.findBySlug(slug, user).get()));
|
}
|
||||||
}).orElseThrow(ResourceNotFoundException::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
@DeleteMapping
|
@DeleteMapping
|
||||||
public ResponseEntity deleteArticle(@PathVariable("slug") String slug,
|
public ResponseEntity deleteArticle(
|
||||||
@AuthenticationPrincipal User user) {
|
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||||
return articleRepository.findBySlug(slug).map(article -> {
|
return articleRepository
|
||||||
if (!AuthorizationService.canWriteArticle(user, article)) {
|
.findBySlug(slug)
|
||||||
|
.map(
|
||||||
|
article -> {
|
||||||
|
if (!AuthorizationService.canWriteArticle(user, article)) {
|
||||||
throw new NoAuthorizationException();
|
throw new NoAuthorizationException();
|
||||||
}
|
}
|
||||||
articleRepository.remove(article);
|
articleRepository.remove(article);
|
||||||
return ResponseEntity.noContent().build();
|
return ResponseEntity.noContent().build();
|
||||||
}).orElseThrow(ResourceNotFoundException::new);
|
})
|
||||||
}
|
.orElseThrow(ResourceNotFoundException::new);
|
||||||
|
}
|
||||||
|
|
||||||
private Map<String, Object> articleResponse(ArticleData articleData) {
|
private Map<String, Object> articleResponse(ArticleData articleData) {
|
||||||
return new HashMap<String, Object>() {{
|
return new HashMap<String, Object>() {
|
||||||
put("article", articleData);
|
{
|
||||||
}};
|
put("article", articleData);
|
||||||
}
|
}
|
||||||
}
|
};
|
||||||
|
}
|
||||||
@Getter
|
|
||||||
@NoArgsConstructor
|
|
||||||
@JsonRootName("article")
|
|
||||||
class UpdateArticleParam {
|
|
||||||
private String title = "";
|
|
||||||
private String body = "";
|
|
||||||
private String description = "";
|
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
import io.spring.api.exception.ResourceNotFoundException;
|
import io.spring.api.exception.ResourceNotFoundException;
|
||||||
import io.spring.application.data.ArticleData;
|
|
||||||
import io.spring.application.ArticleQueryService;
|
import io.spring.application.ArticleQueryService;
|
||||||
|
import io.spring.application.data.ArticleData;
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
import io.spring.core.article.ArticleRepository;
|
import io.spring.core.article.ArticleRepository;
|
||||||
import io.spring.core.favorite.ArticleFavorite;
|
import io.spring.core.favorite.ArticleFavorite;
|
||||||
import io.spring.core.favorite.ArticleFavoriteRepository;
|
import io.spring.core.favorite.ArticleFavoriteRepository;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
|
import java.util.HashMap;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
@ -17,51 +18,54 @@ import org.springframework.web.bind.annotation.PostMapping;
|
|||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
import org.springframework.web.bind.annotation.RestController;
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(path = "articles/{slug}/favorite")
|
@RequestMapping(path = "articles/{slug}/favorite")
|
||||||
public class ArticleFavoriteApi {
|
public class ArticleFavoriteApi {
|
||||||
private ArticleFavoriteRepository articleFavoriteRepository;
|
private ArticleFavoriteRepository articleFavoriteRepository;
|
||||||
private ArticleRepository articleRepository;
|
private ArticleRepository articleRepository;
|
||||||
private ArticleQueryService articleQueryService;
|
private ArticleQueryService articleQueryService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ArticleFavoriteApi(ArticleFavoriteRepository articleFavoriteRepository,
|
public ArticleFavoriteApi(
|
||||||
ArticleRepository articleRepository,
|
ArticleFavoriteRepository articleFavoriteRepository,
|
||||||
ArticleQueryService articleQueryService) {
|
ArticleRepository articleRepository,
|
||||||
this.articleFavoriteRepository = articleFavoriteRepository;
|
ArticleQueryService articleQueryService) {
|
||||||
this.articleRepository = articleRepository;
|
this.articleFavoriteRepository = articleFavoriteRepository;
|
||||||
this.articleQueryService = articleQueryService;
|
this.articleRepository = articleRepository;
|
||||||
}
|
this.articleQueryService = articleQueryService;
|
||||||
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity favoriteArticle(@PathVariable("slug") String slug,
|
public ResponseEntity favoriteArticle(
|
||||||
@AuthenticationPrincipal User user) {
|
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||||
Article article = getArticle(slug);
|
Article article =
|
||||||
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), user.getId());
|
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||||
articleFavoriteRepository.save(articleFavorite);
|
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), user.getId());
|
||||||
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
articleFavoriteRepository.save(articleFavorite);
|
||||||
}
|
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
||||||
|
}
|
||||||
|
|
||||||
@DeleteMapping
|
@DeleteMapping
|
||||||
public ResponseEntity unfavoriteArticle(@PathVariable("slug") String slug,
|
public ResponseEntity unfavoriteArticle(
|
||||||
@AuthenticationPrincipal User user) {
|
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||||
Article article = getArticle(slug);
|
Article article =
|
||||||
articleFavoriteRepository.find(article.getId(), user.getId()).ifPresent(favorite -> {
|
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||||
articleFavoriteRepository.remove(favorite);
|
articleFavoriteRepository
|
||||||
});
|
.find(article.getId(), user.getId())
|
||||||
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
.ifPresent(
|
||||||
}
|
favorite -> {
|
||||||
|
articleFavoriteRepository.remove(favorite);
|
||||||
|
});
|
||||||
|
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
||||||
|
}
|
||||||
|
|
||||||
private ResponseEntity<HashMap<String, Object>> responseArticleData(final ArticleData articleData) {
|
private ResponseEntity<HashMap<String, Object>> responseArticleData(
|
||||||
return ResponseEntity.ok(new HashMap<String, Object>() {{
|
final ArticleData articleData) {
|
||||||
|
return ResponseEntity.ok(
|
||||||
|
new HashMap<String, Object>() {
|
||||||
|
{
|
||||||
put("article", articleData);
|
put("article", articleData);
|
||||||
}});
|
}
|
||||||
}
|
});
|
||||||
|
}
|
||||||
private Article getArticle(String slug) {
|
|
||||||
return articleRepository.findBySlug(slug).map(article -> article)
|
|
||||||
.orElseThrow(ResourceNotFoundException::new);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -1,25 +1,13 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
|
||||||
import io.spring.application.ArticleQueryService;
|
import io.spring.application.ArticleQueryService;
|
||||||
import io.spring.application.Page;
|
import io.spring.application.Page;
|
||||||
|
import io.spring.application.article.ArticleCommandService;
|
||||||
|
import io.spring.application.article.NewArticleParam;
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
import io.spring.core.article.ArticleRepository;
|
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
import java.lang.annotation.Documented;
|
|
||||||
import java.lang.annotation.ElementType;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.lang.annotation.Target;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import javax.validation.Constraint;
|
|
||||||
import javax.validation.ConstraintValidator;
|
|
||||||
import javax.validation.ConstraintValidatorContext;
|
|
||||||
import javax.validation.Payload;
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.NotBlank;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
@ -33,26 +21,20 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
@RestController
|
@RestController
|
||||||
@RequestMapping(path = "/articles")
|
@RequestMapping(path = "/articles")
|
||||||
public class ArticlesApi {
|
public class ArticlesApi {
|
||||||
private ArticleRepository articleRepository;
|
private ArticleCommandService articleCommandService;
|
||||||
private ArticleQueryService articleQueryService;
|
private ArticleQueryService articleQueryService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ArticlesApi(ArticleRepository articleRepository, ArticleQueryService articleQueryService) {
|
public ArticlesApi(
|
||||||
this.articleRepository = articleRepository;
|
ArticleCommandService articleCommandService, ArticleQueryService articleQueryService) {
|
||||||
|
this.articleCommandService = articleCommandService;
|
||||||
this.articleQueryService = articleQueryService;
|
this.articleQueryService = articleQueryService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@PostMapping
|
@PostMapping
|
||||||
public ResponseEntity createArticle(
|
public ResponseEntity createArticle(
|
||||||
@Valid @RequestBody NewArticleParam newArticleParam, @AuthenticationPrincipal User user) {
|
@Valid @RequestBody NewArticleParam newArticleParam, @AuthenticationPrincipal User user) {
|
||||||
Article article =
|
Article article = articleCommandService.createArticle(newArticleParam, user);
|
||||||
new Article(
|
|
||||||
newArticleParam.getTitle(),
|
|
||||||
newArticleParam.getDescription(),
|
|
||||||
newArticleParam.getBody(),
|
|
||||||
newArticleParam.getTagList(),
|
|
||||||
user.getId());
|
|
||||||
articleRepository.save(article);
|
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
new HashMap<String, Object>() {
|
new HashMap<String, Object>() {
|
||||||
{
|
{
|
||||||
@ -82,43 +64,3 @@ public class ArticlesApi {
|
|||||||
tag, author, favoritedBy, new Page(offset, limit), user));
|
tag, author, favoritedBy, new Page(offset, limit), user));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
|
||||||
@JsonRootName("article")
|
|
||||||
@NoArgsConstructor
|
|
||||||
class NewArticleParam {
|
|
||||||
@NotBlank(message = "can't be empty")
|
|
||||||
@DuplicatedArticleConstraint
|
|
||||||
private String title;
|
|
||||||
|
|
||||||
@NotBlank(message = "can't be empty")
|
|
||||||
private String description;
|
|
||||||
|
|
||||||
@NotBlank(message = "can't be empty")
|
|
||||||
private String body;
|
|
||||||
|
|
||||||
private String[] tagList;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Documented
|
|
||||||
@Constraint(validatedBy = DuplicatedArticleValidator.class)
|
|
||||||
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE})
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@interface DuplicatedArticleConstraint {
|
|
||||||
String message() default "article name exists";
|
|
||||||
|
|
||||||
Class<?>[] groups() default {};
|
|
||||||
|
|
||||||
Class<? extends Payload>[] payload() default {};
|
|
||||||
}
|
|
||||||
|
|
||||||
class DuplicatedArticleValidator
|
|
||||||
implements ConstraintValidator<DuplicatedArticleConstraint, String> {
|
|
||||||
|
|
||||||
@Autowired private ArticleQueryService articleQueryService;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
|
||||||
return !articleQueryService.findBySlug(Article.toSlug(value), null).isPresent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -51,7 +51,8 @@ public class CommentsApi {
|
|||||||
@PathVariable("slug") String slug,
|
@PathVariable("slug") String slug,
|
||||||
@AuthenticationPrincipal User user,
|
@AuthenticationPrincipal User user,
|
||||||
@Valid @RequestBody NewCommentParam newCommentParam) {
|
@Valid @RequestBody NewCommentParam newCommentParam) {
|
||||||
Article article = findArticle(slug);
|
Article article =
|
||||||
|
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||||
Comment comment = new Comment(newCommentParam.getBody(), user.getId(), article.getId());
|
Comment comment = new Comment(newCommentParam.getBody(), user.getId(), article.getId());
|
||||||
commentRepository.save(comment);
|
commentRepository.save(comment);
|
||||||
return ResponseEntity.status(201)
|
return ResponseEntity.status(201)
|
||||||
@ -61,7 +62,8 @@ public class CommentsApi {
|
|||||||
@GetMapping
|
@GetMapping
|
||||||
public ResponseEntity getComments(
|
public ResponseEntity getComments(
|
||||||
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||||
Article article = findArticle(slug);
|
Article article =
|
||||||
|
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||||
List<CommentData> comments = commentQueryService.findByArticleId(article.getId(), user);
|
List<CommentData> comments = commentQueryService.findByArticleId(article.getId(), user);
|
||||||
return ResponseEntity.ok(
|
return ResponseEntity.ok(
|
||||||
new HashMap<String, Object>() {
|
new HashMap<String, Object>() {
|
||||||
@ -76,7 +78,8 @@ public class CommentsApi {
|
|||||||
@PathVariable("slug") String slug,
|
@PathVariable("slug") String slug,
|
||||||
@PathVariable("id") String commentId,
|
@PathVariable("id") String commentId,
|
||||||
@AuthenticationPrincipal User user) {
|
@AuthenticationPrincipal User user) {
|
||||||
Article article = findArticle(slug);
|
Article article =
|
||||||
|
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||||
return commentRepository
|
return commentRepository
|
||||||
.findById(article.getId(), commentId)
|
.findById(article.getId(), commentId)
|
||||||
.map(
|
.map(
|
||||||
@ -90,13 +93,6 @@ public class CommentsApi {
|
|||||||
.orElseThrow(ResourceNotFoundException::new);
|
.orElseThrow(ResourceNotFoundException::new);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Article findArticle(String slug) {
|
|
||||||
return articleRepository
|
|
||||||
.findBySlug(slug)
|
|
||||||
.map(article -> article)
|
|
||||||
.orElseThrow(ResourceNotFoundException::new);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Map<String, Object> commentResponse(CommentData commentData) {
|
private Map<String, Object> commentResponse(CommentData commentData) {
|
||||||
return new HashMap<String, Object>() {
|
return new HashMap<String, Object>() {
|
||||||
{
|
{
|
||||||
|
@ -1,28 +1,18 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
|
||||||
import io.spring.application.UserQueryService;
|
import io.spring.application.UserQueryService;
|
||||||
import io.spring.application.data.UserData;
|
import io.spring.application.data.UserData;
|
||||||
import io.spring.application.data.UserWithToken;
|
import io.spring.application.data.UserWithToken;
|
||||||
|
import io.spring.application.user.UpdateUserCommand;
|
||||||
|
import io.spring.application.user.UpdateUserParam;
|
||||||
|
import io.spring.application.user.UserService;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
import io.spring.core.user.UserRepository;
|
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.validation.Constraint;
|
|
||||||
import javax.validation.ConstraintValidator;
|
|
||||||
import javax.validation.ConstraintValidatorContext;
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.Email;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Getter;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
import org.springframework.validation.annotation.Validated;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.PutMapping;
|
import org.springframework.web.bind.annotation.PutMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
@ -71,99 +61,3 @@ public class CurrentUserApi {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Validated
|
|
||||||
@Service
|
|
||||||
class UserService {
|
|
||||||
|
|
||||||
private UserRepository userRepository;
|
|
||||||
|
|
||||||
@Autowired
|
|
||||||
public UserService(UserRepository userRepository) {
|
|
||||||
this.userRepository = userRepository;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateUser(@Valid UpdateUserCommand command) {
|
|
||||||
User user = command.getTargetUser();
|
|
||||||
UpdateUserParam updateUserParam = command.getParam();
|
|
||||||
user.update(
|
|
||||||
updateUserParam.getEmail(),
|
|
||||||
updateUserParam.getUsername(),
|
|
||||||
updateUserParam.getPassword(),
|
|
||||||
updateUserParam.getBio(),
|
|
||||||
updateUserParam.getImage());
|
|
||||||
userRepository.save(user);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@AllArgsConstructor
|
|
||||||
@UpdateUserConstraint
|
|
||||||
class UpdateUserCommand {
|
|
||||||
|
|
||||||
private User targetUser;
|
|
||||||
private UpdateUserParam param;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Constraint(validatedBy = UpdateUserValidator.class)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@interface UpdateUserConstraint {
|
|
||||||
|
|
||||||
String message() default "invalid update param";
|
|
||||||
|
|
||||||
Class[] groups() default {};
|
|
||||||
|
|
||||||
Class[] payload() default {};
|
|
||||||
}
|
|
||||||
|
|
||||||
class UpdateUserValidator implements ConstraintValidator<UpdateUserConstraint, UpdateUserCommand> {
|
|
||||||
|
|
||||||
@Autowired private UserRepository userRepository;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(UpdateUserCommand value, ConstraintValidatorContext context) {
|
|
||||||
String inputEmail = value.getParam().getEmail();
|
|
||||||
String inputUsername = value.getParam().getUsername();
|
|
||||||
final User targetUser = value.getTargetUser();
|
|
||||||
|
|
||||||
boolean isEmailValid =
|
|
||||||
userRepository.findByEmail(inputEmail).map(user -> user.equals(targetUser)).orElse(true);
|
|
||||||
boolean isUsernameValid =
|
|
||||||
userRepository
|
|
||||||
.findByUsername(inputUsername)
|
|
||||||
.map(user -> user.equals(targetUser))
|
|
||||||
.orElse(true);
|
|
||||||
if (isEmailValid && isUsernameValid) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
context.disableDefaultConstraintViolation();
|
|
||||||
if (!isEmailValid) {
|
|
||||||
context
|
|
||||||
.buildConstraintViolationWithTemplate("email already exist")
|
|
||||||
.addPropertyNode("email")
|
|
||||||
.addConstraintViolation();
|
|
||||||
}
|
|
||||||
if (!isUsernameValid) {
|
|
||||||
context
|
|
||||||
.buildConstraintViolationWithTemplate("username already exist")
|
|
||||||
.addPropertyNode("username")
|
|
||||||
.addConstraintViolation();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
|
||||||
@JsonRootName("user")
|
|
||||||
@NoArgsConstructor
|
|
||||||
class UpdateUserParam {
|
|
||||||
|
|
||||||
@Email(message = "should be an email")
|
|
||||||
private String email = "";
|
|
||||||
|
|
||||||
private String password = "";
|
|
||||||
private String username = "";
|
|
||||||
private String bio = "";
|
|
||||||
private String image = "";
|
|
||||||
}
|
|
||||||
|
@ -7,26 +7,21 @@ import io.spring.api.exception.InvalidAuthenticationException;
|
|||||||
import io.spring.application.UserQueryService;
|
import io.spring.application.UserQueryService;
|
||||||
import io.spring.application.data.UserData;
|
import io.spring.application.data.UserData;
|
||||||
import io.spring.application.data.UserWithToken;
|
import io.spring.application.data.UserWithToken;
|
||||||
|
import io.spring.application.user.RegisterParam;
|
||||||
|
import io.spring.application.user.UserService;
|
||||||
import io.spring.core.service.JwtService;
|
import io.spring.core.service.JwtService;
|
||||||
import io.spring.core.user.EncryptService;
|
import io.spring.core.user.EncryptService;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
import io.spring.core.user.UserRepository;
|
import io.spring.core.user.UserRepository;
|
||||||
import java.lang.annotation.Retention;
|
|
||||||
import java.lang.annotation.RetentionPolicy;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.validation.Constraint;
|
|
||||||
import javax.validation.ConstraintValidator;
|
|
||||||
import javax.validation.ConstraintValidatorContext;
|
|
||||||
import javax.validation.Payload;
|
|
||||||
import javax.validation.Valid;
|
import javax.validation.Valid;
|
||||||
import javax.validation.constraints.Email;
|
import javax.validation.constraints.Email;
|
||||||
import javax.validation.constraints.NotBlank;
|
import javax.validation.constraints.NotBlank;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.RequestBody;
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@ -36,34 +31,27 @@ import org.springframework.web.bind.annotation.RestController;
|
|||||||
public class UsersApi {
|
public class UsersApi {
|
||||||
private UserRepository userRepository;
|
private UserRepository userRepository;
|
||||||
private UserQueryService userQueryService;
|
private UserQueryService userQueryService;
|
||||||
private String defaultImage;
|
|
||||||
private EncryptService encryptService;
|
private EncryptService encryptService;
|
||||||
private JwtService jwtService;
|
private JwtService jwtService;
|
||||||
|
private UserService userService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public UsersApi(
|
public UsersApi(
|
||||||
UserRepository userRepository,
|
UserRepository userRepository,
|
||||||
UserQueryService userQueryService,
|
UserQueryService userQueryService,
|
||||||
EncryptService encryptService,
|
EncryptService encryptService,
|
||||||
@Value("${image.default}") String defaultImage,
|
JwtService jwtService,
|
||||||
JwtService jwtService) {
|
UserService userService) {
|
||||||
this.userRepository = userRepository;
|
this.userRepository = userRepository;
|
||||||
this.userQueryService = userQueryService;
|
this.userQueryService = userQueryService;
|
||||||
this.encryptService = encryptService;
|
this.encryptService = encryptService;
|
||||||
this.defaultImage = defaultImage;
|
|
||||||
this.jwtService = jwtService;
|
this.jwtService = jwtService;
|
||||||
|
this.userService = userService;
|
||||||
}
|
}
|
||||||
|
|
||||||
@RequestMapping(path = "/users", method = POST)
|
@RequestMapping(path = "/users", method = POST)
|
||||||
public ResponseEntity createUser(@Valid @RequestBody RegisterParam registerParam) {
|
public ResponseEntity createUser(@Valid @RequestBody RegisterParam registerParam) {
|
||||||
User user =
|
User user = userService.createUser(registerParam);
|
||||||
new User(
|
|
||||||
registerParam.getEmail(),
|
|
||||||
registerParam.getUsername(),
|
|
||||||
encryptService.encrypt(registerParam.getPassword()),
|
|
||||||
"",
|
|
||||||
defaultImage);
|
|
||||||
userRepository.save(user);
|
|
||||||
UserData userData = userQueryService.findById(user.getId()).get();
|
UserData userData = userQueryService.findById(user.getId()).get();
|
||||||
return ResponseEntity.status(201)
|
return ResponseEntity.status(201)
|
||||||
.body(userResponse(new UserWithToken(userData, jwtService.toToken(user))));
|
.body(userResponse(new UserWithToken(userData, jwtService.toToken(user))));
|
||||||
@ -91,47 +79,6 @@ public class UsersApi {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Constraint(validatedBy = DuplicatedEmailValidator.class)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@interface DuplicatedEmailConstraint {
|
|
||||||
String message() default "duplicated email";
|
|
||||||
|
|
||||||
Class<?>[] groups() default {};
|
|
||||||
|
|
||||||
Class<? extends Payload>[] payload() default {};
|
|
||||||
}
|
|
||||||
|
|
||||||
class DuplicatedEmailValidator implements ConstraintValidator<DuplicatedEmailConstraint, String> {
|
|
||||||
|
|
||||||
@Autowired private UserRepository userRepository;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
|
||||||
return (value == null || value.isEmpty()) || !userRepository.findByEmail(value).isPresent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Constraint(validatedBy = DuplicatedUsernameValidator.class)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
@interface DuplicatedUsernameConstraint {
|
|
||||||
String message() default "duplicated username";
|
|
||||||
|
|
||||||
Class<?>[] groups() default {};
|
|
||||||
|
|
||||||
Class<? extends Payload>[] payload() default {};
|
|
||||||
}
|
|
||||||
|
|
||||||
class DuplicatedUsernameValidator
|
|
||||||
implements ConstraintValidator<DuplicatedUsernameConstraint, String> {
|
|
||||||
|
|
||||||
@Autowired private UserRepository userRepository;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isValid(String value, ConstraintValidatorContext context) {
|
|
||||||
return (value == null || value.isEmpty()) || !userRepository.findByUsername(value).isPresent();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@JsonRootName("user")
|
@JsonRootName("user")
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@ -143,20 +90,3 @@ class LoginParam {
|
|||||||
@NotBlank(message = "can't be empty")
|
@NotBlank(message = "can't be empty")
|
||||||
private String password;
|
private String password;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Getter
|
|
||||||
@JsonRootName("user")
|
|
||||||
@NoArgsConstructor
|
|
||||||
class RegisterParam {
|
|
||||||
@NotBlank(message = "can't be empty")
|
|
||||||
@Email(message = "should be an email")
|
|
||||||
@DuplicatedEmailConstraint
|
|
||||||
private String email;
|
|
||||||
|
|
||||||
@NotBlank(message = "can't be empty")
|
|
||||||
@DuplicatedUsernameConstraint
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
@NotBlank(message = "can't be empty")
|
|
||||||
private String password;
|
|
||||||
}
|
|
||||||
|
@ -1,14 +0,0 @@
|
|||||||
package io.spring.api.security;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.servlet.config.annotation.CorsRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class CORSConfig implements WebMvcConfigurer {
|
|
||||||
@Override
|
|
||||||
public void addCorsMappings(CorsRegistry registry) {
|
|
||||||
registry.addMapping("/**")
|
|
||||||
.allowedMethods("HEAD", "GET", "PUT", "POST", "DELETE", "PATCH");
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,5 +1,7 @@
|
|||||||
package io.spring.api.security;
|
package io.spring.api.security;
|
||||||
|
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@ -15,8 +17,6 @@ import org.springframework.web.cors.CorsConfiguration;
|
|||||||
import org.springframework.web.cors.CorsConfigurationSource;
|
import org.springframework.web.cors.CorsConfigurationSource;
|
||||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||||
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||||
@ -32,11 +32,12 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
@Override
|
@Override
|
||||||
protected void configure(HttpSecurity http) throws Exception {
|
protected void configure(HttpSecurity http) throws Exception {
|
||||||
|
|
||||||
if (h2ConsoleEnabled)
|
if (h2ConsoleEnabled) {
|
||||||
http.authorizeRequests()
|
http.authorizeRequests()
|
||||||
.antMatchers("/h2-console", "/h2-console/**").permitAll()
|
.antMatchers("/h2-console", "/h2-console/**").permitAll()
|
||||||
.and()
|
.and()
|
||||||
.headers().frameOptions().sameOrigin();
|
.headers().frameOptions().sameOrigin();
|
||||||
|
}
|
||||||
|
|
||||||
http.csrf().disable()
|
http.csrf().disable()
|
||||||
.cors()
|
.cors()
|
||||||
@ -46,6 +47,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||||
.authorizeRequests()
|
.authorizeRequests()
|
||||||
.antMatchers(HttpMethod.OPTIONS).permitAll()
|
.antMatchers(HttpMethod.OPTIONS).permitAll()
|
||||||
|
.antMatchers("/graphiql").permitAll()
|
||||||
|
.antMatchers("/graphql").permitAll()
|
||||||
.antMatchers(HttpMethod.GET, "/articles/feed").authenticated()
|
.antMatchers(HttpMethod.GET, "/articles/feed").authenticated()
|
||||||
.antMatchers(HttpMethod.POST, "/users", "/users/login").permitAll()
|
.antMatchers(HttpMethod.POST, "/users", "/users/login").permitAll()
|
||||||
.antMatchers(HttpMethod.GET, "/articles/**", "/profiles/**", "/tags").permitAll()
|
.antMatchers(HttpMethod.GET, "/articles/**", "/profiles/**", "/tags").permitAll()
|
||||||
@ -62,7 +65,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
"GET", "POST", "PUT", "DELETE", "PATCH"));
|
"GET", "POST", "PUT", "DELETE", "PATCH"));
|
||||||
// setAllowCredentials(true) is important, otherwise:
|
// setAllowCredentials(true) is important, otherwise:
|
||||||
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
|
// The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'.
|
||||||
configuration.setAllowCredentials(true);
|
configuration.setAllowCredentials(false);
|
||||||
// setAllowedHeaders is important! Without it, OPTIONS preflight request
|
// setAllowedHeaders is important! Without it, OPTIONS preflight request
|
||||||
// will fail with 403 Invalid CORS request
|
// will fail with 403 Invalid CORS request
|
||||||
configuration.setAllowedHeaders(asList("Authorization", "Cache-Control", "Content-Type"));
|
configuration.setAllowedHeaders(asList("Authorization", "Cache-Control", "Content-Type"));
|
||||||
|
@ -2,37 +2,40 @@ package io.spring.application;
|
|||||||
|
|
||||||
import io.spring.application.data.ProfileData;
|
import io.spring.application.data.ProfileData;
|
||||||
import io.spring.application.data.UserData;
|
import io.spring.application.data.UserData;
|
||||||
import io.spring.infrastructure.mybatis.readservice.UserReadService;
|
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
|
import io.spring.infrastructure.mybatis.readservice.UserReadService;
|
||||||
import io.spring.infrastructure.mybatis.readservice.UserRelationshipQueryService;
|
import io.spring.infrastructure.mybatis.readservice.UserRelationshipQueryService;
|
||||||
|
import java.util.Optional;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class ProfileQueryService {
|
public class ProfileQueryService {
|
||||||
private UserReadService userReadService;
|
private UserReadService userReadService;
|
||||||
private UserRelationshipQueryService userRelationshipQueryService;
|
private UserRelationshipQueryService userRelationshipQueryService;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
public ProfileQueryService(UserReadService userReadService, UserRelationshipQueryService userRelationshipQueryService) {
|
public ProfileQueryService(
|
||||||
this.userReadService = userReadService;
|
UserReadService userReadService, UserRelationshipQueryService userRelationshipQueryService) {
|
||||||
this.userRelationshipQueryService = userRelationshipQueryService;
|
this.userReadService = userReadService;
|
||||||
}
|
this.userRelationshipQueryService = userRelationshipQueryService;
|
||||||
|
}
|
||||||
|
|
||||||
public Optional<ProfileData> findByUsername(String username, User currentUser) {
|
public Optional<ProfileData> findByUsername(String username, User currentUser) {
|
||||||
UserData userData = userReadService.findByUsername(username);
|
UserData userData = userReadService.findByUsername(username);
|
||||||
if (userData == null) {
|
if (userData == null) {
|
||||||
return Optional.empty();
|
return Optional.empty();
|
||||||
} else {
|
} else {
|
||||||
ProfileData profileData = new ProfileData(
|
ProfileData profileData =
|
||||||
userData.getId(),
|
new ProfileData(
|
||||||
userData.getUsername(),
|
userData.getId(),
|
||||||
userData.getBio(),
|
userData.getUsername(),
|
||||||
userData.getImage(),
|
userData.getBio(),
|
||||||
userRelationshipQueryService.isUserFollowing(currentUser.getId(), userData.getId()));
|
userData.getImage(),
|
||||||
return Optional.of(profileData);
|
currentUser != null
|
||||||
}
|
&& userRelationshipQueryService.isUserFollowing(
|
||||||
|
currentUser.getId(), userData.getId()));
|
||||||
|
return Optional.of(profileData);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,42 @@
|
|||||||
|
package io.spring.application.article;
|
||||||
|
|
||||||
|
import io.spring.core.article.Article;
|
||||||
|
import io.spring.core.article.ArticleRepository;
|
||||||
|
import io.spring.core.user.User;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class ArticleCommandService {
|
||||||
|
|
||||||
|
private ArticleRepository articleRepository;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public ArticleCommandService(ArticleRepository articleRepository) {
|
||||||
|
this.articleRepository = articleRepository;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Article createArticle(@Valid NewArticleParam newArticleParam, User creator) {
|
||||||
|
Article article =
|
||||||
|
new Article(
|
||||||
|
newArticleParam.getTitle(),
|
||||||
|
newArticleParam.getDescription(),
|
||||||
|
newArticleParam.getBody(),
|
||||||
|
newArticleParam.getTagList(),
|
||||||
|
creator.getId());
|
||||||
|
articleRepository.save(article);
|
||||||
|
return article;
|
||||||
|
}
|
||||||
|
|
||||||
|
public Article updateArticle(Article article, @Valid UpdateArticleParam updateArticleParam) {
|
||||||
|
article.update(
|
||||||
|
updateArticleParam.getTitle(),
|
||||||
|
updateArticleParam.getDescription(),
|
||||||
|
updateArticleParam.getBody());
|
||||||
|
articleRepository.save(article);
|
||||||
|
return article;
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
package io.spring.application.article;
|
||||||
|
|
||||||
|
import java.lang.annotation.Documented;
|
||||||
|
import java.lang.annotation.ElementType;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import java.lang.annotation.Target;
|
||||||
|
import javax.validation.Constraint;
|
||||||
|
import javax.validation.Payload;
|
||||||
|
|
||||||
|
@Documented
|
||||||
|
@Constraint(validatedBy = DuplicatedArticleValidator.class)
|
||||||
|
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.TYPE_USE})
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface DuplicatedArticleConstraint {
|
||||||
|
String message() default "article name exists";
|
||||||
|
|
||||||
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
}
|
@ -0,0 +1,18 @@
|
|||||||
|
package io.spring.application.article;
|
||||||
|
|
||||||
|
import io.spring.application.ArticleQueryService;
|
||||||
|
import io.spring.core.article.Article;
|
||||||
|
import javax.validation.ConstraintValidator;
|
||||||
|
import javax.validation.ConstraintValidatorContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
class DuplicatedArticleValidator
|
||||||
|
implements ConstraintValidator<DuplicatedArticleConstraint, String> {
|
||||||
|
|
||||||
|
@Autowired private ArticleQueryService articleQueryService;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||||
|
return !articleQueryService.findBySlug(Article.toSlug(value), null).isPresent();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,28 @@
|
|||||||
|
package io.spring.application.article;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@JsonRootName("article")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class NewArticleParam {
|
||||||
|
@NotBlank(message = "can't be empty")
|
||||||
|
@DuplicatedArticleConstraint
|
||||||
|
private String title;
|
||||||
|
|
||||||
|
@NotBlank(message = "can't be empty")
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@NotBlank(message = "can't be empty")
|
||||||
|
private String body;
|
||||||
|
|
||||||
|
private List<String> tagList;
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.spring.application.article;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@JsonRootName("article")
|
||||||
|
public class UpdateArticleParam {
|
||||||
|
private String title = "";
|
||||||
|
private String body = "";
|
||||||
|
private String description = "";
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import javax.validation.Constraint;
|
||||||
|
import javax.validation.Payload;
|
||||||
|
|
||||||
|
@Constraint(validatedBy = DuplicatedEmailValidator.class)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
public @interface DuplicatedEmailConstraint {
|
||||||
|
String message() default "duplicated email";
|
||||||
|
|
||||||
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import io.spring.core.user.UserRepository;
|
||||||
|
import javax.validation.ConstraintValidator;
|
||||||
|
import javax.validation.ConstraintValidatorContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
public class DuplicatedEmailValidator
|
||||||
|
implements ConstraintValidator<DuplicatedEmailConstraint, String> {
|
||||||
|
|
||||||
|
@Autowired private UserRepository userRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||||
|
return (value == null || value.isEmpty()) || !userRepository.findByEmail(value).isPresent();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import javax.validation.Constraint;
|
||||||
|
import javax.validation.Payload;
|
||||||
|
|
||||||
|
@Constraint(validatedBy = DuplicatedUsernameValidator.class)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@interface DuplicatedUsernameConstraint {
|
||||||
|
String message() default "duplicated username";
|
||||||
|
|
||||||
|
Class<?>[] groups() default {};
|
||||||
|
|
||||||
|
Class<? extends Payload>[] payload() default {};
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import io.spring.core.user.UserRepository;
|
||||||
|
import javax.validation.ConstraintValidator;
|
||||||
|
import javax.validation.ConstraintValidatorContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
|
||||||
|
class DuplicatedUsernameValidator
|
||||||
|
implements ConstraintValidator<DuplicatedUsernameConstraint, String> {
|
||||||
|
|
||||||
|
@Autowired private UserRepository userRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(String value, ConstraintValidatorContext context) {
|
||||||
|
return (value == null || value.isEmpty()) || !userRepository.findByUsername(value).isPresent();
|
||||||
|
}
|
||||||
|
}
|
26
src/main/java/io/spring/application/user/RegisterParam.java
Normal file
26
src/main/java/io/spring/application/user/RegisterParam.java
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import javax.validation.constraints.NotBlank;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@JsonRootName("user")
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class RegisterParam {
|
||||||
|
@NotBlank(message = "can't be empty")
|
||||||
|
@Email(message = "should be an email")
|
||||||
|
@DuplicatedEmailConstraint
|
||||||
|
private String email;
|
||||||
|
|
||||||
|
@NotBlank(message = "can't be empty")
|
||||||
|
@DuplicatedUsernameConstraint
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
@NotBlank(message = "can't be empty")
|
||||||
|
private String password;
|
||||||
|
}
|
@ -0,0 +1,14 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import io.spring.core.user.User;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Getter;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@AllArgsConstructor
|
||||||
|
@UpdateUserConstraint
|
||||||
|
public class UpdateUserCommand {
|
||||||
|
|
||||||
|
private User targetUser;
|
||||||
|
private UpdateUserParam param;
|
||||||
|
}
|
@ -0,0 +1,25 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||||
|
import javax.validation.constraints.Email;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
@Getter
|
||||||
|
@JsonRootName("user")
|
||||||
|
@NoArgsConstructor
|
||||||
|
@AllArgsConstructor
|
||||||
|
@Builder
|
||||||
|
public class UpdateUserParam {
|
||||||
|
|
||||||
|
@Builder.Default
|
||||||
|
@Email(message = "should be an email")
|
||||||
|
private String email = "";
|
||||||
|
|
||||||
|
@Builder.Default private String password = "";
|
||||||
|
@Builder.Default private String username = "";
|
||||||
|
@Builder.Default private String bio = "";
|
||||||
|
@Builder.Default private String image = "";
|
||||||
|
}
|
106
src/main/java/io/spring/application/user/UserService.java
Normal file
106
src/main/java/io/spring/application/user/UserService.java
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
package io.spring.application.user;
|
||||||
|
|
||||||
|
import io.spring.core.user.EncryptService;
|
||||||
|
import io.spring.core.user.User;
|
||||||
|
import io.spring.core.user.UserRepository;
|
||||||
|
import java.lang.annotation.Retention;
|
||||||
|
import java.lang.annotation.RetentionPolicy;
|
||||||
|
import javax.validation.Constraint;
|
||||||
|
import javax.validation.ConstraintValidator;
|
||||||
|
import javax.validation.ConstraintValidatorContext;
|
||||||
|
import javax.validation.Valid;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.validation.annotation.Validated;
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Validated
|
||||||
|
public class UserService {
|
||||||
|
private UserRepository userRepository;
|
||||||
|
private String defaultImage;
|
||||||
|
private EncryptService encryptService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
public UserService(
|
||||||
|
UserRepository userRepository,
|
||||||
|
@Value("${image.default}") String defaultImage,
|
||||||
|
EncryptService encryptService) {
|
||||||
|
this.userRepository = userRepository;
|
||||||
|
this.defaultImage = defaultImage;
|
||||||
|
this.encryptService = encryptService;
|
||||||
|
}
|
||||||
|
|
||||||
|
public User createUser(@Valid RegisterParam registerParam) {
|
||||||
|
User user =
|
||||||
|
new User(
|
||||||
|
registerParam.getEmail(),
|
||||||
|
registerParam.getUsername(),
|
||||||
|
encryptService.encrypt(registerParam.getPassword()),
|
||||||
|
"",
|
||||||
|
defaultImage);
|
||||||
|
userRepository.save(user);
|
||||||
|
return user;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void updateUser(@Valid UpdateUserCommand command) {
|
||||||
|
User user = command.getTargetUser();
|
||||||
|
UpdateUserParam updateUserParam = command.getParam();
|
||||||
|
user.update(
|
||||||
|
updateUserParam.getEmail(),
|
||||||
|
updateUserParam.getUsername(),
|
||||||
|
updateUserParam.getPassword(),
|
||||||
|
updateUserParam.getBio(),
|
||||||
|
updateUserParam.getImage());
|
||||||
|
userRepository.save(user);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Constraint(validatedBy = UpdateUserValidator.class)
|
||||||
|
@Retention(RetentionPolicy.RUNTIME)
|
||||||
|
@interface UpdateUserConstraint {
|
||||||
|
|
||||||
|
String message() default "invalid update param";
|
||||||
|
|
||||||
|
Class[] groups() default {};
|
||||||
|
|
||||||
|
Class[] payload() default {};
|
||||||
|
}
|
||||||
|
|
||||||
|
class UpdateUserValidator implements ConstraintValidator<UpdateUserConstraint, UpdateUserCommand> {
|
||||||
|
|
||||||
|
@Autowired private UserRepository userRepository;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isValid(UpdateUserCommand value, ConstraintValidatorContext context) {
|
||||||
|
String inputEmail = value.getParam().getEmail();
|
||||||
|
String inputUsername = value.getParam().getUsername();
|
||||||
|
final User targetUser = value.getTargetUser();
|
||||||
|
|
||||||
|
boolean isEmailValid =
|
||||||
|
userRepository.findByEmail(inputEmail).map(user -> user.equals(targetUser)).orElse(true);
|
||||||
|
boolean isUsernameValid =
|
||||||
|
userRepository
|
||||||
|
.findByUsername(inputUsername)
|
||||||
|
.map(user -> user.equals(targetUser))
|
||||||
|
.orElse(true);
|
||||||
|
if (isEmailValid && isUsernameValid) {
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
context.disableDefaultConstraintViolation();
|
||||||
|
if (!isEmailValid) {
|
||||||
|
context
|
||||||
|
.buildConstraintViolationWithTemplate("email already exist")
|
||||||
|
.addPropertyNode("email")
|
||||||
|
.addConstraintViolation();
|
||||||
|
}
|
||||||
|
if (!isUsernameValid) {
|
||||||
|
context
|
||||||
|
.buildConstraintViolationWithTemplate("username already exist")
|
||||||
|
.addPropertyNode("username")
|
||||||
|
.addConstraintViolation();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,62 +1,70 @@
|
|||||||
package io.spring.core.article;
|
package io.spring.core.article;
|
||||||
|
|
||||||
|
import static java.util.stream.Collectors.toList;
|
||||||
|
|
||||||
|
import io.spring.Util;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
import static java.util.stream.Collectors.toList;
|
|
||||||
import static java.util.stream.Collectors.toSet;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@EqualsAndHashCode(of = {"id"})
|
@EqualsAndHashCode(of = {"id"})
|
||||||
public class Article {
|
public class Article {
|
||||||
private String userId;
|
private String userId;
|
||||||
private String id;
|
private String id;
|
||||||
private String slug;
|
private String slug;
|
||||||
private String title;
|
private String title;
|
||||||
private String description;
|
private String description;
|
||||||
private String body;
|
private String body;
|
||||||
private List<Tag> tags;
|
private List<Tag> tags;
|
||||||
private DateTime createdAt;
|
private DateTime createdAt;
|
||||||
private DateTime updatedAt;
|
private DateTime updatedAt;
|
||||||
|
|
||||||
public Article(String title, String description, String body, String[] tagList, String userId) {
|
public Article(
|
||||||
this(title, description, body, tagList, userId, new DateTime());
|
String title, String description, String body, List<String> tagList, String userId) {
|
||||||
}
|
this(title, description, body, tagList, userId, new DateTime());
|
||||||
|
}
|
||||||
|
|
||||||
public Article(String title, String description, String body, String[] tagList, String userId, DateTime createdAt) {
|
public Article(
|
||||||
this.id = UUID.randomUUID().toString();
|
String title,
|
||||||
this.slug = toSlug(title);
|
String description,
|
||||||
this.title = title;
|
String body,
|
||||||
this.description = description;
|
List<String> tagList,
|
||||||
this.body = body;
|
String userId,
|
||||||
this.tags = Arrays.stream(tagList).collect(toSet()).stream().map(Tag::new).collect(toList());
|
DateTime createdAt) {
|
||||||
this.userId = userId;
|
this.id = UUID.randomUUID().toString();
|
||||||
this.createdAt = createdAt;
|
this.slug = toSlug(title);
|
||||||
this.updatedAt = createdAt;
|
this.title = title;
|
||||||
}
|
this.description = description;
|
||||||
|
this.body = body;
|
||||||
|
this.tags = new HashSet<>(tagList).stream().map(Tag::new).collect(toList());
|
||||||
|
this.userId = userId;
|
||||||
|
this.createdAt = createdAt;
|
||||||
|
this.updatedAt = createdAt;
|
||||||
|
}
|
||||||
|
|
||||||
public void update(String title, String description, String body) {
|
public void update(String title, String description, String body) {
|
||||||
if (!"".equals(title)) {
|
if (!Util.isEmpty(title)) {
|
||||||
this.title = title;
|
this.title = title;
|
||||||
this.slug = toSlug(title);
|
this.slug = toSlug(title);
|
||||||
}
|
this.updatedAt = new DateTime();
|
||||||
if (!"".equals(description)) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
if (!"".equals(body)) {
|
|
||||||
this.body = body;
|
|
||||||
}
|
|
||||||
this.updatedAt = new DateTime();
|
|
||||||
}
|
}
|
||||||
|
if (!Util.isEmpty(description)) {
|
||||||
|
this.description = description;
|
||||||
|
this.updatedAt = new DateTime();
|
||||||
|
}
|
||||||
|
if (!Util.isEmpty(body)) {
|
||||||
|
this.body = body;
|
||||||
|
this.updatedAt = new DateTime();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static String toSlug(String title) {
|
public static String toSlug(String title) {
|
||||||
return title.toLowerCase().replaceAll("[\\&|[\\uFE30-\\uFFA0]|\\’|\\”|\\s\\?\\,\\.]+", "-");
|
return title.toLowerCase().replaceAll("[\\&|[\\uFE30-\\uFFA0]|\\’|\\”|\\s\\?\\,\\.]+", "-");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,50 +1,50 @@
|
|||||||
package io.spring.core.user;
|
package io.spring.core.user;
|
||||||
|
|
||||||
|
import io.spring.Util;
|
||||||
|
import java.util.UUID;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
import lombok.NoArgsConstructor;
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
@Getter
|
@Getter
|
||||||
@NoArgsConstructor
|
@NoArgsConstructor
|
||||||
@EqualsAndHashCode(of = {"id"})
|
@EqualsAndHashCode(of = {"id"})
|
||||||
public class User {
|
public class User {
|
||||||
private String id;
|
private String id;
|
||||||
private String email;
|
private String email;
|
||||||
private String username;
|
private String username;
|
||||||
private String password;
|
private String password;
|
||||||
private String bio;
|
private String bio;
|
||||||
private String image;
|
private String image;
|
||||||
|
|
||||||
public User(String email, String username, String password, String bio, String image) {
|
public User(String email, String username, String password, String bio, String image) {
|
||||||
this.id = UUID.randomUUID().toString();
|
this.id = UUID.randomUUID().toString();
|
||||||
this.email = email;
|
this.email = email;
|
||||||
this.username = username;
|
this.username = username;
|
||||||
this.password = password;
|
this.password = password;
|
||||||
this.bio = bio;
|
this.bio = bio;
|
||||||
this.image = image;
|
this.image = image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(String email, String username, String password, String bio, String image) {
|
||||||
|
if (!Util.isEmpty(email)) {
|
||||||
|
this.email = email;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void update(String email, String username, String password, String bio, String image) {
|
if (!Util.isEmpty(username)) {
|
||||||
if (!"".equals(email)) {
|
this.username = username;
|
||||||
this.email = email;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!"".equals(username)) {
|
|
||||||
this.username = username;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!"".equals(password)) {
|
|
||||||
this.password = password;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!"".equals(bio)) {
|
|
||||||
this.bio = bio;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!"".equals(image)) {
|
|
||||||
this.image = image;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!Util.isEmpty(password)) {
|
||||||
|
this.password = password;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Util.isEmpty(bio)) {
|
||||||
|
this.bio = bio;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Util.isEmpty(image)) {
|
||||||
|
this.image = image;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
C.id commentId,
|
C.id commentId,
|
||||||
C.body commentBody,
|
C.body commentBody,
|
||||||
C.created_at commentCreatedAt,
|
C.created_at commentCreatedAt,
|
||||||
|
C.article_id commentArticleId,
|
||||||
<include refid="io.spring.infrastructure.mybatis.readservice.ArticleReadService.profileColumns"/>
|
<include refid="io.spring.infrastructure.mybatis.readservice.ArticleReadService.profileColumns"/>
|
||||||
from comments C
|
from comments C
|
||||||
left join users U
|
left join users U
|
||||||
|
@ -34,6 +34,7 @@
|
|||||||
<result column="commentBody" property="body"/>
|
<result column="commentBody" property="body"/>
|
||||||
<result column="commentCreatedAt" property="createdAt"/>
|
<result column="commentCreatedAt" property="createdAt"/>
|
||||||
<result column="commentCreatedAt" property="updatedAt"/>
|
<result column="commentCreatedAt" property="updatedAt"/>
|
||||||
|
<result column="commentArticleId" property="articleId"/>
|
||||||
<association property="profileData" resultMap="profileData"/>
|
<association property="profileData" resultMap="profileData"/>
|
||||||
</resultMap>
|
</resultMap>
|
||||||
</mapper>
|
</mapper>
|
@ -1,15 +1,28 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
|
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
||||||
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||||
import io.spring.JacksonCustomizations;
|
import io.spring.JacksonCustomizations;
|
||||||
import io.spring.TestHelper;
|
import io.spring.TestHelper;
|
||||||
import io.spring.api.security.WebSecurityConfig;
|
import io.spring.api.security.WebSecurityConfig;
|
||||||
import io.spring.application.ArticleQueryService;
|
import io.spring.application.ArticleQueryService;
|
||||||
|
import io.spring.application.article.ArticleCommandService;
|
||||||
import io.spring.application.data.ArticleData;
|
import io.spring.application.data.ArticleData;
|
||||||
import io.spring.application.data.ProfileData;
|
import io.spring.application.data.ProfileData;
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
import io.spring.core.article.ArticleRepository;
|
import io.spring.core.article.ArticleRepository;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.joda.time.format.ISODateTimeFormat;
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -20,104 +33,98 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
|
||||||
import static org.hamcrest.core.IsEqual.equalTo;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@WebMvcTest({ArticleApi.class})
|
@WebMvcTest({ArticleApi.class})
|
||||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||||
public class ArticleApiTest extends TestWithCurrentUser {
|
public class ArticleApiTest extends TestWithCurrentUser {
|
||||||
@Autowired
|
@Autowired private MockMvc mvc;
|
||||||
private MockMvc mvc;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean private ArticleQueryService articleQueryService;
|
||||||
private ArticleQueryService articleQueryService;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@Override
|
@MockBean ArticleCommandService articleCommandService;
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
RestAssuredMockMvc.mockMvc(mvc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Override
|
||||||
public void should_read_article_success() throws Exception {
|
@Before
|
||||||
String slug = "test-new-article";
|
public void setUp() throws Exception {
|
||||||
DateTime time = new DateTime();
|
super.setUp();
|
||||||
Article article = new Article("Test New Article", "Desc", "Body", new String[]{"java", "spring", "jpg"}, user.getId(), time);
|
RestAssuredMockMvc.mockMvc(mvc);
|
||||||
ArticleData articleData = TestHelper.getArticleDataFromArticleAndUser(article, user);
|
}
|
||||||
|
|
||||||
when(articleQueryService.findBySlug(eq(slug), eq(null))).thenReturn(Optional.of(articleData));
|
@Test
|
||||||
|
public void should_read_article_success() throws Exception {
|
||||||
|
String slug = "test-new-article";
|
||||||
|
DateTime time = new DateTime();
|
||||||
|
Article article =
|
||||||
|
new Article(
|
||||||
|
"Test New Article",
|
||||||
|
"Desc",
|
||||||
|
"Body",
|
||||||
|
Arrays.asList("java", "spring", "jpg"),
|
||||||
|
user.getId(),
|
||||||
|
time);
|
||||||
|
ArticleData articleData = TestHelper.getArticleDataFromArticleAndUser(article, user);
|
||||||
|
|
||||||
RestAssuredMockMvc.when()
|
when(articleQueryService.findBySlug(eq(slug), eq(null))).thenReturn(Optional.of(articleData));
|
||||||
.get("/articles/{slug}", slug)
|
|
||||||
.then()
|
|
||||||
.statusCode(200)
|
|
||||||
.body("article.slug", equalTo(slug))
|
|
||||||
.body("article.body", equalTo(articleData.getBody()))
|
|
||||||
.body("article.createdAt", equalTo(ISODateTimeFormat.dateTime().withZoneUTC().print(time)));
|
|
||||||
|
|
||||||
}
|
RestAssuredMockMvc.when()
|
||||||
|
.get("/articles/{slug}", slug)
|
||||||
|
.then()
|
||||||
|
.statusCode(200)
|
||||||
|
.body("article.slug", equalTo(slug))
|
||||||
|
.body("article.body", equalTo(articleData.getBody()))
|
||||||
|
.body("article.createdAt", equalTo(ISODateTimeFormat.dateTime().withZoneUTC().print(time)));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_404_if_article_not_found() throws Exception {
|
public void should_404_if_article_not_found() throws Exception {
|
||||||
when(articleQueryService.findBySlug(anyString(), any())).thenReturn(Optional.empty());
|
when(articleQueryService.findBySlug(anyString(), any())).thenReturn(Optional.empty());
|
||||||
RestAssuredMockMvc.when()
|
RestAssuredMockMvc.when().get("/articles/not-exists").then().statusCode(404);
|
||||||
.get("/articles/not-exists")
|
}
|
||||||
.then()
|
|
||||||
.statusCode(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_update_article_content_success() throws Exception {
|
public void should_update_article_content_success() throws Exception {
|
||||||
String title = "new-title";
|
String title = "new-title";
|
||||||
String body = "new body";
|
String body = "new body";
|
||||||
String description = "new description";
|
String description = "new description";
|
||||||
Map<String, Object> updateParam = prepareUpdateParam(title, body, description);
|
Map<String, Object> updateParam = prepareUpdateParam(title, body, description);
|
||||||
|
|
||||||
Article article = new Article(title, description, body, new String[]{"java", "spring", "jpg"}, user.getId());
|
Article article =
|
||||||
|
new Article(title, description, body, Arrays.asList("java", "spring", "jpg"), user.getId());
|
||||||
|
|
||||||
ArticleData articleData = TestHelper.getArticleDataFromArticleAndUser(article, user);
|
ArticleData articleData = TestHelper.getArticleDataFromArticleAndUser(article, user);
|
||||||
|
|
||||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||||
when(articleQueryService.findBySlug(eq(article.getSlug()), eq(user))).thenReturn(Optional.of(articleData));
|
when(articleQueryService.findBySlug(eq(article.getSlug()), eq(user)))
|
||||||
|
.thenReturn(Optional.of(articleData));
|
||||||
|
|
||||||
given()
|
given()
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.body(updateParam)
|
.body(updateParam)
|
||||||
.when()
|
.when()
|
||||||
.put("/articles/{slug}", article.getSlug())
|
.put("/articles/{slug}", article.getSlug())
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.body("article.slug", equalTo(articleData.getSlug()));
|
.body("article.slug", equalTo(articleData.getSlug()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_403_if_not_author_to_update_article() throws Exception {
|
public void should_get_403_if_not_author_to_update_article() throws Exception {
|
||||||
String title = "new-title";
|
String title = "new-title";
|
||||||
String body = "new body";
|
String body = "new body";
|
||||||
String description = "new description";
|
String description = "new description";
|
||||||
Map<String, Object> updateParam = prepareUpdateParam(title, body, description);
|
Map<String, Object> updateParam = prepareUpdateParam(title, body, description);
|
||||||
|
|
||||||
User anotherUser = new User("test@test.com", "test", "123123", "", "");
|
User anotherUser = new User("test@test.com", "test", "123123", "", "");
|
||||||
|
|
||||||
Article article = new Article(title, description, body, new String[]{"java", "spring", "jpg"}, anotherUser.getId());
|
Article article =
|
||||||
|
new Article(
|
||||||
|
title, description, body, Arrays.asList("java", "spring", "jpg"), anotherUser.getId());
|
||||||
|
|
||||||
DateTime time = new DateTime();
|
DateTime time = new DateTime();
|
||||||
ArticleData articleData = new ArticleData(
|
ArticleData articleData =
|
||||||
|
new ArticleData(
|
||||||
article.getId(),
|
article.getId(),
|
||||||
article.getSlug(),
|
article.getSlug(),
|
||||||
article.getTitle(),
|
article.getTitle(),
|
||||||
@ -128,66 +135,82 @@ public class ArticleApiTest extends TestWithCurrentUser {
|
|||||||
time,
|
time,
|
||||||
time,
|
time,
|
||||||
Arrays.asList("joda"),
|
Arrays.asList("joda"),
|
||||||
new ProfileData(anotherUser.getId(), anotherUser.getUsername(), anotherUser.getBio(), anotherUser.getImage(), false));
|
new ProfileData(
|
||||||
|
anotherUser.getId(),
|
||||||
|
anotherUser.getUsername(),
|
||||||
|
anotherUser.getBio(),
|
||||||
|
anotherUser.getImage(),
|
||||||
|
false));
|
||||||
|
|
||||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||||
when(articleQueryService.findBySlug(eq(article.getSlug()), eq(user))).thenReturn(Optional.of(articleData));
|
when(articleQueryService.findBySlug(eq(article.getSlug()), eq(user)))
|
||||||
|
.thenReturn(Optional.of(articleData));
|
||||||
|
|
||||||
given()
|
given()
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.body(updateParam)
|
.body(updateParam)
|
||||||
.when()
|
.when()
|
||||||
.put("/articles/{slug}", article.getSlug())
|
.put("/articles/{slug}", article.getSlug())
|
||||||
.then()
|
.then()
|
||||||
.statusCode(403);
|
.statusCode(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_delete_article_success() throws Exception {
|
public void should_delete_article_success() throws Exception {
|
||||||
String title = "title";
|
String title = "title";
|
||||||
String body = "body";
|
String body = "body";
|
||||||
String description = "description";
|
String description = "description";
|
||||||
|
|
||||||
Article article = new Article(title, description, body, new String[]{"java", "spring", "jpg"}, user.getId());
|
Article article =
|
||||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
new Article(title, description, body, Arrays.asList("java", "spring", "jpg"), user.getId());
|
||||||
|
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||||
|
|
||||||
given()
|
given()
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.when()
|
.when()
|
||||||
.delete("/articles/{slug}", article.getSlug())
|
.delete("/articles/{slug}", article.getSlug())
|
||||||
.then()
|
.then()
|
||||||
.statusCode(204);
|
.statusCode(204);
|
||||||
|
|
||||||
verify(articleRepository).remove(eq(article));
|
verify(articleRepository).remove(eq(article));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_403_if_not_author_delete_article() throws Exception {
|
public void should_403_if_not_author_delete_article() throws Exception {
|
||||||
String title = "new-title";
|
String title = "new-title";
|
||||||
String body = "new body";
|
String body = "new body";
|
||||||
String description = "new description";
|
String description = "new description";
|
||||||
|
|
||||||
User anotherUser = new User("test@test.com", "test", "123123", "", "");
|
User anotherUser = new User("test@test.com", "test", "123123", "", "");
|
||||||
|
|
||||||
Article article = new Article(title, description, body, new String[]{"java", "spring", "jpg"}, anotherUser.getId());
|
Article article =
|
||||||
|
new Article(
|
||||||
|
title, description, body, Arrays.asList("java", "spring", "jpg"), anotherUser.getId());
|
||||||
|
|
||||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||||
given()
|
given()
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.when()
|
.when()
|
||||||
.delete("/articles/{slug}", article.getSlug())
|
.delete("/articles/{slug}", article.getSlug())
|
||||||
.then()
|
.then()
|
||||||
.statusCode(403);
|
.statusCode(403);
|
||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<String, Object> prepareUpdateParam(final String title, final String body, final String description) {
|
private HashMap<String, Object> prepareUpdateParam(
|
||||||
return new HashMap<String, Object>() {{
|
final String title, final String body, final String description) {
|
||||||
put("article", new HashMap<String, Object>() {{
|
return new HashMap<String, Object>() {
|
||||||
|
{
|
||||||
|
put(
|
||||||
|
"article",
|
||||||
|
new HashMap<String, Object>() {
|
||||||
|
{
|
||||||
put("title", title);
|
put("title", title);
|
||||||
put("body", body);
|
put("body", body);
|
||||||
put("description", description);
|
put("description", description);
|
||||||
}});
|
}
|
||||||
}};
|
});
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
|
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
||||||
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||||
import io.spring.JacksonCustomizations;
|
import io.spring.JacksonCustomizations;
|
||||||
import io.spring.api.security.WebSecurityConfig;
|
import io.spring.api.security.WebSecurityConfig;
|
||||||
@ -12,6 +19,9 @@ import io.spring.core.article.Tag;
|
|||||||
import io.spring.core.favorite.ArticleFavorite;
|
import io.spring.core.favorite.ArticleFavorite;
|
||||||
import io.spring.core.favorite.ArticleFavoriteRepository;
|
import io.spring.core.favorite.ArticleFavoriteRepository;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -20,41 +30,28 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
|
||||||
import static org.hamcrest.core.IsEqual.equalTo;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.verify;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@WebMvcTest(ArticleFavoriteApi.class)
|
@WebMvcTest(ArticleFavoriteApi.class)
|
||||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||||
public class ArticleFavoriteApiTest extends TestWithCurrentUser {
|
public class ArticleFavoriteApiTest extends TestWithCurrentUser {
|
||||||
@Autowired
|
@Autowired private MockMvc mvc;
|
||||||
private MockMvc mvc;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean private ArticleFavoriteRepository articleFavoriteRepository;
|
||||||
private ArticleFavoriteRepository articleFavoriteRepository;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean private ArticleQueryService articleQueryService;
|
||||||
private ArticleQueryService articleQueryService;
|
|
||||||
|
|
||||||
private Article article;
|
private Article article;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
super.setUp();
|
super.setUp();
|
||||||
RestAssuredMockMvc.mockMvc(mvc);
|
RestAssuredMockMvc.mockMvc(mvc);
|
||||||
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
||||||
article = new Article("title", "desc", "body", new String[]{"java"}, anotherUser.getId());
|
article = new Article("title", "desc", "body", Arrays.asList("java"), anotherUser.getId());
|
||||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||||
ArticleData articleData = new ArticleData(
|
ArticleData articleData =
|
||||||
|
new ArticleData(
|
||||||
article.getId(),
|
article.getId(),
|
||||||
article.getSlug(),
|
article.getSlug(),
|
||||||
article.getTitle(),
|
article.getTitle(),
|
||||||
@ -70,36 +67,37 @@ public class ArticleFavoriteApiTest extends TestWithCurrentUser {
|
|||||||
anotherUser.getUsername(),
|
anotherUser.getUsername(),
|
||||||
anotherUser.getBio(),
|
anotherUser.getBio(),
|
||||||
anotherUser.getImage(),
|
anotherUser.getImage(),
|
||||||
false
|
false));
|
||||||
));
|
when(articleQueryService.findBySlug(eq(articleData.getSlug()), eq(user)))
|
||||||
when(articleQueryService.findBySlug(eq(articleData.getSlug()), eq(user))).thenReturn(Optional.of(articleData));
|
.thenReturn(Optional.of(articleData));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_favorite_an_article_success() throws Exception {
|
public void should_favorite_an_article_success() throws Exception {
|
||||||
given()
|
given()
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.when()
|
.when()
|
||||||
.post("/articles/{slug}/favorite", article.getSlug())
|
.post("/articles/{slug}/favorite", article.getSlug())
|
||||||
.prettyPeek()
|
.prettyPeek()
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200)
|
.statusCode(200)
|
||||||
.body("article.id", equalTo(article.getId()));
|
.body("article.id", equalTo(article.getId()));
|
||||||
|
|
||||||
verify(articleFavoriteRepository).save(any());
|
verify(articleFavoriteRepository).save(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_unfavorite_an_article_success() throws Exception {
|
public void should_unfavorite_an_article_success() throws Exception {
|
||||||
when(articleFavoriteRepository.find(eq(article.getId()), eq(user.getId()))).thenReturn(Optional.of(new ArticleFavorite(article.getId(), user.getId())));
|
when(articleFavoriteRepository.find(eq(article.getId()), eq(user.getId())))
|
||||||
given()
|
.thenReturn(Optional.of(new ArticleFavorite(article.getId(), user.getId())));
|
||||||
.header("Authorization", "Token " + token)
|
given()
|
||||||
.when()
|
.header("Authorization", "Token " + token)
|
||||||
.delete("/articles/{slug}/favorite", article.getSlug())
|
.when()
|
||||||
.prettyPeek()
|
.delete("/articles/{slug}/favorite", article.getSlug())
|
||||||
.then()
|
.prettyPeek()
|
||||||
.statusCode(200)
|
.then()
|
||||||
.body("article.id", equalTo(article.getId()));
|
.statusCode(200)
|
||||||
verify(articleFavoriteRepository).remove(new ArticleFavorite(article.getId(), user.getId()));
|
.body("article.id", equalTo(article.getId()));
|
||||||
}
|
verify(articleFavoriteRepository).remove(new ArticleFavorite(article.getId(), user.getId()));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
import static org.hamcrest.core.IsEqual.equalTo;
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
@ -11,12 +12,12 @@ import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
|||||||
import io.spring.JacksonCustomizations;
|
import io.spring.JacksonCustomizations;
|
||||||
import io.spring.api.security.WebSecurityConfig;
|
import io.spring.api.security.WebSecurityConfig;
|
||||||
import io.spring.application.ArticleQueryService;
|
import io.spring.application.ArticleQueryService;
|
||||||
|
import io.spring.application.article.ArticleCommandService;
|
||||||
import io.spring.application.data.ArticleData;
|
import io.spring.application.data.ArticleData;
|
||||||
import io.spring.application.data.ProfileData;
|
import io.spring.application.data.ProfileData;
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
import io.spring.core.article.ArticleRepository;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
@ -33,10 +34,10 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||||||
public class ArticlesApiTest extends TestWithCurrentUser {
|
public class ArticlesApiTest extends TestWithCurrentUser {
|
||||||
@Autowired private MockMvc mvc;
|
@Autowired private MockMvc mvc;
|
||||||
|
|
||||||
@MockBean private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@MockBean private ArticleQueryService articleQueryService;
|
@MockBean private ArticleQueryService articleQueryService;
|
||||||
|
|
||||||
|
@MockBean private ArticleCommandService articleCommandService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
@ -50,7 +51,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
|||||||
String slug = "how-to-train-your-dragon";
|
String slug = "how-to-train-your-dragon";
|
||||||
String description = "Ever wonder how?";
|
String description = "Ever wonder how?";
|
||||||
String body = "You have to believe";
|
String body = "You have to believe";
|
||||||
String[] tagList = {"reactjs", "angularjs", "dragons"};
|
List<String> tagList = asList("reactjs", "angularjs", "dragons");
|
||||||
Map<String, Object> param = prepareParam(title, description, body, tagList);
|
Map<String, Object> param = prepareParam(title, description, body, tagList);
|
||||||
|
|
||||||
ArticleData articleData =
|
ArticleData articleData =
|
||||||
@ -64,9 +65,12 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
|||||||
0,
|
0,
|
||||||
new DateTime(),
|
new DateTime(),
|
||||||
new DateTime(),
|
new DateTime(),
|
||||||
Arrays.asList(tagList),
|
tagList,
|
||||||
new ProfileData("userid", user.getUsername(), user.getBio(), user.getImage(), false));
|
new ProfileData("userid", user.getUsername(), user.getBio(), user.getImage(), false));
|
||||||
|
|
||||||
|
when(articleCommandService.createArticle(any(), any()))
|
||||||
|
.thenReturn(new Article(title, description, body, tagList, user.getId()));
|
||||||
|
|
||||||
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any()))
|
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any()))
|
||||||
.thenReturn(Optional.empty());
|
.thenReturn(Optional.empty());
|
||||||
|
|
||||||
@ -87,7 +91,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
|||||||
.body("article.author.username", equalTo(user.getUsername()))
|
.body("article.author.username", equalTo(user.getUsername()))
|
||||||
.body("article.author.id", equalTo(null));
|
.body("article.author.id", equalTo(null));
|
||||||
|
|
||||||
verify(articleRepository).save(any());
|
verify(articleCommandService).createArticle(any(), any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -96,7 +100,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
|||||||
String description = "Ever wonder how?";
|
String description = "Ever wonder how?";
|
||||||
String body = "";
|
String body = "";
|
||||||
String[] tagList = {"reactjs", "angularjs", "dragons"};
|
String[] tagList = {"reactjs", "angularjs", "dragons"};
|
||||||
Map<String, Object> param = prepareParam(title, description, body, tagList);
|
Map<String, Object> param = prepareParam(title, description, body, asList(tagList));
|
||||||
|
|
||||||
given()
|
given()
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
@ -117,7 +121,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
|||||||
String description = "Ever wonder how?";
|
String description = "Ever wonder how?";
|
||||||
String body = "You have to believe";
|
String body = "You have to believe";
|
||||||
String[] tagList = {"reactjs", "angularjs", "dragons"};
|
String[] tagList = {"reactjs", "angularjs", "dragons"};
|
||||||
Map<String, Object> param = prepareParam(title, description, body, tagList);
|
Map<String, Object> param = prepareParam(title, description, body, asList(tagList));
|
||||||
|
|
||||||
ArticleData articleData =
|
ArticleData articleData =
|
||||||
new ArticleData(
|
new ArticleData(
|
||||||
@ -130,7 +134,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
|||||||
0,
|
0,
|
||||||
new DateTime(),
|
new DateTime(),
|
||||||
new DateTime(),
|
new DateTime(),
|
||||||
Arrays.asList(tagList),
|
asList(tagList),
|
||||||
new ProfileData("userid", user.getUsername(), user.getBio(), user.getImage(), false));
|
new ProfileData("userid", user.getUsername(), user.getBio(), user.getImage(), false));
|
||||||
|
|
||||||
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any()))
|
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any()))
|
||||||
@ -150,7 +154,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private HashMap<String, Object> prepareParam(
|
private HashMap<String, Object> prepareParam(
|
||||||
final String title, final String description, final String body, final String[] tagList) {
|
final String title, final String description, final String body, final List<String> tagList) {
|
||||||
return new HashMap<String, Object>() {
|
return new HashMap<String, Object>() {
|
||||||
{
|
{
|
||||||
put(
|
put(
|
||||||
|
@ -1,5 +1,12 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
|
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
||||||
|
import static org.hamcrest.core.IsEqual.equalTo;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||||
import io.spring.JacksonCustomizations;
|
import io.spring.JacksonCustomizations;
|
||||||
import io.spring.api.security.WebSecurityConfig;
|
import io.spring.api.security.WebSecurityConfig;
|
||||||
@ -11,6 +18,10 @@ import io.spring.core.article.ArticleRepository;
|
|||||||
import io.spring.core.comment.Comment;
|
import io.spring.core.comment.Comment;
|
||||||
import io.spring.core.comment.CommentRepository;
|
import io.spring.core.comment.CommentRepository;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -19,132 +30,136 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
|
||||||
import static org.hamcrest.core.IsEqual.equalTo;
|
|
||||||
import static org.mockito.ArgumentMatchers.any;
|
|
||||||
import static org.mockito.ArgumentMatchers.anyString;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@WebMvcTest(CommentsApi.class)
|
@WebMvcTest(CommentsApi.class)
|
||||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||||
public class CommentsApiTest extends TestWithCurrentUser {
|
public class CommentsApiTest extends TestWithCurrentUser {
|
||||||
|
|
||||||
@MockBean
|
@MockBean private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean private CommentRepository commentRepository;
|
||||||
private CommentRepository commentRepository;
|
@MockBean private CommentQueryService commentQueryService;
|
||||||
@MockBean
|
|
||||||
private CommentQueryService commentQueryService;
|
|
||||||
|
|
||||||
private Article article;
|
private Article article;
|
||||||
private CommentData commentData;
|
private CommentData commentData;
|
||||||
private Comment comment;
|
private Comment comment;
|
||||||
@Autowired
|
@Autowired private MockMvc mvc;
|
||||||
private MockMvc mvc;
|
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
RestAssuredMockMvc.mockMvc(mvc);
|
RestAssuredMockMvc.mockMvc(mvc);
|
||||||
super.setUp();
|
super.setUp();
|
||||||
article = new Article("title", "desc", "body", new String[]{"test", "java"}, user.getId());
|
article = new Article("title", "desc", "body", Arrays.asList("test", "java"), user.getId());
|
||||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||||
comment = new Comment("comment", user.getId(), article.getId());
|
comment = new Comment("comment", user.getId(), article.getId());
|
||||||
commentData = new CommentData(
|
commentData =
|
||||||
|
new CommentData(
|
||||||
comment.getId(),
|
comment.getId(),
|
||||||
comment.getBody(),
|
comment.getBody(),
|
||||||
comment.getArticleId(),
|
comment.getArticleId(),
|
||||||
comment.getCreatedAt(),
|
comment.getCreatedAt(),
|
||||||
comment.getCreatedAt(),
|
comment.getCreatedAt(),
|
||||||
new ProfileData(user.getId(), user.getUsername(), user.getBio(), user.getImage(), false));
|
new ProfileData(
|
||||||
}
|
user.getId(), user.getUsername(), user.getBio(), user.getImage(), false));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_create_comment_success() throws Exception {
|
public void should_create_comment_success() throws Exception {
|
||||||
Map<String, Object> param = new HashMap<String, Object>() {{
|
Map<String, Object> param =
|
||||||
put("comment", new HashMap<String, Object>() {{
|
new HashMap<String, Object>() {
|
||||||
put("body", "comment content");
|
{
|
||||||
}});
|
put(
|
||||||
}};
|
"comment",
|
||||||
|
new HashMap<String, Object>() {
|
||||||
|
{
|
||||||
|
put("body", "comment content");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
when(commentQueryService.findById(anyString(), eq(user))).thenReturn(Optional.of(commentData));
|
when(commentQueryService.findById(anyString(), eq(user))).thenReturn(Optional.of(commentData));
|
||||||
|
|
||||||
given()
|
given()
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.body(param)
|
.body(param)
|
||||||
.when()
|
.when()
|
||||||
.post("/articles/{slug}/comments", article.getSlug())
|
.post("/articles/{slug}/comments", article.getSlug())
|
||||||
.then()
|
.then()
|
||||||
.statusCode(201)
|
.statusCode(201)
|
||||||
.body("comment.body", equalTo(commentData.getBody()));
|
.body("comment.body", equalTo(commentData.getBody()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_422_with_empty_body() throws Exception {
|
public void should_get_422_with_empty_body() throws Exception {
|
||||||
Map<String, Object> param = new HashMap<String, Object>() {{
|
Map<String, Object> param =
|
||||||
put("comment", new HashMap<String, Object>() {{
|
new HashMap<String, Object>() {
|
||||||
put("body", "");
|
{
|
||||||
}});
|
put(
|
||||||
}};
|
"comment",
|
||||||
|
new HashMap<String, Object>() {
|
||||||
|
{
|
||||||
|
put("body", "");
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
given()
|
given()
|
||||||
.contentType("application/json")
|
.contentType("application/json")
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.body(param)
|
.body(param)
|
||||||
.when()
|
.when()
|
||||||
.post("/articles/{slug}/comments", article.getSlug())
|
.post("/articles/{slug}/comments", article.getSlug())
|
||||||
.then()
|
.then()
|
||||||
.statusCode(422)
|
.statusCode(422)
|
||||||
.body("errors.body[0]", equalTo("can't be empty"));
|
.body("errors.body[0]", equalTo("can't be empty"));
|
||||||
|
}
|
||||||
|
|
||||||
}
|
@Test
|
||||||
|
public void should_get_comments_of_article_success() throws Exception {
|
||||||
|
when(commentQueryService.findByArticleId(anyString(), eq(null)))
|
||||||
|
.thenReturn(Arrays.asList(commentData));
|
||||||
|
RestAssuredMockMvc.when()
|
||||||
|
.get("/articles/{slug}/comments", article.getSlug())
|
||||||
|
.prettyPeek()
|
||||||
|
.then()
|
||||||
|
.statusCode(200)
|
||||||
|
.body("comments[0].id", equalTo(commentData.getId()));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_comments_of_article_success() throws Exception {
|
public void should_delete_comment_success() throws Exception {
|
||||||
when(commentQueryService.findByArticleId(anyString(), eq(null))).thenReturn(Arrays.asList(commentData));
|
when(commentRepository.findById(eq(article.getId()), eq(comment.getId())))
|
||||||
RestAssuredMockMvc.when()
|
.thenReturn(Optional.of(comment));
|
||||||
.get("/articles/{slug}/comments", article.getSlug())
|
|
||||||
.prettyPeek()
|
|
||||||
.then()
|
|
||||||
.statusCode(200)
|
|
||||||
.body("comments[0].id", equalTo(commentData.getId()));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
given()
|
||||||
public void should_delete_comment_success() throws Exception {
|
.header("Authorization", "Token " + token)
|
||||||
when(commentRepository.findById(eq(article.getId()), eq(comment.getId()))).thenReturn(Optional.of(comment));
|
.when()
|
||||||
|
.delete("/articles/{slug}/comments/{id}", article.getSlug(), comment.getId())
|
||||||
|
.then()
|
||||||
|
.statusCode(204);
|
||||||
|
}
|
||||||
|
|
||||||
given()
|
@Test
|
||||||
.header("Authorization", "Token " + token)
|
public void should_get_403_if_not_author_of_article_or_author_of_comment_when_delete_comment()
|
||||||
.when()
|
throws Exception {
|
||||||
.delete("/articles/{slug}/comments/{id}", article.getSlug(), comment.getId())
|
User anotherUser = new User("other@example.com", "other", "123", "", "");
|
||||||
.then()
|
when(userRepository.findByUsername(eq(anotherUser.getUsername())))
|
||||||
.statusCode(204);
|
.thenReturn(Optional.of(anotherUser));
|
||||||
}
|
when(jwtService.getSubFromToken(any())).thenReturn(Optional.of(anotherUser.getId()));
|
||||||
|
when(userRepository.findById(eq(anotherUser.getId())))
|
||||||
|
.thenReturn(Optional.ofNullable(anotherUser));
|
||||||
|
|
||||||
@Test
|
when(commentRepository.findById(eq(article.getId()), eq(comment.getId())))
|
||||||
public void should_get_403_if_not_author_of_article_or_author_of_comment_when_delete_comment() throws Exception {
|
.thenReturn(Optional.of(comment));
|
||||||
User anotherUser = new User("other@example.com", "other", "123", "", "");
|
String token = jwtService.toToken(anotherUser);
|
||||||
when(userRepository.findByUsername(eq(anotherUser.getUsername()))).thenReturn(Optional.of(anotherUser));
|
when(userRepository.findById(eq(anotherUser.getId()))).thenReturn(Optional.of(anotherUser));
|
||||||
when(jwtService.getSubFromToken(any())).thenReturn(Optional.of(anotherUser.getId()));
|
given()
|
||||||
when(userRepository.findById(eq(anotherUser.getId()))).thenReturn(Optional.ofNullable(anotherUser));
|
.header("Authorization", "Token " + token)
|
||||||
|
.when()
|
||||||
when(commentRepository.findById(eq(article.getId()), eq(comment.getId()))).thenReturn(Optional.of(comment));
|
.delete("/articles/{slug}/comments/{id}", article.getSlug(), comment.getId())
|
||||||
String token = jwtService.toToken(anotherUser);
|
.then()
|
||||||
when(userRepository.findById(eq(anotherUser.getId()))).thenReturn(Optional.of(anotherUser));
|
.statusCode(403);
|
||||||
given()
|
}
|
||||||
.header("Authorization", "Token " + token)
|
|
||||||
.when()
|
|
||||||
.delete("/articles/{slug}/comments/{id}", article.getSlug(), comment.getId())
|
|
||||||
.then()
|
|
||||||
.statusCode(403);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,9 @@ import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
|||||||
import io.spring.JacksonCustomizations;
|
import io.spring.JacksonCustomizations;
|
||||||
import io.spring.api.security.WebSecurityConfig;
|
import io.spring.api.security.WebSecurityConfig;
|
||||||
import io.spring.application.UserQueryService;
|
import io.spring.application.UserQueryService;
|
||||||
|
import io.spring.application.user.UserService;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
|
import io.spring.infrastructure.service.NaiveEncryptService;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
@ -28,7 +30,8 @@ import org.springframework.test.web.servlet.MockMvc;
|
|||||||
WebSecurityConfig.class,
|
WebSecurityConfig.class,
|
||||||
JacksonCustomizations.class,
|
JacksonCustomizations.class,
|
||||||
UserService.class,
|
UserService.class,
|
||||||
ValidationAutoConfiguration.class
|
ValidationAutoConfiguration.class,
|
||||||
|
NaiveEncryptService.class
|
||||||
})
|
})
|
||||||
public class CurrentUserApiTest extends TestWithCurrentUser {
|
public class CurrentUserApiTest extends TestWithCurrentUser {
|
||||||
|
|
||||||
|
@ -1,10 +1,17 @@
|
|||||||
package io.spring.api;
|
package io.spring.api;
|
||||||
|
|
||||||
|
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
||||||
|
import static io.spring.TestHelper.articleDataFixture;
|
||||||
|
import static java.util.Arrays.asList;
|
||||||
|
import static org.mockito.ArgumentMatchers.eq;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||||
import io.spring.JacksonCustomizations;
|
import io.spring.JacksonCustomizations;
|
||||||
import io.spring.api.security.WebSecurityConfig;
|
import io.spring.api.security.WebSecurityConfig;
|
||||||
import io.spring.application.ArticleQueryService;
|
import io.spring.application.ArticleQueryService;
|
||||||
import io.spring.application.Page;
|
import io.spring.application.Page;
|
||||||
|
import io.spring.application.article.ArticleCommandService;
|
||||||
import io.spring.application.data.ArticleDataList;
|
import io.spring.application.data.ArticleDataList;
|
||||||
import io.spring.core.article.ArticleRepository;
|
import io.spring.core.article.ArticleRepository;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
@ -15,64 +22,54 @@ import org.springframework.boot.test.mock.mockito.MockBean;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.web.servlet.MockMvc;
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
|
||||||
import static io.spring.TestHelper.articleDataFixture;
|
|
||||||
import static java.util.Arrays.asList;
|
|
||||||
import static org.mockito.ArgumentMatchers.eq;
|
|
||||||
import static org.mockito.Mockito.when;
|
|
||||||
|
|
||||||
@WebMvcTest(ArticlesApi.class)
|
@WebMvcTest(ArticlesApi.class)
|
||||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||||
public class ListArticleApiTest extends TestWithCurrentUser {
|
public class ListArticleApiTest extends TestWithCurrentUser {
|
||||||
@MockBean
|
@MockBean private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@MockBean
|
@MockBean private ArticleQueryService articleQueryService;
|
||||||
private ArticleQueryService articleQueryService;
|
|
||||||
|
|
||||||
@Autowired
|
@MockBean private ArticleCommandService articleCommandService;
|
||||||
private MockMvc mvc;
|
|
||||||
|
|
||||||
@Override
|
@Autowired private MockMvc mvc;
|
||||||
@Before
|
|
||||||
public void setUp() throws Exception {
|
|
||||||
super.setUp();
|
|
||||||
RestAssuredMockMvc.mockMvc(mvc);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Override
|
||||||
public void should_get_default_article_list() throws Exception {
|
@Before
|
||||||
ArticleDataList articleDataList = new ArticleDataList(
|
public void setUp() throws Exception {
|
||||||
|
super.setUp();
|
||||||
|
RestAssuredMockMvc.mockMvc(mvc);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void should_get_default_article_list() throws Exception {
|
||||||
|
ArticleDataList articleDataList =
|
||||||
|
new ArticleDataList(
|
||||||
asList(articleDataFixture("1", user), articleDataFixture("2", user)), 2);
|
asList(articleDataFixture("1", user), articleDataFixture("2", user)), 2);
|
||||||
when(articleQueryService.findRecentArticles(eq(null), eq(null), eq(null), eq(new Page(0, 20)), eq(null))).thenReturn(articleDataList);
|
when(articleQueryService.findRecentArticles(
|
||||||
RestAssuredMockMvc.when()
|
eq(null), eq(null), eq(null), eq(new Page(0, 20)), eq(null)))
|
||||||
.get("/articles")
|
.thenReturn(articleDataList);
|
||||||
.prettyPeek()
|
RestAssuredMockMvc.when().get("/articles").prettyPeek().then().statusCode(200);
|
||||||
.then()
|
}
|
||||||
.statusCode(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_feeds_401_without_login() throws Exception {
|
public void should_get_feeds_401_without_login() throws Exception {
|
||||||
RestAssuredMockMvc.when()
|
RestAssuredMockMvc.when().get("/articles/feed").prettyPeek().then().statusCode(401);
|
||||||
.get("/articles/feed")
|
}
|
||||||
.prettyPeek()
|
|
||||||
.then()
|
|
||||||
.statusCode(401);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_feeds_success() throws Exception {
|
public void should_get_feeds_success() throws Exception {
|
||||||
ArticleDataList articleDataList = new ArticleDataList(
|
ArticleDataList articleDataList =
|
||||||
|
new ArticleDataList(
|
||||||
asList(articleDataFixture("1", user), articleDataFixture("2", user)), 2);
|
asList(articleDataFixture("1", user), articleDataFixture("2", user)), 2);
|
||||||
when(articleQueryService.findUserFeed(eq(user), eq(new Page(0, 20)))).thenReturn(articleDataList);
|
when(articleQueryService.findUserFeed(eq(user), eq(new Page(0, 20))))
|
||||||
|
.thenReturn(articleDataList);
|
||||||
|
|
||||||
given()
|
given()
|
||||||
.header("Authorization", "Token " + token)
|
.header("Authorization", "Token " + token)
|
||||||
.when()
|
.when()
|
||||||
.get("/articles/feed")
|
.get("/articles/feed")
|
||||||
.prettyPeek()
|
.prettyPeek()
|
||||||
.then()
|
.then()
|
||||||
.statusCode(200);
|
.statusCode(200);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,6 +12,7 @@ import io.spring.JacksonCustomizations;
|
|||||||
import io.spring.api.security.WebSecurityConfig;
|
import io.spring.api.security.WebSecurityConfig;
|
||||||
import io.spring.application.UserQueryService;
|
import io.spring.application.UserQueryService;
|
||||||
import io.spring.application.data.UserData;
|
import io.spring.application.data.UserData;
|
||||||
|
import io.spring.application.user.UserService;
|
||||||
import io.spring.core.service.JwtService;
|
import io.spring.core.service.JwtService;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
import io.spring.core.user.UserRepository;
|
import io.spring.core.user.UserRepository;
|
||||||
@ -46,6 +47,9 @@ public class UsersApiTest {
|
|||||||
@MockBean private JwtService jwtService;
|
@MockBean private JwtService jwtService;
|
||||||
|
|
||||||
@MockBean private UserReadService userReadService;
|
@MockBean private UserReadService userReadService;
|
||||||
|
|
||||||
|
@MockBean private UserService userService;
|
||||||
|
|
||||||
private String defaultAvatar;
|
private String defaultAvatar;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
@ -64,6 +68,8 @@ public class UsersApiTest {
|
|||||||
UserData userData = new UserData(user.getId(), email, username, "", defaultAvatar);
|
UserData userData = new UserData(user.getId(), email, username, "", defaultAvatar);
|
||||||
when(userReadService.findById(any())).thenReturn(userData);
|
when(userReadService.findById(any())).thenReturn(userData);
|
||||||
|
|
||||||
|
when(userService.createUser(any())).thenReturn(user);
|
||||||
|
|
||||||
when(userRepository.findByUsername(eq(username))).thenReturn(Optional.empty());
|
when(userRepository.findByUsername(eq(username))).thenReturn(Optional.empty());
|
||||||
when(userRepository.findByEmail(eq(email))).thenReturn(Optional.empty());
|
when(userRepository.findByEmail(eq(email))).thenReturn(Optional.empty());
|
||||||
|
|
||||||
@ -82,7 +88,7 @@ public class UsersApiTest {
|
|||||||
.body("user.image", equalTo(defaultAvatar))
|
.body("user.image", equalTo(defaultAvatar))
|
||||||
.body("user.token", equalTo("123"));
|
.body("user.token", equalTo("123"));
|
||||||
|
|
||||||
verify(userRepository).save(any());
|
verify(userService).createUser(any());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package io.spring.application.article;
|
package io.spring.application.article;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import io.spring.application.ArticleQueryService;
|
import io.spring.application.ArticleQueryService;
|
||||||
import io.spring.application.Page;
|
import io.spring.application.Page;
|
||||||
import io.spring.application.data.ArticleData;
|
import io.spring.application.data.ArticleData;
|
||||||
@ -14,6 +19,8 @@ import io.spring.core.user.UserRepository;
|
|||||||
import io.spring.infrastructure.repository.MyBatisArticleFavoriteRepository;
|
import io.spring.infrastructure.repository.MyBatisArticleFavoriteRepository;
|
||||||
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
||||||
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
@ -23,161 +30,170 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotNull;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@MybatisTest
|
@MybatisTest
|
||||||
@Import({
|
@Import({
|
||||||
ArticleQueryService.class,
|
ArticleQueryService.class,
|
||||||
MyBatisUserRepository.class,
|
MyBatisUserRepository.class,
|
||||||
MyBatisArticleRepository.class,
|
MyBatisArticleRepository.class,
|
||||||
MyBatisArticleFavoriteRepository.class})
|
MyBatisArticleFavoriteRepository.class
|
||||||
|
})
|
||||||
public class ArticleQueryServiceTest {
|
public class ArticleQueryServiceTest {
|
||||||
@Autowired
|
@Autowired private ArticleQueryService queryService;
|
||||||
private ArticleQueryService queryService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private UserRepository userRepository;
|
||||||
private UserRepository userRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private ArticleFavoriteRepository articleFavoriteRepository;
|
||||||
private ArticleFavoriteRepository articleFavoriteRepository;
|
|
||||||
|
|
||||||
private User user;
|
private User user;
|
||||||
private Article article;
|
private Article article;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
user = new User("aisensiy@gmail.com", "aisensiy", "123", "", "");
|
user = new User("aisensiy@gmail.com", "aisensiy", "123", "", "");
|
||||||
userRepository.save(user);
|
userRepository.save(user);
|
||||||
article = new Article("test", "desc", "body", new String[]{"java", "spring"}, user.getId(), new DateTime());
|
article =
|
||||||
articleRepository.save(article);
|
new Article(
|
||||||
}
|
"test", "desc", "body", Arrays.asList("java", "spring"), user.getId(), new DateTime());
|
||||||
|
articleRepository.save(article);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_fetch_article_success() {
|
public void should_fetch_article_success() {
|
||||||
Optional<ArticleData> optional = queryService.findById(article.getId(), user);
|
Optional<ArticleData> optional = queryService.findById(article.getId(), user);
|
||||||
assertTrue(optional.isPresent());
|
assertTrue(optional.isPresent());
|
||||||
|
|
||||||
ArticleData fetched = optional.get();
|
ArticleData fetched = optional.get();
|
||||||
assertEquals(fetched.getFavoritesCount(),0);
|
assertEquals(fetched.getFavoritesCount(), 0);
|
||||||
assertFalse(fetched.isFavorited());
|
assertFalse(fetched.isFavorited());
|
||||||
assertNotNull(fetched.getCreatedAt());
|
assertNotNull(fetched.getCreatedAt());
|
||||||
assertNotNull(fetched.getUpdatedAt());
|
assertNotNull(fetched.getUpdatedAt());
|
||||||
assertTrue(fetched.getTagList().contains("java"));
|
assertTrue(fetched.getTagList().contains("java"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_article_with_right_favorite_and_favorite_count() {
|
public void should_get_article_with_right_favorite_and_favorite_count() {
|
||||||
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
||||||
userRepository.save(anotherUser);
|
userRepository.save(anotherUser);
|
||||||
articleFavoriteRepository.save(new ArticleFavorite(article.getId(), anotherUser.getId()));
|
articleFavoriteRepository.save(new ArticleFavorite(article.getId(), anotherUser.getId()));
|
||||||
|
|
||||||
Optional<ArticleData> optional = queryService.findById(article.getId(), anotherUser);
|
Optional<ArticleData> optional = queryService.findById(article.getId(), anotherUser);
|
||||||
assertTrue(optional.isPresent());
|
assertTrue(optional.isPresent());
|
||||||
|
|
||||||
ArticleData articleData = optional.get();
|
ArticleData articleData = optional.get();
|
||||||
assertEquals(articleData.getFavoritesCount(), 1);
|
assertEquals(articleData.getFavoritesCount(), 1);
|
||||||
assertTrue(articleData.isFavorited());
|
assertTrue(articleData.isFavorited());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_default_article_list() {
|
public void should_get_default_article_list() {
|
||||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, user.getId(), new DateTime().minusHours(1));
|
Article anotherArticle =
|
||||||
articleRepository.save(anotherArticle);
|
new Article(
|
||||||
|
"new article",
|
||||||
|
"desc",
|
||||||
|
"body",
|
||||||
|
Arrays.asList("test"),
|
||||||
|
user.getId(),
|
||||||
|
new DateTime().minusHours(1));
|
||||||
|
articleRepository.save(anotherArticle);
|
||||||
|
|
||||||
ArticleDataList recentArticles = queryService.findRecentArticles(null, null, null, new Page(), user);
|
ArticleDataList recentArticles =
|
||||||
assertEquals(recentArticles.getCount(), 2);
|
queryService.findRecentArticles(null, null, null, new Page(), user);
|
||||||
assertEquals(recentArticles.getArticleDatas().size(), 2);
|
assertEquals(recentArticles.getCount(), 2);
|
||||||
assertEquals(recentArticles.getArticleDatas().get(0).getId(), article.getId());
|
assertEquals(recentArticles.getArticleDatas().size(), 2);
|
||||||
|
assertEquals(recentArticles.getArticleDatas().get(0).getId(), article.getId());
|
||||||
|
|
||||||
ArticleDataList nodata = queryService.findRecentArticles(null, null, null, new Page(2, 10), user);
|
ArticleDataList nodata =
|
||||||
assertEquals(nodata.getCount(),2);
|
queryService.findRecentArticles(null, null, null, new Page(2, 10), user);
|
||||||
assertEquals(nodata.getArticleDatas().size(), 0);
|
assertEquals(nodata.getCount(), 2);
|
||||||
}
|
assertEquals(nodata.getArticleDatas().size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_query_article_by_author() {
|
public void should_query_article_by_author() {
|
||||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||||
userRepository.save(anotherUser);
|
userRepository.save(anotherUser);
|
||||||
|
|
||||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, anotherUser.getId());
|
Article anotherArticle =
|
||||||
articleRepository.save(anotherArticle);
|
new Article("new article", "desc", "body", Arrays.asList("test"), anotherUser.getId());
|
||||||
|
articleRepository.save(anotherArticle);
|
||||||
|
|
||||||
ArticleDataList recentArticles = queryService.findRecentArticles(null, user.getUsername(), null, new Page(), user);
|
ArticleDataList recentArticles =
|
||||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
queryService.findRecentArticles(null, user.getUsername(), null, new Page(), user);
|
||||||
assertEquals(recentArticles.getCount(), 1);
|
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||||
}
|
assertEquals(recentArticles.getCount(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_query_article_by_favorite() {
|
public void should_query_article_by_favorite() {
|
||||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||||
userRepository.save(anotherUser);
|
userRepository.save(anotherUser);
|
||||||
|
|
||||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, anotherUser.getId());
|
Article anotherArticle =
|
||||||
articleRepository.save(anotherArticle);
|
new Article("new article", "desc", "body", Arrays.asList("test"), anotherUser.getId());
|
||||||
|
articleRepository.save(anotherArticle);
|
||||||
|
|
||||||
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), anotherUser.getId());
|
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), anotherUser.getId());
|
||||||
articleFavoriteRepository.save(articleFavorite);
|
articleFavoriteRepository.save(articleFavorite);
|
||||||
|
|
||||||
ArticleDataList recentArticles = queryService.findRecentArticles(null, null, anotherUser.getUsername(), new Page(), anotherUser);
|
ArticleDataList recentArticles =
|
||||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
queryService.findRecentArticles(
|
||||||
assertEquals(recentArticles.getCount(), 1);
|
null, null, anotherUser.getUsername(), new Page(), anotherUser);
|
||||||
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||||
assertEquals(articleData.getId(), article.getId());
|
assertEquals(recentArticles.getCount(), 1);
|
||||||
assertEquals(articleData.getFavoritesCount(),1);
|
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
||||||
assertTrue(articleData.isFavorited());
|
assertEquals(articleData.getId(), article.getId());
|
||||||
}
|
assertEquals(articleData.getFavoritesCount(), 1);
|
||||||
|
assertTrue(articleData.isFavorited());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_query_article_by_tag() {
|
public void should_query_article_by_tag() {
|
||||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, user.getId());
|
Article anotherArticle =
|
||||||
articleRepository.save(anotherArticle);
|
new Article("new article", "desc", "body", Arrays.asList("test"), user.getId());
|
||||||
|
articleRepository.save(anotherArticle);
|
||||||
|
|
||||||
ArticleDataList recentArticles = queryService.findRecentArticles("spring", null, null, new Page(), user);
|
ArticleDataList recentArticles =
|
||||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
queryService.findRecentArticles("spring", null, null, new Page(), user);
|
||||||
assertEquals(recentArticles.getCount(), 1);
|
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||||
assertEquals(recentArticles.getArticleDatas().get(0).getId(), article.getId());
|
assertEquals(recentArticles.getCount(), 1);
|
||||||
|
assertEquals(recentArticles.getArticleDatas().get(0).getId(), article.getId());
|
||||||
|
|
||||||
ArticleDataList notag = queryService.findRecentArticles("notag", null, null, new Page(), user);
|
ArticleDataList notag = queryService.findRecentArticles("notag", null, null, new Page(), user);
|
||||||
assertEquals(notag.getCount(), 0);
|
assertEquals(notag.getCount(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_show_following_if_user_followed_author() {
|
public void should_show_following_if_user_followed_author() {
|
||||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||||
userRepository.save(anotherUser);
|
userRepository.save(anotherUser);
|
||||||
|
|
||||||
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
||||||
userRepository.saveRelation(followRelation);
|
userRepository.saveRelation(followRelation);
|
||||||
|
|
||||||
ArticleDataList recentArticles = queryService.findRecentArticles(null, null, null, new Page(), anotherUser);
|
ArticleDataList recentArticles =
|
||||||
assertEquals(recentArticles.getCount(), 1);
|
queryService.findRecentArticles(null, null, null, new Page(), anotherUser);
|
||||||
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
assertEquals(recentArticles.getCount(), 1);
|
||||||
assertTrue(articleData.getProfileData().isFollowing());
|
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
||||||
}
|
assertTrue(articleData.getProfileData().isFollowing());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_user_feed() {
|
public void should_get_user_feed() {
|
||||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||||
userRepository.save(anotherUser);
|
userRepository.save(anotherUser);
|
||||||
|
|
||||||
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
||||||
userRepository.saveRelation(followRelation);
|
userRepository.saveRelation(followRelation);
|
||||||
|
|
||||||
ArticleDataList userFeed = queryService.findUserFeed(user, new Page());
|
ArticleDataList userFeed = queryService.findUserFeed(user, new Page());
|
||||||
assertEquals(userFeed.getCount(), 0);
|
assertEquals(userFeed.getCount(), 0);
|
||||||
|
|
||||||
ArticleDataList anotherUserFeed = queryService.findUserFeed(anotherUser, new Page());
|
ArticleDataList anotherUserFeed = queryService.findUserFeed(anotherUser, new Page());
|
||||||
assertEquals(anotherUserFeed.getCount(), 1);
|
assertEquals(anotherUserFeed.getCount(), 1);
|
||||||
ArticleData articleData = anotherUserFeed.getArticleDatas().get(0);
|
ArticleData articleData = anotherUserFeed.getArticleDatas().get(0);
|
||||||
assertTrue(articleData.getProfileData().isFollowing());
|
assertTrue(articleData.getProfileData().isFollowing());
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,5 +1,8 @@
|
|||||||
package io.spring.application.comment;
|
package io.spring.application.comment;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import io.spring.application.CommentQueryService;
|
import io.spring.application.CommentQueryService;
|
||||||
import io.spring.application.data.CommentData;
|
import io.spring.application.data.CommentData;
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
@ -12,6 +15,9 @@ import io.spring.core.user.UserRepository;
|
|||||||
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
||||||
import io.spring.infrastructure.repository.MyBatisCommentRepository;
|
import io.spring.infrastructure.repository.MyBatisCommentRepository;
|
||||||
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -20,63 +26,57 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
@MybatisTest
|
@MybatisTest
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@Import({MyBatisCommentRepository.class, MyBatisUserRepository.class, CommentQueryService.class, MyBatisArticleRepository.class})
|
@Import({
|
||||||
|
MyBatisCommentRepository.class,
|
||||||
|
MyBatisUserRepository.class,
|
||||||
|
CommentQueryService.class,
|
||||||
|
MyBatisArticleRepository.class
|
||||||
|
})
|
||||||
public class CommentQueryServiceTest {
|
public class CommentQueryServiceTest {
|
||||||
@Autowired
|
@Autowired private CommentRepository commentRepository;
|
||||||
private CommentRepository commentRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private UserRepository userRepository;
|
||||||
private UserRepository userRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private CommentQueryService commentQueryService;
|
||||||
private CommentQueryService commentQueryService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
private User user;
|
private User user;
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() {
|
public void setUp() {
|
||||||
user = new User("aisensiy@test.com", "aisensiy", "123", "", "");
|
user = new User("aisensiy@test.com", "aisensiy", "123", "", "");
|
||||||
userRepository.save(user);
|
userRepository.save(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_read_comment_success() {
|
public void should_read_comment_success() {
|
||||||
Comment comment = new Comment("content", user.getId(), "123");
|
Comment comment = new Comment("content", user.getId(), "123");
|
||||||
commentRepository.save(comment);
|
commentRepository.save(comment);
|
||||||
|
|
||||||
Optional<CommentData> optional = commentQueryService.findById(comment.getId(), user);
|
Optional<CommentData> optional = commentQueryService.findById(comment.getId(), user);
|
||||||
assertTrue(optional.isPresent());
|
assertTrue(optional.isPresent());
|
||||||
CommentData commentData = optional.get();
|
CommentData commentData = optional.get();
|
||||||
assertEquals(commentData.getProfileData().getUsername(), user.getUsername());
|
assertEquals(commentData.getProfileData().getUsername(), user.getUsername());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_read_comments_of_article() {
|
public void should_read_comments_of_article() {
|
||||||
Article article = new Article("title", "desc", "body", new String[]{"java"}, user.getId());
|
Article article = new Article("title", "desc", "body", Arrays.asList("java"), user.getId());
|
||||||
articleRepository.save(article);
|
articleRepository.save(article);
|
||||||
|
|
||||||
User user2 = new User("user2@email.com", "user2", "123", "", "");
|
User user2 = new User("user2@email.com", "user2", "123", "", "");
|
||||||
userRepository.save(user2);
|
userRepository.save(user2);
|
||||||
userRepository.saveRelation(new FollowRelation(user.getId(), user2.getId()));
|
userRepository.saveRelation(new FollowRelation(user.getId(), user2.getId()));
|
||||||
|
|
||||||
Comment comment1 = new Comment("content1", user.getId(), article.getId());
|
Comment comment1 = new Comment("content1", user.getId(), article.getId());
|
||||||
commentRepository.save(comment1);
|
commentRepository.save(comment1);
|
||||||
Comment comment2 = new Comment("content2", user2.getId(), article.getId());
|
Comment comment2 = new Comment("content2", user2.getId(), article.getId());
|
||||||
commentRepository.save(comment2);
|
commentRepository.save(comment2);
|
||||||
|
|
||||||
List<CommentData> comments = commentQueryService.findByArticleId(article.getId(), user);
|
List<CommentData> comments = commentQueryService.findByArticleId(article.getId(), user);
|
||||||
assertEquals(comments.size(), 2);
|
assertEquals(comments.size(), 2);
|
||||||
|
}
|
||||||
}
|
|
||||||
}
|
}
|
@ -1,9 +1,12 @@
|
|||||||
package io.spring.application.tag;
|
package io.spring.application.tag;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import io.spring.application.TagsQueryService;
|
import io.spring.application.TagsQueryService;
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
import io.spring.core.article.ArticleRepository;
|
import io.spring.core.article.ArticleRepository;
|
||||||
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
||||||
|
import java.util.Arrays;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
|
import org.mybatis.spring.boot.test.autoconfigure.MybatisTest;
|
||||||
@ -11,21 +14,17 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@MybatisTest
|
@MybatisTest
|
||||||
@Import({TagsQueryService.class, MyBatisArticleRepository.class})
|
@Import({TagsQueryService.class, MyBatisArticleRepository.class})
|
||||||
public class TagsQueryServiceTest {
|
public class TagsQueryServiceTest {
|
||||||
@Autowired
|
@Autowired private TagsQueryService tagsQueryService;
|
||||||
private TagsQueryService tagsQueryService;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_all_tags() {
|
public void should_get_all_tags() {
|
||||||
articleRepository.save(new Article("test", "test", "test", new String[]{"java"}, "123"));
|
articleRepository.save(new Article("test", "test", "test", Arrays.asList("java"), "123"));
|
||||||
assertTrue(tagsQueryService.allTags().contains("java"));
|
assertTrue(tagsQueryService.allTags().contains("java"));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,39 +1,40 @@
|
|||||||
package io.spring.core.article;
|
package io.spring.core.article;
|
||||||
|
|
||||||
import org.junit.Test;
|
|
||||||
|
|
||||||
import static org.hamcrest.CoreMatchers.is;
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
import static org.hamcrest.MatcherAssert.assertThat;
|
import static org.hamcrest.MatcherAssert.assertThat;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
public class ArticleTest {
|
public class ArticleTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_right_slug() {
|
public void should_get_right_slug() {
|
||||||
Article article = new Article("a new title", "desc", "body", new String[]{"java"}, "123");
|
Article article = new Article("a new title", "desc", "body", Arrays.asList("java"), "123");
|
||||||
assertThat(article.getSlug(), is("a-new-title"));
|
assertThat(article.getSlug(), is("a-new-title"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_right_slug_with_number_in_title() {
|
public void should_get_right_slug_with_number_in_title() {
|
||||||
Article article = new Article("a new title 2", "desc", "body", new String[]{"java"}, "123");
|
Article article = new Article("a new title 2", "desc", "body", Arrays.asList("java"), "123");
|
||||||
assertThat(article.getSlug(), is("a-new-title-2"));
|
assertThat(article.getSlug(), is("a-new-title-2"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_get_lower_case_slug() {
|
public void should_get_lower_case_slug() {
|
||||||
Article article = new Article("A NEW TITLE", "desc", "body", new String[]{"java"}, "123");
|
Article article = new Article("A NEW TITLE", "desc", "body", Arrays.asList("java"), "123");
|
||||||
assertThat(article.getSlug(), is("a-new-title"));
|
assertThat(article.getSlug(), is("a-new-title"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_handle_other_language() {
|
public void should_handle_other_language() {
|
||||||
Article article = new Article("中文:标题", "desc", "body", new String[]{"java"}, "123");
|
Article article = new Article("中文:标题", "desc", "body", Arrays.asList("java"), "123");
|
||||||
assertThat(article.getSlug(), is("中文-标题"));
|
assertThat(article.getSlug(), is("中文-标题"));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_handle_commas() {
|
public void should_handle_commas() {
|
||||||
Article article = new Article("what?the.hell,w", "desc", "body", new String[]{"java"}, "123");
|
Article article = new Article("what?the.hell,w", "desc", "body", Arrays.asList("java"), "123");
|
||||||
assertThat(article.getSlug(), is("what-the-hell-w"));
|
assertThat(article.getSlug(), is("what-the-hell-w"));
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,10 +1,13 @@
|
|||||||
package io.spring.infrastructure.article;
|
package io.spring.infrastructure.article;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertNull;
|
||||||
|
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
import io.spring.core.article.ArticleRepository;
|
import io.spring.core.article.ArticleRepository;
|
||||||
import io.spring.core.user.User;
|
import io.spring.core.user.User;
|
||||||
import io.spring.core.user.UserRepository;
|
import io.spring.core.user.UserRepository;
|
||||||
import io.spring.infrastructure.mybatis.mapper.ArticleMapper;
|
import io.spring.infrastructure.mybatis.mapper.ArticleMapper;
|
||||||
|
import java.util.Arrays;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -12,35 +15,29 @@ import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabas
|
|||||||
import org.springframework.boot.test.context.SpringBootTest;
|
import org.springframework.boot.test.context.SpringBootTest;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNull;
|
|
||||||
|
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
@AutoConfigureTestDatabase
|
@AutoConfigureTestDatabase
|
||||||
public class ArticleRepositoryTransactionTest {
|
public class ArticleRepositoryTransactionTest {
|
||||||
@Autowired
|
@Autowired private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private UserRepository userRepository;
|
||||||
private UserRepository userRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private ArticleMapper articleMapper;
|
||||||
private ArticleMapper articleMapper;
|
|
||||||
|
|
||||||
|
@Test
|
||||||
@Test
|
public void transactional_test() {
|
||||||
public void transactional_test() {
|
User user = new User("aisensiy@gmail.com", "aisensiy", "123", "bio", "default");
|
||||||
User user = new User("aisensiy@gmail.com", "aisensiy", "123", "bio", "default");
|
userRepository.save(user);
|
||||||
userRepository.save(user);
|
Article article =
|
||||||
Article article = new Article("test", "desc", "body", new String[]{"java", "spring"}, user.getId());
|
new Article("test", "desc", "body", Arrays.asList("java", "spring"), user.getId());
|
||||||
articleRepository.save(article);
|
articleRepository.save(article);
|
||||||
Article anotherArticle = new Article("test", "desc", "body", new String[]{"java", "spring", "other"}, user.getId());
|
Article anotherArticle =
|
||||||
try {
|
new Article("test", "desc", "body", Arrays.asList("java", "spring", "other"), user.getId());
|
||||||
articleRepository.save(anotherArticle);
|
try {
|
||||||
} catch (Exception e) {
|
articleRepository.save(anotherArticle);
|
||||||
assertNull(articleMapper.findTag("other"));
|
} catch (Exception e) {
|
||||||
}
|
assertNull(articleMapper.findTag("other"));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,10 @@
|
|||||||
package io.spring.infrastructure.article;
|
package io.spring.infrastructure.article;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotEquals;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import io.spring.core.article.Article;
|
import io.spring.core.article.Article;
|
||||||
import io.spring.core.article.ArticleRepository;
|
import io.spring.core.article.ArticleRepository;
|
||||||
import io.spring.core.article.Tag;
|
import io.spring.core.article.Tag;
|
||||||
@ -7,6 +12,8 @@ import io.spring.core.user.User;
|
|||||||
import io.spring.core.user.UserRepository;
|
import io.spring.core.user.UserRepository;
|
||||||
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
||||||
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Optional;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
@ -15,63 +22,53 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.context.annotation.Import;
|
import org.springframework.context.annotation.Import;
|
||||||
import org.springframework.test.context.junit4.SpringRunner;
|
import org.springframework.test.context.junit4.SpringRunner;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
import static org.junit.Assert.assertFalse;
|
|
||||||
import static org.junit.Assert.assertNotEquals;
|
|
||||||
import static org.junit.Assert.assertTrue;
|
|
||||||
|
|
||||||
@MybatisTest
|
@MybatisTest
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@Import({MyBatisArticleRepository.class, MyBatisUserRepository.class})
|
@Import({MyBatisArticleRepository.class, MyBatisUserRepository.class})
|
||||||
public class MyBatisArticleRepositoryTest {
|
public class MyBatisArticleRepositoryTest {
|
||||||
@Autowired
|
@Autowired private ArticleRepository articleRepository;
|
||||||
private ArticleRepository articleRepository;
|
|
||||||
|
|
||||||
@Autowired
|
@Autowired private UserRepository userRepository;
|
||||||
private UserRepository userRepository;
|
|
||||||
|
|
||||||
private Article article;
|
private Article article;
|
||||||
|
|
||||||
|
@Before
|
||||||
|
public void setUp() {
|
||||||
|
User user = new User("aisensiy@gmail.com", "aisensiy", "123", "bio", "default");
|
||||||
|
userRepository.save(user);
|
||||||
|
article = new Article("test", "desc", "body", Arrays.asList("java", "spring"), user.getId());
|
||||||
|
}
|
||||||
|
|
||||||
@Before
|
@Test
|
||||||
public void setUp() {
|
public void should_create_and_fetch_article_success() {
|
||||||
User user = new User("aisensiy@gmail.com", "aisensiy", "123", "bio", "default");
|
articleRepository.save(article);
|
||||||
userRepository.save(user);
|
Optional<Article> optional = articleRepository.findById(article.getId());
|
||||||
article = new Article("test", "desc", "body", new String[]{"java", "spring"}, user.getId());
|
assertTrue(optional.isPresent());
|
||||||
}
|
assertEquals(optional.get(), article);
|
||||||
|
assertTrue(optional.get().getTags().contains(new Tag("java")));
|
||||||
|
assertTrue(optional.get().getTags().contains(new Tag("spring")));
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void should_create_and_fetch_article_success() {
|
public void should_update_and_fetch_article_success() {
|
||||||
articleRepository.save(article);
|
articleRepository.save(article);
|
||||||
Optional<Article> optional = articleRepository.findById(article.getId());
|
|
||||||
assertTrue(optional.isPresent());
|
|
||||||
assertEquals(optional.get(), article);
|
|
||||||
assertTrue(optional.get().getTags().contains(new Tag("java")));
|
|
||||||
assertTrue(optional.get().getTags().contains(new Tag("spring")));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
String newTitle = "new test 2";
|
||||||
public void should_update_and_fetch_article_success() {
|
article.update(newTitle, "", "");
|
||||||
articleRepository.save(article);
|
articleRepository.save(article);
|
||||||
|
System.out.println(article.getSlug());
|
||||||
|
Optional<Article> optional = articleRepository.findBySlug(article.getSlug());
|
||||||
|
assertTrue(optional.isPresent());
|
||||||
|
Article fetched = optional.get();
|
||||||
|
assertEquals(fetched.getTitle(), newTitle);
|
||||||
|
assertNotEquals(fetched.getBody(), "");
|
||||||
|
}
|
||||||
|
|
||||||
String newTitle = "new test 2";
|
@Test
|
||||||
article.update(newTitle, "", "");
|
public void should_delete_article() {
|
||||||
articleRepository.save(article);
|
articleRepository.save(article);
|
||||||
System.out.println(article.getSlug());
|
|
||||||
Optional<Article> optional = articleRepository.findBySlug(article.getSlug());
|
|
||||||
assertTrue(optional.isPresent());
|
|
||||||
Article fetched = optional.get();
|
|
||||||
assertEquals(fetched.getTitle(), newTitle);
|
|
||||||
assertNotEquals(fetched.getBody(), "");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
articleRepository.remove(article);
|
||||||
public void should_delete_article() {
|
assertFalse(articleRepository.findById(article.getId()).isPresent());
|
||||||
articleRepository.save(article);
|
}
|
||||||
|
|
||||||
articleRepository.remove(article);
|
|
||||||
assertFalse(articleRepository.findById(article.getId()).isPresent());
|
|
||||||
}
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue
Block a user