diff --git a/src/main/java/io/spring/api/CurrentUserApi.java b/src/main/java/io/spring/api/CurrentUserApi.java index a3867b1..dfa5e6e 100644 --- a/src/main/java/io/spring/api/CurrentUserApi.java +++ b/src/main/java/io/spring/api/CurrentUserApi.java @@ -1,28 +1,68 @@ package io.spring.api; +import com.fasterxml.jackson.annotation.JsonRootName; import io.spring.application.user.UserQueryService; import io.spring.core.user.User; +import io.spring.core.user.UserRepository; +import lombok.Getter; +import lombok.NoArgsConstructor; +import org.hibernate.validator.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.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PutMapping; +import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestHeader; 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; + @RestController +@RequestMapping(path = "/user") public class CurrentUserApi { private UserQueryService userQueryService; + private UserRepository userRepository; @Autowired - public CurrentUserApi(UserQueryService userQueryService) { + public CurrentUserApi(UserQueryService userQueryService, UserRepository userRepository) { this.userQueryService = userQueryService; + this.userRepository = userRepository; } - @RequestMapping(path = "/user", method = RequestMethod.GET) + @GetMapping public ResponseEntity currentUser(@AuthenticationPrincipal User currentUser, @RequestHeader(value = "Authorization") String authorization) { return ResponseEntity.ok(userQueryService.fetchCurrentUser(currentUser.getUsername(), authorization.split(" ")[1])); } + @PutMapping + public ResponseEntity updateProfile(@AuthenticationPrincipal User currentUser, + @RequestHeader(value = "Authorization") String authorization, + @Valid @RequestBody UpdateUserParam updateUserParam, + BindingResult bindingResult) { + currentUser.update( + updateUserParam.getEmail(), + updateUserParam.getUsername(), + updateUserParam.getPassword(), + updateUserParam.getBio(), + updateUserParam.getImage()); + userRepository.save(currentUser); + return ResponseEntity.ok(userQueryService.fetchCurrentUser(currentUser.getUsername(), authorization.split(" ")[1])); + } +} + +@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 = ""; } diff --git a/src/main/java/io/spring/application/user/UserData.java b/src/main/java/io/spring/application/user/UserData.java index 6e87c79..0c171f7 100644 --- a/src/main/java/io/spring/application/user/UserData.java +++ b/src/main/java/io/spring/application/user/UserData.java @@ -14,8 +14,9 @@ import javax.persistence.Id; @Entity @JsonRootName("user") public class UserData { - private String email; @Id + private String id; + private String email; private String username; private String bio; private String image; diff --git a/src/main/java/io/spring/core/user/User.java b/src/main/java/io/spring/core/user/User.java index aa2b1c9..3a909fb 100644 --- a/src/main/java/io/spring/core/user/User.java +++ b/src/main/java/io/spring/core/user/User.java @@ -5,10 +5,13 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.NoArgsConstructor; +import java.util.UUID; + @Getter @NoArgsConstructor @EqualsAndHashCode(of = {"username"}) public class User { + private String id; private String email; private String username; private String password; @@ -16,10 +19,33 @@ public class User { 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 void update(String email, String username, String password, String bio, String image) { + if (!email.equals("")) { + this.email = email; + } + + if (!username.equals("")) { + this.username = username; + } + + if (!password.equals("")) { + this.password = password; + } + + if (!bio.equals("")) { + this.bio = bio; + } + + if (!image.equals("")) { + this.image = image; + } + } } diff --git a/src/main/java/io/spring/core/user/UserRepository.java b/src/main/java/io/spring/core/user/UserRepository.java index 82603fd..da4675f 100644 --- a/src/main/java/io/spring/core/user/UserRepository.java +++ b/src/main/java/io/spring/core/user/UserRepository.java @@ -8,6 +8,8 @@ import java.util.Optional; public interface UserRepository { void save(User user); + Optional findById(String id); + Optional findByUsername(String username); Optional findByEmail(String email); diff --git a/src/main/java/io/spring/infrastructure/user/MyBatisUserRepository.java b/src/main/java/io/spring/infrastructure/user/MyBatisUserRepository.java index 83d8215..11e187b 100644 --- a/src/main/java/io/spring/infrastructure/user/MyBatisUserRepository.java +++ b/src/main/java/io/spring/infrastructure/user/MyBatisUserRepository.java @@ -18,7 +18,16 @@ public class MyBatisUserRepository implements UserRepository { @Override public void save(User user) { - userMapper.save(user); + if (userMapper.findById(user.getId()) == null) { + userMapper.insert(user); + } else { + userMapper.update(user); + } + } + + @Override + public Optional findById(String id) { + return Optional.ofNullable(userMapper.findById(id)); } @Override diff --git a/src/main/java/io/spring/infrastructure/user/UserMapper.java b/src/main/java/io/spring/infrastructure/user/UserMapper.java index 6568443..35df97a 100644 --- a/src/main/java/io/spring/infrastructure/user/UserMapper.java +++ b/src/main/java/io/spring/infrastructure/user/UserMapper.java @@ -8,8 +8,12 @@ import org.springframework.stereotype.Component; @Component @Mapper public interface UserMapper { - void save(@Param("user") User user); + void insert(@Param("user") User user); User findByUsername(@Param("username") String username); User findByEmail(@Param("email") String email); + + User findById(@Param("id") String id); + + void update(@Param("user") User user); } diff --git a/src/main/resources/db/migration/V1__create_tables.sql b/src/main/resources/db/migration/V1__create_tables.sql index edf79d7..02ab196 100644 --- a/src/main/resources/db/migration/V1__create_tables.sql +++ b/src/main/resources/db/migration/V1__create_tables.sql @@ -1,5 +1,6 @@ create table users ( - username varchar(255) primary key, + id varchar(255) primary key, + username varchar(255) UNIQUE, password varchar(255), email varchar(255) UNIQUE, bio text, diff --git a/src/main/resources/mapper/UserMapper.xml b/src/main/resources/mapper/UserMapper.xml index f7a2cf9..bde0228 100644 --- a/src/main/resources/mapper/UserMapper.xml +++ b/src/main/resources/mapper/UserMapper.xml @@ -1,8 +1,9 @@ - - insert into users (username, email, password, bio, image) values( + + insert into users (id, username, email, password, bio, image) values( + #{user.id}, #{user.username}, #{user.email}, #{user.password}, @@ -10,15 +11,30 @@ #{user.image} ) + + update users + + username = #{user.username}, + email = #{user.email}, + password = #{user.password}, + bio = #{user.bio}, + image = #{user.image} + + where id = #{user.id} + + - + + diff --git a/src/test/java/io/spring/api/CurrentUserApiTest.java b/src/test/java/io/spring/api/CurrentUserApiTest.java index 1f2bf9f..de81d01 100644 --- a/src/test/java/io/spring/api/CurrentUserApiTest.java +++ b/src/test/java/io/spring/api/CurrentUserApiTest.java @@ -6,7 +6,6 @@ import io.spring.application.user.UserData; import io.spring.application.user.UserReadService; import io.spring.core.user.User; import io.spring.core.user.UserRepository; -import io.spring.infrastructure.service.DefaultJwtService; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -16,9 +15,13 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.test.context.junit4.SpringRunner; +import java.util.HashMap; +import java.util.Map; import java.util.Optional; import static io.restassured.RestAssured.given; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.IsEqual.equalTo; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.when; @@ -38,24 +41,32 @@ public class CurrentUserApiTest { @Autowired private JwtService jwtService; + private User user; + private UserData userData; + private String token; + private String email; + private String username; + private String defaultAvatar; @Before public void setUp() throws Exception { RestAssured.port = port; + email = "john@jacob.com"; + username = "johnjacob"; + + defaultAvatar = "https://static.productionready.io/images/smiley-cyrus.jpg"; + user = new User(email, username, "123", "", defaultAvatar); + when(userRepository.findByUsername(eq(username))).thenReturn(Optional.of(user)); + + userData = new UserData(user.getId(), email, username, "", defaultAvatar); + when(userReadService.findOne(eq(username))).thenReturn(userData); + + token = jwtService.toToken(userData); } @Test public void should_get_current_user_with_token() throws Exception { - String email = "john@jacob.com"; - String username = "johnjacob"; - User user = new User(email, username, "123", "", "https://static.productionready.io/images/smiley-cyrus.jpg"); - when(userRepository.findByUsername(eq(username))).thenReturn(Optional.of(user)); - - UserData userData = new UserData(email, username, "", "https://static.productionready.io/images/smiley-cyrus.jpg"); - when(userReadService.findOne(eq(username))).thenReturn(userData); - - String token = jwtService.toToken(userData); given() .header("Authorization", "Token " + token) @@ -92,4 +103,42 @@ public class CurrentUserApiTest { .then() .statusCode(401); } + + @Test + public void should_update_current_user_profile() throws Exception { + String newEmail = "newemail@example.com"; + String newBio = "updated"; + + Map param = new HashMap() {{ + put("user", new HashMap() {{ + put("email", newEmail); + put("bio", newBio); + }}); + }}; + + given() + .contentType("application/json") + .header("Authorization", "Token " + token) + .body(param) + .when() + .put("/user") + .then() + .statusCode(200); + + assertThat(user.getEmail(), is(newEmail)); + assertThat(user.getBio(), is(newBio)); + assertThat(user.getImage(), is(defaultAvatar)); + } + + @Test + public void should_get_401_if_not_login() throws Exception { + given() + .contentType("application/json") + .body(new HashMap() {{ + put("user", new HashMap()); + }}) + .when() + .put("/user") + .then().statusCode(401); + } } diff --git a/src/test/java/io/spring/api/UsersApiTest.java b/src/test/java/io/spring/api/UsersApiTest.java index ccb8870..039f81b 100644 --- a/src/test/java/io/spring/api/UsersApiTest.java +++ b/src/test/java/io/spring/api/UsersApiTest.java @@ -54,7 +54,7 @@ public class UsersApiTest { String username = "johnjacob"; when(jwtService.toToken(any())).thenReturn("123"); - UserData userData = new UserData(email, username, "", defaultAvatar); + UserData userData = new UserData("123", email, username, "", defaultAvatar); when(userReadService.findOne(eq(username))).thenReturn(userData); when(userRepository.findByUsername(eq(username))).thenReturn(Optional.empty()); @@ -175,7 +175,7 @@ public class UsersApiTest { String password = "123"; User user = new User(email, username, password, "", defaultAvatar); - UserData userData = new UserData(email, username, "", defaultAvatar); + UserData userData = new UserData("123", email, username, "", defaultAvatar); when(userRepository.findByEmail(eq(email))).thenReturn(Optional.of(user)); when(userReadService.findOne(eq(username))).thenReturn(userData); @@ -209,7 +209,7 @@ public class UsersApiTest { String password = "123"; User user = new User(email, username, password, "", defaultAvatar); - UserData userData = new UserData(email, username, "", defaultAvatar); + UserData userData = new UserData(user.getId(), email, username, "", defaultAvatar); when(userRepository.findByEmail(eq(email))).thenReturn(Optional.of(user)); when(userReadService.findOne(eq(username))).thenReturn(userData); diff --git a/src/test/java/io/spring/infrastructure/service/DefaultJwtServiceTest.java b/src/test/java/io/spring/infrastructure/service/DefaultJwtServiceTest.java index 2749717..9a3981f 100644 --- a/src/test/java/io/spring/infrastructure/service/DefaultJwtServiceTest.java +++ b/src/test/java/io/spring/infrastructure/service/DefaultJwtServiceTest.java @@ -24,7 +24,7 @@ public class DefaultJwtServiceTest { public void should_generate_and_parse_token() throws Exception { String username = "aisensiy"; - UserData userData = new UserData("aisensiy@163.com", username, "", ""); + UserData userData = new UserData("123", "aisensiy@163.com", username, "", ""); String token = jwtService.toToken(userData); assertThat(token, notNullValue()); Optional optional = jwtService.getSubFromToken(token); diff --git a/src/test/java/io/spring/infrastructure/user/MyBatisUserRepositoryTest.java b/src/test/java/io/spring/infrastructure/user/MyBatisUserRepositoryTest.java index 96205ed..7b3e0a2 100644 --- a/src/test/java/io/spring/infrastructure/user/MyBatisUserRepositoryTest.java +++ b/src/test/java/io/spring/infrastructure/user/MyBatisUserRepositoryTest.java @@ -2,6 +2,7 @@ package io.spring.infrastructure.user; import io.spring.core.user.User; import io.spring.core.user.UserRepository; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mybatis.spring.boot.test.autoconfigure.MybatisTest; @@ -20,14 +21,37 @@ import static org.junit.Assert.*; public class MyBatisUserRepositoryTest { @Autowired private UserRepository userRepository; + private User user; + + @Before + public void setUp() throws Exception { + user = new User("aisensiy@163.com", "aisensiy", "123", "", "default"); + } @Test public void should_save_and_fetch_user_success() throws Exception { - User user = new User("aisensiy@163.com", "aisensiy", "123", "", "default"); userRepository.save(user); Optional userOptional = userRepository.findByUsername("aisensiy"); assertThat(userOptional.get(), is(user)); Optional userOptional2 = userRepository.findByEmail("aisensiy@163.com"); assertThat(userOptional2.get(), is(user)); } + + @Test + public void should_update_user_success() throws Exception { + String newEmail = "newemail@email.com"; + user.update(newEmail, "", "", "", ""); + userRepository.save(user); + Optional optional = userRepository.findByUsername(user.getUsername()); + assertThat(optional.isPresent(), is(true)); + assertThat(optional.get().getEmail(), is(newEmail)); + + String newUsername = "newUsername"; + user.update("", newUsername, "", "", ""); + userRepository.save(user); + optional = userRepository.findByEmail(user.getEmail()); + assertThat(optional.isPresent(), is(true)); + assertThat(optional.get().getUsername(), is(newUsername)); + assertThat(optional.get().getImage(), is(user.getImage())); + } } \ No newline at end of file