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;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import io.spring.api.exception.NoAuthorizationException;
|
||||
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.article.ArticleCommandService;
|
||||
import io.spring.application.article.UpdateArticleParam;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
import io.spring.core.service.AuthorizationService;
|
||||
import io.spring.core.user.User;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.validation.Valid;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
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.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "/articles/{slug}")
|
||||
public class ArticleApi {
|
||||
private ArticleQueryService articleQueryService;
|
||||
private ArticleRepository articleRepository;
|
||||
private ArticleQueryService articleQueryService;
|
||||
private ArticleRepository articleRepository;
|
||||
private ArticleCommandService articleCommandService;
|
||||
|
||||
@Autowired
|
||||
public ArticleApi(ArticleQueryService articleQueryService, ArticleRepository articleRepository) {
|
||||
this.articleQueryService = articleQueryService;
|
||||
this.articleRepository = articleRepository;
|
||||
}
|
||||
@Autowired
|
||||
public ArticleApi(
|
||||
ArticleQueryService articleQueryService,
|
||||
ArticleRepository articleRepository,
|
||||
ArticleCommandService articleCommandService) {
|
||||
this.articleQueryService = articleQueryService;
|
||||
this.articleRepository = articleRepository;
|
||||
this.articleCommandService = articleCommandService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity<?> article(@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user) {
|
||||
return articleQueryService.findBySlug(slug, user)
|
||||
.map(articleData -> ResponseEntity.ok(articleResponse(articleData)))
|
||||
.orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
@GetMapping
|
||||
public ResponseEntity<?> article(
|
||||
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||
return articleQueryService
|
||||
.findBySlug(slug, user)
|
||||
.map(articleData -> ResponseEntity.ok(articleResponse(articleData)))
|
||||
.orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public ResponseEntity<?> updateArticle(@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user,
|
||||
@Valid @RequestBody UpdateArticleParam updateArticleParam) {
|
||||
return articleRepository.findBySlug(slug).map(article -> {
|
||||
if (!AuthorizationService.canWriteArticle(user, article)) {
|
||||
@PutMapping
|
||||
public ResponseEntity<?> updateArticle(
|
||||
@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user,
|
||||
@Valid @RequestBody UpdateArticleParam updateArticleParam) {
|
||||
return articleRepository
|
||||
.findBySlug(slug)
|
||||
.map(
|
||||
article -> {
|
||||
if (!AuthorizationService.canWriteArticle(user, article)) {
|
||||
throw new NoAuthorizationException();
|
||||
}
|
||||
article.update(
|
||||
updateArticleParam.getTitle(),
|
||||
updateArticleParam.getDescription(),
|
||||
updateArticleParam.getBody());
|
||||
articleRepository.save(article);
|
||||
return ResponseEntity.ok(articleResponse(articleQueryService.findBySlug(slug, user).get()));
|
||||
}).orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
}
|
||||
articleCommandService.updateArticle(article, updateArticleParam);
|
||||
return ResponseEntity.ok(
|
||||
articleResponse(articleQueryService.findBySlug(slug, user).get()));
|
||||
})
|
||||
.orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public ResponseEntity deleteArticle(@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user) {
|
||||
return articleRepository.findBySlug(slug).map(article -> {
|
||||
if (!AuthorizationService.canWriteArticle(user, article)) {
|
||||
@DeleteMapping
|
||||
public ResponseEntity deleteArticle(
|
||||
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||
return articleRepository
|
||||
.findBySlug(slug)
|
||||
.map(
|
||||
article -> {
|
||||
if (!AuthorizationService.canWriteArticle(user, article)) {
|
||||
throw new NoAuthorizationException();
|
||||
}
|
||||
articleRepository.remove(article);
|
||||
return ResponseEntity.noContent().build();
|
||||
}).orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
}
|
||||
articleRepository.remove(article);
|
||||
return ResponseEntity.noContent().build();
|
||||
})
|
||||
.orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
|
||||
private Map<String, Object> articleResponse(ArticleData articleData) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("article", articleData);
|
||||
}};
|
||||
}
|
||||
}
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@JsonRootName("article")
|
||||
class UpdateArticleParam {
|
||||
private String title = "";
|
||||
private String body = "";
|
||||
private String description = "";
|
||||
private Map<String, Object> articleResponse(ArticleData articleData) {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put("article", articleData);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,13 +1,14 @@
|
||||
package io.spring.api;
|
||||
|
||||
import io.spring.api.exception.ResourceNotFoundException;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.application.ArticleQueryService;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.core.article.Article;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
import io.spring.core.favorite.ArticleFavorite;
|
||||
import io.spring.core.favorite.ArticleFavoriteRepository;
|
||||
import io.spring.core.user.User;
|
||||
import java.util.HashMap;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
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.RestController;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "articles/{slug}/favorite")
|
||||
public class ArticleFavoriteApi {
|
||||
private ArticleFavoriteRepository articleFavoriteRepository;
|
||||
private ArticleRepository articleRepository;
|
||||
private ArticleQueryService articleQueryService;
|
||||
private ArticleFavoriteRepository articleFavoriteRepository;
|
||||
private ArticleRepository articleRepository;
|
||||
private ArticleQueryService articleQueryService;
|
||||
|
||||
@Autowired
|
||||
public ArticleFavoriteApi(ArticleFavoriteRepository articleFavoriteRepository,
|
||||
ArticleRepository articleRepository,
|
||||
ArticleQueryService articleQueryService) {
|
||||
this.articleFavoriteRepository = articleFavoriteRepository;
|
||||
this.articleRepository = articleRepository;
|
||||
this.articleQueryService = articleQueryService;
|
||||
}
|
||||
@Autowired
|
||||
public ArticleFavoriteApi(
|
||||
ArticleFavoriteRepository articleFavoriteRepository,
|
||||
ArticleRepository articleRepository,
|
||||
ArticleQueryService articleQueryService) {
|
||||
this.articleFavoriteRepository = articleFavoriteRepository;
|
||||
this.articleRepository = articleRepository;
|
||||
this.articleQueryService = articleQueryService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity favoriteArticle(@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user) {
|
||||
Article article = getArticle(slug);
|
||||
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), user.getId());
|
||||
articleFavoriteRepository.save(articleFavorite);
|
||||
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
||||
}
|
||||
@PostMapping
|
||||
public ResponseEntity favoriteArticle(
|
||||
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||
Article article =
|
||||
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), user.getId());
|
||||
articleFavoriteRepository.save(articleFavorite);
|
||||
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
||||
}
|
||||
|
||||
@DeleteMapping
|
||||
public ResponseEntity unfavoriteArticle(@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user) {
|
||||
Article article = getArticle(slug);
|
||||
articleFavoriteRepository.find(article.getId(), user.getId()).ifPresent(favorite -> {
|
||||
articleFavoriteRepository.remove(favorite);
|
||||
});
|
||||
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
||||
}
|
||||
@DeleteMapping
|
||||
public ResponseEntity unfavoriteArticle(
|
||||
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||
Article article =
|
||||
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||
articleFavoriteRepository
|
||||
.find(article.getId(), user.getId())
|
||||
.ifPresent(
|
||||
favorite -> {
|
||||
articleFavoriteRepository.remove(favorite);
|
||||
});
|
||||
return responseArticleData(articleQueryService.findBySlug(slug, user).get());
|
||||
}
|
||||
|
||||
private ResponseEntity<HashMap<String, Object>> responseArticleData(final ArticleData articleData) {
|
||||
return ResponseEntity.ok(new HashMap<String, Object>() {{
|
||||
private ResponseEntity<HashMap<String, Object>> responseArticleData(
|
||||
final ArticleData articleData) {
|
||||
return ResponseEntity.ok(
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
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;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import io.spring.application.ArticleQueryService;
|
||||
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.ArticleRepository;
|
||||
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 javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
import javax.validation.Payload;
|
||||
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.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
@ -33,26 +21,20 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
@RestController
|
||||
@RequestMapping(path = "/articles")
|
||||
public class ArticlesApi {
|
||||
private ArticleRepository articleRepository;
|
||||
private ArticleCommandService articleCommandService;
|
||||
private ArticleQueryService articleQueryService;
|
||||
|
||||
@Autowired
|
||||
public ArticlesApi(ArticleRepository articleRepository, ArticleQueryService articleQueryService) {
|
||||
this.articleRepository = articleRepository;
|
||||
public ArticlesApi(
|
||||
ArticleCommandService articleCommandService, ArticleQueryService articleQueryService) {
|
||||
this.articleCommandService = articleCommandService;
|
||||
this.articleQueryService = articleQueryService;
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity createArticle(
|
||||
@Valid @RequestBody NewArticleParam newArticleParam, @AuthenticationPrincipal User user) {
|
||||
Article article =
|
||||
new Article(
|
||||
newArticleParam.getTitle(),
|
||||
newArticleParam.getDescription(),
|
||||
newArticleParam.getBody(),
|
||||
newArticleParam.getTagList(),
|
||||
user.getId());
|
||||
articleRepository.save(article);
|
||||
Article article = articleCommandService.createArticle(newArticleParam, user);
|
||||
return ResponseEntity.ok(
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
@ -82,43 +64,3 @@ public class ArticlesApi {
|
||||
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,
|
||||
@AuthenticationPrincipal User user,
|
||||
@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());
|
||||
commentRepository.save(comment);
|
||||
return ResponseEntity.status(201)
|
||||
@ -61,7 +62,8 @@ public class CommentsApi {
|
||||
@GetMapping
|
||||
public ResponseEntity getComments(
|
||||
@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);
|
||||
return ResponseEntity.ok(
|
||||
new HashMap<String, Object>() {
|
||||
@ -76,7 +78,8 @@ public class CommentsApi {
|
||||
@PathVariable("slug") String slug,
|
||||
@PathVariable("id") String commentId,
|
||||
@AuthenticationPrincipal User user) {
|
||||
Article article = findArticle(slug);
|
||||
Article article =
|
||||
articleRepository.findBySlug(slug).orElseThrow(ResourceNotFoundException::new);
|
||||
return commentRepository
|
||||
.findById(article.getId(), commentId)
|
||||
.map(
|
||||
@ -90,13 +93,6 @@ public class CommentsApi {
|
||||
.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) {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
|
@ -1,28 +1,18 @@
|
||||
package io.spring.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import io.spring.application.UserQueryService;
|
||||
import io.spring.application.data.UserData;
|
||||
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.UserRepository;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import javax.validation.Constraint;
|
||||
import javax.validation.ConstraintValidator;
|
||||
import javax.validation.ConstraintValidatorContext;
|
||||
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.http.ResponseEntity;
|
||||
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.PutMapping;
|
||||
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.data.UserData;
|
||||
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.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 java.util.HashMap;
|
||||
import java.util.Map;
|
||||
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.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@ -36,34 +31,27 @@ import org.springframework.web.bind.annotation.RestController;
|
||||
public class UsersApi {
|
||||
private UserRepository userRepository;
|
||||
private UserQueryService userQueryService;
|
||||
private String defaultImage;
|
||||
private EncryptService encryptService;
|
||||
private JwtService jwtService;
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
public UsersApi(
|
||||
UserRepository userRepository,
|
||||
UserQueryService userQueryService,
|
||||
EncryptService encryptService,
|
||||
@Value("${image.default}") String defaultImage,
|
||||
JwtService jwtService) {
|
||||
JwtService jwtService,
|
||||
UserService userService) {
|
||||
this.userRepository = userRepository;
|
||||
this.userQueryService = userQueryService;
|
||||
this.encryptService = encryptService;
|
||||
this.defaultImage = defaultImage;
|
||||
this.jwtService = jwtService;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/users", method = POST)
|
||||
public ResponseEntity createUser(@Valid @RequestBody RegisterParam registerParam) {
|
||||
User user =
|
||||
new User(
|
||||
registerParam.getEmail(),
|
||||
registerParam.getUsername(),
|
||||
encryptService.encrypt(registerParam.getPassword()),
|
||||
"",
|
||||
defaultImage);
|
||||
userRepository.save(user);
|
||||
User user = userService.createUser(registerParam);
|
||||
UserData userData = userQueryService.findById(user.getId()).get();
|
||||
return ResponseEntity.status(201)
|
||||
.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
|
||||
@JsonRootName("user")
|
||||
@NoArgsConstructor
|
||||
@ -143,20 +90,3 @@ class LoginParam {
|
||||
@NotBlank(message = "can't be empty")
|
||||
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;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
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.UrlBasedCorsConfigurationSource;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
|
||||
@Configuration
|
||||
@EnableWebSecurity
|
||||
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@ -32,11 +32,12 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
|
||||
if (h2ConsoleEnabled)
|
||||
if (h2ConsoleEnabled) {
|
||||
http.authorizeRequests()
|
||||
.antMatchers("/h2-console", "/h2-console/**").permitAll()
|
||||
.and()
|
||||
.headers().frameOptions().sameOrigin();
|
||||
}
|
||||
|
||||
http.csrf().disable()
|
||||
.cors()
|
||||
@ -46,6 +47,8 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
|
||||
.authorizeRequests()
|
||||
.antMatchers(HttpMethod.OPTIONS).permitAll()
|
||||
.antMatchers("/graphiql").permitAll()
|
||||
.antMatchers("/graphql").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/articles/feed").authenticated()
|
||||
.antMatchers(HttpMethod.POST, "/users", "/users/login").permitAll()
|
||||
.antMatchers(HttpMethod.GET, "/articles/**", "/profiles/**", "/tags").permitAll()
|
||||
@ -62,7 +65,7 @@ public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
"GET", "POST", "PUT", "DELETE", "PATCH"));
|
||||
// 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'.
|
||||
configuration.setAllowCredentials(true);
|
||||
configuration.setAllowCredentials(false);
|
||||
// setAllowedHeaders is important! Without it, OPTIONS preflight request
|
||||
// will fail with 403 Invalid CORS request
|
||||
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.UserData;
|
||||
import io.spring.infrastructure.mybatis.readservice.UserReadService;
|
||||
import io.spring.core.user.User;
|
||||
import io.spring.infrastructure.mybatis.readservice.UserReadService;
|
||||
import io.spring.infrastructure.mybatis.readservice.UserRelationshipQueryService;
|
||||
import java.util.Optional;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
@Component
|
||||
public class ProfileQueryService {
|
||||
private UserReadService userReadService;
|
||||
private UserRelationshipQueryService userRelationshipQueryService;
|
||||
private UserReadService userReadService;
|
||||
private UserRelationshipQueryService userRelationshipQueryService;
|
||||
|
||||
@Autowired
|
||||
public ProfileQueryService(UserReadService userReadService, UserRelationshipQueryService userRelationshipQueryService) {
|
||||
this.userReadService = userReadService;
|
||||
this.userRelationshipQueryService = userRelationshipQueryService;
|
||||
}
|
||||
@Autowired
|
||||
public ProfileQueryService(
|
||||
UserReadService userReadService, UserRelationshipQueryService userRelationshipQueryService) {
|
||||
this.userReadService = userReadService;
|
||||
this.userRelationshipQueryService = userRelationshipQueryService;
|
||||
}
|
||||
|
||||
public Optional<ProfileData> findByUsername(String username, User currentUser) {
|
||||
UserData userData = userReadService.findByUsername(username);
|
||||
if (userData == null) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
ProfileData profileData = new ProfileData(
|
||||
userData.getId(),
|
||||
userData.getUsername(),
|
||||
userData.getBio(),
|
||||
userData.getImage(),
|
||||
userRelationshipQueryService.isUserFollowing(currentUser.getId(), userData.getId()));
|
||||
return Optional.of(profileData);
|
||||
}
|
||||
public Optional<ProfileData> findByUsername(String username, User currentUser) {
|
||||
UserData userData = userReadService.findByUsername(username);
|
||||
if (userData == null) {
|
||||
return Optional.empty();
|
||||
} else {
|
||||
ProfileData profileData =
|
||||
new ProfileData(
|
||||
userData.getId(),
|
||||
userData.getUsername(),
|
||||
userData.getBio(),
|
||||
userData.getImage(),
|
||||
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;
|
||||
|
||||
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.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
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
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = {"id"})
|
||||
public class Article {
|
||||
private String userId;
|
||||
private String id;
|
||||
private String slug;
|
||||
private String title;
|
||||
private String description;
|
||||
private String body;
|
||||
private List<Tag> tags;
|
||||
private DateTime createdAt;
|
||||
private DateTime updatedAt;
|
||||
private String userId;
|
||||
private String id;
|
||||
private String slug;
|
||||
private String title;
|
||||
private String description;
|
||||
private String body;
|
||||
private List<Tag> tags;
|
||||
private DateTime createdAt;
|
||||
private DateTime updatedAt;
|
||||
|
||||
public Article(String title, String description, String body, String[] tagList, String userId) {
|
||||
this(title, description, body, tagList, userId, new DateTime());
|
||||
}
|
||||
public Article(
|
||||
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) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.slug = toSlug(title);
|
||||
this.title = title;
|
||||
this.description = description;
|
||||
this.body = body;
|
||||
this.tags = Arrays.stream(tagList).collect(toSet()).stream().map(Tag::new).collect(toList());
|
||||
this.userId = userId;
|
||||
this.createdAt = createdAt;
|
||||
this.updatedAt = createdAt;
|
||||
}
|
||||
public Article(
|
||||
String title,
|
||||
String description,
|
||||
String body,
|
||||
List<String> tagList,
|
||||
String userId,
|
||||
DateTime createdAt) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.slug = toSlug(title);
|
||||
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) {
|
||||
if (!"".equals(title)) {
|
||||
this.title = title;
|
||||
this.slug = toSlug(title);
|
||||
}
|
||||
if (!"".equals(description)) {
|
||||
this.description = description;
|
||||
}
|
||||
if (!"".equals(body)) {
|
||||
this.body = body;
|
||||
}
|
||||
this.updatedAt = new DateTime();
|
||||
public void update(String title, String description, String body) {
|
||||
if (!Util.isEmpty(title)) {
|
||||
this.title = title;
|
||||
this.slug = toSlug(title);
|
||||
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) {
|
||||
return title.toLowerCase().replaceAll("[\\&|[\\uFE30-\\uFFA0]|\\’|\\”|\\s\\?\\,\\.]+", "-");
|
||||
}
|
||||
public static String toSlug(String title) {
|
||||
return title.toLowerCase().replaceAll("[\\&|[\\uFE30-\\uFFA0]|\\’|\\”|\\s\\?\\,\\.]+", "-");
|
||||
}
|
||||
}
|
||||
|
@ -1,50 +1,50 @@
|
||||
package io.spring.core.user;
|
||||
|
||||
import io.spring.Util;
|
||||
import java.util.UUID;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@Getter
|
||||
@NoArgsConstructor
|
||||
@EqualsAndHashCode(of = {"id"})
|
||||
public class User {
|
||||
private String id;
|
||||
private String email;
|
||||
private String username;
|
||||
private String password;
|
||||
private String bio;
|
||||
private String image;
|
||||
private String id;
|
||||
private String email;
|
||||
private String username;
|
||||
private String password;
|
||||
private String bio;
|
||||
private String image;
|
||||
|
||||
public User(String email, String username, String password, String bio, String image) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.email = email;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.bio = bio;
|
||||
this.image = image;
|
||||
public User(String email, String username, String password, String bio, String image) {
|
||||
this.id = UUID.randomUUID().toString();
|
||||
this.email = email;
|
||||
this.username = username;
|
||||
this.password = password;
|
||||
this.bio = bio;
|
||||
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 (!"".equals(email)) {
|
||||
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(username)) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
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.body commentBody,
|
||||
C.created_at commentCreatedAt,
|
||||
C.article_id commentArticleId,
|
||||
<include refid="io.spring.infrastructure.mybatis.readservice.ArticleReadService.profileColumns"/>
|
||||
from comments C
|
||||
left join users U
|
||||
|
@ -34,6 +34,7 @@
|
||||
<result column="commentBody" property="body"/>
|
||||
<result column="commentCreatedAt" property="createdAt"/>
|
||||
<result column="commentCreatedAt" property="updatedAt"/>
|
||||
<result column="commentArticleId" property="articleId"/>
|
||||
<association property="profileData" resultMap="profileData"/>
|
||||
</resultMap>
|
||||
</mapper>
|
@ -1,15 +1,28 @@
|
||||
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.spring.JacksonCustomizations;
|
||||
import io.spring.TestHelper;
|
||||
import io.spring.api.security.WebSecurityConfig;
|
||||
import io.spring.application.ArticleQueryService;
|
||||
import io.spring.application.article.ArticleCommandService;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.application.data.ProfileData;
|
||||
import io.spring.core.article.Article;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
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.format.ISODateTimeFormat;
|
||||
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.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})
|
||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||
public class ArticleApiTest extends TestWithCurrentUser {
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private ArticleQueryService articleQueryService;
|
||||
@MockBean private ArticleQueryService articleQueryService;
|
||||
|
||||
@MockBean
|
||||
private ArticleRepository articleRepository;
|
||||
@MockBean private ArticleRepository articleRepository;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
}
|
||||
@MockBean ArticleCommandService articleCommandService;
|
||||
|
||||
@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", new String[]{"java", "spring", "jpg"}, user.getId(), time);
|
||||
ArticleData articleData = TestHelper.getArticleDataFromArticleAndUser(article, user);
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
}
|
||||
|
||||
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()
|
||||
.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)));
|
||||
when(articleQueryService.findBySlug(eq(slug), eq(null))).thenReturn(Optional.of(articleData));
|
||||
|
||||
}
|
||||
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
|
||||
public void should_404_if_article_not_found() throws Exception {
|
||||
when(articleQueryService.findBySlug(anyString(), any())).thenReturn(Optional.empty());
|
||||
RestAssuredMockMvc.when()
|
||||
.get("/articles/not-exists")
|
||||
.then()
|
||||
.statusCode(404);
|
||||
}
|
||||
@Test
|
||||
public void should_404_if_article_not_found() throws Exception {
|
||||
when(articleQueryService.findBySlug(anyString(), any())).thenReturn(Optional.empty());
|
||||
RestAssuredMockMvc.when().get("/articles/not-exists").then().statusCode(404);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_update_article_content_success() throws Exception {
|
||||
String title = "new-title";
|
||||
String body = "new body";
|
||||
String description = "new description";
|
||||
Map<String, Object> updateParam = prepareUpdateParam(title, body, description);
|
||||
@Test
|
||||
public void should_update_article_content_success() throws Exception {
|
||||
String title = "new-title";
|
||||
String body = "new body";
|
||||
String description = "new 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(articleQueryService.findBySlug(eq(article.getSlug()), eq(user))).thenReturn(Optional.of(articleData));
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
when(articleQueryService.findBySlug(eq(article.getSlug()), eq(user)))
|
||||
.thenReturn(Optional.of(articleData));
|
||||
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(updateParam)
|
||||
.when()
|
||||
.put("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body("article.slug", equalTo(articleData.getSlug()));
|
||||
}
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(updateParam)
|
||||
.when()
|
||||
.put("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body("article.slug", equalTo(articleData.getSlug()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_403_if_not_author_to_update_article() throws Exception {
|
||||
String title = "new-title";
|
||||
String body = "new body";
|
||||
String description = "new description";
|
||||
Map<String, Object> updateParam = prepareUpdateParam(title, body, description);
|
||||
@Test
|
||||
public void should_get_403_if_not_author_to_update_article() throws Exception {
|
||||
String title = "new-title";
|
||||
String body = "new body";
|
||||
String description = "new 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();
|
||||
ArticleData articleData = new ArticleData(
|
||||
DateTime time = new DateTime();
|
||||
ArticleData articleData =
|
||||
new ArticleData(
|
||||
article.getId(),
|
||||
article.getSlug(),
|
||||
article.getTitle(),
|
||||
@ -128,66 +135,82 @@ public class ArticleApiTest extends TestWithCurrentUser {
|
||||
time,
|
||||
time,
|
||||
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(articleQueryService.findBySlug(eq(article.getSlug()), eq(user))).thenReturn(Optional.of(articleData));
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
when(articleQueryService.findBySlug(eq(article.getSlug()), eq(user)))
|
||||
.thenReturn(Optional.of(articleData));
|
||||
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(updateParam)
|
||||
.when()
|
||||
.put("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(403);
|
||||
}
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(updateParam)
|
||||
.when()
|
||||
.put("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(403);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_delete_article_success() throws Exception {
|
||||
String title = "title";
|
||||
String body = "body";
|
||||
String description = "description";
|
||||
@Test
|
||||
public void should_delete_article_success() throws Exception {
|
||||
String title = "title";
|
||||
String body = "body";
|
||||
String description = "description";
|
||||
|
||||
Article article = new Article(title, description, body, new String[]{"java", "spring", "jpg"}, user.getId());
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
Article article =
|
||||
new Article(title, description, body, Arrays.asList("java", "spring", "jpg"), user.getId());
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(204);
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(204);
|
||||
|
||||
verify(articleRepository).remove(eq(article));
|
||||
}
|
||||
verify(articleRepository).remove(eq(article));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_403_if_not_author_delete_article() throws Exception {
|
||||
String title = "new-title";
|
||||
String body = "new body";
|
||||
String description = "new description";
|
||||
@Test
|
||||
public void should_403_if_not_author_delete_article() throws Exception {
|
||||
String title = "new-title";
|
||||
String body = "new body";
|
||||
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));
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(403);
|
||||
}
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}", article.getSlug())
|
||||
.then()
|
||||
.statusCode(403);
|
||||
}
|
||||
|
||||
private HashMap<String, Object> prepareUpdateParam(final String title, final String body, final String description) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("article", new HashMap<String, Object>() {{
|
||||
private HashMap<String, Object> prepareUpdateParam(
|
||||
final String title, final String body, final String description) {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"article",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("title", title);
|
||||
put("body", body);
|
||||
put("description", description);
|
||||
}});
|
||||
}};
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,12 @@
|
||||
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.spring.JacksonCustomizations;
|
||||
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.ArticleFavoriteRepository;
|
||||
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.Test;
|
||||
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.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)
|
||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||
public class ArticleFavoriteApiTest extends TestWithCurrentUser {
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private ArticleFavoriteRepository articleFavoriteRepository;
|
||||
@MockBean private ArticleFavoriteRepository articleFavoriteRepository;
|
||||
|
||||
@MockBean
|
||||
private ArticleRepository articleRepository;
|
||||
@MockBean private ArticleRepository articleRepository;
|
||||
|
||||
@MockBean
|
||||
private ArticleQueryService articleQueryService;
|
||||
@MockBean private ArticleQueryService articleQueryService;
|
||||
|
||||
private Article article;
|
||||
private Article article;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
||||
article = new Article("title", "desc", "body", new String[]{"java"}, anotherUser.getId());
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
ArticleData articleData = new ArticleData(
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
||||
article = new Article("title", "desc", "body", Arrays.asList("java"), anotherUser.getId());
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
ArticleData articleData =
|
||||
new ArticleData(
|
||||
article.getId(),
|
||||
article.getSlug(),
|
||||
article.getTitle(),
|
||||
@ -70,36 +67,37 @@ public class ArticleFavoriteApiTest extends TestWithCurrentUser {
|
||||
anotherUser.getUsername(),
|
||||
anotherUser.getBio(),
|
||||
anotherUser.getImage(),
|
||||
false
|
||||
));
|
||||
when(articleQueryService.findBySlug(eq(articleData.getSlug()), eq(user))).thenReturn(Optional.of(articleData));
|
||||
}
|
||||
false));
|
||||
when(articleQueryService.findBySlug(eq(articleData.getSlug()), eq(user)))
|
||||
.thenReturn(Optional.of(articleData));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_favorite_an_article_success() throws Exception {
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.post("/articles/{slug}/favorite", article.getSlug())
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body("article.id", equalTo(article.getId()));
|
||||
@Test
|
||||
public void should_favorite_an_article_success() throws Exception {
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.post("/articles/{slug}/favorite", article.getSlug())
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body("article.id", equalTo(article.getId()));
|
||||
|
||||
verify(articleFavoriteRepository).save(any());
|
||||
}
|
||||
verify(articleFavoriteRepository).save(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
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())));
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}/favorite", article.getSlug())
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body("article.id", equalTo(article.getId()));
|
||||
verify(articleFavoriteRepository).remove(new ArticleFavorite(article.getId(), user.getId()));
|
||||
}
|
||||
@Test
|
||||
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())));
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}/favorite", article.getSlug())
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(200)
|
||||
.body("article.id", equalTo(article.getId()));
|
||||
verify(articleFavoriteRepository).remove(new ArticleFavorite(article.getId(), user.getId()));
|
||||
}
|
||||
}
|
||||
|
@ -1,6 +1,7 @@
|
||||
package io.spring.api;
|
||||
|
||||
import static io.restassured.module.mockmvc.RestAssuredMockMvc.given;
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.hamcrest.core.IsEqual.equalTo;
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.ArgumentMatchers.eq;
|
||||
@ -11,12 +12,12 @@ import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||
import io.spring.JacksonCustomizations;
|
||||
import io.spring.api.security.WebSecurityConfig;
|
||||
import io.spring.application.ArticleQueryService;
|
||||
import io.spring.application.article.ArticleCommandService;
|
||||
import io.spring.application.data.ArticleData;
|
||||
import io.spring.application.data.ProfileData;
|
||||
import io.spring.core.article.Article;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
@ -33,10 +34,10 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@MockBean private ArticleRepository articleRepository;
|
||||
|
||||
@MockBean private ArticleQueryService articleQueryService;
|
||||
|
||||
@MockBean private ArticleCommandService articleCommandService;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
@ -50,7 +51,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
String slug = "how-to-train-your-dragon";
|
||||
String description = "Ever wonder how?";
|
||||
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);
|
||||
|
||||
ArticleData articleData =
|
||||
@ -64,9 +65,12 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
0,
|
||||
new DateTime(),
|
||||
new DateTime(),
|
||||
Arrays.asList(tagList),
|
||||
tagList,
|
||||
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()))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
@ -87,7 +91,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
.body("article.author.username", equalTo(user.getUsername()))
|
||||
.body("article.author.id", equalTo(null));
|
||||
|
||||
verify(articleRepository).save(any());
|
||||
verify(articleCommandService).createArticle(any(), any());
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -96,7 +100,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
String description = "Ever wonder how?";
|
||||
String body = "";
|
||||
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()
|
||||
.contentType("application/json")
|
||||
@ -117,7 +121,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
String description = "Ever wonder how?";
|
||||
String body = "You have to believe";
|
||||
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 =
|
||||
new ArticleData(
|
||||
@ -130,7 +134,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
0,
|
||||
new DateTime(),
|
||||
new DateTime(),
|
||||
Arrays.asList(tagList),
|
||||
asList(tagList),
|
||||
new ProfileData("userid", user.getUsername(), user.getBio(), user.getImage(), false));
|
||||
|
||||
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any()))
|
||||
@ -150,7 +154,7 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
}
|
||||
|
||||
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>() {
|
||||
{
|
||||
put(
|
||||
|
@ -1,5 +1,12 @@
|
||||
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.spring.JacksonCustomizations;
|
||||
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.CommentRepository;
|
||||
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.Test;
|
||||
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.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)
|
||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||
public class CommentsApiTest extends TestWithCurrentUser {
|
||||
|
||||
@MockBean
|
||||
private ArticleRepository articleRepository;
|
||||
@MockBean private ArticleRepository articleRepository;
|
||||
|
||||
@MockBean
|
||||
private CommentRepository commentRepository;
|
||||
@MockBean
|
||||
private CommentQueryService commentQueryService;
|
||||
@MockBean private CommentRepository commentRepository;
|
||||
@MockBean private CommentQueryService commentQueryService;
|
||||
|
||||
private Article article;
|
||||
private CommentData commentData;
|
||||
private Comment comment;
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
private Article article;
|
||||
private CommentData commentData;
|
||||
private Comment comment;
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
super.setUp();
|
||||
article = new Article("title", "desc", "body", new String[]{"test", "java"}, user.getId());
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
comment = new Comment("comment", user.getId(), article.getId());
|
||||
commentData = new CommentData(
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
super.setUp();
|
||||
article = new Article("title", "desc", "body", Arrays.asList("test", "java"), user.getId());
|
||||
when(articleRepository.findBySlug(eq(article.getSlug()))).thenReturn(Optional.of(article));
|
||||
comment = new Comment("comment", user.getId(), article.getId());
|
||||
commentData =
|
||||
new CommentData(
|
||||
comment.getId(),
|
||||
comment.getBody(),
|
||||
comment.getArticleId(),
|
||||
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
|
||||
public void should_create_comment_success() throws Exception {
|
||||
Map<String, Object> param = new HashMap<String, Object>() {{
|
||||
put("comment", new HashMap<String, Object>() {{
|
||||
put("body", "comment content");
|
||||
}});
|
||||
}};
|
||||
@Test
|
||||
public void should_create_comment_success() throws Exception {
|
||||
Map<String, Object> param =
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
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()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/articles/{slug}/comments", article.getSlug())
|
||||
.then()
|
||||
.statusCode(201)
|
||||
.body("comment.body", equalTo(commentData.getBody()));
|
||||
}
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/articles/{slug}/comments", article.getSlug())
|
||||
.then()
|
||||
.statusCode(201)
|
||||
.body("comment.body", equalTo(commentData.getBody()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_422_with_empty_body() throws Exception {
|
||||
Map<String, Object> param = new HashMap<String, Object>() {{
|
||||
put("comment", new HashMap<String, Object>() {{
|
||||
put("body", "");
|
||||
}});
|
||||
}};
|
||||
@Test
|
||||
public void should_get_422_with_empty_body() throws Exception {
|
||||
Map<String, Object> param =
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"comment",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("body", "");
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/articles/{slug}/comments", article.getSlug())
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.body("errors.body[0]", equalTo("can't be empty"));
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.header("Authorization", "Token " + token)
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/articles/{slug}/comments", article.getSlug())
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.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
|
||||
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
|
||||
public void should_delete_comment_success() throws Exception {
|
||||
when(commentRepository.findById(eq(article.getId()), eq(comment.getId())))
|
||||
.thenReturn(Optional.of(comment));
|
||||
|
||||
@Test
|
||||
public void should_delete_comment_success() throws Exception {
|
||||
when(commentRepository.findById(eq(article.getId()), eq(comment.getId()))).thenReturn(Optional.of(comment));
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}/comments/{id}", article.getSlug(), comment.getId())
|
||||
.then()
|
||||
.statusCode(204);
|
||||
}
|
||||
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}/comments/{id}", article.getSlug(), comment.getId())
|
||||
.then()
|
||||
.statusCode(204);
|
||||
}
|
||||
@Test
|
||||
public void should_get_403_if_not_author_of_article_or_author_of_comment_when_delete_comment()
|
||||
throws Exception {
|
||||
User anotherUser = new User("other@example.com", "other", "123", "", "");
|
||||
when(userRepository.findByUsername(eq(anotherUser.getUsername())))
|
||||
.thenReturn(Optional.of(anotherUser));
|
||||
when(jwtService.getSubFromToken(any())).thenReturn(Optional.of(anotherUser.getId()));
|
||||
when(userRepository.findById(eq(anotherUser.getId())))
|
||||
.thenReturn(Optional.ofNullable(anotherUser));
|
||||
|
||||
@Test
|
||||
public void should_get_403_if_not_author_of_article_or_author_of_comment_when_delete_comment() throws Exception {
|
||||
User anotherUser = new User("other@example.com", "other", "123", "", "");
|
||||
when(userRepository.findByUsername(eq(anotherUser.getUsername()))).thenReturn(Optional.of(anotherUser));
|
||||
when(jwtService.getSubFromToken(any())).thenReturn(Optional.of(anotherUser.getId()));
|
||||
when(userRepository.findById(eq(anotherUser.getId()))).thenReturn(Optional.ofNullable(anotherUser));
|
||||
|
||||
when(commentRepository.findById(eq(article.getId()), eq(comment.getId()))).thenReturn(Optional.of(comment));
|
||||
String token = jwtService.toToken(anotherUser);
|
||||
when(userRepository.findById(eq(anotherUser.getId()))).thenReturn(Optional.of(anotherUser));
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.delete("/articles/{slug}/comments/{id}", article.getSlug(), comment.getId())
|
||||
.then()
|
||||
.statusCode(403);
|
||||
|
||||
}
|
||||
when(commentRepository.findById(eq(article.getId()), eq(comment.getId())))
|
||||
.thenReturn(Optional.of(comment));
|
||||
String token = jwtService.toToken(anotherUser);
|
||||
when(userRepository.findById(eq(anotherUser.getId()))).thenReturn(Optional.of(anotherUser));
|
||||
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.api.security.WebSecurityConfig;
|
||||
import io.spring.application.UserQueryService;
|
||||
import io.spring.application.user.UserService;
|
||||
import io.spring.core.user.User;
|
||||
import io.spring.infrastructure.service.NaiveEncryptService;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
@ -28,7 +30,8 @@ import org.springframework.test.web.servlet.MockMvc;
|
||||
WebSecurityConfig.class,
|
||||
JacksonCustomizations.class,
|
||||
UserService.class,
|
||||
ValidationAutoConfiguration.class
|
||||
ValidationAutoConfiguration.class,
|
||||
NaiveEncryptService.class
|
||||
})
|
||||
public class CurrentUserApiTest extends TestWithCurrentUser {
|
||||
|
||||
|
@ -1,10 +1,17 @@
|
||||
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.spring.JacksonCustomizations;
|
||||
import io.spring.api.security.WebSecurityConfig;
|
||||
import io.spring.application.ArticleQueryService;
|
||||
import io.spring.application.Page;
|
||||
import io.spring.application.article.ArticleCommandService;
|
||||
import io.spring.application.data.ArticleDataList;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
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.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)
|
||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||
public class ListArticleApiTest extends TestWithCurrentUser {
|
||||
@MockBean
|
||||
private ArticleRepository articleRepository;
|
||||
@MockBean private ArticleRepository articleRepository;
|
||||
|
||||
@MockBean
|
||||
private ArticleQueryService articleQueryService;
|
||||
@MockBean private ArticleQueryService articleQueryService;
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@MockBean private ArticleCommandService articleCommandService;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
super.setUp();
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
}
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@Test
|
||||
public void should_get_default_article_list() throws Exception {
|
||||
ArticleDataList articleDataList = new ArticleDataList(
|
||||
@Override
|
||||
@Before
|
||||
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);
|
||||
when(articleQueryService.findRecentArticles(eq(null), eq(null), eq(null), eq(new Page(0, 20)), eq(null))).thenReturn(articleDataList);
|
||||
RestAssuredMockMvc.when()
|
||||
.get("/articles")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(200);
|
||||
}
|
||||
when(articleQueryService.findRecentArticles(
|
||||
eq(null), eq(null), eq(null), eq(new Page(0, 20)), eq(null)))
|
||||
.thenReturn(articleDataList);
|
||||
RestAssuredMockMvc.when().get("/articles").prettyPeek().then().statusCode(200);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_feeds_401_without_login() throws Exception {
|
||||
RestAssuredMockMvc.when()
|
||||
.get("/articles/feed")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(401);
|
||||
}
|
||||
@Test
|
||||
public void should_get_feeds_401_without_login() throws Exception {
|
||||
RestAssuredMockMvc.when().get("/articles/feed").prettyPeek().then().statusCode(401);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_feeds_success() throws Exception {
|
||||
ArticleDataList articleDataList = new ArticleDataList(
|
||||
@Test
|
||||
public void should_get_feeds_success() throws Exception {
|
||||
ArticleDataList articleDataList =
|
||||
new ArticleDataList(
|
||||
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()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.get("/articles/feed")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(200);
|
||||
}
|
||||
given()
|
||||
.header("Authorization", "Token " + token)
|
||||
.when()
|
||||
.get("/articles/feed")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(200);
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@ import io.spring.JacksonCustomizations;
|
||||
import io.spring.api.security.WebSecurityConfig;
|
||||
import io.spring.application.UserQueryService;
|
||||
import io.spring.application.data.UserData;
|
||||
import io.spring.application.user.UserService;
|
||||
import io.spring.core.service.JwtService;
|
||||
import io.spring.core.user.User;
|
||||
import io.spring.core.user.UserRepository;
|
||||
@ -46,6 +47,9 @@ public class UsersApiTest {
|
||||
@MockBean private JwtService jwtService;
|
||||
|
||||
@MockBean private UserReadService userReadService;
|
||||
|
||||
@MockBean private UserService userService;
|
||||
|
||||
private String defaultAvatar;
|
||||
|
||||
@Before
|
||||
@ -64,6 +68,8 @@ public class UsersApiTest {
|
||||
UserData userData = new UserData(user.getId(), email, username, "", defaultAvatar);
|
||||
when(userReadService.findById(any())).thenReturn(userData);
|
||||
|
||||
when(userService.createUser(any())).thenReturn(user);
|
||||
|
||||
when(userRepository.findByUsername(eq(username))).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.token", equalTo("123"));
|
||||
|
||||
verify(userRepository).save(any());
|
||||
verify(userService).createUser(any());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -1,5 +1,10 @@
|
||||
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.Page;
|
||||
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.MyBatisArticleRepository;
|
||||
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -23,161 +30,170 @@ import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.context.annotation.Import;
|
||||
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)
|
||||
@MybatisTest
|
||||
@Import({
|
||||
ArticleQueryService.class,
|
||||
MyBatisUserRepository.class,
|
||||
MyBatisArticleRepository.class,
|
||||
MyBatisArticleFavoriteRepository.class})
|
||||
ArticleQueryService.class,
|
||||
MyBatisUserRepository.class,
|
||||
MyBatisArticleRepository.class,
|
||||
MyBatisArticleFavoriteRepository.class
|
||||
})
|
||||
public class ArticleQueryServiceTest {
|
||||
@Autowired
|
||||
private ArticleQueryService queryService;
|
||||
@Autowired private ArticleQueryService queryService;
|
||||
|
||||
@Autowired
|
||||
private ArticleRepository articleRepository;
|
||||
@Autowired private ArticleRepository articleRepository;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Autowired private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private ArticleFavoriteRepository articleFavoriteRepository;
|
||||
@Autowired private ArticleFavoriteRepository articleFavoriteRepository;
|
||||
|
||||
private User user;
|
||||
private Article article;
|
||||
private User user;
|
||||
private Article article;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
user = new User("aisensiy@gmail.com", "aisensiy", "123", "", "");
|
||||
userRepository.save(user);
|
||||
article = new Article("test", "desc", "body", new String[]{"java", "spring"}, user.getId(), new DateTime());
|
||||
articleRepository.save(article);
|
||||
}
|
||||
@Before
|
||||
public void setUp() {
|
||||
user = new User("aisensiy@gmail.com", "aisensiy", "123", "", "");
|
||||
userRepository.save(user);
|
||||
article =
|
||||
new Article(
|
||||
"test", "desc", "body", Arrays.asList("java", "spring"), user.getId(), new DateTime());
|
||||
articleRepository.save(article);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_fetch_article_success() {
|
||||
Optional<ArticleData> optional = queryService.findById(article.getId(), user);
|
||||
assertTrue(optional.isPresent());
|
||||
@Test
|
||||
public void should_fetch_article_success() {
|
||||
Optional<ArticleData> optional = queryService.findById(article.getId(), user);
|
||||
assertTrue(optional.isPresent());
|
||||
|
||||
ArticleData fetched = optional.get();
|
||||
assertEquals(fetched.getFavoritesCount(),0);
|
||||
assertFalse(fetched.isFavorited());
|
||||
assertNotNull(fetched.getCreatedAt());
|
||||
assertNotNull(fetched.getUpdatedAt());
|
||||
assertTrue(fetched.getTagList().contains("java"));
|
||||
}
|
||||
ArticleData fetched = optional.get();
|
||||
assertEquals(fetched.getFavoritesCount(), 0);
|
||||
assertFalse(fetched.isFavorited());
|
||||
assertNotNull(fetched.getCreatedAt());
|
||||
assertNotNull(fetched.getUpdatedAt());
|
||||
assertTrue(fetched.getTagList().contains("java"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_article_with_right_favorite_and_favorite_count() {
|
||||
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
articleFavoriteRepository.save(new ArticleFavorite(article.getId(), anotherUser.getId()));
|
||||
@Test
|
||||
public void should_get_article_with_right_favorite_and_favorite_count() {
|
||||
User anotherUser = new User("other@test.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
articleFavoriteRepository.save(new ArticleFavorite(article.getId(), anotherUser.getId()));
|
||||
|
||||
Optional<ArticleData> optional = queryService.findById(article.getId(), anotherUser);
|
||||
assertTrue(optional.isPresent());
|
||||
Optional<ArticleData> optional = queryService.findById(article.getId(), anotherUser);
|
||||
assertTrue(optional.isPresent());
|
||||
|
||||
ArticleData articleData = optional.get();
|
||||
assertEquals(articleData.getFavoritesCount(), 1);
|
||||
assertTrue(articleData.isFavorited());
|
||||
}
|
||||
ArticleData articleData = optional.get();
|
||||
assertEquals(articleData.getFavoritesCount(), 1);
|
||||
assertTrue(articleData.isFavorited());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_default_article_list() {
|
||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, user.getId(), new DateTime().minusHours(1));
|
||||
articleRepository.save(anotherArticle);
|
||||
@Test
|
||||
public void should_get_default_article_list() {
|
||||
Article 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);
|
||||
assertEquals(recentArticles.getCount(), 2);
|
||||
assertEquals(recentArticles.getArticleDatas().size(), 2);
|
||||
assertEquals(recentArticles.getArticleDatas().get(0).getId(), article.getId());
|
||||
ArticleDataList recentArticles =
|
||||
queryService.findRecentArticles(null, null, null, new Page(), user);
|
||||
assertEquals(recentArticles.getCount(), 2);
|
||||
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);
|
||||
assertEquals(nodata.getCount(),2);
|
||||
assertEquals(nodata.getArticleDatas().size(), 0);
|
||||
}
|
||||
ArticleDataList nodata =
|
||||
queryService.findRecentArticles(null, null, null, new Page(2, 10), user);
|
||||
assertEquals(nodata.getCount(), 2);
|
||||
assertEquals(nodata.getArticleDatas().size(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_query_article_by_author() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
@Test
|
||||
public void should_query_article_by_author() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
|
||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, anotherUser.getId());
|
||||
articleRepository.save(anotherArticle);
|
||||
Article 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);
|
||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
}
|
||||
ArticleDataList recentArticles =
|
||||
queryService.findRecentArticles(null, user.getUsername(), null, new Page(), user);
|
||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_query_article_by_favorite() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
@Test
|
||||
public void should_query_article_by_favorite() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
|
||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, anotherUser.getId());
|
||||
articleRepository.save(anotherArticle);
|
||||
Article anotherArticle =
|
||||
new Article("new article", "desc", "body", Arrays.asList("test"), anotherUser.getId());
|
||||
articleRepository.save(anotherArticle);
|
||||
|
||||
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), anotherUser.getId());
|
||||
articleFavoriteRepository.save(articleFavorite);
|
||||
ArticleFavorite articleFavorite = new ArticleFavorite(article.getId(), anotherUser.getId());
|
||||
articleFavoriteRepository.save(articleFavorite);
|
||||
|
||||
ArticleDataList recentArticles = queryService.findRecentArticles(null, null, anotherUser.getUsername(), new Page(), anotherUser);
|
||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
||||
assertEquals(articleData.getId(), article.getId());
|
||||
assertEquals(articleData.getFavoritesCount(),1);
|
||||
assertTrue(articleData.isFavorited());
|
||||
}
|
||||
ArticleDataList recentArticles =
|
||||
queryService.findRecentArticles(
|
||||
null, null, anotherUser.getUsername(), new Page(), anotherUser);
|
||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
||||
assertEquals(articleData.getId(), article.getId());
|
||||
assertEquals(articleData.getFavoritesCount(), 1);
|
||||
assertTrue(articleData.isFavorited());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_query_article_by_tag() {
|
||||
Article anotherArticle = new Article("new article", "desc", "body", new String[]{"test"}, user.getId());
|
||||
articleRepository.save(anotherArticle);
|
||||
@Test
|
||||
public void should_query_article_by_tag() {
|
||||
Article 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);
|
||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
assertEquals(recentArticles.getArticleDatas().get(0).getId(), article.getId());
|
||||
ArticleDataList recentArticles =
|
||||
queryService.findRecentArticles("spring", null, null, new Page(), user);
|
||||
assertEquals(recentArticles.getArticleDatas().size(), 1);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
assertEquals(recentArticles.getArticleDatas().get(0).getId(), article.getId());
|
||||
|
||||
ArticleDataList notag = queryService.findRecentArticles("notag", null, null, new Page(), user);
|
||||
assertEquals(notag.getCount(), 0);
|
||||
}
|
||||
ArticleDataList notag = queryService.findRecentArticles("notag", null, null, new Page(), user);
|
||||
assertEquals(notag.getCount(), 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_show_following_if_user_followed_author() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
@Test
|
||||
public void should_show_following_if_user_followed_author() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
|
||||
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
||||
userRepository.saveRelation(followRelation);
|
||||
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
||||
userRepository.saveRelation(followRelation);
|
||||
|
||||
ArticleDataList recentArticles = queryService.findRecentArticles(null, null, null, new Page(), anotherUser);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
||||
assertTrue(articleData.getProfileData().isFollowing());
|
||||
}
|
||||
ArticleDataList recentArticles =
|
||||
queryService.findRecentArticles(null, null, null, new Page(), anotherUser);
|
||||
assertEquals(recentArticles.getCount(), 1);
|
||||
ArticleData articleData = recentArticles.getArticleDatas().get(0);
|
||||
assertTrue(articleData.getProfileData().isFollowing());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_user_feed() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
@Test
|
||||
public void should_get_user_feed() {
|
||||
User anotherUser = new User("other@email.com", "other", "123", "", "");
|
||||
userRepository.save(anotherUser);
|
||||
|
||||
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
||||
userRepository.saveRelation(followRelation);
|
||||
FollowRelation followRelation = new FollowRelation(anotherUser.getId(), user.getId());
|
||||
userRepository.saveRelation(followRelation);
|
||||
|
||||
ArticleDataList userFeed = queryService.findUserFeed(user, new Page());
|
||||
assertEquals(userFeed.getCount(), 0);
|
||||
ArticleDataList userFeed = queryService.findUserFeed(user, new Page());
|
||||
assertEquals(userFeed.getCount(), 0);
|
||||
|
||||
ArticleDataList anotherUserFeed = queryService.findUserFeed(anotherUser, new Page());
|
||||
assertEquals(anotherUserFeed.getCount(), 1);
|
||||
ArticleData articleData = anotherUserFeed.getArticleDatas().get(0);
|
||||
assertTrue(articleData.getProfileData().isFollowing());
|
||||
}
|
||||
ArticleDataList anotherUserFeed = queryService.findUserFeed(anotherUser, new Page());
|
||||
assertEquals(anotherUserFeed.getCount(), 1);
|
||||
ArticleData articleData = anotherUserFeed.getArticleDatas().get(0);
|
||||
assertTrue(articleData.getProfileData().isFollowing());
|
||||
}
|
||||
}
|
@ -1,5 +1,8 @@
|
||||
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.data.CommentData;
|
||||
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.MyBatisCommentRepository;
|
||||
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.Test;
|
||||
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.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
|
||||
@RunWith(SpringRunner.class)
|
||||
@Import({MyBatisCommentRepository.class, MyBatisUserRepository.class, CommentQueryService.class, MyBatisArticleRepository.class})
|
||||
@Import({
|
||||
MyBatisCommentRepository.class,
|
||||
MyBatisUserRepository.class,
|
||||
CommentQueryService.class,
|
||||
MyBatisArticleRepository.class
|
||||
})
|
||||
public class CommentQueryServiceTest {
|
||||
@Autowired
|
||||
private CommentRepository commentRepository;
|
||||
@Autowired private CommentRepository commentRepository;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Autowired private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private CommentQueryService commentQueryService;
|
||||
@Autowired private CommentQueryService commentQueryService;
|
||||
|
||||
@Autowired
|
||||
private ArticleRepository articleRepository;
|
||||
@Autowired private ArticleRepository articleRepository;
|
||||
|
||||
private User user;
|
||||
private User user;
|
||||
|
||||
@Before
|
||||
public void setUp() {
|
||||
user = new User("aisensiy@test.com", "aisensiy", "123", "", "");
|
||||
userRepository.save(user);
|
||||
}
|
||||
@Before
|
||||
public void setUp() {
|
||||
user = new User("aisensiy@test.com", "aisensiy", "123", "", "");
|
||||
userRepository.save(user);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_read_comment_success() {
|
||||
Comment comment = new Comment("content", user.getId(), "123");
|
||||
commentRepository.save(comment);
|
||||
@Test
|
||||
public void should_read_comment_success() {
|
||||
Comment comment = new Comment("content", user.getId(), "123");
|
||||
commentRepository.save(comment);
|
||||
|
||||
Optional<CommentData> optional = commentQueryService.findById(comment.getId(), user);
|
||||
assertTrue(optional.isPresent());
|
||||
CommentData commentData = optional.get();
|
||||
assertEquals(commentData.getProfileData().getUsername(), user.getUsername());
|
||||
}
|
||||
Optional<CommentData> optional = commentQueryService.findById(comment.getId(), user);
|
||||
assertTrue(optional.isPresent());
|
||||
CommentData commentData = optional.get();
|
||||
assertEquals(commentData.getProfileData().getUsername(), user.getUsername());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_read_comments_of_article() {
|
||||
Article article = new Article("title", "desc", "body", new String[]{"java"}, user.getId());
|
||||
articleRepository.save(article);
|
||||
@Test
|
||||
public void should_read_comments_of_article() {
|
||||
Article article = new Article("title", "desc", "body", Arrays.asList("java"), user.getId());
|
||||
articleRepository.save(article);
|
||||
|
||||
User user2 = new User("user2@email.com", "user2", "123", "", "");
|
||||
userRepository.save(user2);
|
||||
userRepository.saveRelation(new FollowRelation(user.getId(), user2.getId()));
|
||||
User user2 = new User("user2@email.com", "user2", "123", "", "");
|
||||
userRepository.save(user2);
|
||||
userRepository.saveRelation(new FollowRelation(user.getId(), user2.getId()));
|
||||
|
||||
Comment comment1 = new Comment("content1", user.getId(), article.getId());
|
||||
commentRepository.save(comment1);
|
||||
Comment comment2 = new Comment("content2", user2.getId(), article.getId());
|
||||
commentRepository.save(comment2);
|
||||
Comment comment1 = new Comment("content1", user.getId(), article.getId());
|
||||
commentRepository.save(comment1);
|
||||
Comment comment2 = new Comment("content2", user2.getId(), article.getId());
|
||||
commentRepository.save(comment2);
|
||||
|
||||
List<CommentData> comments = commentQueryService.findByArticleId(article.getId(), user);
|
||||
assertEquals(comments.size(), 2);
|
||||
|
||||
}
|
||||
List<CommentData> comments = commentQueryService.findByArticleId(article.getId(), user);
|
||||
assertEquals(comments.size(), 2);
|
||||
}
|
||||
}
|
@ -1,9 +1,12 @@
|
||||
package io.spring.application.tag;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
import io.spring.application.TagsQueryService;
|
||||
import io.spring.core.article.Article;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
import io.spring.infrastructure.repository.MyBatisArticleRepository;
|
||||
import java.util.Arrays;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
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.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.junit.Assert.assertTrue;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@MybatisTest
|
||||
@Import({TagsQueryService.class, MyBatisArticleRepository.class})
|
||||
public class TagsQueryServiceTest {
|
||||
@Autowired
|
||||
private TagsQueryService tagsQueryService;
|
||||
@Autowired private TagsQueryService tagsQueryService;
|
||||
|
||||
@Autowired
|
||||
private ArticleRepository articleRepository;
|
||||
@Autowired private ArticleRepository articleRepository;
|
||||
|
||||
@Test
|
||||
public void should_get_all_tags() {
|
||||
articleRepository.save(new Article("test", "test", "test", new String[]{"java"}, "123"));
|
||||
assertTrue(tagsQueryService.allTags().contains("java"));
|
||||
}
|
||||
@Test
|
||||
public void should_get_all_tags() {
|
||||
articleRepository.save(new Article("test", "test", "test", Arrays.asList("java"), "123"));
|
||||
assertTrue(tagsQueryService.allTags().contains("java"));
|
||||
}
|
||||
}
|
@ -1,39 +1,40 @@
|
||||
package io.spring.core.article;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import static org.hamcrest.CoreMatchers.is;
|
||||
import static org.hamcrest.MatcherAssert.assertThat;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ArticleTest {
|
||||
|
||||
@Test
|
||||
public void should_get_right_slug() {
|
||||
Article article = new Article("a new title", "desc", "body", new String[]{"java"}, "123");
|
||||
assertThat(article.getSlug(), is("a-new-title"));
|
||||
}
|
||||
@Test
|
||||
public void should_get_right_slug() {
|
||||
Article article = new Article("a new title", "desc", "body", Arrays.asList("java"), "123");
|
||||
assertThat(article.getSlug(), is("a-new-title"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_right_slug_with_number_in_title() {
|
||||
Article article = new Article("a new title 2", "desc", "body", new String[]{"java"}, "123");
|
||||
assertThat(article.getSlug(), is("a-new-title-2"));
|
||||
}
|
||||
@Test
|
||||
public void should_get_right_slug_with_number_in_title() {
|
||||
Article article = new Article("a new title 2", "desc", "body", Arrays.asList("java"), "123");
|
||||
assertThat(article.getSlug(), is("a-new-title-2"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_lower_case_slug() {
|
||||
Article article = new Article("A NEW TITLE", "desc", "body", new String[]{"java"}, "123");
|
||||
assertThat(article.getSlug(), is("a-new-title"));
|
||||
}
|
||||
@Test
|
||||
public void should_get_lower_case_slug() {
|
||||
Article article = new Article("A NEW TITLE", "desc", "body", Arrays.asList("java"), "123");
|
||||
assertThat(article.getSlug(), is("a-new-title"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_handle_other_language() {
|
||||
Article article = new Article("中文:标题", "desc", "body", new String[]{"java"}, "123");
|
||||
assertThat(article.getSlug(), is("中文-标题"));
|
||||
}
|
||||
@Test
|
||||
public void should_handle_other_language() {
|
||||
Article article = new Article("中文:标题", "desc", "body", Arrays.asList("java"), "123");
|
||||
assertThat(article.getSlug(), is("中文-标题"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_handle_commas() {
|
||||
Article article = new Article("what?the.hell,w", "desc", "body", new String[]{"java"}, "123");
|
||||
assertThat(article.getSlug(), is("what-the-hell-w"));
|
||||
}
|
||||
@Test
|
||||
public void should_handle_commas() {
|
||||
Article article = new Article("what?the.hell,w", "desc", "body", Arrays.asList("java"), "123");
|
||||
assertThat(article.getSlug(), is("what-the-hell-w"));
|
||||
}
|
||||
}
|
@ -1,10 +1,13 @@
|
||||
package io.spring.infrastructure.article;
|
||||
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
import io.spring.core.article.Article;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
import io.spring.core.user.User;
|
||||
import io.spring.core.user.UserRepository;
|
||||
import io.spring.infrastructure.mybatis.mapper.ArticleMapper;
|
||||
import java.util.Arrays;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
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.test.context.junit4.SpringRunner;
|
||||
|
||||
import static org.junit.Assert.assertFalse;
|
||||
import static org.junit.Assert.assertNull;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
@AutoConfigureTestDatabase
|
||||
public class ArticleRepositoryTransactionTest {
|
||||
@Autowired
|
||||
private ArticleRepository articleRepository;
|
||||
@Autowired private ArticleRepository articleRepository;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Autowired private UserRepository userRepository;
|
||||
|
||||
@Autowired
|
||||
private ArticleMapper articleMapper;
|
||||
@Autowired private ArticleMapper articleMapper;
|
||||
|
||||
|
||||
@Test
|
||||
public void transactional_test() {
|
||||
User user = new User("aisensiy@gmail.com", "aisensiy", "123", "bio", "default");
|
||||
userRepository.save(user);
|
||||
Article article = new Article("test", "desc", "body", new String[]{"java", "spring"}, user.getId());
|
||||
articleRepository.save(article);
|
||||
Article anotherArticle = new Article("test", "desc", "body", new String[]{"java", "spring", "other"}, user.getId());
|
||||
try {
|
||||
articleRepository.save(anotherArticle);
|
||||
} catch (Exception e) {
|
||||
assertNull(articleMapper.findTag("other"));
|
||||
}
|
||||
@Test
|
||||
public void transactional_test() {
|
||||
User user = new User("aisensiy@gmail.com", "aisensiy", "123", "bio", "default");
|
||||
userRepository.save(user);
|
||||
Article article =
|
||||
new Article("test", "desc", "body", Arrays.asList("java", "spring"), user.getId());
|
||||
articleRepository.save(article);
|
||||
Article anotherArticle =
|
||||
new Article("test", "desc", "body", Arrays.asList("java", "spring", "other"), user.getId());
|
||||
try {
|
||||
articleRepository.save(anotherArticle);
|
||||
} catch (Exception e) {
|
||||
assertNull(articleMapper.findTag("other"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,10 @@
|
||||
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.ArticleRepository;
|
||||
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.infrastructure.repository.MyBatisArticleRepository;
|
||||
import io.spring.infrastructure.repository.MyBatisUserRepository;
|
||||
import java.util.Arrays;
|
||||
import java.util.Optional;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
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.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
|
||||
@RunWith(SpringRunner.class)
|
||||
@Import({MyBatisArticleRepository.class, MyBatisUserRepository.class})
|
||||
public class MyBatisArticleRepositoryTest {
|
||||
@Autowired
|
||||
private ArticleRepository articleRepository;
|
||||
@Autowired private ArticleRepository articleRepository;
|
||||
|
||||
@Autowired
|
||||
private UserRepository userRepository;
|
||||
@Autowired 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
|
||||
public void setUp() {
|
||||
User user = new User("aisensiy@gmail.com", "aisensiy", "123", "bio", "default");
|
||||
userRepository.save(user);
|
||||
article = new Article("test", "desc", "body", new String[]{"java", "spring"}, user.getId());
|
||||
}
|
||||
@Test
|
||||
public void should_create_and_fetch_article_success() {
|
||||
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
|
||||
public void should_create_and_fetch_article_success() {
|
||||
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
|
||||
public void should_update_and_fetch_article_success() {
|
||||
articleRepository.save(article);
|
||||
|
||||
@Test
|
||||
public void should_update_and_fetch_article_success() {
|
||||
articleRepository.save(article);
|
||||
String newTitle = "new test 2";
|
||||
article.update(newTitle, "", "");
|
||||
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";
|
||||
article.update(newTitle, "", "");
|
||||
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
|
||||
public void should_delete_article() {
|
||||
articleRepository.save(article);
|
||||
|
||||
@Test
|
||||
public void should_delete_article() {
|
||||
articleRepository.save(article);
|
||||
|
||||
articleRepository.remove(article);
|
||||
assertFalse(articleRepository.findById(article.getId()).isPresent());
|
||||
}
|
||||
articleRepository.remove(article);
|
||||
assertFalse(articleRepository.findById(article.getId()).isPresent());
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user