Add Update Account HTTP API
- Add Command API test - Refactor Interceptor, SessionManager, ArgumentResolver
This commit is contained in:
@@ -11,6 +11,8 @@ import com.yam.app.account.presentation.AccountResponse;
|
||||
import com.yam.app.account.presentation.ConfirmRegisterAccountCommand;
|
||||
import com.yam.app.account.presentation.LoginAccountCommand;
|
||||
import com.yam.app.account.presentation.RegisterAccountCommand;
|
||||
import com.yam.app.account.presentation.UpdateAccountCommand;
|
||||
import com.yam.app.common.Authentication;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
@@ -61,4 +63,9 @@ public class AccountFacade {
|
||||
return translator.toResponse(accountReader.findByEmail(email)
|
||||
.orElseThrow(() -> new AccountNotFoundException(email)));
|
||||
}
|
||||
|
||||
@Transactional
|
||||
public void update(UpdateAccountCommand command, Authentication authentication) {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package com.yam.app.account.infrastructure;
|
||||
|
||||
import com.yam.app.common.AuthenticationPrincipal;
|
||||
import com.yam.app.common.UnauthorizedRequestException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import org.springframework.core.MethodParameter;
|
||||
@@ -24,6 +25,7 @@ public final class AuthenticationPrincipalArgumentResolver
|
||||
.getSession(false);
|
||||
|
||||
var sessionManager = new SessionManager(session);
|
||||
return sessionManager.fetchPrincipal();
|
||||
return sessionManager.fetchPrincipal()
|
||||
.orElseThrow(() -> new UnauthorizedRequestException("Failed fetch principal"));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,12 +16,6 @@ public final class SessionAuthInterceptor implements HandlerInterceptor {
|
||||
throw new UnauthorizedRequestException("Unauthorized request");
|
||||
}
|
||||
|
||||
var sessionManager = new SessionManager(session);
|
||||
|
||||
if (!sessionManager.isExistPrincipal()) {
|
||||
throw new UnauthorizedRequestException("Failed fetch principal");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.yam.app.account.infrastructure;
|
||||
|
||||
import java.util.Optional;
|
||||
import javax.servlet.http.HttpSession;
|
||||
|
||||
public final class SessionManager {
|
||||
@@ -16,12 +17,8 @@ public final class SessionManager {
|
||||
this.httpSession.setAttribute(LOGIN_ACCOUNT, principal);
|
||||
}
|
||||
|
||||
public AccountPrincipal fetchPrincipal() {
|
||||
return (AccountPrincipal) httpSession.getAttribute(LOGIN_ACCOUNT);
|
||||
}
|
||||
|
||||
public boolean isExistPrincipal() {
|
||||
return httpSession.getAttribute(LOGIN_ACCOUNT) != null;
|
||||
public Optional<AccountPrincipal> fetchPrincipal() {
|
||||
return Optional.ofNullable((AccountPrincipal) httpSession.getAttribute(LOGIN_ACCOUNT));
|
||||
}
|
||||
|
||||
public void removePrincipal() {
|
||||
|
||||
@@ -2,6 +2,8 @@ package com.yam.app.account.presentation;
|
||||
|
||||
import com.yam.app.account.application.AccountFacade;
|
||||
import com.yam.app.account.infrastructure.SessionManager;
|
||||
import com.yam.app.common.Authentication;
|
||||
import com.yam.app.common.AuthenticationPrincipal;
|
||||
import java.net.URI;
|
||||
import javax.servlet.http.HttpSession;
|
||||
import javax.validation.Valid;
|
||||
@@ -11,6 +13,7 @@ import org.springframework.http.MediaType;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ModelAttribute;
|
||||
import org.springframework.web.bind.annotation.PatchMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
@@ -65,4 +68,12 @@ public final class AccountCommandApi {
|
||||
session.removePrincipal();
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
|
||||
@PatchMapping("/api/accounts/update")
|
||||
public ResponseEntity<Void> update(
|
||||
@RequestBody @Valid UpdateAccountCommand command,
|
||||
@AuthenticationPrincipal Authentication authentication) {
|
||||
accountFacade.update(command, authentication);
|
||||
return ResponseEntity.ok().build();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.yam.app.account.presentation;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.Pattern;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public final class UpdateAccountCommand {
|
||||
|
||||
@NotBlank
|
||||
@Pattern(regexp = "^[A-Za-z1-9~!@#$%^&*()+|=]{8,12}$",
|
||||
message = "Please enter the password in English, numbers, "
|
||||
+ "and special characters within 8-12 digits.")
|
||||
private String password;
|
||||
|
||||
@NotBlank
|
||||
private String nickname;
|
||||
|
||||
@NotBlank
|
||||
private String image;
|
||||
}
|
||||
@@ -7,8 +7,7 @@ public final class AccountApiUri {
|
||||
public static final String LOGIN = "/api/accounts/login";
|
||||
public static final String FIND_INFO = "/api/accounts/me";
|
||||
public static final String LOGOUT = "/api/accounts/logout";
|
||||
|
||||
public static final String UNAUTHORIZED_REQUEST = "/api/accounts/error/UnauthorizedRequest";
|
||||
public static final String UPDATE = "/api/accounts/update";
|
||||
|
||||
private AccountApiUri() {
|
||||
}
|
||||
|
||||
@@ -4,8 +4,10 @@ import static com.yam.app.account.presentation.AccountApiUri.EMAIL_CONFIRM;
|
||||
import static com.yam.app.account.presentation.AccountApiUri.LOGIN;
|
||||
import static com.yam.app.account.presentation.AccountApiUri.LOGOUT;
|
||||
import static com.yam.app.account.presentation.AccountApiUri.REGISTER;
|
||||
import static com.yam.app.account.presentation.AccountApiUri.UPDATE;
|
||||
import static org.mockito.Mockito.doThrow;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
|
||||
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
|
||||
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
||||
@@ -24,6 +26,7 @@ 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.http.MediaType;
|
||||
import org.springframework.mock.web.MockHttpSession;
|
||||
import org.springframework.test.web.servlet.MockMvc;
|
||||
import org.springframework.test.web.servlet.ResultActions;
|
||||
|
||||
@@ -46,6 +49,81 @@ final class AccountCommandApiTests {
|
||||
.andExpect(jsonPath("$.message").value("Invalid argument"));
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("회원 정보 수정 HTTP API")
|
||||
class UpdateAccountApi {
|
||||
|
||||
@Test
|
||||
@DisplayName("인증되지 않은 사용자가 정보 변경을 요청하면 401 에러를 반환한다.")
|
||||
void not_authentication_update_command() throws Exception {
|
||||
var command = new UpdateAccountCommand();
|
||||
command.setImage("temp.png");
|
||||
command.setNickname("jiwon");
|
||||
command.setPassword("password!2");
|
||||
|
||||
//Act
|
||||
final var actions = mockMvc.perform(patch(UPDATE)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(command))
|
||||
);
|
||||
|
||||
//Assert
|
||||
actions
|
||||
.andExpect(status().isUnauthorized())
|
||||
.andExpect(jsonPath("$.success").value(false))
|
||||
.andExpect(jsonPath("$.data").doesNotExist())
|
||||
.andExpect(jsonPath("$.message").value("Unauthorized request"));
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@ValueSource(strings = {"1", "a", "1a234567890123456"})
|
||||
@DisplayName("인증된 사용자의 요청 Body 비밀번호 형식이 맞지 않은 경우 400 에러를 반환한다.")
|
||||
void http_json_password_is_invalid(String args) throws Exception {
|
||||
// Arrange
|
||||
var session = new MockHttpSession();
|
||||
var command = new UpdateAccountCommand();
|
||||
command.setImage("temp.png");
|
||||
command.setNickname("jiwon");
|
||||
command.setPassword(args);
|
||||
|
||||
// Act
|
||||
final var actions = mockMvc.perform(patch(UPDATE)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(command))
|
||||
.session(session)
|
||||
);
|
||||
|
||||
// Assert
|
||||
assertThatInvalidArgumentError(actions);
|
||||
}
|
||||
|
||||
@ParameterizedTest
|
||||
@NullAndEmptySource
|
||||
@DisplayName("인증된 사용자의 요청 Body 정보가 null 혹은 empty인 경우 400 에러를 반환한다.")
|
||||
void http_json_value_is_empty_or_null(String args) throws Exception {
|
||||
//Arrange
|
||||
var session = new MockHttpSession();
|
||||
var command = new UpdateAccountCommand();
|
||||
command.setNickname(args);
|
||||
command.setPassword(args);
|
||||
command.setImage(args);
|
||||
|
||||
//Act
|
||||
final var actions = mockMvc.perform(patch(UPDATE)
|
||||
.accept(MediaType.APPLICATION_JSON)
|
||||
.contentType(MediaType.APPLICATION_JSON)
|
||||
.content(objectMapper.writeValueAsString(command))
|
||||
.session(session)
|
||||
);
|
||||
|
||||
//Assert
|
||||
assertThatInvalidArgumentError(actions);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("로그인 HTTP API")
|
||||
class LoginApi {
|
||||
|
||||
Reference in New Issue
Block a user