Update bean validation
This commit is contained in:
parent
1d6e4af94a
commit
3602ebdc81
@ -1,19 +1,28 @@
|
||||
package io.spring.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import io.spring.api.exception.InvalidRequestException;
|
||||
import io.spring.application.Page;
|
||||
import io.spring.application.ArticleQueryService;
|
||||
import io.spring.application.Page;
|
||||
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 javax.validation.constraints.NotBlank;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
@ -21,9 +30,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.HashMap;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "/articles")
|
||||
public class ArticlesApi {
|
||||
@ -37,45 +43,43 @@ public class ArticlesApi {
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity createArticle(@Valid @RequestBody NewArticleParam newArticleParam,
|
||||
BindingResult bindingResult,
|
||||
@AuthenticationPrincipal User user) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
}
|
||||
|
||||
if (articleQueryService.findBySlug(Article.toSlug(newArticleParam.getTitle()), null).isPresent()) {
|
||||
bindingResult.rejectValue("title", "DUPLICATED", "article name exists");
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
}
|
||||
|
||||
Article article = new Article(
|
||||
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);
|
||||
return ResponseEntity.ok(new HashMap<String, Object>() {{
|
||||
return ResponseEntity.ok(
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("article", articleQueryService.findById(article.getId(), user).get());
|
||||
}});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@GetMapping(path = "feed")
|
||||
public ResponseEntity getFeed(@RequestParam(value = "offset", defaultValue = "0") int offset,
|
||||
public ResponseEntity getFeed(
|
||||
@RequestParam(value = "offset", defaultValue = "0") int offset,
|
||||
@RequestParam(value = "limit", defaultValue = "20") int limit,
|
||||
@AuthenticationPrincipal User user) {
|
||||
return ResponseEntity.ok(articleQueryService.findUserFeed(user, new Page(offset, limit)));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity getArticles(@RequestParam(value = "offset", defaultValue = "0") int offset,
|
||||
public ResponseEntity getArticles(
|
||||
@RequestParam(value = "offset", defaultValue = "0") int offset,
|
||||
@RequestParam(value = "limit", defaultValue = "20") int limit,
|
||||
@RequestParam(value = "tag", required = false) String tag,
|
||||
@RequestParam(value = "favorited", required = false) String favoritedBy,
|
||||
@RequestParam(value = "author", required = false) String author,
|
||||
@AuthenticationPrincipal User user) {
|
||||
return ResponseEntity.ok(articleQueryService.findRecentArticles(tag, author, favoritedBy, new Page(offset, limit), user));
|
||||
return ResponseEntity.ok(
|
||||
articleQueryService.findRecentArticles(
|
||||
tag, author, favoritedBy, new Page(offset, limit), user));
|
||||
}
|
||||
}
|
||||
|
||||
@ -84,10 +88,37 @@ public class ArticlesApi {
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
@ -1,24 +1,26 @@
|
||||
package io.spring.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import io.spring.api.exception.InvalidRequestException;
|
||||
import io.spring.api.exception.NoAuthorizationException;
|
||||
import io.spring.api.exception.ResourceNotFoundException;
|
||||
import io.spring.core.service.AuthorizationService;
|
||||
import io.spring.application.data.CommentData;
|
||||
import io.spring.application.CommentQueryService;
|
||||
import io.spring.application.data.CommentData;
|
||||
import io.spring.core.article.Article;
|
||||
import io.spring.core.article.ArticleRepository;
|
||||
import io.spring.core.comment.Comment;
|
||||
import io.spring.core.comment.CommentRepository;
|
||||
import io.spring.core.service.AuthorizationService;
|
||||
import io.spring.core.user.User;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import javax.validation.Valid;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.validation.BindingResult;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
@ -27,11 +29,6 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMethod;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.validation.Valid;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "/articles/{slug}/comments")
|
||||
public class CommentsApi {
|
||||
@ -40,7 +37,8 @@ public class CommentsApi {
|
||||
private CommentQueryService commentQueryService;
|
||||
|
||||
@Autowired
|
||||
public CommentsApi(ArticleRepository articleRepository,
|
||||
public CommentsApi(
|
||||
ArticleRepository articleRepository,
|
||||
CommentRepository commentRepository,
|
||||
CommentQueryService commentQueryService) {
|
||||
this.articleRepository = articleRepository;
|
||||
@ -49,51 +47,62 @@ public class CommentsApi {
|
||||
}
|
||||
|
||||
@PostMapping
|
||||
public ResponseEntity<?> createComment(@PathVariable("slug") String slug,
|
||||
public ResponseEntity<?> createComment(
|
||||
@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user,
|
||||
@Valid @RequestBody NewCommentParam newCommentParam,
|
||||
BindingResult bindingResult) {
|
||||
@Valid @RequestBody NewCommentParam newCommentParam) {
|
||||
Article article = findArticle(slug);
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
}
|
||||
Comment comment = new Comment(newCommentParam.getBody(), user.getId(), article.getId());
|
||||
commentRepository.save(comment);
|
||||
return ResponseEntity.status(201).body(commentResponse(commentQueryService.findById(comment.getId(), user).get()));
|
||||
return ResponseEntity.status(201)
|
||||
.body(commentResponse(commentQueryService.findById(comment.getId(), user).get()));
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity getComments(@PathVariable("slug") String slug,
|
||||
@AuthenticationPrincipal User user) {
|
||||
public ResponseEntity getComments(
|
||||
@PathVariable("slug") String slug, @AuthenticationPrincipal User user) {
|
||||
Article article = findArticle(slug);
|
||||
List<CommentData> comments = commentQueryService.findByArticleId(article.getId(), user);
|
||||
return ResponseEntity.ok(new HashMap<String, Object>() {{
|
||||
return ResponseEntity.ok(
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("comments", comments);
|
||||
}});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@RequestMapping(path = "{id}", method = RequestMethod.DELETE)
|
||||
public ResponseEntity deleteComment(@PathVariable("slug") String slug,
|
||||
public ResponseEntity deleteComment(
|
||||
@PathVariable("slug") String slug,
|
||||
@PathVariable("id") String commentId,
|
||||
@AuthenticationPrincipal User user) {
|
||||
Article article = findArticle(slug);
|
||||
return commentRepository.findById(article.getId(), commentId).map(comment -> {
|
||||
return commentRepository
|
||||
.findById(article.getId(), commentId)
|
||||
.map(
|
||||
comment -> {
|
||||
if (!AuthorizationService.canWriteComment(user, article, comment)) {
|
||||
throw new NoAuthorizationException();
|
||||
}
|
||||
commentRepository.remove(comment);
|
||||
return ResponseEntity.noContent().build();
|
||||
}).orElseThrow(ResourceNotFoundException::new);
|
||||
})
|
||||
.orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
|
||||
private Article findArticle(String slug) {
|
||||
return articleRepository.findBySlug(slug).map(article -> article).orElseThrow(ResourceNotFoundException::new);
|
||||
return articleRepository
|
||||
.findBySlug(slug)
|
||||
.map(article -> article)
|
||||
.orElseThrow(ResourceNotFoundException::new);
|
||||
}
|
||||
|
||||
private Map<String, Object> commentResponse(CommentData commentData) {
|
||||
return new HashMap<String, Object>() {{
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put("comment", commentData);
|
||||
}};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,19 +1,28 @@
|
||||
package io.spring.api;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import io.spring.api.exception.InvalidRequestException;
|
||||
import io.spring.application.UserQueryService;
|
||||
import io.spring.application.data.UserWithToken;
|
||||
import io.spring.application.data.UserData;
|
||||
import io.spring.application.data.UserWithToken;
|
||||
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 javax.validation.constraints.Email;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.security.core.annotation.AuthenticationPrincipal;
|
||||
import org.springframework.validation.BindingResult;
|
||||
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;
|
||||
@ -21,79 +30,127 @@ import org.springframework.web.bind.annotation.RequestHeader;
|
||||
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;
|
||||
import java.util.Optional;
|
||||
|
||||
@RestController
|
||||
@RequestMapping(path = "/user")
|
||||
public class CurrentUserApi {
|
||||
|
||||
private UserQueryService userQueryService;
|
||||
private UserRepository userRepository;
|
||||
private UserService userService;
|
||||
|
||||
@Autowired
|
||||
public CurrentUserApi(UserQueryService userQueryService, UserRepository userRepository) {
|
||||
public CurrentUserApi(UserQueryService userQueryService, UserService userService) {
|
||||
this.userQueryService = userQueryService;
|
||||
this.userRepository = userRepository;
|
||||
this.userService = userService;
|
||||
}
|
||||
|
||||
@GetMapping
|
||||
public ResponseEntity currentUser(@AuthenticationPrincipal User currentUser,
|
||||
public ResponseEntity currentUser(
|
||||
@AuthenticationPrincipal User currentUser,
|
||||
@RequestHeader(value = "Authorization") String authorization) {
|
||||
UserData userData = userQueryService.findById(currentUser.getId()).get();
|
||||
return ResponseEntity.ok(userResponse(
|
||||
new UserWithToken(userData, authorization.split(" ")[1])
|
||||
));
|
||||
return ResponseEntity.ok(
|
||||
userResponse(new UserWithToken(userData, authorization.split(" ")[1])));
|
||||
}
|
||||
|
||||
@PutMapping
|
||||
public ResponseEntity updateProfile(@AuthenticationPrincipal User currentUser,
|
||||
public ResponseEntity updateProfile(
|
||||
@AuthenticationPrincipal User currentUser,
|
||||
@RequestHeader("Authorization") String token,
|
||||
@Valid @RequestBody UpdateUserParam updateUserParam,
|
||||
BindingResult bindingResult) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
}
|
||||
checkUniquenessOfUsernameAndEmail(currentUser, updateUserParam, bindingResult);
|
||||
@Valid @RequestBody UpdateUserParam updateUserParam) {
|
||||
|
||||
currentUser.update(
|
||||
userService.updateUser(new UpdateUserCommand(currentUser, updateUserParam));
|
||||
UserData userData = userQueryService.findById(currentUser.getId()).get();
|
||||
return ResponseEntity.ok(userResponse(new UserWithToken(userData, token.split(" ")[1])));
|
||||
}
|
||||
|
||||
private Map<String, Object> userResponse(UserWithToken userWithToken) {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put("user", userWithToken);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@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(currentUser);
|
||||
UserData userData = userQueryService.findById(currentUser.getId()).get();
|
||||
return ResponseEntity.ok(userResponse(
|
||||
new UserWithToken(userData, token.split(" ")[1])
|
||||
));
|
||||
userRepository.save(user);
|
||||
}
|
||||
}
|
||||
|
||||
private void checkUniquenessOfUsernameAndEmail(User currentUser, UpdateUserParam updateUserParam, BindingResult bindingResult) {
|
||||
if (!"".equals(updateUserParam.getUsername())) {
|
||||
Optional<User> byUsername = userRepository.findByUsername(updateUserParam.getUsername());
|
||||
if (byUsername.isPresent() && !byUsername.get().equals(currentUser)) {
|
||||
bindingResult.rejectValue("username", "DUPLICATED", "username already exist");
|
||||
}
|
||||
}
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
@UpdateUserConstraint
|
||||
class UpdateUserCommand {
|
||||
|
||||
if (!"".equals(updateUserParam.getEmail())) {
|
||||
Optional<User> byEmail = userRepository.findByEmail(updateUserParam.getEmail());
|
||||
if (byEmail.isPresent() && !byEmail.get().equals(currentUser)) {
|
||||
bindingResult.rejectValue("email", "DUPLICATED", "email already exist");
|
||||
}
|
||||
}
|
||||
private User targetUser;
|
||||
private UpdateUserParam param;
|
||||
}
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
}
|
||||
}
|
||||
@Constraint(validatedBy = UpdateUserValidator.class)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@interface UpdateUserConstraint {
|
||||
|
||||
private Map<String, Object> userResponse(UserWithToken userWithToken) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("user", userWithToken);
|
||||
}};
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -101,8 +158,10 @@ public class CurrentUserApi {
|
||||
@JsonRootName("user")
|
||||
@NoArgsConstructor
|
||||
class UpdateUserParam {
|
||||
|
||||
@Email(message = "should be an email")
|
||||
private String email = "";
|
||||
|
||||
private String password = "";
|
||||
private String username = "";
|
||||
private String bio = "";
|
||||
|
@ -1,32 +1,36 @@
|
||||
package io.spring.api;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonRootName;
|
||||
import io.spring.api.exception.InvalidRequestException;
|
||||
import io.spring.api.exception.InvalidAuthenticationException;
|
||||
import io.spring.application.UserQueryService;
|
||||
import io.spring.application.data.UserWithToken;
|
||||
import io.spring.application.data.UserData;
|
||||
import io.spring.application.data.UserWithToken;
|
||||
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 lombok.Getter;
|
||||
import lombok.NoArgsConstructor;
|
||||
import javax.validation.constraints.Email;
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.validation.BindingResult;
|
||||
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.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
import static org.springframework.web.bind.annotation.RequestMethod.POST;
|
||||
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;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
@RestController
|
||||
public class UsersApi {
|
||||
@ -37,7 +41,8 @@ public class UsersApi {
|
||||
private JwtService jwtService;
|
||||
|
||||
@Autowired
|
||||
public UsersApi(UserRepository userRepository,
|
||||
public UsersApi(
|
||||
UserRepository userRepository,
|
||||
UserQueryService userQueryService,
|
||||
EncryptService encryptService,
|
||||
@Value("${image.default}") String defaultImage,
|
||||
@ -50,10 +55,9 @@ public class UsersApi {
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/users", method = POST)
|
||||
public ResponseEntity createUser(@Valid @RequestBody RegisterParam registerParam, BindingResult bindingResult) {
|
||||
checkInput(registerParam, bindingResult);
|
||||
|
||||
User user = new User(
|
||||
public ResponseEntity createUser(@Valid @RequestBody RegisterParam registerParam) {
|
||||
User user =
|
||||
new User(
|
||||
registerParam.getEmail(),
|
||||
registerParam.getUsername(),
|
||||
encryptService.encrypt(registerParam.getPassword()),
|
||||
@ -61,42 +65,70 @@ public class UsersApi {
|
||||
defaultImage);
|
||||
userRepository.save(user);
|
||||
UserData userData = userQueryService.findById(user.getId()).get();
|
||||
return ResponseEntity.status(201).body(userResponse(new UserWithToken(userData, jwtService.toToken(user))));
|
||||
}
|
||||
|
||||
private void checkInput(@Valid @RequestBody RegisterParam registerParam, BindingResult bindingResult) {
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
}
|
||||
if (userRepository.findByUsername(registerParam.getUsername()).isPresent()) {
|
||||
bindingResult.rejectValue("username", "DUPLICATED", "duplicated username");
|
||||
}
|
||||
|
||||
if (userRepository.findByEmail(registerParam.getEmail()).isPresent()) {
|
||||
bindingResult.rejectValue("email", "DUPLICATED", "duplicated email");
|
||||
}
|
||||
|
||||
if (bindingResult.hasErrors()) {
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
}
|
||||
return ResponseEntity.status(201)
|
||||
.body(userResponse(new UserWithToken(userData, jwtService.toToken(user))));
|
||||
}
|
||||
|
||||
@RequestMapping(path = "/users/login", method = POST)
|
||||
public ResponseEntity userLogin(@Valid @RequestBody LoginParam loginParam, BindingResult bindingResult) {
|
||||
public ResponseEntity userLogin(@Valid @RequestBody LoginParam loginParam) {
|
||||
Optional<User> optional = userRepository.findByEmail(loginParam.getEmail());
|
||||
if (optional.isPresent() && encryptService.check(loginParam.getPassword(), optional.get().getPassword())) {
|
||||
if (optional.isPresent()
|
||||
&& encryptService.check(loginParam.getPassword(), optional.get().getPassword())) {
|
||||
UserData userData = userQueryService.findById(optional.get().getId()).get();
|
||||
return ResponseEntity.ok(userResponse(new UserWithToken(userData, jwtService.toToken(optional.get()))));
|
||||
return ResponseEntity.ok(
|
||||
userResponse(new UserWithToken(userData, jwtService.toToken(optional.get()))));
|
||||
} else {
|
||||
bindingResult.rejectValue("password", "INVALID", "invalid email or password");
|
||||
throw new InvalidRequestException(bindingResult);
|
||||
throw new InvalidAuthenticationException();
|
||||
}
|
||||
}
|
||||
|
||||
private Map<String, Object> userResponse(UserWithToken userWithToken) {
|
||||
return new HashMap<String, Object>() {{
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put("user", userWithToken);
|
||||
}};
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@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();
|
||||
}
|
||||
}
|
||||
|
||||
@ -107,6 +139,7 @@ class LoginParam {
|
||||
@NotBlank(message = "can't be empty")
|
||||
@Email(message = "should be an email")
|
||||
private String email;
|
||||
|
||||
@NotBlank(message = "can't be empty")
|
||||
private String password;
|
||||
}
|
||||
@ -117,9 +150,13 @@ class LoginParam {
|
||||
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,18 +1,26 @@
|
||||
package io.spring.api.exception;
|
||||
|
||||
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import javax.validation.ConstraintViolation;
|
||||
import javax.validation.ConstraintViolationException;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
||||
import org.springframework.web.context.request.WebRequest;
|
||||
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static org.springframework.http.HttpStatus.UNPROCESSABLE_ENTITY;
|
||||
|
||||
@RestControllerAdvice
|
||||
public class CustomizeExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
@ -20,12 +28,16 @@ public class CustomizeExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
public ResponseEntity<Object> handleInvalidRequest(RuntimeException e, WebRequest request) {
|
||||
InvalidRequestException ire = (InvalidRequestException) e;
|
||||
|
||||
List<FieldErrorResource> errorResources = ire.getErrors().getFieldErrors().stream().map(fieldError ->
|
||||
List<FieldErrorResource> errorResources =
|
||||
ire.getErrors().getFieldErrors().stream()
|
||||
.map(
|
||||
fieldError ->
|
||||
new FieldErrorResource(
|
||||
fieldError.getObjectName(),
|
||||
fieldError.getField(),
|
||||
fieldError.getCode(),
|
||||
fieldError.getDefaultMessage())).collect(Collectors.toList());
|
||||
fieldError.getDefaultMessage()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
ErrorResource error = new ErrorResource(errorResources);
|
||||
|
||||
@ -34,4 +46,64 @@ public class CustomizeExceptionHandler extends ResponseEntityExceptionHandler {
|
||||
|
||||
return handleExceptionInternal(e, error, headers, UNPROCESSABLE_ENTITY, request);
|
||||
}
|
||||
|
||||
@ExceptionHandler(InvalidAuthenticationException.class)
|
||||
public ResponseEntity<Object> handleInvalidAuthentication(
|
||||
InvalidAuthenticationException e, WebRequest request) {
|
||||
return ResponseEntity.status(UNPROCESSABLE_ENTITY)
|
||||
.body(
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("message", e.getMessage());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ResponseEntity<Object> handleMethodArgumentNotValid(
|
||||
MethodArgumentNotValidException e,
|
||||
HttpHeaders headers,
|
||||
HttpStatus status,
|
||||
WebRequest request) {
|
||||
List<FieldErrorResource> errorResources =
|
||||
e.getBindingResult().getFieldErrors().stream()
|
||||
.map(
|
||||
fieldError ->
|
||||
new FieldErrorResource(
|
||||
fieldError.getObjectName(),
|
||||
fieldError.getField(),
|
||||
fieldError.getCode(),
|
||||
fieldError.getDefaultMessage()))
|
||||
.collect(Collectors.toList());
|
||||
|
||||
return ResponseEntity.status(UNPROCESSABLE_ENTITY).body(new ErrorResource(errorResources));
|
||||
}
|
||||
|
||||
@ExceptionHandler({ConstraintViolationException.class})
|
||||
@ResponseStatus(UNPROCESSABLE_ENTITY)
|
||||
@ResponseBody
|
||||
public ErrorResource handleConstraintViolation(
|
||||
ConstraintViolationException ex, WebRequest request) {
|
||||
List<FieldErrorResource> errors = new ArrayList<>();
|
||||
for (ConstraintViolation<?> violation : ex.getConstraintViolations()) {
|
||||
FieldErrorResource fieldErrorResource =
|
||||
new FieldErrorResource(
|
||||
violation.getRootBeanClass().getName(),
|
||||
getParam(violation.getPropertyPath().toString()),
|
||||
violation.getConstraintDescriptor().getAnnotation().annotationType().getSimpleName(),
|
||||
violation.getMessage());
|
||||
errors.add(fieldErrorResource);
|
||||
}
|
||||
|
||||
return new ErrorResource(errors);
|
||||
}
|
||||
|
||||
private String getParam(String s) {
|
||||
String[] splits = s.split("\\.");
|
||||
if (splits.length == 1) {
|
||||
return s;
|
||||
} else {
|
||||
return String.join(".", Arrays.copyOfRange(splits, 2, splits.length));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,8 @@
|
||||
package io.spring.api.exception;
|
||||
|
||||
public class InvalidAuthenticationException extends RuntimeException {
|
||||
|
||||
public InvalidAuthenticationException() {
|
||||
super("invalid email or password");
|
||||
}
|
||||
}
|
@ -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;
|
||||
@ -8,6 +15,10 @@ 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.Map;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.DateTime;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
@ -17,30 +28,14 @@ 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.eq;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@WebMvcTest({ArticlesApi.class})
|
||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||
public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private ArticleRepository articleRepository;
|
||||
@MockBean private ArticleRepository articleRepository;
|
||||
|
||||
@MockBean
|
||||
private ArticleQueryService articleQueryService;
|
||||
@MockBean private ArticleQueryService articleQueryService;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
@ -58,7 +53,8 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
String[] tagList = {"reactjs", "angularjs", "dragons"};
|
||||
Map<String, Object> param = prepareParam(title, description, body, tagList);
|
||||
|
||||
ArticleData articleData = new ArticleData(
|
||||
ArticleData articleData =
|
||||
new ArticleData(
|
||||
"123",
|
||||
slug,
|
||||
title,
|
||||
@ -71,7 +67,8 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
Arrays.asList(tagList),
|
||||
new ProfileData("userid", user.getUsername(), user.getBio(), user.getImage(), false));
|
||||
|
||||
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any())).thenReturn(Optional.empty());
|
||||
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any()))
|
||||
.thenReturn(Optional.empty());
|
||||
|
||||
when(articleQueryService.findById(any(), any())).thenReturn(Optional.of(articleData));
|
||||
|
||||
@ -111,7 +108,6 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.body("errors.body[0]", equalTo("can't be empty"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -123,7 +119,8 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
String[] tagList = {"reactjs", "angularjs", "dragons"};
|
||||
Map<String, Object> param = prepareParam(title, description, body, tagList);
|
||||
|
||||
ArticleData articleData = new ArticleData(
|
||||
ArticleData articleData =
|
||||
new ArticleData(
|
||||
"123",
|
||||
slug,
|
||||
title,
|
||||
@ -136,7 +133,8 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
Arrays.asList(tagList),
|
||||
new ProfileData("userid", user.getUsername(), user.getBio(), user.getImage(), false));
|
||||
|
||||
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any())).thenReturn(Optional.of(articleData));
|
||||
when(articleQueryService.findBySlug(eq(Article.toSlug(title)), any()))
|
||||
.thenReturn(Optional.of(articleData));
|
||||
|
||||
when(articleQueryService.findById(any(), any())).thenReturn(Optional.of(articleData));
|
||||
|
||||
@ -146,19 +144,26 @@ public class ArticlesApiTest extends TestWithCurrentUser {
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/articles")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(422);
|
||||
|
||||
}
|
||||
|
||||
private HashMap<String, Object> prepareParam(final String title, final String description, final String body, final String[] tagList) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("article", new HashMap<String, Object>() {{
|
||||
private HashMap<String, Object> prepareParam(
|
||||
final String title, final String description, final String body, final String[] tagList) {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"article",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("title", title);
|
||||
put("description", description);
|
||||
put("body", body);
|
||||
put("tagList", tagList);
|
||||
}});
|
||||
}};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
@ -1,37 +1,40 @@
|
||||
package io.spring.api;
|
||||
|
||||
import io.restassured.module.mockmvc.RestAssuredMockMvc;
|
||||
import io.spring.JacksonCustomizations;
|
||||
import io.spring.api.security.WebSecurityConfig;
|
||||
import io.spring.application.UserQueryService;
|
||||
import io.spring.core.user.User;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
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.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.UserQueryService;
|
||||
import io.spring.core.user.User;
|
||||
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;
|
||||
import org.springframework.boot.autoconfigure.validation.ValidationAutoConfiguration;
|
||||
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||
import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
@WebMvcTest(CurrentUserApi.class)
|
||||
@Import({WebSecurityConfig.class, JacksonCustomizations.class})
|
||||
@Import({
|
||||
WebSecurityConfig.class,
|
||||
JacksonCustomizations.class,
|
||||
UserService.class,
|
||||
ValidationAutoConfiguration.class
|
||||
})
|
||||
public class CurrentUserApiTest extends TestWithCurrentUser {
|
||||
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private UserQueryService userQueryService;
|
||||
@MockBean private UserQueryService userQueryService;
|
||||
|
||||
@Override
|
||||
@Before
|
||||
@ -60,13 +63,7 @@ public class CurrentUserApiTest extends TestWithCurrentUser {
|
||||
|
||||
@Test
|
||||
public void should_get_401_without_token() throws Exception {
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.when()
|
||||
.get("/user")
|
||||
.then()
|
||||
.statusCode(401);
|
||||
|
||||
given().contentType("application/json").when().get("/user").then().statusCode(401);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -88,13 +85,20 @@ public class CurrentUserApiTest extends TestWithCurrentUser {
|
||||
String newBio = "updated";
|
||||
String newUsername = "newusernamee";
|
||||
|
||||
Map<String, Object> param = new HashMap<String, Object>() {{
|
||||
put("user", new HashMap<String, Object>() {{
|
||||
Map<String, Object> param =
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"user",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("email", newEmail);
|
||||
put("bio", newBio);
|
||||
put("username", newUsername);
|
||||
}});
|
||||
}};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
when(userRepository.findByUsername(eq(newUsername))).thenReturn(Optional.empty());
|
||||
when(userRepository.findByEmail(eq(newEmail))).thenReturn(Optional.empty());
|
||||
@ -119,7 +123,8 @@ public class CurrentUserApiTest extends TestWithCurrentUser {
|
||||
|
||||
Map<String, Object> param = prepareUpdateParam(newEmail, newBio, newUsername);
|
||||
|
||||
when(userRepository.findByEmail(eq(newEmail))).thenReturn(Optional.of(new User(newEmail, "username", "123", "", "")));
|
||||
when(userRepository.findByEmail(eq(newEmail)))
|
||||
.thenReturn(Optional.of(new User(newEmail, "username", "123", "", "")));
|
||||
when(userRepository.findByUsername(eq(newUsername))).thenReturn(Optional.empty());
|
||||
|
||||
when(userQueryService.findById(eq(user.getId()))).thenReturn(Optional.of(userData));
|
||||
@ -134,28 +139,38 @@ public class CurrentUserApiTest extends TestWithCurrentUser {
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.body("errors.email[0]", equalTo("email already exist"));
|
||||
|
||||
}
|
||||
|
||||
private HashMap<String, Object> prepareUpdateParam(final String newEmail, final String newBio, final String newUsername) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("user", new HashMap<String, Object>() {{
|
||||
private HashMap<String, Object> prepareUpdateParam(
|
||||
final String newEmail, final String newBio, final String newUsername) {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"user",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("email", newEmail);
|
||||
put("bio", newBio);
|
||||
put("username", newUsername);
|
||||
}});
|
||||
}};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void should_get_401_if_not_login() throws Exception {
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.body(new HashMap<String, Object>() {{
|
||||
.body(
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("user", new HashMap<String, Object>());
|
||||
}})
|
||||
}
|
||||
})
|
||||
.when()
|
||||
.put("/user")
|
||||
.then().statusCode(401);
|
||||
.then()
|
||||
.statusCode(401);
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
@ -10,6 +17,9 @@ import io.spring.core.user.User;
|
||||
import io.spring.core.user.UserRepository;
|
||||
import io.spring.infrastructure.mybatis.readservice.UserReadService;
|
||||
import io.spring.infrastructure.service.NaiveEncryptService;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@ -20,35 +30,24 @@ import org.springframework.context.annotation.Import;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
|
||||
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.eq;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@WebMvcTest(UsersApi.class)
|
||||
@Import({WebSecurityConfig.class, UserQueryService.class, NaiveEncryptService.class, JacksonCustomizations.class})
|
||||
@Import({
|
||||
WebSecurityConfig.class,
|
||||
UserQueryService.class,
|
||||
NaiveEncryptService.class,
|
||||
JacksonCustomizations.class
|
||||
})
|
||||
public class UsersApiTest {
|
||||
@Autowired
|
||||
private MockMvc mvc;
|
||||
@Autowired private MockMvc mvc;
|
||||
|
||||
@MockBean
|
||||
private UserRepository userRepository;
|
||||
@MockBean private UserRepository userRepository;
|
||||
|
||||
@MockBean
|
||||
private JwtService jwtService;
|
||||
@MockBean private JwtService jwtService;
|
||||
|
||||
@MockBean
|
||||
private UserReadService userReadService;
|
||||
@MockBean private UserReadService userReadService;
|
||||
private String defaultAvatar;
|
||||
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
RestAssuredMockMvc.mockMvc(mvc);
|
||||
@ -99,6 +98,7 @@ public class UsersApiTest {
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/users")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.body("errors.username[0]", equalTo("can't be empty"));
|
||||
@ -116,10 +116,10 @@ public class UsersApiTest {
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/users")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.body("errors.email[0]", equalTo("should be an email"));
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -127,9 +127,8 @@ public class UsersApiTest {
|
||||
String email = "john@jacob.com";
|
||||
String username = "johnjacob";
|
||||
|
||||
when(userRepository.findByUsername(eq(username))).thenReturn(Optional.of(new User(
|
||||
email, username, "123", "bio", ""
|
||||
)));
|
||||
when(userRepository.findByUsername(eq(username)))
|
||||
.thenReturn(Optional.of(new User(email, username, "123", "bio", "")));
|
||||
when(userRepository.findByEmail(any())).thenReturn(Optional.empty());
|
||||
|
||||
Map<String, Object> param = prepareRegisterParameter(email, username);
|
||||
@ -139,6 +138,7 @@ public class UsersApiTest {
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/users")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.body("errors.username[0]", equalTo("duplicated username"));
|
||||
@ -149,9 +149,8 @@ public class UsersApiTest {
|
||||
String email = "john@jacob.com";
|
||||
String username = "johnjacob2";
|
||||
|
||||
when(userRepository.findByEmail(eq(email))).thenReturn(Optional.of(new User(
|
||||
email, username, "123", "bio", ""
|
||||
)));
|
||||
when(userRepository.findByEmail(eq(email)))
|
||||
.thenReturn(Optional.of(new User(email, username, "123", "bio", "")));
|
||||
|
||||
when(userRepository.findByUsername(eq(username))).thenReturn(Optional.empty());
|
||||
|
||||
@ -167,14 +166,21 @@ public class UsersApiTest {
|
||||
.body("errors.email[0]", equalTo("duplicated email"));
|
||||
}
|
||||
|
||||
private HashMap<String, Object> prepareRegisterParameter(final String email, final String username) {
|
||||
return new HashMap<String, Object>() {{
|
||||
put("user", new HashMap<String, Object>() {{
|
||||
private HashMap<String, Object> prepareRegisterParameter(
|
||||
final String email, final String username) {
|
||||
return new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"user",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("email", email);
|
||||
put("password", "johnnyjacob");
|
||||
put("username", username);
|
||||
}});
|
||||
}};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -191,12 +197,19 @@ public class UsersApiTest {
|
||||
when(userReadService.findById(eq(user.getId()))).thenReturn(userData);
|
||||
when(jwtService.toToken(any())).thenReturn("123");
|
||||
|
||||
Map<String, Object> param = new HashMap<String, Object>() {{
|
||||
put("user", new HashMap<String, Object>() {{
|
||||
Map<String, Object> param =
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"user",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("email", email);
|
||||
put("password", password);
|
||||
}});
|
||||
}};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
given()
|
||||
.contentType("application/json")
|
||||
@ -209,7 +222,8 @@ public class UsersApiTest {
|
||||
.body("user.username", equalTo(username))
|
||||
.body("user.bio", equalTo(""))
|
||||
.body("user.image", equalTo(defaultAvatar))
|
||||
.body("user.token", equalTo("123"));;
|
||||
.body("user.token", equalTo("123"));
|
||||
;
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -224,20 +238,28 @@ public class UsersApiTest {
|
||||
when(userRepository.findByEmail(eq(email))).thenReturn(Optional.of(user));
|
||||
when(userReadService.findByUsername(eq(username))).thenReturn(userData);
|
||||
|
||||
Map<String, Object> param = new HashMap<String, Object>() {{
|
||||
put("user", new HashMap<String, Object>() {{
|
||||
Map<String, Object> param =
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put(
|
||||
"user",
|
||||
new HashMap<String, Object>() {
|
||||
{
|
||||
put("email", email);
|
||||
put("password", "123123");
|
||||
}});
|
||||
}};
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
given()
|
||||
.contentType("application/json")
|
||||
.body(param)
|
||||
.when()
|
||||
.post("/users/login")
|
||||
.prettyPeek()
|
||||
.then()
|
||||
.statusCode(422)
|
||||
.body("errors.password[0]", equalTo("invalid email or password"));
|
||||
.body("message", equalTo("invalid email or password"));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user