diff --git a/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java b/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java index 279a8ea..a666b57 100644 --- a/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java +++ b/server/src/main/java/com/ticketing/server/global/exception/ErrorCode.java @@ -17,6 +17,7 @@ public enum ErrorCode { MISMATCH_PASSWORD(BAD_REQUEST, "비밀번호가 일치하지 않습니다."), TOKEN_TYPE(BAD_REQUEST, "토큰 타입이 올바르지 않습니다."), UNAVAILABLE_REFRESH_TOKEN(BAD_REQUEST, "사용할 수 없는 토큰 입니다."), + UNABLE_CHANGE_GRADE(BAD_REQUEST, "동일한 등급으로 변경할 수 없습니다."), /* 403 FORBIDDEN : 접근 권한 제한 */ VALID_USER_ID(FORBIDDEN, "해당 정보에 접근 권한이 존재하지 않습니다."), @@ -50,6 +51,10 @@ public enum ErrorCode { throw new TicketingException(UNAVAILABLE_REFRESH_TOKEN); } + public static TicketingException throwUnableChangeGrade() { + throw new TicketingException(UNABLE_CHANGE_GRADE); + } + /* 403 FORBIDDEN : 접근 권한 제한 */ public static TicketingException throwValidUserId() { throw new TicketingException(VALID_USER_ID); diff --git a/server/src/main/java/com/ticketing/server/user/application/UserChangeGradeResponse.java b/server/src/main/java/com/ticketing/server/user/application/UserChangeGradeResponse.java new file mode 100644 index 0000000..93b5878 --- /dev/null +++ b/server/src/main/java/com/ticketing/server/user/application/UserChangeGradeResponse.java @@ -0,0 +1,17 @@ +package com.ticketing.server.user.application; + +import com.ticketing.server.user.domain.UserGrade; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class UserChangeGradeResponse { + + private String email; + + private UserGrade beforeGrade; + + private UserGrade afterGrade; + +} diff --git a/server/src/main/java/com/ticketing/server/user/application/UserController.java b/server/src/main/java/com/ticketing/server/user/application/UserController.java index aa97400..7c659ae 100644 --- a/server/src/main/java/com/ticketing/server/user/application/UserController.java +++ b/server/src/main/java/com/ticketing/server/user/application/UserController.java @@ -1,6 +1,10 @@ package com.ticketing.server.user.application; +import static com.ticketing.server.user.domain.UserGrade.ROLES.ADMIN; +import static com.ticketing.server.user.domain.UserGrade.ROLES.USER; + import com.ticketing.server.user.application.request.SignUpRequest; +import com.ticketing.server.user.application.request.UserChangeGradeRequest; import com.ticketing.server.user.application.request.UserChangePasswordRequest; import com.ticketing.server.user.application.request.UserDeleteRequest; import com.ticketing.server.user.application.response.PaymentsResponse; @@ -53,7 +57,7 @@ public class UserController { } @GetMapping("/details") - @Secured(UserGrade.ROLES.USER) + @Secured(USER) public ResponseEntity details(@AuthenticationPrincipal UserDetails userRequest) { UserDetailDTO userDetail = userService.findDetailByEmail(userRequest.getUsername()); @@ -62,7 +66,7 @@ public class UserController { } @DeleteMapping - @Secured(UserGrade.ROLES.USER) + @Secured(USER) public ResponseEntity deleteUser(@RequestBody @Valid UserDeleteRequest request) { DeletedUserDTO deletedUserDto = userService.delete(request.toDeleteUserDto(passwordEncoder)); @@ -71,7 +75,7 @@ public class UserController { } @PutMapping("/password") - @Secured(UserGrade.ROLES.USER) + @Secured(USER) public ResponseEntity changePassword( @AuthenticationPrincipal UserDetails userRequest, @RequestBody @Valid UserChangePasswordRequest request) { @@ -82,8 +86,15 @@ public class UserController { .body(changedUserDto.toResponse()); } + @PostMapping("/grade") + @Secured(ADMIN) + public ResponseEntity changeGrade(@RequestBody @Valid UserChangeGradeRequest request) { + ChangeGradeDTO changeGradeDto = userService.changeGrade(request.getEmail(), request.getAfterGrade()); + return ResponseEntity.status(HttpStatus.OK).body(changeGradeDto.toResponse()); + } + @GetMapping("/payments") - @Secured(UserGrade.ROLES.USER) + @Secured(USER) public ResponseEntity getPayments(@AuthenticationPrincipal UserDetails userRequest) { PaymentsDTO paymentsDto = userApisService.findPaymentsByEmail(userRequest.getUsername()); diff --git a/server/src/main/java/com/ticketing/server/user/application/request/UserChangeGradeRequest.java b/server/src/main/java/com/ticketing/server/user/application/request/UserChangeGradeRequest.java new file mode 100644 index 0000000..ba70360 --- /dev/null +++ b/server/src/main/java/com/ticketing/server/user/application/request/UserChangeGradeRequest.java @@ -0,0 +1,19 @@ +package com.ticketing.server.user.application.request; + +import com.ticketing.server.user.domain.UserGrade; +import javax.validation.constraints.Email; +import javax.validation.constraints.NotEmpty; +import javax.validation.constraints.NotNull; +import lombok.Getter; + +@Getter +public class UserChangeGradeRequest { + + @NotEmpty(message = "{validation.not.empty.email}") + @Email(message = "{validation.email}") + private String email; + + @NotNull(message = "{validation.not.null.grade}") + private UserGrade afterGrade; + +} diff --git a/server/src/main/java/com/ticketing/server/user/domain/ChangeGradeDTO.java b/server/src/main/java/com/ticketing/server/user/domain/ChangeGradeDTO.java new file mode 100644 index 0000000..249b782 --- /dev/null +++ b/server/src/main/java/com/ticketing/server/user/domain/ChangeGradeDTO.java @@ -0,0 +1,19 @@ +package com.ticketing.server.user.domain; + +import com.ticketing.server.user.application.UserChangeGradeResponse; +import lombok.AllArgsConstructor; +import lombok.Getter; + +@Getter +@AllArgsConstructor +public class ChangeGradeDTO { + + private final String email; + private final UserGrade beforeGrade; + private final UserGrade afterGrade; + + public UserChangeGradeResponse toResponse() { + return new UserChangeGradeResponse(email, beforeGrade, afterGrade); + } + +} diff --git a/server/src/main/java/com/ticketing/server/user/domain/User.java b/server/src/main/java/com/ticketing/server/user/domain/User.java index 44c4732..7d58eee 100644 --- a/server/src/main/java/com/ticketing/server/user/domain/User.java +++ b/server/src/main/java/com/ticketing/server/user/domain/User.java @@ -93,4 +93,14 @@ public class User extends AbstractEntity { } } + public ChangeGradeDTO changeGrade(UserGrade afterGrade) { + if (grade.equals(afterGrade)) { + throw ErrorCode.throwUnableChangeGrade(); + } + final UserGrade beforeGrade = this.grade; + + this.grade = afterGrade; + return new ChangeGradeDTO(email, beforeGrade, afterGrade); + } + } diff --git a/server/src/main/java/com/ticketing/server/user/service/UserServiceImpl.java b/server/src/main/java/com/ticketing/server/user/service/UserServiceImpl.java index fc59a45..af8fdac 100644 --- a/server/src/main/java/com/ticketing/server/user/service/UserServiceImpl.java +++ b/server/src/main/java/com/ticketing/server/user/service/UserServiceImpl.java @@ -1,8 +1,10 @@ package com.ticketing.server.user.service; import com.ticketing.server.global.exception.ErrorCode; +import com.ticketing.server.user.domain.ChangeGradeDTO; import com.ticketing.server.user.domain.SequenceGenerator; import com.ticketing.server.user.domain.User; +import com.ticketing.server.user.domain.UserGrade; import com.ticketing.server.user.domain.repository.UserRepository; import com.ticketing.server.user.service.dto.ChangePasswordDTO; import com.ticketing.server.user.service.dto.ChangedPasswordUserDTO; @@ -61,6 +63,13 @@ public class UserServiceImpl implements UserService { return new ChangedPasswordUserDTO(user); } + @Override + @Transactional + public ChangeGradeDTO changeGrade(@NotNull String email, @NotNull UserGrade grade) { + User user = findNotDeletedUserByEmail(email); + return user.changeGrade(grade); + } + @Override public UserDetailDTO findDetailByEmail(@NotNull String email) { User user = userRepository.findByEmail(email) diff --git a/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java b/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java index 49449f0..0b521ec 100644 --- a/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java +++ b/server/src/main/java/com/ticketing/server/user/service/interfaces/UserService.java @@ -1,5 +1,6 @@ package com.ticketing.server.user.service.interfaces; +import com.ticketing.server.user.domain.ChangeGradeDTO; import com.ticketing.server.user.domain.User; import com.ticketing.server.user.service.dto.ChangedPasswordUserDTO; import com.ticketing.server.user.service.dto.DeletedUserDTO; @@ -10,6 +11,7 @@ import com.ticketing.server.user.service.dto.SignUpDTO; import com.ticketing.server.user.service.dto.UserDetailDTO; import javax.validation.Valid; import javax.validation.constraints.NotNull; +import org.springframework.transaction.annotation.Transactional; public interface UserService { @@ -19,6 +21,9 @@ public interface UserService { ChangedPasswordUserDTO changePassword(@Valid ChangePasswordDTO changePasswordDto); + @Transactional + ChangeGradeDTO changeGrade(@NotNull String email, @NotNull UserGrade grade); + UserDetailDTO findDetailByEmail(@NotNull String email); User findNotDeletedUserByEmail(@NotNull String email); diff --git a/server/src/test/java/com/ticketing/server/user/domain/UserTest.java b/server/src/test/java/com/ticketing/server/user/domain/UserTest.java index 221d691..bb7ee84 100644 --- a/server/src/test/java/com/ticketing/server/user/domain/UserTest.java +++ b/server/src/test/java/com/ticketing/server/user/domain/UserTest.java @@ -2,7 +2,9 @@ package com.ticketing.server.user.domain; import static org.assertj.core.api.Assertions.assertThat; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.api.Assertions.assertAll; +import com.ticketing.server.global.exception.ErrorCode; import com.ticketing.server.global.exception.TicketingException; import com.ticketing.server.user.service.dto.ChangePasswordDTO; import com.ticketing.server.user.service.dto.DeleteUserDTO; @@ -33,6 +35,37 @@ public class UserTest { users = provideCorrectUsers().collect(Collectors.toMap(User::getEmail, user -> user)); } + @Test + @DisplayName("동일한 권한으로 변경 시 예외처리") + void changeGradeFail() { + // given + User user = users.get("ticketing1@gmail.com"); + + // when + // then + assertThatThrownBy(() -> user.changeGrade(UserGrade.USER)) + .isInstanceOf(TicketingException.class) + .extracting("errorCode") + .isEqualTo(ErrorCode.UNABLE_CHANGE_GRADE); + } + + @Test + @DisplayName("권한 변경 성공") + void changeGradeSuccess() { + // given + User user = users.get("ticketing1@gmail.com"); + + // when + ChangeGradeDTO changeGradeDto = user.changeGrade(UserGrade.ADMIN); + + // then + assertAll( + () -> assertThat(changeGradeDto.getEmail()).isEqualTo("ticketing1@gmail.com"), + () -> assertThat(changeGradeDto.getBeforeGrade()).isEqualTo(UserGrade.USER), + () -> assertThat(changeGradeDto.getAfterGrade()).isEqualTo(UserGrade.ADMIN) + ); + } + @ParameterizedTest @MethodSource("provideDifferentPasswordDeleteUsers") @DisplayName("입력된 패스워드가 다를 경우")