Skip to content

Commit

Permalink
Merge pull request #47 from Kusitms-POPTATO-DEV/feat/change-mypage-name
Browse files Browse the repository at this point in the history
Feat#40: 마이페이지 이름 변경
  • Loading branch information
pkl0912 authored Oct 17, 2024
2 parents af0b1e6 + 49575ee commit dea37a6
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 36 deletions.
14 changes: 14 additions & 0 deletions src/main/java/server/poptato/auth/exception/AuthException.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package server.poptato.auth.exception;

import lombok.Getter;
import server.poptato.global.response.status.ResponseStatus;

@Getter
public class AuthException extends RuntimeException{
private final ResponseStatus exceptionStatus;

public AuthException(ResponseStatus exceptionStatus) {
super(exceptionStatus.getMessage());
this.exceptionStatus = exceptionStatus;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package server.poptato.auth.exception.errorcode;

import lombok.RequiredArgsConstructor;
import org.springframework.http.HttpStatus;
import server.poptato.global.response.status.ResponseStatus;

@RequiredArgsConstructor
public enum AuthExceptionErrorCode implements ResponseStatus {

/**
* 6000: Auth 도메인 오류
*/

TOKEN_NOT_EXIST(6000, HttpStatus.BAD_REQUEST.value(), "토큰 값이 필요합니다."),
TOKEN_TIME_EXPIRED(6001, HttpStatus.BAD_REQUEST.value(), "토큰이 만료되었습니다"),
INVALID_TOKEN(6002, HttpStatus.BAD_REQUEST.value(), "토큰이 유효하지 않습니다");

private final int code;
private final int status;
private final String message;


@Override
public int getCode() {
return code;
}

@Override
public int getStatus() {
return status;
}

@Override
public String getMessage() {
return message;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package server.poptato.auth.exception.handler;

import lombok.extern.slf4j.Slf4j;
import org.springframework.core.annotation.Order;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import server.poptato.auth.exception.AuthException;
import server.poptato.global.response.BaseErrorResponse;

@Slf4j
@Order(0)
@RestControllerAdvice
public class AuthExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ExceptionHandler(AuthException.class)
public BaseErrorResponse handleAuthException(AuthException e) {
log.error("[UserException: handle_UserException 호출]", e);
return new BaseErrorResponse(e.getExceptionStatus(), e.getMessage());
}
}
13 changes: 9 additions & 4 deletions src/main/java/server/poptato/user/api/UserController.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
package server.poptato.user.api;

import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import server.poptato.global.response.BaseResponse;
import server.poptato.user.api.request.UserChangeNameRequestDto;
import server.poptato.user.application.service.UserService;
import server.poptato.user.resolver.UserId;

Expand All @@ -20,6 +20,11 @@ public class UserController {
@DeleteMapping
public BaseResponse deleteUser(@UserId Long userId) {
userService.deleteUser(userId);
return new BaseResponse(SUCCESS);
return new BaseResponse();
}
@PatchMapping("/mypage")
public BaseResponse updateUserName(@UserId Long userId, @Validated @RequestBody UserChangeNameRequestDto request) {
userService.updateUserName(userId, request.getNewName());
return new BaseResponse();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package server.poptato.user.api.request;

import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Builder
@Getter
@AllArgsConstructor
@NoArgsConstructor
public class UserChangeNameRequestDto {
@NotBlank(message = "이름은 빈 값일 수 없습니다.")
String newName;
}
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,13 @@ public Optional<User> findUserByKakaoId(String kakaoId) {
entityManager.clear(); // 영속성 컨텍스트 초기화
return userRepository.findByKakaoId(kakaoId);
}
@Transactional
public void updateUserName(Long userId, String newName) {
// 사용자 조회
User user = userRepository.findById(userId)
.orElseThrow(() -> new UserException(UserExceptionErrorCode.USER_NOT_EXIST));

// name 업데이트
user.changeName(newName);
}
}
4 changes: 4 additions & 0 deletions src/main/java/server/poptato/user/domain/entity/User.java
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,8 @@ public class User {
@LastModifiedDate // 엔티티가 수정될 때 시간 자동 저장
private LocalDateTime modifyDate;

// name 변경 메서드
public void changeName(String newName) {
this.name = newName;
}
}
8 changes: 5 additions & 3 deletions src/main/java/server/poptato/user/resolver/UserResolver.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,12 @@
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;
import server.poptato.auth.application.service.JwtService;
import server.poptato.auth.exception.AuthException;
import server.poptato.global.exception.BaseException;
import server.poptato.global.response.BaseErrorResponse;
import server.poptato.user.resolver.UserId;

import static server.poptato.auth.exception.errorcode.AuthExceptionErrorCode.*;
import static server.poptato.global.exception.errorcode.BaseExceptionErrorCode.*;


Expand All @@ -32,17 +34,17 @@ public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer m
final HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest();
final String token = request.getHeader("Authorization");
if (token == null || token.isBlank() || !token.startsWith("Bearer ")) {
throw new BaseException(TOKEN_NOT_CONTAINED_EXCEPTION);
throw new AuthException(TOKEN_NOT_EXIST);
}
final String encodedUserId = token.substring("Bearer ".length());
if (!jwtService.verifyToken(encodedUserId)) {
throw new BaseException(TOKEN_TIME_EXPIRED_EXCEPTION);
throw new AuthException(TOKEN_TIME_EXPIRED);
}
final String decodedUserId = jwtService.getUserIdInToken(encodedUserId);
try {
return Long.parseLong(decodedUserId);
} catch (NumberFormatException e) {
return new BaseErrorResponse(INVALID_TOKEN_EXCEPTION);
return new AuthException(INVALID_TOKEN);
}
}
}
77 changes: 48 additions & 29 deletions src/test/java/server/poptato/user/api/UserControllerTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package server.poptato.user.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.validation.Validator;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
Expand All @@ -9,16 +11,17 @@
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import server.poptato.auth.application.service.JwtService;
import server.poptato.todo.infra.repository.JpaTodoRepository;
import server.poptato.todo.application.TodoService;
import server.poptato.user.api.request.UserChangeNameRequestDto;
import server.poptato.user.application.service.UserService;
import server.poptato.user.infra.repository.JpaUserRepository;

import static org.mockito.ArgumentMatchers.anyString;
import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.when;
import static org.mockito.Mockito.*;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

Expand All @@ -28,44 +31,63 @@ class UserControllerTest {

@Autowired
private MockMvc mockMvc;

@MockBean
private JwtService jwtService;

private TodoService todoService;
@MockBean
private UserService userService;

@MockBean
private JpaUserRepository userRepository;

@MockBean
private JpaTodoRepository todoRepository;

@Autowired
private JwtService jwtService;
@MockBean
private RedisTemplate<String, String> redisTemplate;

private Validator validator;
private String accessToken;
private final Long userId = 1L;
private final String userId = "1";
private ObjectMapper objectMapper;

@BeforeEach
void createAccessToken() {
accessToken = jwtService.createAccessToken(userId.toString());
void userId가_1인_액세스토큰_생성() {
accessToken = jwtService.createAccessToken(userId);
}

@AfterEach
void deleteRefreshToken() {
jwtService.deleteRefreshToken(userId.toString());
void 액세스토큰_비활성화() {
jwtService.deleteRefreshToken(userId);
}
@Test
@DisplayName("사용자 이름 변경 성공 테스트")
void updateUserName_ShouldReturnSuccess() throws Exception {

// when & then
mockMvc.perform(patch("/user/mypage")
.header("Authorization", "Bearer " + accessToken) // JWT 토큰을 전달하는 부분
.contentType(MediaType.APPLICATION_JSON)
.content("{\"newName\": \"NewName\"}")) // content를 "NewName"으로 수정
.andExpect(status().isOk());

// userService의 updateUserName이 올바르게 호출되는지 확인
verify(userService, times(1)).updateUserName(anyLong(), eq("NewName")); // "NewName"과 일치하도록 수정
}

@Test
@DisplayName("사용자 이름 변경 실패 - 이름이 빈 값일 때")
void updateUserName_ShouldReturnBadRequest_WhenNameIsEmpty() throws Exception {
// given
Long userId = 1L;
UserChangeNameRequestDto requestDto = new UserChangeNameRequestDto(""); // 빈 이름

// when & then
mockMvc.perform(patch("/user/mypage")
.header("Authorization", "Bearer "+accessToken)
.contentType(MediaType.APPLICATION_JSON)
.content("{\"newName\": \"\"}"))
.andExpect(status().isBadRequest());

// userService가 호출되지 않는지 확인
verify(userService, times(0)).updateUserName(anyLong(), anyString());
}
@Test
@DisplayName("회원 탈퇴 성공 - 토큰 검증 후 응답 확인")
void deleteUserSuccess() throws Exception {
// 토큰 검증 성공
when(jwtService.verifyToken(anyString())).thenReturn(true);
when(jwtService.getUserIdInToken(anyString())).thenReturn(userId.toString());

// UserService의 deleteUser()가 호출되는지 확인
doNothing().when(userService).deleteUser(userId);

mockMvc.perform(MockMvcRequestBuilders.delete("/user")
.header("Authorization", "Bearer " + accessToken))
Expand All @@ -86,9 +108,6 @@ void deleteUserFailureNoToken() throws Exception {
void deleteUserFailureInvalidToken() throws Exception {
String invalidToken = "invalidToken";

// 토큰 검증 실패
when(jwtService.verifyToken(anyString())).thenReturn(false);

mockMvc.perform(MockMvcRequestBuilders.delete("/user")
.header("Authorization", "Bearer " + invalidToken))
.andExpect(status().isBadRequest())
Expand Down
58 changes: 58 additions & 0 deletions src/test/java/server/poptato/user/application/UserServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package server.poptato.user.application;

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import server.poptato.user.application.service.UserService;
import server.poptato.user.domain.entity.User;
import server.poptato.user.domain.repository.UserRepository;
import server.poptato.user.exception.UserException;
import server.poptato.user.exception.errorcode.UserExceptionErrorCode;

import static org.assertj.core.api.Assertions.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;

@SpringBootTest
class UserServiceTest {

@Autowired
private UserService userService;

@Autowired
private UserRepository userRepository;

@Test
@DisplayName("사용자 이름 변경 성공 테스트")
@Transactional
void updateUserName_ShouldChangeUserName() {
// given
Long userId = 1L;
String newName = "New Name";

// when
userService.updateUserName(userId, newName);

// then
User updatedUser = userRepository.findById(userId).orElseThrow();
assertThat(updatedUser.getName()).isEqualTo(newName);
}

@Test
@DisplayName("존재하지 않는 사용자일 경우 예외 발생 테스트")
@Transactional
void updateUserName_ShouldThrowException_WhenUserNotFound() {
// given
Long nonExistentUserId = 999L; // 존재하지 않는 유저 ID
String newName = "New Name";

// when & then
UserException exception = assertThrows(UserException.class, () -> {
userService.updateUserName(nonExistentUserId, newName);
});

assertThat(exception.getMessage()).isEqualTo(UserExceptionErrorCode.USER_NOT_EXIST.getMessage());
}
}

0 comments on commit dea37a6

Please sign in to comment.