diff --git a/src/main/java/com/universe/uni/config/jwt/JwtAuthenticationFilter.java b/src/main/java/com/universe/uni/config/jwt/JwtAuthenticationFilter.java index c3d6d64..45aa1db 100644 --- a/src/main/java/com/universe/uni/config/jwt/JwtAuthenticationFilter.java +++ b/src/main/java/com/universe/uni/config/jwt/JwtAuthenticationFilter.java @@ -14,7 +14,6 @@ import com.universe.uni.service.JwtManager; -import io.jsonwebtoken.JwtException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import lombok.val; diff --git a/src/main/java/com/universe/uni/controller/ControllerExceptionAdvice.java b/src/main/java/com/universe/uni/controller/ControllerExceptionAdvice.java index efc61e9..1433209 100644 --- a/src/main/java/com/universe/uni/controller/ControllerExceptionAdvice.java +++ b/src/main/java/com/universe/uni/controller/ControllerExceptionAdvice.java @@ -35,7 +35,7 @@ protected ResponseEntity handleMethodArgumentNotValid( HttpStatus status, WebRequest request ) { - ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.VALIDATION_REQUEST_MISSING_EXCEPTION); + ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.INVALID_REQUEST_METHOD); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } @@ -46,7 +46,7 @@ protected ResponseEntity handleMissingServletRequestParameter( HttpStatus status, WebRequest request ) { - ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.VALIDATION_REQUEST_MISSING_EXCEPTION); + ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.INVALID_REQUEST_METHOD); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } @@ -57,7 +57,7 @@ protected ResponseEntity handleMissingPathVariable( HttpStatus status, WebRequest request ) { - ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.VALIDATION_REQUEST_MISSING_EXCEPTION); + ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.INVALID_REQUEST_METHOD); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } @@ -65,7 +65,7 @@ protected ResponseEntity handleMissingPathVariable( protected ResponseEntity handleMissingRequestHeaderException( MissingRequestHeaderException exception ) { - ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.VALIDATION_EXCEPTION); + ErrorResponse errorResponse = ErrorResponse.businessErrorOf(ErrorType.INVALID_REQUEST_METHOD); return new ResponseEntity<>(errorResponse, HttpStatus.BAD_REQUEST); } diff --git a/src/main/java/com/universe/uni/controller/WishCouponController.java b/src/main/java/com/universe/uni/controller/WishCouponController.java new file mode 100644 index 0000000..c4b4beb --- /dev/null +++ b/src/main/java/com/universe/uni/controller/WishCouponController.java @@ -0,0 +1,30 @@ +package com.universe.uni.controller; + +import org.springframework.http.HttpStatus; +import org.springframework.web.bind.annotation.PatchMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.ResponseStatus; +import org.springframework.web.bind.annotation.RestController; + +import com.universe.uni.dto.request.UpdateWishCouponRequestDto; +import com.universe.uni.dto.response.UpdateWishCouponResponseDto; +import com.universe.uni.service.WishCouponService; + +import lombok.RequiredArgsConstructor; + +@RestController +@RequiredArgsConstructor +@RequestMapping("/api/wish") +public class WishCouponController { + + private final WishCouponService wishCouponService; + + @PatchMapping + @ResponseStatus(HttpStatus.OK) + public UpdateWishCouponResponseDto updateWishCoupon( + @RequestBody UpdateWishCouponRequestDto requestDto + ) { + return wishCouponService.uploadWishCoupon(requestDto); + } +} diff --git a/src/main/java/com/universe/uni/domain/entity/WishCoupon.java b/src/main/java/com/universe/uni/domain/entity/WishCoupon.java index 781ae4a..b43262b 100644 --- a/src/main/java/com/universe/uni/domain/entity/WishCoupon.java +++ b/src/main/java/com/universe/uni/domain/entity/WishCoupon.java @@ -1,5 +1,8 @@ package com.universe.uni.domain.entity; +import static javax.persistence.GenerationType.IDENTITY; +import static lombok.AccessLevel.PROTECTED; + import java.time.LocalDateTime; import javax.persistence.Column; @@ -15,12 +18,10 @@ import com.universe.uni.domain.GameType; import com.universe.uni.domain.entity.convertor.GameTypeAttributeConverter; +import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; -import static javax.persistence.GenerationType.IDENTITY; -import static lombok.AccessLevel.PROTECTED; - @Entity @Table(name = "wish_coupon") @NoArgsConstructor(access = PROTECTED) @@ -58,4 +59,26 @@ public class WishCoupon { @Column(name = "game_type", nullable = false) @Convert(converter = GameTypeAttributeConverter.class) private GameType gameType; + + @Builder + public WishCoupon(Long id, String image, String content, boolean isVisible, boolean isUsed, LocalDateTime usedAt, + User user, Game game, GameType gameType) { + this.id = id; + this.image = image; + this.content = content; + this.isVisible = isVisible; + this.isUsed = isUsed; + this.usedAt = usedAt; + this.user = user; + this.game = game; + this.gameType = gameType; + } + + public void updateContent(String content) { + this.content = content; + } + + public void makeVisible() { + this.isVisible = true; + } } diff --git a/src/main/java/com/universe/uni/dto/request/UpdateWishCouponRequestDto.java b/src/main/java/com/universe/uni/dto/request/UpdateWishCouponRequestDto.java new file mode 100644 index 0000000..3820b38 --- /dev/null +++ b/src/main/java/com/universe/uni/dto/request/UpdateWishCouponRequestDto.java @@ -0,0 +1,4 @@ +package com.universe.uni.dto.request; + +public record UpdateWishCouponRequestDto(String gameType, String content) { +} diff --git a/src/main/java/com/universe/uni/dto/response/UpdateWishCouponResponseDto.java b/src/main/java/com/universe/uni/dto/response/UpdateWishCouponResponseDto.java new file mode 100644 index 0000000..a09edb3 --- /dev/null +++ b/src/main/java/com/universe/uni/dto/response/UpdateWishCouponResponseDto.java @@ -0,0 +1,19 @@ +package com.universe.uni.dto.response; + +import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.annotation.JsonPropertyOrder; + +import lombok.Builder; + +@JsonPropertyOrder({"id", "image", "content", "isVisible", "isUsed", "usedAt", "gameType"}) +@Builder +public record UpdateWishCouponResponseDto( + Long id, + String image, + String content, + @JsonProperty("isVisible") boolean visible, + @JsonProperty("isUsed") boolean used, + String usedAt, + String gameType +) { +} diff --git a/src/main/java/com/universe/uni/exception/dto/ErrorType.java b/src/main/java/com/universe/uni/exception/dto/ErrorType.java index f4bd7b8..71aeb37 100644 --- a/src/main/java/com/universe/uni/exception/dto/ErrorType.java +++ b/src/main/java/com/universe/uni/exception/dto/ErrorType.java @@ -13,45 +13,55 @@ public enum ErrorType { /** * 400 BAD REQUEST */ - VALIDATION_EXCEPTION(HttpStatus.BAD_REQUEST, "UE1001", "잘못된 요청입니다."), - VALIDATION_REQUEST_MISSING_EXCEPTION(HttpStatus.BAD_REQUEST, "UE1002", "요청값이 입력되지 않았습니다."), + INVALID_REQUEST_METHOD(HttpStatus.BAD_REQUEST, "UE1001", + "요청 방식이 잘못된 경우입니다. 요청 방식 자체가 잘못된 경우입니다."), + VALIDATION_TOKEN_MISSING_EXCEPTION(HttpStatus.BAD_REQUEST, "UE1002", + "요청 시 토큰이 누락되어 토큰 값이 없는 경우입니다."), /** - * 401 UNAUTHORIZED + * 401 Unauthorized */ - EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "UE2001", "만료된 토큰 입니다."), - UNSUPPORTED_TOKEN(HttpStatus.UNAUTHORIZED, "UE2002", "잘못된 토큰 입니다"), + EXPIRED_TOKEN(HttpStatus.UNAUTHORIZED, "UE2001", "토큰이 만료된 경우입니다."), + UNSUPPORTED_TOKEN(HttpStatus.UNAUTHORIZED, "UE2002", + "서버에서 인증하지 않는 방식의 토큰 혹은 변조된 토큰을 사용한 경우입니다."), /** * 404 NOT FOUND */ - METHOD_NOT_SUPPORTED(HttpStatus.NOT_FOUND, "UE5001", "존제하지 않는 EndPoint 입니다"), - NOT_FOUND_USER_EXCEPTION(HttpStatus.NOT_FOUND, "UE5002", "존재하지 않는 유저입니다"), + INVALID_ENDPOINT_EXCEPTION(HttpStatus.NOT_FOUND, "UE5001", + "잘못된 endpoint에 요청한 경우입니다."), + USER_NOT_FOUND_EXCEPTION(HttpStatus.NOT_FOUND, "UE5002", + "조회한 유저가 존재하지 않는 경우 입니다."), /** * 406 Not Acceptable */ - NOT_ACCEPTABLE(HttpStatus.NOT_ACCEPTABLE, "UE7001", "Accept 헤더에 유효하지 않거나 지원되지 않는 미디어 유형을 지정되었습니다."), + UNSUPPORTED_MEDIA_TYPE_EXCEPTION(HttpStatus.NOT_ACCEPTABLE, "UE7001", + "Accept 헤더에 유효하지 않거나 지원되지 않는 미디어 유형을 지정한 경우입니다."), /** * 409 CONFLICT */ - ALREADY_EXIST_USER_EXCEPTION(HttpStatus.CONFLICT, "UE10001", "이미 존재하는 유저입니다"), + USER_ALREADY_EXISTS_EXCEPTION(HttpStatus.CONFLICT, "UE10001", + "이미 존재하는 유저에 대한 생성에 대한 경우입니다."), /** - * 415 Unsupported Media Type. + * 415 Unsupported Media Type */ - UNSUPPORTED_METHOD_TYPE(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "UE16001", "지원하지 않는 미디어 포멧입니다."), + UNSUPPORTED_MEDIA_FORMAT_EXCEPTION(HttpStatus.UNSUPPORTED_MEDIA_TYPE, "UE16001", + "지원하지 않는 미디어 포멧으로 요청한 경우 입니다."), /** * 500 INTERNAL SERVER ERROR */ - INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "UE0500", "예상치 못한 서버 에러가 발생하였습니다."), + INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "UE500", + "서버 내부 오류입니다."), /** * 503 Service Unavailable */ - SERVICE_UNAVAILABLE(HttpStatus.SERVICE_UNAVAILABLE, "UE0503", "서버가 작동중이지 않거나 과부하 상태입니다."); + SERVICE_UNAVAILABLE_EXCEPTION(HttpStatus.SERVICE_UNAVAILABLE, "UE503", + "서버가 작동중이지 않거나 과부하 상태입니다."); private final HttpStatus httpStatus; private final String uniErrorCode; diff --git a/src/main/java/com/universe/uni/repository/WishCouponRepository.java b/src/main/java/com/universe/uni/repository/WishCouponRepository.java new file mode 100644 index 0000000..ed3e853 --- /dev/null +++ b/src/main/java/com/universe/uni/repository/WishCouponRepository.java @@ -0,0 +1,14 @@ +package com.universe.uni.repository; + +import java.util.List; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.universe.uni.domain.GameType; +import com.universe.uni.domain.entity.WishCoupon; + +public interface WishCouponRepository extends JpaRepository { + + List findByGameTypeAndIsVisibleFalseAndIsUsedFalseAndUsedAtIsNull(GameType gameType); + +} diff --git a/src/main/java/com/universe/uni/service/WishCouponService.java b/src/main/java/com/universe/uni/service/WishCouponService.java new file mode 100644 index 0000000..0b1c1d7 --- /dev/null +++ b/src/main/java/com/universe/uni/service/WishCouponService.java @@ -0,0 +1,56 @@ +package com.universe.uni.service; + +import java.util.List; + +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.universe.uni.domain.GameType; +import com.universe.uni.domain.entity.WishCoupon; +import com.universe.uni.dto.request.UpdateWishCouponRequestDto; +import com.universe.uni.dto.response.UpdateWishCouponResponseDto; +import com.universe.uni.exception.BadRequestException; +import com.universe.uni.exception.dto.ErrorType; +import com.universe.uni.repository.WishCouponRepository; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +@Transactional +public class WishCouponService { + + private final WishCouponRepository wishCouponRepository; + + @Transactional + public UpdateWishCouponResponseDto uploadWishCoupon(UpdateWishCouponRequestDto requestDto) { + GameType gameType = GameType.valueOf(requestDto.gameType()); + List wishCouponList = wishCouponRepository.findByGameTypeAndIsVisibleFalseAndIsUsedFalseAndUsedAtIsNull( + gameType); + + if (wishCouponList.isEmpty()) { + throw new BadRequestException(ErrorType.INVALID_REQUEST_METHOD); + } + + WishCoupon wishCoupon = wishCouponList.get(0); + + wishCoupon.updateContent(requestDto.content()); + wishCoupon.makeVisible(); + + return fromWishCoupon(wishCoupon); + } + + private UpdateWishCouponResponseDto fromWishCoupon(WishCoupon wishCoupon) { + String usedAt = wishCoupon.getUsedAt() != null ? wishCoupon.getUsedAt().toString() : null; + + return UpdateWishCouponResponseDto.builder() + .id(wishCoupon.getId()) + .image(wishCoupon.getImage()) + .content(wishCoupon.getContent()) + .visible(wishCoupon.isVisible()) + .used(wishCoupon.isUsed()) + .usedAt(usedAt) + .gameType(String.valueOf(wishCoupon.getGameType())) + .build(); + } +}