generated from pricelees/issue-pr-template
[#5]: 공통 기능 코틀린 마이그레이션 및 패키지 분리 #6
@ -12,16 +12,12 @@ body:
|
|||||||
label: 배경
|
label: 배경
|
||||||
description: 이 기능을 추가하게 된 배경을 작성해주세요.
|
description: 이 기능을 추가하게 된 배경을 작성해주세요.
|
||||||
placeholder: 기능을 추가하기 전 상황은 간단하게, 추가하게 된 이유는 가급적 자세하게 작성해주세요!
|
placeholder: 기능을 추가하기 전 상황은 간단하게, 추가하게 된 이유는 가급적 자세하게 작성해주세요!
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: changes
|
id: changes
|
||||||
attributes:
|
attributes:
|
||||||
label: 작업 내용
|
label: 작업 내용
|
||||||
description: 필요한 작업 내용을 작성해주세요.
|
description: 필요한 작업 내용을 작성해주세요.
|
||||||
placeholder: 작업과 그 작업의 예상 결과를 작성해주세요!
|
placeholder: 작업과 그 작업의 예상 결과를 작성해주세요!
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: notes
|
id: notes
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@ -12,8 +12,6 @@ body:
|
|||||||
label: 배경
|
label: 배경
|
||||||
description: 발생한 버그가 어떤 상황에서 발생했는지 작성해주세요.
|
description: 발생한 버그가 어떤 상황에서 발생했는지 작성해주세요.
|
||||||
placeholder: 버그 발생 시나리오, 재현 방법, 로그 등을 자세히 작성해주세요!
|
placeholder: 버그 발생 시나리오, 재현 방법, 로그 등을 자세히 작성해주세요!
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: changes
|
id: changes
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@ -12,16 +12,12 @@ body:
|
|||||||
label: 배경
|
label: 배경
|
||||||
description: 리팩터링을 결정하게 된 배경을 작성해주세요.
|
description: 리팩터링을 결정하게 된 배경을 작성해주세요.
|
||||||
placeholder: 현재 코드의 문제점, 리팩토링을 통해 얻을 수 있는 이점 등을 상세히 작성해 주세요!
|
placeholder: 현재 코드의 문제점, 리팩토링을 통해 얻을 수 있는 이점 등을 상세히 작성해 주세요!
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: changes
|
id: changes
|
||||||
attributes:
|
attributes:
|
||||||
label: 작업 내용
|
label: 작업 내용
|
||||||
description: 필요한 작업 내용을 작성해주세요.
|
description: 필요한 작업 내용을 작성해주세요.
|
||||||
placeholder: 작업과 그 작업의 예상 결과를 작성해주세요!
|
placeholder: 작업과 그 작업의 예상 결과를 작성해주세요!
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: notes
|
id: notes
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@ -12,8 +12,6 @@ body:
|
|||||||
label: 배경
|
label: 배경
|
||||||
description: 작업의 배경과 상황을 작성해주세요.
|
description: 작업의 배경과 상황을 작성해주세요.
|
||||||
placeholder: 구체적으로 작성할 수록 좋아요!
|
placeholder: 구체적으로 작성할 수록 좋아요!
|
||||||
validations:
|
|
||||||
required: true
|
|
||||||
- type: textarea
|
- type: textarea
|
||||||
id: changes
|
id: changes
|
||||||
attributes:
|
attributes:
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package roomescape.system.auth.infrastructure.jwt
|
package roomescape.auth.infrastructure.jwt
|
||||||
|
|
||||||
import io.jsonwebtoken.*
|
import io.jsonwebtoken.*
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.stereotype.Component
|
import org.springframework.stereotype.Component
|
||||||
import roomescape.system.exception.ErrorType
|
import roomescape.common.exception.ErrorType
|
||||||
import roomescape.system.exception.RoomEscapeException
|
import roomescape.common.exception.RoomescapeException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
@ -38,12 +38,12 @@ class JwtHandler(
|
|||||||
.toLong()
|
.toLong()
|
||||||
} catch (e: Exception) {
|
} catch (e: Exception) {
|
||||||
when (e) {
|
when (e) {
|
||||||
is ExpiredJwtException -> throw RoomEscapeException(ErrorType.EXPIRED_TOKEN, HttpStatus.UNAUTHORIZED)
|
is ExpiredJwtException -> throw RoomescapeException(ErrorType.EXPIRED_TOKEN, HttpStatus.UNAUTHORIZED)
|
||||||
is UnsupportedJwtException -> throw RoomEscapeException(ErrorType.UNSUPPORTED_TOKEN, HttpStatus.UNAUTHORIZED)
|
is UnsupportedJwtException -> throw RoomescapeException(ErrorType.UNSUPPORTED_TOKEN, HttpStatus.UNAUTHORIZED)
|
||||||
is MalformedJwtException -> throw RoomEscapeException(ErrorType.MALFORMED_TOKEN, HttpStatus.UNAUTHORIZED)
|
is MalformedJwtException -> throw RoomescapeException(ErrorType.MALFORMED_TOKEN, HttpStatus.UNAUTHORIZED)
|
||||||
is SignatureException -> throw RoomEscapeException(ErrorType.INVALID_SIGNATURE_TOKEN, HttpStatus.UNAUTHORIZED)
|
is SignatureException -> throw RoomescapeException(ErrorType.INVALID_SIGNATURE_TOKEN, HttpStatus.UNAUTHORIZED)
|
||||||
is IllegalArgumentException -> throw RoomEscapeException(ErrorType.INVALID_TOKEN, HttpStatus.UNAUTHORIZED)
|
is IllegalArgumentException -> throw RoomescapeException(ErrorType.INVALID_TOKEN, HttpStatus.UNAUTHORIZED)
|
||||||
else -> throw RoomEscapeException(ErrorType.UNEXPECTED_ERROR, HttpStatus.INTERNAL_SERVER_ERROR)
|
else -> throw RoomescapeException(ErrorType.UNEXPECTED_ERROR, HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,12 +1,12 @@
|
|||||||
package roomescape.system.auth.service
|
package roomescape.auth.service
|
||||||
|
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import roomescape.member.business.MemberService
|
import roomescape.member.business.MemberService
|
||||||
import roomescape.member.infrastructure.persistence.Member
|
import roomescape.member.infrastructure.persistence.Member
|
||||||
import roomescape.system.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
import roomescape.system.auth.web.LoginCheckResponse
|
import roomescape.auth.web.LoginCheckResponse
|
||||||
import roomescape.system.auth.web.LoginRequest
|
import roomescape.auth.web.LoginRequest
|
||||||
import roomescape.system.auth.web.TokenResponse
|
import roomescape.auth.web.TokenResponse
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
class AuthService(
|
class AuthService(
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.system.auth.web
|
package roomescape.auth.web
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Operation
|
import io.swagger.v3.oas.annotations.Operation
|
||||||
import io.swagger.v3.oas.annotations.Parameter
|
import io.swagger.v3.oas.annotations.Parameter
|
||||||
@ -13,10 +13,10 @@ import jakarta.validation.Valid
|
|||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.web.bind.annotation.RequestBody
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus
|
import org.springframework.web.bind.annotation.ResponseStatus
|
||||||
import roomescape.system.auth.web.support.LoginRequired
|
import roomescape.auth.web.support.LoginRequired
|
||||||
import roomescape.system.auth.web.support.MemberId
|
import roomescape.auth.web.support.MemberId
|
||||||
import roomescape.system.dto.response.ErrorResponse
|
import roomescape.common.dto.response.ErrorResponse
|
||||||
import roomescape.system.dto.response.RoomEscapeApiResponse
|
import roomescape.common.dto.response.RoomEscapeApiResponse
|
||||||
|
|
||||||
@Tag(name = "1. 인증 / 인가 API", description = "로그인, 로그아웃 및 로그인 상태를 확인합니다")
|
@Tag(name = "1. 인증 / 인가 API", description = "로그인, 로그아웃 및 로그인 상태를 확인합니다")
|
||||||
interface AuthAPI {
|
interface AuthAPI {
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.system.auth.web
|
package roomescape.auth.web
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.Parameter
|
import io.swagger.v3.oas.annotations.Parameter
|
||||||
import jakarta.servlet.http.Cookie
|
import jakarta.servlet.http.Cookie
|
||||||
@ -9,9 +9,13 @@ import org.springframework.web.bind.annotation.GetMapping
|
|||||||
import org.springframework.web.bind.annotation.PostMapping
|
import org.springframework.web.bind.annotation.PostMapping
|
||||||
import org.springframework.web.bind.annotation.RequestBody
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
import roomescape.system.auth.service.AuthService
|
import roomescape.auth.service.AuthService
|
||||||
import roomescape.system.auth.web.support.*
|
import roomescape.auth.web.support.MemberId
|
||||||
import roomescape.system.dto.response.RoomEscapeApiResponse
|
import roomescape.auth.web.support.accessTokenCookie
|
||||||
|
import roomescape.auth.web.support.addAccessTokenCookie
|
||||||
|
import roomescape.auth.web.support.expire
|
||||||
|
import roomescape.auth.web.support.toCookie
|
||||||
|
import roomescape.common.dto.response.RoomEscapeApiResponse
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
class AuthController(
|
class AuthController(
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.system.auth.web
|
package roomescape.auth.web
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema
|
import io.swagger.v3.oas.annotations.media.Schema
|
||||||
import jakarta.validation.constraints.Email
|
import jakarta.validation.constraints.Email
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.system.auth.web.support
|
package roomescape.auth.web.support
|
||||||
|
|
||||||
@Target(AnnotationTarget.FUNCTION)
|
@Target(AnnotationTarget.FUNCTION)
|
||||||
@Retention(AnnotationRetention.RUNTIME)
|
@Retention(AnnotationRetention.RUNTIME)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.system.auth.web.support
|
package roomescape.auth.web.support
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import jakarta.servlet.http.HttpServletResponse
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
@ -8,9 +8,9 @@ import org.springframework.web.method.HandlerMethod
|
|||||||
import org.springframework.web.servlet.HandlerInterceptor
|
import org.springframework.web.servlet.HandlerInterceptor
|
||||||
import roomescape.member.business.MemberService
|
import roomescape.member.business.MemberService
|
||||||
import roomescape.member.infrastructure.persistence.Member
|
import roomescape.member.infrastructure.persistence.Member
|
||||||
import roomescape.system.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
import roomescape.system.exception.ErrorType
|
import roomescape.common.exception.ErrorType
|
||||||
import roomescape.system.exception.RoomEscapeException
|
import roomescape.common.exception.RoomescapeException
|
||||||
|
|
||||||
private fun Any.isIrrelevantWith(annotationType: Class<out Annotation>): Boolean {
|
private fun Any.isIrrelevantWith(annotationType: Class<out Annotation>): Boolean {
|
||||||
if (this !is HandlerMethod) {
|
if (this !is HandlerMethod) {
|
||||||
@ -40,9 +40,9 @@ class LoginInterceptor(
|
|||||||
val memberId: Long = jwtHandler.getMemberIdFromToken(token)
|
val memberId: Long = jwtHandler.getMemberIdFromToken(token)
|
||||||
|
|
||||||
return memberService.existsById(memberId)
|
return memberService.existsById(memberId)
|
||||||
} catch (e: RoomEscapeException) {
|
} catch (e: RoomescapeException) {
|
||||||
response.sendRedirect("/login")
|
response.sendRedirect("/login")
|
||||||
throw RoomEscapeException(ErrorType.LOGIN_REQUIRED, HttpStatus.FORBIDDEN)
|
throw RoomescapeException(ErrorType.LOGIN_REQUIRED, HttpStatus.FORBIDDEN)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +69,7 @@ class AdminInterceptor(
|
|||||||
val token: String? = request.accessTokenCookie().value
|
val token: String? = request.accessTokenCookie().value
|
||||||
val memberId: Long = jwtHandler.getMemberIdFromToken(token)
|
val memberId: Long = jwtHandler.getMemberIdFromToken(token)
|
||||||
member = memberService.findById(memberId)
|
member = memberService.findById(memberId)
|
||||||
} catch (e: RoomEscapeException) {
|
} catch (e: RoomescapeException) {
|
||||||
response.sendRedirect("/login")
|
response.sendRedirect("/login")
|
||||||
throw e
|
throw e
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ class AdminInterceptor(
|
|||||||
}
|
}
|
||||||
|
|
||||||
response.sendRedirect("/login")
|
response.sendRedirect("/login")
|
||||||
throw RoomEscapeException(
|
throw RoomescapeException(
|
||||||
ErrorType.PERMISSION_DOES_NOT_EXIST,
|
ErrorType.PERMISSION_DOES_NOT_EXIST,
|
||||||
String.format("[memberId: %d, Role: %s]", this.id, this.role),
|
String.format("[memberId: %d, Role: %s]", this.id, this.role),
|
||||||
HttpStatus.FORBIDDEN
|
HttpStatus.FORBIDDEN
|
||||||
@ -1,9 +1,9 @@
|
|||||||
package roomescape.system.auth.web.support
|
package roomescape.auth.web.support
|
||||||
|
|
||||||
import jakarta.servlet.http.Cookie
|
import jakarta.servlet.http.Cookie
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import jakarta.servlet.http.HttpServletResponse
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
import roomescape.system.auth.web.TokenResponse
|
import roomescape.auth.web.TokenResponse
|
||||||
|
|
||||||
const val ACCESS_TOKEN_COOKIE_NAME = "accessToken"
|
const val ACCESS_TOKEN_COOKIE_NAME = "accessToken"
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.system.auth.web.support
|
package roomescape.auth.web.support
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest
|
import jakarta.servlet.http.HttpServletRequest
|
||||||
import org.springframework.core.MethodParameter
|
import org.springframework.core.MethodParameter
|
||||||
@ -7,7 +7,7 @@ import org.springframework.web.bind.support.WebDataBinderFactory
|
|||||||
import org.springframework.web.context.request.NativeWebRequest
|
import org.springframework.web.context.request.NativeWebRequest
|
||||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver
|
||||||
import org.springframework.web.method.support.ModelAndViewContainer
|
import org.springframework.web.method.support.ModelAndViewContainer
|
||||||
import roomescape.system.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
class MemberIdResolver(
|
class MemberIdResolver(
|
||||||
41
src/main/java/roomescape/common/config/JacksonConfig.kt
Normal file
41
src/main/java/roomescape/common/config/JacksonConfig.kt
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
package roomescape.common.config
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer
|
||||||
|
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer
|
||||||
|
import com.fasterxml.jackson.module.kotlin.kotlinModule
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalTime
|
||||||
|
import java.time.format.DateTimeFormatter
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class JacksonConfig {
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
fun objectMapper(): ObjectMapper = ObjectMapper()
|
||||||
|
.registerModule(javaTimeModule())
|
||||||
|
.registerModule(kotlinModule())
|
||||||
|
|
||||||
|
private fun javaTimeModule(): JavaTimeModule = JavaTimeModule()
|
||||||
|
.addSerializer(
|
||||||
|
LocalDate::class.java,
|
||||||
|
LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||||
|
)
|
||||||
|
.addDeserializer(
|
||||||
|
LocalDate::class.java,
|
||||||
|
LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE)
|
||||||
|
)
|
||||||
|
.addSerializer(
|
||||||
|
LocalTime::class.java,
|
||||||
|
LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
|
)
|
||||||
|
.addDeserializer(
|
||||||
|
LocalTime::class.java,
|
||||||
|
LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm"))
|
||||||
|
) as JavaTimeModule
|
||||||
|
}
|
||||||
@ -1,23 +1,22 @@
|
|||||||
package roomescape.system.config;
|
package roomescape.common.config
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import io.swagger.v3.oas.models.OpenAPI
|
||||||
import org.springframework.context.annotation.Configuration;
|
import io.swagger.v3.oas.models.info.Info
|
||||||
|
import org.springframework.context.annotation.Bean
|
||||||
import io.swagger.v3.oas.models.OpenAPI;
|
import org.springframework.context.annotation.Configuration
|
||||||
import io.swagger.v3.oas.models.info.Info;
|
|
||||||
|
|
||||||
@Configuration
|
@Configuration
|
||||||
public class SwaggerConfig {
|
class SwaggerConfig {
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
public OpenAPI openAPI() {
|
fun openAPI(): OpenAPI {
|
||||||
return new OpenAPI().info(apiInfo());
|
return OpenAPI().info(apiInfo())
|
||||||
}
|
}
|
||||||
|
|
||||||
private Info apiInfo() {
|
private fun apiInfo(): Info {
|
||||||
return new Info()
|
return Info()
|
||||||
.title("방탈출 예약 API 문서")
|
.title("방탈출 예약 API 문서")
|
||||||
.description("""
|
.description("""
|
||||||
## API 테스트는 '1. 인증 / 인가 API' 의 '/login' 을 통해 로그인 후 사용해주세요.
|
## API 테스트는 '1. 인증 / 인가 API' 의 '/login' 을 통해 로그인 후 사용해주세요.
|
||||||
|
|
||||||
### 테스트시 로그인 가능한 계정 정보
|
### 테스트시 로그인 가능한 계정 정보
|
||||||
@ -70,7 +69,8 @@ public class SwaggerConfig {
|
|||||||
- 7: 예약은 승인되었으나, 결제 대기 상태
|
- 7: 예약은 승인되었으나, 결제 대기 상태
|
||||||
|
|
||||||
- 8 ~ 10: 예약 대기 상태
|
- 8 ~ 10: 예약 대기 상태
|
||||||
""")
|
|
||||||
.version("1.0.0");
|
""".trimIndent())
|
||||||
}
|
.version("1.0.0")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
26
src/main/java/roomescape/common/config/WebMvcConfig.kt
Normal file
26
src/main/java/roomescape/common/config/WebMvcConfig.kt
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
package roomescape.common.config
|
||||||
|
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import org.springframework.web.method.support.HandlerMethodArgumentResolver
|
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer
|
||||||
|
import roomescape.auth.web.support.AdminInterceptor
|
||||||
|
import roomescape.auth.web.support.LoginInterceptor
|
||||||
|
import roomescape.auth.web.support.MemberIdResolver
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class WebMvcConfig(
|
||||||
|
private val memberIdResolver: MemberIdResolver,
|
||||||
|
private val adminInterceptor: AdminInterceptor,
|
||||||
|
private val loginInterceptor: LoginInterceptor
|
||||||
|
) : WebMvcConfigurer {
|
||||||
|
|
||||||
|
override fun addArgumentResolvers(resolvers: MutableList<HandlerMethodArgumentResolver>) {
|
||||||
|
resolvers.add(memberIdResolver)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun addInterceptors(registry: InterceptorRegistry) {
|
||||||
|
registry.addInterceptor(adminInterceptor)
|
||||||
|
registry.addInterceptor(loginInterceptor)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,21 @@
|
|||||||
|
package roomescape.common.dto.response
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema
|
||||||
|
import roomescape.common.exception.ErrorType
|
||||||
|
|
||||||
|
@Schema(name = "예외 응답", description = "예외 발생 시 응답에 사용됩니다.")
|
||||||
|
@JvmRecord
|
||||||
|
data class ErrorResponse(
|
||||||
|
@field:Schema(description = "발생한 예외의 종류", example = "INVALID_REQUEST_DATA")
|
||||||
|
val errorType: ErrorType,
|
||||||
|
|
||||||
|
@field:Schema(description = "예외 메시지", example = "요청 데이터 값이 올바르지 않습니다.")
|
||||||
|
val message: String
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
fun of(errorType: ErrorType, message: String): ErrorResponse {
|
||||||
|
return ErrorResponse(errorType, message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,27 @@
|
|||||||
|
package roomescape.common.dto.response
|
||||||
|
|
||||||
|
import io.swagger.v3.oas.annotations.media.Schema
|
||||||
|
|
||||||
|
@Schema(description = "API 응답 시에 사용합니다.")
|
||||||
|
@JvmRecord
|
||||||
|
data class RoomEscapeApiResponse<T>(
|
||||||
|
@field:Schema(description = "응답 메시지", defaultValue = SUCCESS_MESSAGE)
|
||||||
|
val message: String,
|
||||||
|
|
||||||
|
@field:Schema(description = "응답 바디")
|
||||||
|
val data: T? = null
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
private const val SUCCESS_MESSAGE = "요청이 성공적으로 수행되었습니다."
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun <T> success(data: T): RoomEscapeApiResponse<T> {
|
||||||
|
return RoomEscapeApiResponse(SUCCESS_MESSAGE, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun success(): RoomEscapeApiResponse<Void> {
|
||||||
|
return RoomEscapeApiResponse(SUCCESS_MESSAGE, null)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,33 @@
|
|||||||
|
package roomescape.common.dto.response
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude
|
||||||
|
import roomescape.common.exception.ErrorType
|
||||||
|
|
||||||
|
|
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL)
|
||||||
|
data class RoomescapeApiResponseKT<T>(
|
||||||
|
val success: Boolean,
|
||||||
|
val data: T? = null,
|
||||||
|
val errorType: ErrorType? = null,
|
||||||
|
val message: String? = null,
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun <T> success(data: T? = null): RoomescapeApiResponseKT<T> {
|
||||||
|
return RoomescapeApiResponseKT(
|
||||||
|
success = true,
|
||||||
|
data = data,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@JvmStatic
|
||||||
|
fun <T> fail(errorType: ErrorType, message: String? = null): RoomescapeApiResponseKT<T> {
|
||||||
|
return RoomescapeApiResponseKT(
|
||||||
|
success = false,
|
||||||
|
errorType = errorType,
|
||||||
|
message = message ?: errorType.description
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
70
src/main/java/roomescape/common/exception/ErrorType.kt
Normal file
70
src/main/java/roomescape/common/exception/ErrorType.kt
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
package roomescape.common.exception
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonCreator
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
|
||||||
|
enum class ErrorType(
|
||||||
|
@JvmField val description: String
|
||||||
|
) {
|
||||||
|
// 400 Bad Request
|
||||||
|
REQUEST_DATA_BLANK("요청 데이터에 유효하지 않은 값(null OR 공백)이 포함되어있습니다."),
|
||||||
|
INVALID_REQUEST_DATA_TYPE("요청 데이터 형식이 올바르지 않습니다."),
|
||||||
|
INVALID_REQUEST_DATA("요청 데이터 값이 올바르지 않습니다."),
|
||||||
|
INVALID_DATE_RANGE("종료 날짜는 시작 날짜 이전일 수 없습니다."),
|
||||||
|
HAS_RESERVATION_OR_WAITING("같은 테마에 대한 예약(대기)는 한 번만 가능합니다."),
|
||||||
|
|
||||||
|
// 401 Unauthorized
|
||||||
|
EXPIRED_TOKEN("토큰이 만료되었습니다. 다시 로그인 해주세요."),
|
||||||
|
UNSUPPORTED_TOKEN("지원하지 않는 JWT 토큰입니다."),
|
||||||
|
MALFORMED_TOKEN("형식이 맞지 않는 JWT 토큰입니다."),
|
||||||
|
INVALID_SIGNATURE_TOKEN("잘못된 JWT 토큰 Signature 입니다."),
|
||||||
|
ILLEGAL_TOKEN("JWT 토큰의 Claim 이 비어있습니다."),
|
||||||
|
INVALID_TOKEN("JWT 토큰이 존재하지 않거나 유효하지 않습니다."),
|
||||||
|
NOT_EXIST_COOKIE("쿠키가 존재하지 않습니다. 로그인이 필요한 서비스입니다."),
|
||||||
|
|
||||||
|
// 403 Forbidden
|
||||||
|
LOGIN_REQUIRED("로그인이 필요한 서비스입니다."),
|
||||||
|
PERMISSION_DOES_NOT_EXIST("접근 권한이 존재하지 않습니다."),
|
||||||
|
|
||||||
|
// 404 Not Found
|
||||||
|
MEMBER_NOT_FOUND("회원(Member) 정보가 존재하지 않습니다."),
|
||||||
|
RESERVATION_NOT_FOUND("예약(Reservation) 정보가 존재하지 않습니다."),
|
||||||
|
RESERVATION_TIME_NOT_FOUND("예약 시간(ReservationTime) 정보가 존재하지 않습니다."),
|
||||||
|
THEME_NOT_FOUND("테마(Theme) 정보가 존재하지 않습니다."),
|
||||||
|
PAYMENT_NOT_POUND("결제(Payment) 정보가 존재하지 않습니다."),
|
||||||
|
|
||||||
|
// 405 Method Not Allowed
|
||||||
|
METHOD_NOT_ALLOWED("지원하지 않는 HTTP Method 입니다."),
|
||||||
|
|
||||||
|
// 409 Conflict
|
||||||
|
TIME_IS_USED_CONFLICT("삭제할 수 없는 시간대입니다. 예약이 존재하는지 확인해주세요."),
|
||||||
|
THEME_IS_USED_CONFLICT("삭제할 수 없는 테마입니다. 예약이 존재하는지 확인해주세요."),
|
||||||
|
TIME_DUPLICATED("이미 해당 시간이 존재합니다."),
|
||||||
|
THEME_DUPLICATED("같은 이름의 테마가 존재합니다."),
|
||||||
|
RESERVATION_DUPLICATED("해당 시간에 이미 예약이 존재합니다."),
|
||||||
|
RESERVATION_PERIOD_IN_PAST("이미 지난 시간대는 예약할 수 없습니다."),
|
||||||
|
CANCELED_BEFORE_PAYMENT("취소 시간이 결제 시간 이전일 수 없습니다."),
|
||||||
|
|
||||||
|
// 500 Internal Server Error,
|
||||||
|
INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생하였습니다."),
|
||||||
|
UNEXPECTED_ERROR("예상치 못한 에러가 발생하였습니다. 잠시 후 다시 시도해주세요."),
|
||||||
|
|
||||||
|
// Payment Error
|
||||||
|
PAYMENT_ERROR("결제(취소)에 실패했습니다. 결제(취소) 정보를 확인해주세요."),
|
||||||
|
PAYMENT_SERVER_ERROR("결제 서버에서 에러가 발생하였습니다. 잠시 후 다시 시도해주세요.");
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@JvmStatic
|
||||||
|
@JsonCreator
|
||||||
|
fun from(@JsonProperty("errorType") errorType: String): ErrorType {
|
||||||
|
return entries.toTypedArray()
|
||||||
|
.firstOrNull { it.name == errorType }
|
||||||
|
?: throw RoomescapeException(
|
||||||
|
INVALID_REQUEST_DATA,
|
||||||
|
"[ErrorType: ${errorType}]",
|
||||||
|
HttpStatus.BAD_REQUEST
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,75 @@
|
|||||||
|
package roomescape.common.exception
|
||||||
|
|
||||||
|
import io.github.oshai.kotlinlogging.KLogger
|
||||||
|
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||||
|
import jakarta.servlet.http.HttpServletResponse
|
||||||
|
import org.springframework.http.HttpStatus
|
||||||
|
import org.springframework.http.converter.HttpMessageNotReadableException
|
||||||
|
import org.springframework.web.HttpRequestMethodNotSupportedException
|
||||||
|
import org.springframework.web.bind.MethodArgumentNotValidException
|
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler
|
||||||
|
import org.springframework.web.bind.annotation.ResponseStatus
|
||||||
|
import org.springframework.web.bind.annotation.RestControllerAdvice
|
||||||
|
import org.springframework.web.client.ResourceAccessException
|
||||||
|
import roomescape.common.dto.response.ErrorResponse
|
||||||
|
|
||||||
|
@RestControllerAdvice
|
||||||
|
class ExceptionControllerAdvice(
|
||||||
|
private val logger: KLogger = KotlinLogging.logger {}
|
||||||
|
) {
|
||||||
|
|
||||||
|
@ExceptionHandler(value = [RoomescapeException::class])
|
||||||
|
fun handleRoomEscapeException(
|
||||||
|
e: RoomescapeException,
|
||||||
|
response: HttpServletResponse
|
||||||
|
): ErrorResponse {
|
||||||
|
logger.error(e) { "message: ${e.message}, invalidValue: ${e.invalidValue}" }
|
||||||
|
response.status = e.httpStatus.value()
|
||||||
|
|
||||||
|
return ErrorResponse.of(e.errorType, e.message!!)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(ResourceAccessException::class)
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
fun handleResourceAccessException(e: ResourceAccessException): ErrorResponse {
|
||||||
|
logger.error(e) { "message: ${e.message}" }
|
||||||
|
|
||||||
|
return ErrorResponse.of(ErrorType.PAYMENT_SERVER_ERROR, ErrorType.PAYMENT_SERVER_ERROR.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = [HttpMessageNotReadableException::class])
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
|
fun handleHttpMessageNotReadableException(e: HttpMessageNotReadableException): ErrorResponse {
|
||||||
|
logger.error(e) { "message: ${e.message}" }
|
||||||
|
|
||||||
|
return ErrorResponse.of(ErrorType.INVALID_REQUEST_DATA_TYPE,
|
||||||
|
ErrorType.INVALID_REQUEST_DATA_TYPE.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = [MethodArgumentNotValidException::class])
|
||||||
|
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
||||||
|
fun handleMethodArgumentNotValidException(e: MethodArgumentNotValidException): ErrorResponse {
|
||||||
|
val messages: String = e.bindingResult.allErrors
|
||||||
|
.mapNotNull { it.defaultMessage }
|
||||||
|
.joinToString(", ")
|
||||||
|
logger.error(e) { "message: $messages" }
|
||||||
|
|
||||||
|
return ErrorResponse.of(ErrorType.INVALID_REQUEST_DATA, messages)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = [HttpRequestMethodNotSupportedException::class])
|
||||||
|
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
|
||||||
|
fun handleHttpRequestMethodNotSupportedException(e: HttpRequestMethodNotSupportedException): ErrorResponse {
|
||||||
|
logger.error(e) { "message: ${e.message}" }
|
||||||
|
|
||||||
|
return ErrorResponse.of(ErrorType.METHOD_NOT_ALLOWED, ErrorType.METHOD_NOT_ALLOWED.description)
|
||||||
|
}
|
||||||
|
|
||||||
|
@ExceptionHandler(value = [Exception::class])
|
||||||
|
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
|
fun handleException(e: Exception): ErrorResponse {
|
||||||
|
logger.error(e) { "message: ${e.message}" }
|
||||||
|
|
||||||
|
return ErrorResponse.of(ErrorType.UNEXPECTED_ERROR, ErrorType.UNEXPECTED_ERROR.description)
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
package roomescape.common.exception
|
||||||
|
|
||||||
|
import org.springframework.http.HttpStatusCode
|
||||||
|
|
||||||
|
class RoomescapeException(
|
||||||
|
val errorType: ErrorType,
|
||||||
|
val invalidValue: String? = "",
|
||||||
|
val httpStatus: HttpStatusCode,
|
||||||
|
) : RuntimeException(errorType.description) {
|
||||||
|
constructor(errorType: ErrorType, httpStatus: HttpStatusCode) : this(errorType, null, httpStatus)
|
||||||
|
}
|
||||||
@ -8,8 +8,8 @@ import roomescape.member.infrastructure.persistence.Member
|
|||||||
import roomescape.member.infrastructure.persistence.MemberRepository
|
import roomescape.member.infrastructure.persistence.MemberRepository
|
||||||
import roomescape.member.web.MembersResponse
|
import roomescape.member.web.MembersResponse
|
||||||
import roomescape.member.web.toResponse
|
import roomescape.member.web.toResponse
|
||||||
import roomescape.system.exception.ErrorType
|
import roomescape.common.exception.ErrorType
|
||||||
import roomescape.system.exception.RoomEscapeException
|
import roomescape.common.exception.RoomescapeException
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
@ -23,7 +23,7 @@ class MemberService(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fun findById(memberId: Long): Member = memberRepository.findByIdOrNull(memberId)
|
fun findById(memberId: Long): Member = memberRepository.findByIdOrNull(memberId)
|
||||||
?: throw RoomEscapeException(
|
?: throw RoomescapeException(
|
||||||
ErrorType.MEMBER_NOT_FOUND,
|
ErrorType.MEMBER_NOT_FOUND,
|
||||||
String.format("[memberId: %d]", memberId),
|
String.format("[memberId: %d]", memberId),
|
||||||
HttpStatus.BAD_REQUEST
|
HttpStatus.BAD_REQUEST
|
||||||
@ -31,7 +31,7 @@ class MemberService(
|
|||||||
|
|
||||||
fun findMemberByEmailAndPassword(email: String, password: String): Member =
|
fun findMemberByEmailAndPassword(email: String, password: String): Member =
|
||||||
memberRepository.findByEmailAndPassword(email, password)
|
memberRepository.findByEmailAndPassword(email, password)
|
||||||
?: throw RoomEscapeException(
|
?: throw RoomescapeException(
|
||||||
ErrorType.MEMBER_NOT_FOUND,
|
ErrorType.MEMBER_NOT_FOUND,
|
||||||
String.format("[email: %s, password: %s]", email, password),
|
String.format("[email: %s, password: %s]", email, password),
|
||||||
HttpStatus.BAD_REQUEST
|
HttpStatus.BAD_REQUEST
|
||||||
|
|||||||
@ -6,8 +6,8 @@ import io.swagger.v3.oas.annotations.responses.ApiResponses
|
|||||||
import io.swagger.v3.oas.annotations.tags.Tag
|
import io.swagger.v3.oas.annotations.tags.Tag
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus
|
import org.springframework.web.bind.annotation.ResponseStatus
|
||||||
import roomescape.system.auth.web.support.Admin
|
import roomescape.auth.web.support.Admin
|
||||||
import roomescape.system.dto.response.RoomEscapeApiResponse
|
import roomescape.common.dto.response.RoomEscapeApiResponse
|
||||||
|
|
||||||
@Tag(name = "2. 회원 API", description = "회원 정보를 관리할 때 사용합니다.")
|
@Tag(name = "2. 회원 API", description = "회원 정보를 관리할 때 사용합니다.")
|
||||||
interface MemberAPI {
|
interface MemberAPI {
|
||||||
|
|||||||
@ -5,7 +5,7 @@ import org.springframework.web.bind.annotation.GetMapping
|
|||||||
import org.springframework.web.bind.annotation.RestController
|
import org.springframework.web.bind.annotation.RestController
|
||||||
import roomescape.member.business.MemberService
|
import roomescape.member.business.MemberService
|
||||||
import roomescape.member.infrastructure.persistence.Member
|
import roomescape.member.infrastructure.persistence.Member
|
||||||
import roomescape.system.dto.response.RoomEscapeApiResponse
|
import roomescape.common.dto.response.RoomEscapeApiResponse
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
class MemberController(
|
class MemberController(
|
||||||
|
|||||||
@ -19,8 +19,8 @@ import roomescape.payment.dto.request.PaymentRequest;
|
|||||||
import roomescape.payment.dto.response.PaymentCancelResponse;
|
import roomescape.payment.dto.response.PaymentCancelResponse;
|
||||||
import roomescape.payment.dto.response.PaymentResponse;
|
import roomescape.payment.dto.response.PaymentResponse;
|
||||||
import roomescape.payment.dto.response.TossPaymentErrorResponse;
|
import roomescape.payment.dto.response.TossPaymentErrorResponse;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@Component
|
@Component
|
||||||
public class TossPaymentClient {
|
public class TossPaymentClient {
|
||||||
@ -76,7 +76,7 @@ public class TossPaymentClient {
|
|||||||
ErrorType errorType = getErrorTypeByStatusCode(statusCode);
|
ErrorType errorType = getErrorTypeByStatusCode(statusCode);
|
||||||
TossPaymentErrorResponse errorResponse = getErrorResponse(res);
|
TossPaymentErrorResponse errorResponse = getErrorResponse(res);
|
||||||
|
|
||||||
throw new RoomEscapeException(errorType,
|
throw new RoomescapeException(errorType,
|
||||||
String.format("[ErrorCode = %s, ErrorMessage = %s]", errorResponse.code(), errorResponse.message()),
|
String.format("[ErrorCode = %s, ErrorMessage = %s]", errorResponse.code(), errorResponse.message()),
|
||||||
statusCode);
|
statusCode);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import jakarta.persistence.Entity;
|
|||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.GenerationType;
|
import jakarta.persistence.GenerationType;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class CanceledPayment {
|
public class CanceledPayment {
|
||||||
@ -39,7 +39,7 @@ public class CanceledPayment {
|
|||||||
|
|
||||||
private void validateDate(OffsetDateTime approvedAt, OffsetDateTime canceledAt) {
|
private void validateDate(OffsetDateTime approvedAt, OffsetDateTime canceledAt) {
|
||||||
if (canceledAt.isBefore(approvedAt)) {
|
if (canceledAt.isBefore(approvedAt)) {
|
||||||
throw new RoomEscapeException(ErrorType.CANCELED_BEFORE_PAYMENT,
|
throw new RoomescapeException(ErrorType.CANCELED_BEFORE_PAYMENT,
|
||||||
String.format("[approvedAt: %s, canceledAt: %s]", approvedAt, canceledAt),
|
String.format("[approvedAt: %s, canceledAt: %s]", approvedAt, canceledAt),
|
||||||
HttpStatus.CONFLICT);
|
HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -13,8 +13,8 @@ import jakarta.persistence.Id;
|
|||||||
import jakarta.persistence.JoinColumn;
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.OneToOne;
|
import jakarta.persistence.OneToOne;
|
||||||
import roomescape.reservation.domain.Reservation;
|
import roomescape.reservation.domain.Reservation;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class Payment {
|
public class Payment {
|
||||||
@ -63,21 +63,21 @@ public class Payment {
|
|||||||
|
|
||||||
private void validateIsNullOrBlank(String input, String fieldName) {
|
private void validateIsNullOrBlank(String input, String fieldName) {
|
||||||
if (input == null || input.isBlank()) {
|
if (input == null || input.isBlank()) {
|
||||||
throw new RoomEscapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[value : %s]", fieldName),
|
throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[value : %s]", fieldName),
|
||||||
HttpStatus.BAD_REQUEST);
|
HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validateIsInvalidAmount(Long totalAmount) {
|
private void validateIsInvalidAmount(Long totalAmount) {
|
||||||
if (totalAmount == null || totalAmount < 0) {
|
if (totalAmount == null || totalAmount < 0) {
|
||||||
throw new RoomEscapeException(ErrorType.INVALID_REQUEST_DATA,
|
throw new RoomescapeException(ErrorType.INVALID_REQUEST_DATA,
|
||||||
String.format("[totalAmount : %d]", totalAmount), HttpStatus.BAD_REQUEST);
|
String.format("[totalAmount : %d]", totalAmount), HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private <T> void validateIsNull(T value, String fieldName) {
|
private <T> void validateIsNull(T value, String fieldName) {
|
||||||
if (value == null) {
|
if (value == null) {
|
||||||
throw new RoomEscapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[value : %s]", fieldName),
|
throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[value : %s]", fieldName),
|
||||||
HttpStatus.BAD_REQUEST);
|
HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,8 @@ import roomescape.payment.dto.response.PaymentCancelResponse;
|
|||||||
import roomescape.payment.dto.response.PaymentResponse;
|
import roomescape.payment.dto.response.PaymentResponse;
|
||||||
import roomescape.payment.dto.response.ReservationPaymentResponse;
|
import roomescape.payment.dto.response.ReservationPaymentResponse;
|
||||||
import roomescape.reservation.domain.Reservation;
|
import roomescape.reservation.domain.Reservation;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
@ -50,7 +50,7 @@ public class PaymentService {
|
|||||||
|
|
||||||
public PaymentCancelRequest cancelPaymentByAdmin(Long reservationId) {
|
public PaymentCancelRequest cancelPaymentByAdmin(Long reservationId) {
|
||||||
String paymentKey = findPaymentByReservationId(reservationId)
|
String paymentKey = findPaymentByReservationId(reservationId)
|
||||||
.orElseThrow(() -> new RoomEscapeException(ErrorType.PAYMENT_NOT_POUND,
|
.orElseThrow(() -> new RoomescapeException(ErrorType.PAYMENT_NOT_POUND,
|
||||||
String.format("[reservationId: %d]", reservationId), HttpStatus.NOT_FOUND))
|
String.format("[reservationId: %d]", reservationId), HttpStatus.NOT_FOUND))
|
||||||
.getPaymentKey();
|
.getPaymentKey();
|
||||||
// 취소 시간은 현재 시간으로 일단 생성한 뒤, 결제 취소 완료 후 해당 시간으로 변경합니다.
|
// 취소 시간은 현재 시간으로 일단 생성한 뒤, 결제 취소 완료 후 해당 시간으로 변경합니다.
|
||||||
@ -74,8 +74,8 @@ public class PaymentService {
|
|||||||
canceledPayment.setCanceledAt(canceledAt);
|
canceledPayment.setCanceledAt(canceledAt);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoomEscapeException throwPaymentNotFoundByPaymentKey(String paymentKey) {
|
private RoomescapeException throwPaymentNotFoundByPaymentKey(String paymentKey) {
|
||||||
return new RoomEscapeException(
|
return new RoomescapeException(
|
||||||
ErrorType.PAYMENT_NOT_POUND, String.format("[paymentKey: %s]", paymentKey),
|
ErrorType.PAYMENT_NOT_POUND, String.format("[paymentKey: %s]", paymentKey),
|
||||||
HttpStatus.NOT_FOUND);
|
HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -37,12 +37,12 @@ import roomescape.reservation.dto.response.ReservationResponse;
|
|||||||
import roomescape.reservation.dto.response.ReservationsResponse;
|
import roomescape.reservation.dto.response.ReservationsResponse;
|
||||||
import roomescape.reservation.service.ReservationService;
|
import roomescape.reservation.service.ReservationService;
|
||||||
import roomescape.reservation.service.ReservationWithPaymentService;
|
import roomescape.reservation.service.ReservationWithPaymentService;
|
||||||
import roomescape.system.auth.web.support.Admin;
|
import roomescape.auth.web.support.Admin;
|
||||||
import roomescape.system.auth.web.support.LoginRequired;
|
import roomescape.auth.web.support.LoginRequired;
|
||||||
import roomescape.system.auth.web.support.MemberId;
|
import roomescape.auth.web.support.MemberId;
|
||||||
import roomescape.system.dto.response.ErrorResponse;
|
import roomescape.common.dto.response.ErrorResponse;
|
||||||
import roomescape.system.dto.response.RoomEscapeApiResponse;
|
import roomescape.common.dto.response.RoomEscapeApiResponse;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "3. 예약 API", description = "예약 및 대기 정보를 추가 / 조회 / 삭제할 때 사용합니다.")
|
@Tag(name = "3. 예약 API", description = "예약 및 대기 정보를 추가 / 조회 / 삭제할 때 사용합니다.")
|
||||||
@ -151,7 +151,7 @@ public class ReservationController {
|
|||||||
ReservationResponse reservationResponse = reservationWithPaymentService.addReservationWithPayment(
|
ReservationResponse reservationResponse = reservationWithPaymentService.addReservationWithPayment(
|
||||||
reservationRequest, paymentResponse, memberId);
|
reservationRequest, paymentResponse, memberId);
|
||||||
return getCreatedReservationResponse(reservationResponse, response);
|
return getCreatedReservationResponse(reservationResponse, response);
|
||||||
} catch (RoomEscapeException e) {
|
} catch (RoomescapeException e) {
|
||||||
PaymentCancelRequest cancelRequest = new PaymentCancelRequest(paymentRequest.paymentKey(),
|
PaymentCancelRequest cancelRequest = new PaymentCancelRequest(paymentRequest.paymentKey(),
|
||||||
paymentRequest.amount(), e.getMessage());
|
paymentRequest.amount(), e.getMessage());
|
||||||
|
|
||||||
|
|||||||
@ -28,10 +28,10 @@ import roomescape.reservation.dto.response.ReservationTimeInfosResponse;
|
|||||||
import roomescape.reservation.dto.response.ReservationTimeResponse;
|
import roomescape.reservation.dto.response.ReservationTimeResponse;
|
||||||
import roomescape.reservation.dto.response.ReservationTimesResponse;
|
import roomescape.reservation.dto.response.ReservationTimesResponse;
|
||||||
import roomescape.reservation.service.ReservationTimeService;
|
import roomescape.reservation.service.ReservationTimeService;
|
||||||
import roomescape.system.auth.web.support.Admin;
|
import roomescape.auth.web.support.Admin;
|
||||||
import roomescape.system.auth.web.support.LoginRequired;
|
import roomescape.auth.web.support.LoginRequired;
|
||||||
import roomescape.system.dto.response.ErrorResponse;
|
import roomescape.common.dto.response.ErrorResponse;
|
||||||
import roomescape.system.dto.response.RoomEscapeApiResponse;
|
import roomescape.common.dto.response.RoomEscapeApiResponse;
|
||||||
|
|
||||||
@RestController
|
@RestController
|
||||||
@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.")
|
@Tag(name = "4. 예약 시간 API", description = "예약 시간을 조회 / 추가 / 삭제할 때 사용합니다.")
|
||||||
|
|||||||
@ -16,8 +16,8 @@ import jakarta.persistence.Id;
|
|||||||
import jakarta.persistence.JoinColumn;
|
import jakarta.persistence.JoinColumn;
|
||||||
import jakarta.persistence.ManyToOne;
|
import jakarta.persistence.ManyToOne;
|
||||||
import roomescape.member.infrastructure.persistence.Member;
|
import roomescape.member.infrastructure.persistence.Member;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
@ -77,7 +77,7 @@ public class Reservation {
|
|||||||
private void validateIsNull(LocalDate date, ReservationTime reservationTime, Theme theme, Member member,
|
private void validateIsNull(LocalDate date, ReservationTime reservationTime, Theme theme, Member member,
|
||||||
ReservationStatus reservationStatus) {
|
ReservationStatus reservationStatus) {
|
||||||
if (date == null || reservationTime == null || theme == null || member == null || reservationStatus == null) {
|
if (date == null || reservationTime == null || theme == null || member == null || reservationStatus == null) {
|
||||||
throw new RoomEscapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this),
|
throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this),
|
||||||
HttpStatus.BAD_REQUEST);
|
HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import jakarta.persistence.Entity;
|
|||||||
import jakarta.persistence.GeneratedValue;
|
import jakarta.persistence.GeneratedValue;
|
||||||
import jakarta.persistence.GenerationType;
|
import jakarta.persistence.GenerationType;
|
||||||
import jakarta.persistence.Id;
|
import jakarta.persistence.Id;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@Entity
|
@Entity
|
||||||
public class ReservationTime {
|
public class ReservationTime {
|
||||||
@ -36,7 +36,7 @@ public class ReservationTime {
|
|||||||
|
|
||||||
private void validateNull() {
|
private void validateNull() {
|
||||||
if (startAt == null) {
|
if (startAt == null) {
|
||||||
throw new RoomEscapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this),
|
throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK, String.format("[values: %s]", this),
|
||||||
HttpStatus.BAD_REQUEST);
|
HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import io.micrometer.common.util.StringUtils;
|
|||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
import io.swagger.v3.oas.annotations.media.Schema;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import roomescape.reservation.domain.ReservationTime;
|
import roomescape.reservation.domain.ReservationTime;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.")
|
@Schema(name = "예약 시간 저장 요청", description = "예약 시간 저장 요청시 사용됩니다.")
|
||||||
public record ReservationTimeRequest(
|
public record ReservationTimeRequest(
|
||||||
@ -20,7 +20,7 @@ public record ReservationTimeRequest(
|
|||||||
|
|
||||||
public ReservationTimeRequest {
|
public ReservationTimeRequest {
|
||||||
if (StringUtils.isBlank(startAt.toString())) {
|
if (StringUtils.isBlank(startAt.toString())) {
|
||||||
throw new RoomEscapeException(ErrorType.REQUEST_DATA_BLANK,
|
throw new RoomescapeException(ErrorType.REQUEST_DATA_BLANK,
|
||||||
String.format("[values: %s]", this), HttpStatus.BAD_REQUEST);
|
String.format("[values: %s]", this), HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -22,8 +22,8 @@ import roomescape.reservation.dto.request.WaitingRequest;
|
|||||||
import roomescape.reservation.dto.response.MyReservationsResponse;
|
import roomescape.reservation.dto.response.MyReservationsResponse;
|
||||||
import roomescape.reservation.dto.response.ReservationResponse;
|
import roomescape.reservation.dto.response.ReservationResponse;
|
||||||
import roomescape.reservation.dto.response.ReservationsResponse;
|
import roomescape.reservation.dto.response.ReservationsResponse;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
import roomescape.theme.service.ThemeService;
|
import roomescape.theme.service.ThemeService;
|
||||||
|
|
||||||
@ -111,7 +111,7 @@ public class ReservationService {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (reservationRepository.exists(spec)) {
|
if (reservationRepository.exists(spec)) {
|
||||||
throw new RoomEscapeException(ErrorType.HAS_RESERVATION_OR_WAITING, HttpStatus.BAD_REQUEST);
|
throw new RoomescapeException(ErrorType.HAS_RESERVATION_OR_WAITING, HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ public class ReservationService {
|
|||||||
.build();
|
.build();
|
||||||
|
|
||||||
if (reservationRepository.exists(spec)) {
|
if (reservationRepository.exists(spec)) {
|
||||||
throw new RoomEscapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT);
|
throw new RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -135,7 +135,7 @@ public class ReservationService {
|
|||||||
LocalDateTime now = LocalDateTime.now();
|
LocalDateTime now = LocalDateTime.now();
|
||||||
LocalDateTime request = LocalDateTime.of(requestDate, requestReservationTime.getStartAt());
|
LocalDateTime request = LocalDateTime.of(requestDate, requestReservationTime.getStartAt());
|
||||||
if (request.isBefore(now)) {
|
if (request.isBefore(now)) {
|
||||||
throw new RoomEscapeException(ErrorType.RESERVATION_PERIOD_IN_PAST,
|
throw new RoomescapeException(ErrorType.RESERVATION_PERIOD_IN_PAST,
|
||||||
String.format("[now: %s %s | request: %s %s]",
|
String.format("[now: %s %s | request: %s %s]",
|
||||||
now.toLocalDate(), now.toLocalTime(), requestDate, requestReservationTime.getStartAt()),
|
now.toLocalDate(), now.toLocalTime(), requestDate, requestReservationTime.getStartAt()),
|
||||||
HttpStatus.BAD_REQUEST
|
HttpStatus.BAD_REQUEST
|
||||||
@ -178,7 +178,7 @@ public class ReservationService {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (startFrom.isAfter(endAt)) {
|
if (startFrom.isAfter(endAt)) {
|
||||||
throw new RoomEscapeException(ErrorType.INVALID_DATE_RANGE,
|
throw new RoomescapeException(ErrorType.INVALID_DATE_RANGE,
|
||||||
String.format("[startFrom: %s, endAt: %s", startFrom, endAt), HttpStatus.BAD_REQUEST);
|
String.format("[startFrom: %s, endAt: %s", startFrom, endAt), HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -191,7 +191,7 @@ public class ReservationService {
|
|||||||
public void approveWaiting(Long reservationId, Long memberId) {
|
public void approveWaiting(Long reservationId, Long memberId) {
|
||||||
validateIsMemberAdmin(memberId);
|
validateIsMemberAdmin(memberId);
|
||||||
if (reservationRepository.isExistConfirmedReservation(reservationId)) {
|
if (reservationRepository.isExistConfirmedReservation(reservationId)) {
|
||||||
throw new RoomEscapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT);
|
throw new RoomescapeException(ErrorType.RESERVATION_DUPLICATED, HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
reservationRepository.updateStatusByReservationId(reservationId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED);
|
reservationRepository.updateStatusByReservationId(reservationId, ReservationStatus.CONFIRMED_PAYMENT_REQUIRED);
|
||||||
}
|
}
|
||||||
@ -217,11 +217,11 @@ public class ReservationService {
|
|||||||
if (member.isAdmin()) {
|
if (member.isAdmin()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
throw new RoomEscapeException(ErrorType.PERMISSION_DOES_NOT_EXIST, HttpStatus.FORBIDDEN);
|
throw new RoomescapeException(ErrorType.PERMISSION_DOES_NOT_EXIST, HttpStatus.FORBIDDEN);
|
||||||
}
|
}
|
||||||
|
|
||||||
private RoomEscapeException throwReservationNotFound(Long reservationId) {
|
private RoomescapeException throwReservationNotFound(Long reservationId) {
|
||||||
return new RoomEscapeException(ErrorType.RESERVATION_NOT_FOUND,
|
return new RoomescapeException(ErrorType.RESERVATION_NOT_FOUND,
|
||||||
String.format("[reservationId: %d]", reservationId), HttpStatus.NOT_FOUND);
|
String.format("[reservationId: %d]", reservationId), HttpStatus.NOT_FOUND);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -16,8 +16,8 @@ import roomescape.reservation.dto.response.ReservationTimeInfoResponse;
|
|||||||
import roomescape.reservation.dto.response.ReservationTimeInfosResponse;
|
import roomescape.reservation.dto.response.ReservationTimeInfosResponse;
|
||||||
import roomescape.reservation.dto.response.ReservationTimeResponse;
|
import roomescape.reservation.dto.response.ReservationTimeResponse;
|
||||||
import roomescape.reservation.dto.response.ReservationTimesResponse;
|
import roomescape.reservation.dto.response.ReservationTimesResponse;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@Service
|
@Service
|
||||||
@Transactional
|
@Transactional
|
||||||
@ -37,7 +37,7 @@ public class ReservationTimeService {
|
|||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public ReservationTime findTimeById(Long id) {
|
public ReservationTime findTimeById(Long id) {
|
||||||
return reservationTimeRepository.findById(id)
|
return reservationTimeRepository.findById(id)
|
||||||
.orElseThrow(() -> new RoomEscapeException(ErrorType.RESERVATION_TIME_NOT_FOUND,
|
.orElseThrow(() -> new RoomescapeException(ErrorType.RESERVATION_TIME_NOT_FOUND,
|
||||||
String.format("[reservationTimeId: %d]", id), HttpStatus.BAD_REQUEST));
|
String.format("[reservationTimeId: %d]", id), HttpStatus.BAD_REQUEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -63,7 +63,7 @@ public class ReservationTimeService {
|
|||||||
reservationTimeRequest.startAt());
|
reservationTimeRequest.startAt());
|
||||||
|
|
||||||
if (!duplicateReservationTimes.isEmpty()) {
|
if (!duplicateReservationTimes.isEmpty()) {
|
||||||
throw new RoomEscapeException(ErrorType.TIME_DUPLICATED,
|
throw new RoomescapeException(ErrorType.TIME_DUPLICATED,
|
||||||
String.format("[startAt: %s]", reservationTimeRequest.startAt()), HttpStatus.CONFLICT);
|
String.format("[startAt: %s]", reservationTimeRequest.startAt()), HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -73,7 +73,7 @@ public class ReservationTimeService {
|
|||||||
List<Reservation> usingTimeReservations = reservationRepository.findByReservationTime(reservationTime);
|
List<Reservation> usingTimeReservations = reservationRepository.findByReservationTime(reservationTime);
|
||||||
|
|
||||||
if (!usingTimeReservations.isEmpty()) {
|
if (!usingTimeReservations.isEmpty()) {
|
||||||
throw new RoomEscapeException(ErrorType.TIME_IS_USED_CONFLICT, String.format("[timeId: %d]", id),
|
throw new RoomescapeException(ErrorType.TIME_IS_USED_CONFLICT, String.format("[timeId: %d]", id),
|
||||||
HttpStatus.CONFLICT);
|
HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,40 +0,0 @@
|
|||||||
package roomescape.system.config;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalTime;
|
|
||||||
import java.time.format.DateTimeFormatter;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
|
|
||||||
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class JacksonConfig {
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public ObjectMapper objectMapper() {
|
|
||||||
ObjectMapper objectMapper = new ObjectMapper();
|
|
||||||
objectMapper.registerModule(javaTimeModule());
|
|
||||||
return objectMapper;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Bean
|
|
||||||
public JavaTimeModule javaTimeModule() {
|
|
||||||
JavaTimeModule javaTimeModule = new JavaTimeModule();
|
|
||||||
|
|
||||||
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
|
|
||||||
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
|
|
||||||
|
|
||||||
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm")));
|
|
||||||
javaTimeModule.addDeserializer(LocalTime.class,
|
|
||||||
new LocalTimeDeserializer(DateTimeFormatter.ofPattern("HH:mm")));
|
|
||||||
|
|
||||||
return javaTimeModule;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,38 +0,0 @@
|
|||||||
package roomescape.system.config;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
|
|
||||||
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
|
|
||||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
|
||||||
|
|
||||||
import roomescape.system.auth.web.support.AdminInterceptor;
|
|
||||||
import roomescape.system.auth.web.support.LoginInterceptor;
|
|
||||||
import roomescape.system.auth.web.support.MemberIdResolver;
|
|
||||||
|
|
||||||
@Configuration
|
|
||||||
public class WebMvcConfig implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
private final MemberIdResolver memberIdResolver;
|
|
||||||
private final AdminInterceptor adminInterceptor;
|
|
||||||
private final LoginInterceptor loginInterceptor;
|
|
||||||
|
|
||||||
public WebMvcConfig(MemberIdResolver memberIdResolver, AdminInterceptor adminInterceptor,
|
|
||||||
LoginInterceptor loginInterceptor) {
|
|
||||||
this.memberIdResolver = memberIdResolver;
|
|
||||||
this.adminInterceptor = adminInterceptor;
|
|
||||||
this.loginInterceptor = loginInterceptor;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
|
|
||||||
resolvers.add(memberIdResolver);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addInterceptors(InterceptorRegistry registry) {
|
|
||||||
registry.addInterceptor(adminInterceptor);
|
|
||||||
registry.addInterceptor(loginInterceptor);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,15 +0,0 @@
|
|||||||
package roomescape.system.dto.response;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
import roomescape.system.exception.ErrorType;
|
|
||||||
|
|
||||||
@Schema(name = "예외 응답", description = "예외 발생 시 응답에 사용됩니다.")
|
|
||||||
public record ErrorResponse(
|
|
||||||
@Schema(description = "발생한 예외의 종류", example = "INVALID_REQUEST_DATA") ErrorType errorType,
|
|
||||||
@Schema(description = "예외 메시지", example = "요청 데이터 값이 올바르지 않습니다.") String message
|
|
||||||
) {
|
|
||||||
|
|
||||||
public static ErrorResponse of(ErrorType errorType, String message) {
|
|
||||||
return new ErrorResponse(errorType, message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,20 +0,0 @@
|
|||||||
package roomescape.system.dto.response;
|
|
||||||
|
|
||||||
import io.swagger.v3.oas.annotations.media.Schema;
|
|
||||||
|
|
||||||
@Schema(description = "API 응답 시에 사용합니다.")
|
|
||||||
public record RoomEscapeApiResponse<T>(
|
|
||||||
@Schema(description = "응답 메시지", defaultValue = SUCCESS_MESSAGE) String message,
|
|
||||||
@Schema(description = "응답 바디") T data
|
|
||||||
) {
|
|
||||||
|
|
||||||
private static final String SUCCESS_MESSAGE = "요청이 성공적으로 수행되었습니다.";
|
|
||||||
|
|
||||||
public static <T> RoomEscapeApiResponse<T> success(T data) {
|
|
||||||
return new RoomEscapeApiResponse<>(SUCCESS_MESSAGE, data);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static <T> RoomEscapeApiResponse<T> success() {
|
|
||||||
return new RoomEscapeApiResponse<>(SUCCESS_MESSAGE, null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,61 +0,0 @@
|
|||||||
package roomescape.system.exception;
|
|
||||||
|
|
||||||
public enum ErrorType {
|
|
||||||
|
|
||||||
// 400 Bad Request
|
|
||||||
REQUEST_DATA_BLANK("요청 데이터에 유효하지 않은 값(null OR 공백)이 포함되어있습니다."),
|
|
||||||
INVALID_REQUEST_DATA_TYPE("요청 데이터 형식이 올바르지 않습니다."),
|
|
||||||
INVALID_REQUEST_DATA("요청 데이터 값이 올바르지 않습니다."),
|
|
||||||
INVALID_DATE_RANGE("종료 날짜는 시작 날짜 이전일 수 없습니다."),
|
|
||||||
HAS_RESERVATION_OR_WAITING("같은 테마에 대한 예약(대기)는 한 번만 가능합니다."),
|
|
||||||
|
|
||||||
// 401 Unauthorized
|
|
||||||
EXPIRED_TOKEN("토큰이 만료되었습니다. 다시 로그인 해주세요."),
|
|
||||||
UNSUPPORTED_TOKEN("지원하지 않는 JWT 토큰입니다."),
|
|
||||||
MALFORMED_TOKEN("형식이 맞지 않는 JWT 토큰입니다."),
|
|
||||||
INVALID_SIGNATURE_TOKEN("잘못된 JWT 토큰 Signature 입니다."),
|
|
||||||
ILLEGAL_TOKEN("JWT 토큰의 Claim 이 비어있습니다."),
|
|
||||||
INVALID_TOKEN("JWT 토큰이 존재하지 않거나 유효하지 않습니다."),
|
|
||||||
NOT_EXIST_COOKIE("쿠키가 존재하지 않습니다. 로그인이 필요한 서비스입니다."),
|
|
||||||
|
|
||||||
// 403 Forbidden
|
|
||||||
LOGIN_REQUIRED("로그인이 필요한 서비스입니다."),
|
|
||||||
PERMISSION_DOES_NOT_EXIST("접근 권한이 존재하지 않습니다."),
|
|
||||||
|
|
||||||
// 404 Not Found
|
|
||||||
MEMBER_NOT_FOUND("회원(Member) 정보가 존재하지 않습니다."),
|
|
||||||
RESERVATION_NOT_FOUND("예약(Reservation) 정보가 존재하지 않습니다."),
|
|
||||||
RESERVATION_TIME_NOT_FOUND("예약 시간(ReservationTime) 정보가 존재하지 않습니다."),
|
|
||||||
THEME_NOT_FOUND("테마(Theme) 정보가 존재하지 않습니다."),
|
|
||||||
PAYMENT_NOT_POUND("결제(Payment) 정보가 존재하지 않습니다."),
|
|
||||||
|
|
||||||
// 405 Method Not Allowed
|
|
||||||
METHOD_NOT_ALLOWED("지원하지 않는 HTTP Method 입니다."),
|
|
||||||
|
|
||||||
// 409 Conflict
|
|
||||||
TIME_IS_USED_CONFLICT("삭제할 수 없는 시간대입니다. 예약이 존재하는지 확인해주세요."),
|
|
||||||
THEME_IS_USED_CONFLICT("삭제할 수 없는 테마입니다. 예약이 존재하는지 확인해주세요."),
|
|
||||||
TIME_DUPLICATED("이미 해당 시간이 존재합니다."),
|
|
||||||
THEME_DUPLICATED("같은 이름의 테마가 존재합니다."),
|
|
||||||
RESERVATION_DUPLICATED("해당 시간에 이미 예약이 존재합니다."),
|
|
||||||
RESERVATION_PERIOD_IN_PAST("이미 지난 시간대는 예약할 수 없습니다."),
|
|
||||||
CANCELED_BEFORE_PAYMENT("취소 시간이 결제 시간 이전일 수 없습니다."),
|
|
||||||
|
|
||||||
// 500 Internal Server Error,
|
|
||||||
INTERNAL_SERVER_ERROR("서버 내부에서 에러가 발생하였습니다."),
|
|
||||||
UNEXPECTED_ERROR("예상치 못한 에러가 발생하였습니다. 잠시 후 다시 시도해주세요."),
|
|
||||||
|
|
||||||
// Payment Error
|
|
||||||
PAYMENT_ERROR("결제(취소)에 실패했습니다. 결제(취소) 정보를 확인해주세요."),
|
|
||||||
PAYMENT_SERVER_ERROR("결제 서버에서 에러가 발생하였습니다. 잠시 후 다시 시도해주세요.");
|
|
||||||
|
|
||||||
private final String description;
|
|
||||||
|
|
||||||
ErrorType(String description) {
|
|
||||||
this.description = description;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getDescription() {
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,71 +0,0 @@
|
|||||||
package roomescape.system.exception;
|
|
||||||
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.context.support.DefaultMessageSourceResolvable;
|
|
||||||
import org.springframework.http.HttpStatus;
|
|
||||||
import org.springframework.http.converter.HttpMessageNotReadableException;
|
|
||||||
import org.springframework.web.HttpRequestMethodNotSupportedException;
|
|
||||||
import org.springframework.web.bind.MethodArgumentNotValidException;
|
|
||||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
|
||||||
import org.springframework.web.bind.annotation.RestControllerAdvice;
|
|
||||||
import org.springframework.web.client.ResourceAccessException;
|
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletResponse;
|
|
||||||
import roomescape.system.dto.response.ErrorResponse;
|
|
||||||
|
|
||||||
@RestControllerAdvice
|
|
||||||
public class ExceptionControllerAdvice {
|
|
||||||
|
|
||||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
|
||||||
|
|
||||||
@ExceptionHandler(value = {RoomEscapeException.class})
|
|
||||||
public ErrorResponse handleRoomEscapeException(RoomEscapeException e, HttpServletResponse response) {
|
|
||||||
logger.error("{}{}", e.getMessage(), e.getInvalidValue().orElse(""), e);
|
|
||||||
response.setStatus(e.getHttpStatus().value());
|
|
||||||
return ErrorResponse.of(e.getErrorType(), e.getMessage());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(ResourceAccessException.class)
|
|
||||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
||||||
public ErrorResponse handleResourceAccessException(ResourceAccessException e) {
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return ErrorResponse.of(ErrorType.PAYMENT_SERVER_ERROR, ErrorType.PAYMENT_SERVER_ERROR.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(value = HttpMessageNotReadableException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public ErrorResponse handleHttpMessageNotReadableException(HttpMessageNotReadableException e) {
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return ErrorResponse.of(ErrorType.INVALID_REQUEST_DATA_TYPE,
|
|
||||||
ErrorType.INVALID_REQUEST_DATA_TYPE.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(value = MethodArgumentNotValidException.class)
|
|
||||||
@ResponseStatus(HttpStatus.BAD_REQUEST)
|
|
||||||
public ErrorResponse handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
|
|
||||||
String messages = e.getBindingResult().getAllErrors().stream()
|
|
||||||
.map(DefaultMessageSourceResolvable::getDefaultMessage)
|
|
||||||
.collect(Collectors.joining(", "));
|
|
||||||
|
|
||||||
logger.error(messages, e);
|
|
||||||
return ErrorResponse.of(ErrorType.INVALID_REQUEST_DATA, messages);
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(value = HttpRequestMethodNotSupportedException.class)
|
|
||||||
@ResponseStatus(HttpStatus.METHOD_NOT_ALLOWED)
|
|
||||||
public ErrorResponse handleHttpRequestMethodNotSupportedException(HttpRequestMethodNotSupportedException e) {
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return ErrorResponse.of(ErrorType.METHOD_NOT_ALLOWED, ErrorType.METHOD_NOT_ALLOWED.getDescription());
|
|
||||||
}
|
|
||||||
|
|
||||||
@ExceptionHandler(value = Exception.class)
|
|
||||||
@ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR)
|
|
||||||
public ErrorResponse handleException(Exception e) {
|
|
||||||
logger.error(e.getMessage(), e);
|
|
||||||
return ErrorResponse.of(ErrorType.INTERNAL_SERVER_ERROR, ErrorType.INTERNAL_SERVER_ERROR.getDescription());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,41 +0,0 @@
|
|||||||
package roomescape.system.exception;
|
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.springframework.http.HttpStatusCode;
|
|
||||||
|
|
||||||
public class RoomEscapeException extends RuntimeException {
|
|
||||||
|
|
||||||
private final ErrorType errorType;
|
|
||||||
private final String message;
|
|
||||||
private final String invalidValue;
|
|
||||||
private final HttpStatusCode httpStatus;
|
|
||||||
|
|
||||||
public RoomEscapeException(ErrorType errorType, HttpStatusCode httpStatus) {
|
|
||||||
this(errorType, null, httpStatus);
|
|
||||||
}
|
|
||||||
|
|
||||||
public RoomEscapeException(ErrorType errorType, String invalidValue, HttpStatusCode httpStatus) {
|
|
||||||
this.errorType = errorType;
|
|
||||||
this.message = errorType.getDescription();
|
|
||||||
this.invalidValue = invalidValue;
|
|
||||||
this.httpStatus = httpStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public ErrorType getErrorType() {
|
|
||||||
return errorType;
|
|
||||||
}
|
|
||||||
|
|
||||||
public HttpStatusCode getHttpStatus() {
|
|
||||||
return httpStatus;
|
|
||||||
}
|
|
||||||
|
|
||||||
public Optional<String> getInvalidValue() {
|
|
||||||
return Optional.ofNullable(invalidValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getMessage() {
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -21,10 +21,10 @@ import io.swagger.v3.oas.annotations.tags.Tag;
|
|||||||
import jakarta.servlet.http.HttpServletResponse;
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
import jakarta.validation.Valid;
|
import jakarta.validation.Valid;
|
||||||
import jakarta.validation.constraints.NotNull;
|
import jakarta.validation.constraints.NotNull;
|
||||||
import roomescape.system.auth.web.support.Admin;
|
import roomescape.auth.web.support.Admin;
|
||||||
import roomescape.system.auth.web.support.LoginRequired;
|
import roomescape.auth.web.support.LoginRequired;
|
||||||
import roomescape.system.dto.response.ErrorResponse;
|
import roomescape.common.dto.response.ErrorResponse;
|
||||||
import roomescape.system.dto.response.RoomEscapeApiResponse;
|
import roomescape.common.dto.response.RoomEscapeApiResponse;
|
||||||
import roomescape.theme.dto.ThemeRequest;
|
import roomescape.theme.dto.ThemeRequest;
|
||||||
import roomescape.theme.dto.ThemeResponse;
|
import roomescape.theme.dto.ThemeResponse;
|
||||||
import roomescape.theme.dto.ThemesResponse;
|
import roomescape.theme.dto.ThemesResponse;
|
||||||
|
|||||||
@ -8,8 +8,8 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.transaction.annotation.Transactional;
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
import roomescape.reservation.domain.repository.ReservationRepository;
|
import roomescape.reservation.domain.repository.ReservationRepository;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
import roomescape.theme.domain.repository.ThemeRepository;
|
import roomescape.theme.domain.repository.ThemeRepository;
|
||||||
import roomescape.theme.dto.ThemeRequest;
|
import roomescape.theme.dto.ThemeRequest;
|
||||||
@ -31,7 +31,7 @@ public class ThemeService {
|
|||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
public Theme findThemeById(Long id) {
|
public Theme findThemeById(Long id) {
|
||||||
return themeRepository.findById(id)
|
return themeRepository.findById(id)
|
||||||
.orElseThrow(() -> new RoomEscapeException(ErrorType.THEME_NOT_FOUND,
|
.orElseThrow(() -> new RoomescapeException(ErrorType.THEME_NOT_FOUND,
|
||||||
String.format("[themeId: %d]", id), HttpStatus.BAD_REQUEST));
|
String.format("[themeId: %d]", id), HttpStatus.BAD_REQUEST));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,14 +69,14 @@ public class ThemeService {
|
|||||||
|
|
||||||
private void validateIsSameThemeNameExist(String name) {
|
private void validateIsSameThemeNameExist(String name) {
|
||||||
if (themeRepository.existsByName(name)) {
|
if (themeRepository.existsByName(name)) {
|
||||||
throw new RoomEscapeException(ErrorType.THEME_DUPLICATED,
|
throw new RoomescapeException(ErrorType.THEME_DUPLICATED,
|
||||||
String.format("[name: %s]", name), HttpStatus.CONFLICT);
|
String.format("[name: %s]", name), HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeThemeById(Long id) {
|
public void removeThemeById(Long id) {
|
||||||
if (themeRepository.isReservedTheme(id)) {
|
if (themeRepository.isReservedTheme(id)) {
|
||||||
throw new RoomEscapeException(ErrorType.THEME_IS_USED_CONFLICT,
|
throw new RoomescapeException(ErrorType.THEME_IS_USED_CONFLICT,
|
||||||
String.format("[themeId: %d]", id), HttpStatus.CONFLICT);
|
String.format("[themeId: %d]", id), HttpStatus.CONFLICT);
|
||||||
}
|
}
|
||||||
themeRepository.deleteById(id);
|
themeRepository.deleteById(id);
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
package roomescape.view.controller
|
package roomescape.view
|
||||||
|
|
||||||
import org.springframework.stereotype.Controller
|
import org.springframework.stereotype.Controller
|
||||||
import org.springframework.web.bind.annotation.GetMapping
|
import org.springframework.web.bind.annotation.GetMapping
|
||||||
import org.springframework.web.bind.annotation.PathVariable
|
import org.springframework.web.bind.annotation.PathVariable
|
||||||
import org.springframework.web.bind.annotation.RequestMapping
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
import roomescape.system.auth.web.support.Admin
|
import roomescape.auth.web.support.Admin
|
||||||
import roomescape.system.auth.web.support.LoginRequired
|
import roomescape.auth.web.support.LoginRequired
|
||||||
|
|
||||||
@Controller
|
@Controller
|
||||||
class AuthPageController {
|
class AuthPageController {
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.system.auth.business
|
package roomescape.auth.business
|
||||||
|
|
||||||
import io.kotest.assertions.assertSoftly
|
import io.kotest.assertions.assertSoftly
|
||||||
import io.kotest.assertions.throwables.shouldThrow
|
import io.kotest.assertions.throwables.shouldThrow
|
||||||
@ -7,15 +7,15 @@ import io.kotest.matchers.shouldBe
|
|||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.mockk.mockk
|
import io.mockk.mockk
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import roomescape.common.JwtFixture
|
import roomescape.util.JwtFixture
|
||||||
import roomescape.common.MemberFixture
|
import roomescape.util.MemberFixture
|
||||||
import roomescape.member.business.MemberService
|
import roomescape.member.business.MemberService
|
||||||
import roomescape.member.infrastructure.persistence.Member
|
import roomescape.member.infrastructure.persistence.Member
|
||||||
import roomescape.member.infrastructure.persistence.MemberRepository
|
import roomescape.member.infrastructure.persistence.MemberRepository
|
||||||
import roomescape.system.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
import roomescape.system.auth.service.AuthService
|
import roomescape.auth.service.AuthService
|
||||||
import roomescape.system.exception.ErrorType
|
import roomescape.common.exception.ErrorType
|
||||||
import roomescape.system.exception.RoomEscapeException
|
import roomescape.common.exception.RoomescapeException
|
||||||
|
|
||||||
|
|
||||||
class AuthServiceTest : BehaviorSpec({
|
class AuthServiceTest : BehaviorSpec({
|
||||||
@ -46,7 +46,7 @@ class AuthServiceTest : BehaviorSpec({
|
|||||||
memberRepository.findByEmailAndPassword(request.email, request.password)
|
memberRepository.findByEmailAndPassword(request.email, request.password)
|
||||||
} returns null
|
} returns null
|
||||||
|
|
||||||
val exception = shouldThrow<RoomEscapeException> {
|
val exception = shouldThrow<RoomescapeException> {
|
||||||
authService.login(request)
|
authService.login(request)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -72,7 +72,7 @@ class AuthServiceTest : BehaviorSpec({
|
|||||||
Then("회원이 없다면 예외를 던진다.") {
|
Then("회원이 없다면 예외를 던진다.") {
|
||||||
every { memberRepository.findByIdOrNull(userId) } returns null
|
every { memberRepository.findByIdOrNull(userId) } returns null
|
||||||
|
|
||||||
val exception = shouldThrow<RoomEscapeException> {
|
val exception = shouldThrow<RoomescapeException> {
|
||||||
authService.checkLogin(userId)
|
authService.checkLogin(userId)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1,13 +1,13 @@
|
|||||||
package roomescape.system.auth.infrastructure.jwt
|
package roomescape.auth.infrastructure.jwt
|
||||||
|
|
||||||
import io.jsonwebtoken.Jwts
|
import io.jsonwebtoken.Jwts
|
||||||
import io.jsonwebtoken.SignatureAlgorithm
|
import io.jsonwebtoken.SignatureAlgorithm
|
||||||
import io.kotest.assertions.throwables.shouldThrow
|
import io.kotest.assertions.throwables.shouldThrow
|
||||||
import io.kotest.core.spec.style.FunSpec
|
import io.kotest.core.spec.style.FunSpec
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import roomescape.common.JwtFixture
|
import roomescape.util.JwtFixture
|
||||||
import roomescape.system.exception.ErrorType
|
import roomescape.common.exception.ErrorType
|
||||||
import roomescape.system.exception.RoomEscapeException
|
import roomescape.common.exception.RoomescapeException
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import kotlin.random.Random
|
import kotlin.random.Random
|
||||||
|
|
||||||
@ -33,13 +33,13 @@ class JwtHandlerTest : FunSpec({
|
|||||||
Thread.sleep(expirationTime) // 만료 시간 이후로 대기
|
Thread.sleep(expirationTime) // 만료 시간 이후로 대기
|
||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
shouldThrow<RoomEscapeException> {
|
shouldThrow<RoomescapeException> {
|
||||||
shortExpirationTimeJwtHandler.getMemberIdFromToken(token)
|
shortExpirationTimeJwtHandler.getMemberIdFromToken(token)
|
||||||
}.errorType shouldBe ErrorType.EXPIRED_TOKEN
|
}.errorType shouldBe ErrorType.EXPIRED_TOKEN
|
||||||
}
|
}
|
||||||
|
|
||||||
test("토큰이 빈 값이면 예외를 던진다.") {
|
test("토큰이 빈 값이면 예외를 던진다.") {
|
||||||
shouldThrow<RoomEscapeException> {
|
shouldThrow<RoomescapeException> {
|
||||||
jwtHandler.getMemberIdFromToken("")
|
jwtHandler.getMemberIdFromToken("")
|
||||||
}.errorType shouldBe ErrorType.INVALID_TOKEN
|
}.errorType shouldBe ErrorType.INVALID_TOKEN
|
||||||
}
|
}
|
||||||
@ -53,7 +53,7 @@ class JwtHandlerTest : FunSpec({
|
|||||||
.signWith(SignatureAlgorithm.HS256, JwtFixture.SECRET_KEY.substring(1).toByteArray())
|
.signWith(SignatureAlgorithm.HS256, JwtFixture.SECRET_KEY.substring(1).toByteArray())
|
||||||
.compact()
|
.compact()
|
||||||
|
|
||||||
shouldThrow<RoomEscapeException> {
|
shouldThrow<RoomescapeException> {
|
||||||
jwtHandler.getMemberIdFromToken(invalidSignatureToken)
|
jwtHandler.getMemberIdFromToken(invalidSignatureToken)
|
||||||
}.errorType shouldBe ErrorType.INVALID_SIGNATURE_TOKEN
|
}.errorType shouldBe ErrorType.INVALID_SIGNATURE_TOKEN
|
||||||
}
|
}
|
||||||
@ -1,12 +1,13 @@
|
|||||||
package roomescape.system.auth.web
|
package roomescape.auth.web
|
||||||
|
|
||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import org.hamcrest.Matchers.containsString
|
import org.hamcrest.Matchers.containsString
|
||||||
import org.hamcrest.Matchers.`is`
|
import org.hamcrest.Matchers.`is`
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import roomescape.common.MemberFixture
|
import roomescape.auth.web.LoginRequest
|
||||||
import roomescape.common.RoomescapeApiTest
|
import roomescape.util.MemberFixture
|
||||||
import roomescape.system.exception.ErrorType
|
import roomescape.util.RoomescapeApiTest
|
||||||
|
import roomescape.common.exception.ErrorType
|
||||||
|
|
||||||
class AuthControllerTest : RoomescapeApiTest() {
|
class AuthControllerTest : RoomescapeApiTest() {
|
||||||
|
|
||||||
55
src/test/java/roomescape/common/config/JacksonConfigTest.kt
Normal file
55
src/test/java/roomescape/common/config/JacksonConfigTest.kt
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
package roomescape.common.config
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.fasterxml.jackson.databind.exc.InvalidFormatException
|
||||||
|
import io.kotest.assertions.throwables.shouldThrow
|
||||||
|
import io.kotest.core.spec.style.FunSpec
|
||||||
|
import io.kotest.matchers.shouldBe
|
||||||
|
import io.kotest.matchers.string.shouldContain
|
||||||
|
import java.time.LocalDate
|
||||||
|
import java.time.LocalTime
|
||||||
|
|
||||||
|
class JacksonConfigTest(
|
||||||
|
private val objectMapper: ObjectMapper = JacksonConfig().objectMapper()
|
||||||
|
) : FunSpec({
|
||||||
|
|
||||||
|
context("날짜는 yyyy-mm-dd 형식이다.") {
|
||||||
|
val date = "2025-07-14"
|
||||||
|
val serialized: String = objectMapper.writeValueAsString(LocalDate.parse(date))
|
||||||
|
val deserialized: LocalDate = objectMapper.readValue(serialized, LocalDate::class.java)
|
||||||
|
|
||||||
|
test("LocalDate 직렬화") {
|
||||||
|
serialized shouldBe "\"$date\""
|
||||||
|
}
|
||||||
|
|
||||||
|
test("LocalDate 역직렬화") {
|
||||||
|
deserialized shouldBe LocalDate.parse(date)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("형식이 잘못되면 InvalidFormatException을 던진다.") {
|
||||||
|
shouldThrow<InvalidFormatException> {
|
||||||
|
objectMapper.readValue("\"2025/07/14\"", LocalDate::class.java)
|
||||||
|
}.message shouldContain "Text '2025/07/14' could not be parsed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context("시간은 HH:mm 형식이다.") {
|
||||||
|
val (hour, minute, sec) = Triple(12, 30, 45)
|
||||||
|
val serialized: String = objectMapper.writeValueAsString(LocalTime.of(hour, minute, sec))
|
||||||
|
val deserialized: LocalTime = objectMapper.readValue(serialized, LocalTime::class.java)
|
||||||
|
|
||||||
|
test("LocalTime 직렬화") {
|
||||||
|
serialized shouldBe "\"$hour:$minute\""
|
||||||
|
}
|
||||||
|
|
||||||
|
test("LocalTime 역직렬화") {
|
||||||
|
deserialized shouldBe LocalTime.of(hour, minute)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("형식이 잘못되면 InvalidFormatException을 던진다.") {
|
||||||
|
shouldThrow<InvalidFormatException> {
|
||||||
|
objectMapper.readValue("\"$hour:$minute:$sec\"", LocalTime::class.java)
|
||||||
|
}.message shouldContain "Text '$hour:$minute:$sec' could not be parsed"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
@ -0,0 +1,158 @@
|
|||||||
|
package roomescape.common.dto.response
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
|
import com.ninjasquad.springmockk.MockkBean
|
||||||
|
import com.ninjasquad.springmockk.SpykBean
|
||||||
|
import io.kotest.core.spec.style.BehaviorSpec
|
||||||
|
import org.hamcrest.CoreMatchers.equalTo
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest
|
||||||
|
import org.springframework.http.MediaType
|
||||||
|
import org.springframework.test.web.servlet.MockMvc
|
||||||
|
import org.springframework.test.web.servlet.get
|
||||||
|
import org.springframework.test.web.servlet.post
|
||||||
|
import org.springframework.web.bind.annotation.*
|
||||||
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
|
import roomescape.auth.web.support.AdminInterceptor
|
||||||
|
import roomescape.auth.web.support.LoginInterceptor
|
||||||
|
import roomescape.auth.web.support.MemberIdResolver
|
||||||
|
import roomescape.common.exception.ErrorType
|
||||||
|
import roomescape.member.business.MemberService
|
||||||
|
import roomescape.member.infrastructure.persistence.MemberRepository
|
||||||
|
|
||||||
|
@WebMvcTest(ApiResponseTestController::class)
|
||||||
|
class RoomescapeApiResponseKTTest(
|
||||||
|
@Autowired private val mockMvc: MockMvc
|
||||||
|
) : BehaviorSpec() {
|
||||||
|
@Autowired
|
||||||
|
private lateinit var AdminInterceptor: AdminInterceptor
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var loginInterceptor: LoginInterceptor
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private lateinit var memberIdResolver: MemberIdResolver
|
||||||
|
|
||||||
|
@SpykBean
|
||||||
|
private lateinit var memberService: MemberService
|
||||||
|
|
||||||
|
@MockkBean
|
||||||
|
private lateinit var memberRepository: MemberRepository
|
||||||
|
|
||||||
|
@MockkBean
|
||||||
|
private lateinit var jwtHandler: JwtHandler
|
||||||
|
|
||||||
|
init {
|
||||||
|
Given("성공 응답에") {
|
||||||
|
val endpoint = "/success"
|
||||||
|
When("객체 데이터를 담으면") {
|
||||||
|
val id: Long = 1L
|
||||||
|
val name = "name"
|
||||||
|
Then("success=true, data={객체} 형태로 응답한다.") {
|
||||||
|
mockMvc.post("$endpoint/$id/$name") {
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}.andDo {
|
||||||
|
print()
|
||||||
|
}.andExpect {
|
||||||
|
status { isOk() }
|
||||||
|
jsonPath("$.success", equalTo(true))
|
||||||
|
jsonPath("$.data.id", equalTo(id.toInt()))
|
||||||
|
jsonPath("$.data.name", equalTo(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
When("문자열 데이터를 담으면") {
|
||||||
|
val message: String = "Hello, World!"
|
||||||
|
|
||||||
|
Then("success=true, data={문자열} 형태로 응답한다.") {
|
||||||
|
mockMvc.get("/success/$message") {
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
}.andDo {
|
||||||
|
print()
|
||||||
|
}.andExpect {
|
||||||
|
status { isOk() }
|
||||||
|
jsonPath("$.success", equalTo(true))
|
||||||
|
jsonPath("$.data", equalTo(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Given("실패 응답에") {
|
||||||
|
val endpoint = "/fail"
|
||||||
|
val objectMapper = ObjectMapper()
|
||||||
|
|
||||||
|
When("errorType만 담으면") {
|
||||||
|
Then("success=false, errorType={errorType}, message={errorType.description} 형태로 응답한다.") {
|
||||||
|
mockMvc.post(endpoint) {
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
content = objectMapper.writeValueAsString(FailRequest(errorType = ErrorType.INTERNAL_SERVER_ERROR))
|
||||||
|
}.andDo {
|
||||||
|
print()
|
||||||
|
}.andExpect {
|
||||||
|
status { isOk() }
|
||||||
|
jsonPath("$.success", equalTo(false))
|
||||||
|
jsonPath("$.errorType", equalTo(ErrorType.INTERNAL_SERVER_ERROR.name))
|
||||||
|
jsonPath("$.message", equalTo(ErrorType.INTERNAL_SERVER_ERROR.description))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
When("errorType과 message를 담으면") {
|
||||||
|
val message: String = "An error occurred"
|
||||||
|
|
||||||
|
Then("success=false, errorType={errorType}, message={message} 형태로 응답한다.") {
|
||||||
|
mockMvc.post(endpoint) {
|
||||||
|
contentType = MediaType.APPLICATION_JSON
|
||||||
|
content = objectMapper.writeValueAsString(FailRequest(errorType = ErrorType.INTERNAL_SERVER_ERROR, message = message))
|
||||||
|
}.andDo {
|
||||||
|
print()
|
||||||
|
}.andExpect {
|
||||||
|
status { isOk() }
|
||||||
|
jsonPath("$.success", equalTo(false))
|
||||||
|
jsonPath("$.errorType", equalTo(ErrorType.INTERNAL_SERVER_ERROR.name))
|
||||||
|
jsonPath("$.message", equalTo(message))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data class SuccessResponse(
|
||||||
|
val id: Long,
|
||||||
|
val name: String
|
||||||
|
)
|
||||||
|
|
||||||
|
data class FailRequest(
|
||||||
|
val errorType: ErrorType,
|
||||||
|
val message: String? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
class ApiResponseTestController {
|
||||||
|
|
||||||
|
@GetMapping("/success/{message}")
|
||||||
|
fun succeedToGet(
|
||||||
|
@PathVariable message: String,
|
||||||
|
): RoomescapeApiResponseKT<String> =
|
||||||
|
RoomescapeApiResponseKT.success(message)
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/success/{id}/{name}")
|
||||||
|
fun succeedToPost(
|
||||||
|
@PathVariable id: Long,
|
||||||
|
@PathVariable name: String,
|
||||||
|
): RoomescapeApiResponseKT<SuccessResponse> =
|
||||||
|
RoomescapeApiResponseKT.success(SuccessResponse(id, name))
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/fail")
|
||||||
|
fun fail(
|
||||||
|
@RequestBody request: FailRequest
|
||||||
|
): RoomescapeApiResponseKT<Unit> =
|
||||||
|
request.message?.let {
|
||||||
|
RoomescapeApiResponseKT.fail(request.errorType, it)
|
||||||
|
} ?: RoomescapeApiResponseKT.fail(request.errorType)
|
||||||
|
}
|
||||||
@ -7,8 +7,8 @@ import io.kotest.matchers.shouldBe
|
|||||||
import io.mockk.every
|
import io.mockk.every
|
||||||
import io.restassured.module.kotlin.extensions.Extract
|
import io.restassured.module.kotlin.extensions.Extract
|
||||||
import org.hamcrest.Matchers.containsString
|
import org.hamcrest.Matchers.containsString
|
||||||
import roomescape.common.MemberFixture
|
import roomescape.util.MemberFixture
|
||||||
import roomescape.common.RoomescapeApiTest
|
import roomescape.util.RoomescapeApiTest
|
||||||
import roomescape.member.web.MembersResponse
|
import roomescape.member.web.MembersResponse
|
||||||
|
|
||||||
class MemberControllerTest : RoomescapeApiTest() {
|
class MemberControllerTest : RoomescapeApiTest() {
|
||||||
|
|||||||
@ -1,14 +1,10 @@
|
|||||||
package roomescape.payment.client;
|
package roomescape.payment.client;
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
|
||||||
import static org.assertj.core.api.Assertions.assertThat;
|
import static org.assertj.core.api.Assertions.assertThat;
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.*;
|
|
||||||
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
import static org.assertj.core.api.AssertionsForClassTypes.assertThatThrownBy;
|
||||||
import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
|
import static org.springframework.test.web.client.match.MockRestRequestMatchers.*;
|
||||||
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;
|
import static org.springframework.test.web.client.response.MockRestResponseCreators.*;
|
||||||
|
|
||||||
import java.util.Optional;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
@ -22,8 +18,8 @@ import roomescape.payment.dto.request.PaymentCancelRequest;
|
|||||||
import roomescape.payment.dto.request.PaymentRequest;
|
import roomescape.payment.dto.request.PaymentRequest;
|
||||||
import roomescape.payment.dto.response.PaymentCancelResponse;
|
import roomescape.payment.dto.response.PaymentCancelResponse;
|
||||||
import roomescape.payment.dto.response.PaymentResponse;
|
import roomescape.payment.dto.response.PaymentResponse;
|
||||||
import roomescape.system.exception.ErrorType;
|
import roomescape.common.exception.ErrorType;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
@RestClientTest(TossPaymentClient.class)
|
@RestClientTest(TossPaymentClient.class)
|
||||||
class TossPaymentClientTest {
|
class TossPaymentClientTest {
|
||||||
@ -90,10 +86,10 @@ class TossPaymentClientTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
assertThatThrownBy(() -> tossPaymentClient.confirmPayment(SampleTossPaymentConst.paymentRequest))
|
assertThatThrownBy(() -> tossPaymentClient.confirmPayment(SampleTossPaymentConst.paymentRequest))
|
||||||
.isInstanceOf(RoomEscapeException.class)
|
.isInstanceOf(RoomescapeException.class)
|
||||||
.hasFieldOrPropertyWithValue("errorType", ErrorType.PAYMENT_ERROR)
|
.hasFieldOrPropertyWithValue("errorType", ErrorType.PAYMENT_ERROR)
|
||||||
.hasFieldOrPropertyWithValue("invalidValue",
|
.hasFieldOrPropertyWithValue("invalidValue",
|
||||||
Optional.of("[ErrorCode = ERROR_CODE, ErrorMessage = Error message]"))
|
"[ErrorCode = ERROR_CODE, ErrorMessage = Error message]")
|
||||||
.hasFieldOrPropertyWithValue("httpStatus", HttpStatus.BAD_REQUEST);
|
.hasFieldOrPropertyWithValue("httpStatus", HttpStatus.BAD_REQUEST);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -111,10 +107,10 @@ class TossPaymentClientTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
assertThatThrownBy(() -> tossPaymentClient.cancelPayment(SampleTossPaymentConst.cancelRequest))
|
assertThatThrownBy(() -> tossPaymentClient.cancelPayment(SampleTossPaymentConst.cancelRequest))
|
||||||
.isInstanceOf(RoomEscapeException.class)
|
.isInstanceOf(RoomescapeException.class)
|
||||||
.hasFieldOrPropertyWithValue("errorType", ErrorType.PAYMENT_SERVER_ERROR)
|
.hasFieldOrPropertyWithValue("errorType", ErrorType.PAYMENT_SERVER_ERROR)
|
||||||
.hasFieldOrPropertyWithValue("invalidValue",
|
.hasFieldOrPropertyWithValue("invalidValue",
|
||||||
Optional.of("[ErrorCode = ERROR_CODE, ErrorMessage = Error message]"))
|
"[ErrorCode = ERROR_CODE, ErrorMessage = Error message]")
|
||||||
.hasFieldOrPropertyWithValue("httpStatus", HttpStatus.INTERNAL_SERVER_ERROR);
|
.hasFieldOrPropertyWithValue("httpStatus", HttpStatus.INTERNAL_SERVER_ERROR);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ import java.time.OffsetDateTime;
|
|||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
class CanceledPaymentTest {
|
class CanceledPaymentTest {
|
||||||
|
|
||||||
@ -17,6 +17,6 @@ class CanceledPaymentTest {
|
|||||||
OffsetDateTime approvedAt = OffsetDateTime.now();
|
OffsetDateTime approvedAt = OffsetDateTime.now();
|
||||||
OffsetDateTime canceledAt = approvedAt.minusMinutes(1L);
|
OffsetDateTime canceledAt = approvedAt.minusMinutes(1L);
|
||||||
assertThatThrownBy(() -> new CanceledPayment("payment-key", "reason", 10000L, approvedAt, canceledAt))
|
assertThatThrownBy(() -> new CanceledPayment("payment-key", "reason", 10000L, approvedAt, canceledAt))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -18,7 +18,7 @@ import roomescape.member.infrastructure.persistence.Role;
|
|||||||
import roomescape.reservation.domain.Reservation;
|
import roomescape.reservation.domain.Reservation;
|
||||||
import roomescape.reservation.domain.ReservationStatus;
|
import roomescape.reservation.domain.ReservationStatus;
|
||||||
import roomescape.reservation.domain.ReservationTime;
|
import roomescape.reservation.domain.ReservationTime;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
|
|
||||||
class PaymentTest {
|
class PaymentTest {
|
||||||
@ -40,7 +40,7 @@ class PaymentTest {
|
|||||||
@NullAndEmptySource
|
@NullAndEmptySource
|
||||||
void invalidPaymentKey(String paymentKey) {
|
void invalidPaymentKey(String paymentKey) {
|
||||||
assertThatThrownBy(() -> new Payment("order-id", paymentKey, 10000L, reservation, OffsetDateTime.now()))
|
assertThatThrownBy(() -> new Payment("order-id", paymentKey, 10000L, reservation, OffsetDateTime.now()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ -48,7 +48,7 @@ class PaymentTest {
|
|||||||
@NullAndEmptySource
|
@NullAndEmptySource
|
||||||
void invalidOrderId(String orderId) {
|
void invalidOrderId(String orderId) {
|
||||||
assertThatThrownBy(() -> new Payment(orderId, "payment-key", 10000L, reservation, OffsetDateTime.now()))
|
assertThatThrownBy(() -> new Payment(orderId, "payment-key", 10000L, reservation, OffsetDateTime.now()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ -57,7 +57,7 @@ class PaymentTest {
|
|||||||
void invalidOrderId(Long totalAmount) {
|
void invalidOrderId(Long totalAmount) {
|
||||||
assertThatThrownBy(
|
assertThatThrownBy(
|
||||||
() -> new Payment("orderId", "payment-key", totalAmount, reservation, OffsetDateTime.now()))
|
() -> new Payment("orderId", "payment-key", totalAmount, reservation, OffsetDateTime.now()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ -65,7 +65,7 @@ class PaymentTest {
|
|||||||
@NullSource
|
@NullSource
|
||||||
void invalidReservation(Reservation reservation) {
|
void invalidReservation(Reservation reservation) {
|
||||||
assertThatThrownBy(() -> new Payment("orderId", "payment-key", 10000L, reservation, OffsetDateTime.now()))
|
assertThatThrownBy(() -> new Payment("orderId", "payment-key", 10000L, reservation, OffsetDateTime.now()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ParameterizedTest
|
@ParameterizedTest
|
||||||
@ -73,6 +73,6 @@ class PaymentTest {
|
|||||||
@NullSource
|
@NullSource
|
||||||
void invalidApprovedAt(OffsetDateTime approvedAt) {
|
void invalidApprovedAt(OffsetDateTime approvedAt) {
|
||||||
assertThatThrownBy(() -> new Payment("orderId", "payment-key", 10000L, reservation, approvedAt))
|
assertThatThrownBy(() -> new Payment("orderId", "payment-key", 10000L, reservation, approvedAt))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,7 +25,7 @@ import roomescape.reservation.domain.ReservationStatus;
|
|||||||
import roomescape.reservation.domain.ReservationTime;
|
import roomescape.reservation.domain.ReservationTime;
|
||||||
import roomescape.reservation.domain.repository.ReservationRepository;
|
import roomescape.reservation.domain.repository.ReservationRepository;
|
||||||
import roomescape.reservation.domain.repository.ReservationTimeRepository;
|
import roomescape.reservation.domain.repository.ReservationTimeRepository;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
import roomescape.theme.domain.repository.ThemeRepository;
|
import roomescape.theme.domain.repository.ThemeRepository;
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ class PaymentServiceTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
assertThatThrownBy(() -> paymentService.cancelPaymentByAdmin(nonExistentReservationId))
|
assertThatThrownBy(() -> paymentService.cancelPaymentByAdmin(nonExistentReservationId))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -136,6 +136,6 @@ class PaymentServiceTest {
|
|||||||
|
|
||||||
// when
|
// when
|
||||||
assertThatThrownBy(() -> paymentService.updateCanceledTime("non-existent-payment-key", canceledAt))
|
assertThatThrownBy(() -> paymentService.updateCanceledTime("non-existent-payment-key", canceledAt))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,7 +12,7 @@ import org.junit.jupiter.params.provider.MethodSource;
|
|||||||
|
|
||||||
import roomescape.member.infrastructure.persistence.Member;
|
import roomescape.member.infrastructure.persistence.Member;
|
||||||
import roomescape.member.infrastructure.persistence.Role;
|
import roomescape.member.infrastructure.persistence.Role;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
|
|
||||||
public class ReservationTest {
|
public class ReservationTest {
|
||||||
@ -26,7 +26,7 @@ public class ReservationTest {
|
|||||||
// when & then
|
// when & then
|
||||||
Assertions.assertThatThrownBy(
|
Assertions.assertThatThrownBy(
|
||||||
() -> new Reservation(date, reservationTime, theme, member, ReservationStatus.CONFIRMED))
|
() -> new Reservation(date, reservationTime, theme, member, ReservationStatus.CONFIRMED))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
static Stream<Arguments> validateConstructorParameterBlankSource() {
|
static Stream<Arguments> validateConstructorParameterBlankSource() {
|
||||||
|
|||||||
@ -4,7 +4,7 @@ import org.assertj.core.api.Assertions;
|
|||||||
import org.junit.jupiter.api.DisplayName;
|
import org.junit.jupiter.api.DisplayName;
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
|
|
||||||
class ReservationTimeTest {
|
class ReservationTimeTest {
|
||||||
|
|
||||||
@ -14,6 +14,6 @@ class ReservationTimeTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
Assertions.assertThatThrownBy(() -> new ReservationTime(null))
|
Assertions.assertThatThrownBy(() -> new ReservationTime(null))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -26,7 +26,7 @@ import roomescape.reservation.domain.repository.ReservationTimeRepository;
|
|||||||
import roomescape.reservation.dto.request.ReservationRequest;
|
import roomescape.reservation.dto.request.ReservationRequest;
|
||||||
import roomescape.reservation.dto.request.WaitingRequest;
|
import roomescape.reservation.dto.request.WaitingRequest;
|
||||||
import roomescape.reservation.dto.response.ReservationResponse;
|
import roomescape.reservation.dto.response.ReservationResponse;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
import roomescape.theme.domain.repository.ThemeRepository;
|
import roomescape.theme.domain.repository.ThemeRepository;
|
||||||
import roomescape.theme.service.ThemeService;
|
import roomescape.theme.service.ThemeService;
|
||||||
@ -66,7 +66,7 @@ class ReservationServiceTest {
|
|||||||
assertThatThrownBy(() -> reservationService.addReservation(
|
assertThatThrownBy(() -> reservationService.addReservation(
|
||||||
new ReservationRequest(date, reservationTime.getId(), theme.getId(), "paymentKey", "orderId",
|
new ReservationRequest(date, reservationTime.getId(), theme.getId(), "paymentKey", "orderId",
|
||||||
1000L, "paymentType"), member1.getId()))
|
1000L, "paymentType"), member1.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -86,7 +86,7 @@ class ReservationServiceTest {
|
|||||||
// then
|
// then
|
||||||
assertThatThrownBy(() -> reservationService.addWaiting(
|
assertThatThrownBy(() -> reservationService.addWaiting(
|
||||||
new WaitingRequest(date, reservationTime.getId(), theme.getId()), member.getId()))
|
new WaitingRequest(date, reservationTime.getId(), theme.getId()), member.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -110,7 +110,7 @@ class ReservationServiceTest {
|
|||||||
// then
|
// then
|
||||||
assertThatThrownBy(() -> reservationService.addWaiting(
|
assertThatThrownBy(() -> reservationService.addWaiting(
|
||||||
new WaitingRequest(date, reservationTime.getId(), theme.getId()), member1.getId()))
|
new WaitingRequest(date, reservationTime.getId(), theme.getId()), member1.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -126,7 +126,7 @@ class ReservationServiceTest {
|
|||||||
assertThatThrownBy(() -> reservationService.addReservation(
|
assertThatThrownBy(() -> reservationService.addReservation(
|
||||||
new ReservationRequest(beforeDate, reservationTime.getId(), theme.getId(), "paymentKey", "orderId",
|
new ReservationRequest(beforeDate, reservationTime.getId(), theme.getId(), "paymentKey", "orderId",
|
||||||
1000L, "paymentType"), member.getId()))
|
1000L, "paymentType"), member.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -142,7 +142,7 @@ class ReservationServiceTest {
|
|||||||
assertThatThrownBy(() -> reservationService.addReservation(
|
assertThatThrownBy(() -> reservationService.addReservation(
|
||||||
new ReservationRequest(beforeTime.toLocalDate(), reservationTime.getId(), theme.getId(), "paymentKey",
|
new ReservationRequest(beforeTime.toLocalDate(), reservationTime.getId(), theme.getId(), "paymentKey",
|
||||||
"orderId", 1000L, "paymentType"), member.getId()))
|
"orderId", 1000L, "paymentType"), member.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -159,7 +159,7 @@ class ReservationServiceTest {
|
|||||||
new ReservationRequest(beforeTime.toLocalDate(), reservationTime.getId(), theme.getId(), "paymentKey",
|
new ReservationRequest(beforeTime.toLocalDate(), reservationTime.getId(), theme.getId(), "paymentKey",
|
||||||
"orderId", 1000L, "paymentType"),
|
"orderId", 1000L, "paymentType"),
|
||||||
NotExistMemberId))
|
NotExistMemberId))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -171,7 +171,7 @@ class ReservationServiceTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
assertThatThrownBy(() -> reservationService.findFilteredReservations(null, null, dateFrom, dateTo))
|
assertThatThrownBy(() -> reservationService.findFilteredReservations(null, null, dateFrom, dateTo))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -194,7 +194,7 @@ class ReservationServiceTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
assertThatThrownBy(() -> reservationService.approveWaiting(waiting.id(), admin.getId()))
|
assertThatThrownBy(() -> reservationService.approveWaiting(waiting.id(), admin.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|||||||
@ -22,7 +22,7 @@ import roomescape.reservation.domain.ReservationTime;
|
|||||||
import roomescape.reservation.domain.repository.ReservationRepository;
|
import roomescape.reservation.domain.repository.ReservationRepository;
|
||||||
import roomescape.reservation.domain.repository.ReservationTimeRepository;
|
import roomescape.reservation.domain.repository.ReservationTimeRepository;
|
||||||
import roomescape.reservation.dto.request.ReservationTimeRequest;
|
import roomescape.reservation.dto.request.ReservationTimeRequest;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
import roomescape.theme.domain.repository.ThemeRepository;
|
import roomescape.theme.domain.repository.ThemeRepository;
|
||||||
|
|
||||||
@ -50,7 +50,7 @@ class ReservationTimeServiceTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
assertThatThrownBy(() -> reservationTimeService.addTime(new ReservationTimeRequest(LocalTime.of(12, 30))))
|
assertThatThrownBy(() -> reservationTimeService.addTime(new ReservationTimeRequest(LocalTime.of(12, 30))))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -64,7 +64,7 @@ class ReservationTimeServiceTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
assertThatThrownBy(() -> reservationTimeService.findTimeById(invalidTimeId))
|
assertThatThrownBy(() -> reservationTimeService.findTimeById(invalidTimeId))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -83,6 +83,6 @@ class ReservationTimeServiceTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThatThrownBy(() -> reservationTimeService.removeTimeById(reservationTime.getId()))
|
assertThatThrownBy(() -> reservationTimeService.removeTimeById(reservationTime.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,78 +0,0 @@
|
|||||||
package roomescape.system.config;
|
|
||||||
|
|
||||||
import static org.assertj.core.api.Assertions.*;
|
|
||||||
|
|
||||||
import java.time.LocalDate;
|
|
||||||
import java.time.LocalTime;
|
|
||||||
|
|
||||||
import org.junit.jupiter.api.BeforeEach;
|
|
||||||
import org.junit.jupiter.api.DisplayName;
|
|
||||||
import org.junit.jupiter.api.Test;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
||||||
|
|
||||||
class JacksonConfigTest {
|
|
||||||
|
|
||||||
private ObjectMapper objectMapper;
|
|
||||||
|
|
||||||
@BeforeEach
|
|
||||||
void setUp() {
|
|
||||||
JacksonConfig jacksonConfig = new JacksonConfig();
|
|
||||||
objectMapper = jacksonConfig.objectMapper();
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("날짜는 yyyy-MM-dd 형식으로 직렬화 된다.")
|
|
||||||
@Test
|
|
||||||
void dateSerialize() throws JsonProcessingException {
|
|
||||||
// given
|
|
||||||
LocalDate date = LocalDate.parse("2021-07-01");
|
|
||||||
|
|
||||||
// when
|
|
||||||
String json = objectMapper.writeValueAsString(date);
|
|
||||||
LocalDate actual = objectMapper.readValue(json, LocalDate.class);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertThat(actual.toString()).isEqualTo("2021-07-01");
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("시간은 HH:mm 형식으로 직렬화된다.")
|
|
||||||
@Test
|
|
||||||
void timeSerialize() throws JsonProcessingException {
|
|
||||||
// given
|
|
||||||
LocalTime time = LocalTime.parse("12:30:00");
|
|
||||||
|
|
||||||
// when
|
|
||||||
String json = objectMapper.writeValueAsString(time);
|
|
||||||
LocalTime actual = objectMapper.readValue(json, LocalTime.class);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertThat(actual.toString()).isEqualTo("12:30");
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("yyyy-MM-dd 형식의 문자열은 LocalDate로 역직렬화된다.")
|
|
||||||
@Test
|
|
||||||
void dateDeserialize() throws JsonProcessingException {
|
|
||||||
// given
|
|
||||||
String json = "\"2021-07-01\"";
|
|
||||||
|
|
||||||
// when
|
|
||||||
LocalDate actual = objectMapper.readValue(json, LocalDate.class);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertThat(actual).isEqualTo(LocalDate.of(2021, 7, 1));
|
|
||||||
}
|
|
||||||
|
|
||||||
@DisplayName("HH:mm 형식의 문자열은 LocalTime으로 역직렬화된다.")
|
|
||||||
@Test
|
|
||||||
void timeDeserialize() throws JsonProcessingException {
|
|
||||||
// given
|
|
||||||
String json = "\"12:30\"";
|
|
||||||
|
|
||||||
// when
|
|
||||||
LocalTime actual = objectMapper.readValue(json, LocalTime.class);
|
|
||||||
|
|
||||||
// then
|
|
||||||
assertThat(actual).isEqualTo(LocalTime.of(12, 30));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -22,7 +22,7 @@ import roomescape.reservation.dto.request.ReservationTimeRequest;
|
|||||||
import roomescape.reservation.dto.response.ReservationTimeResponse;
|
import roomescape.reservation.dto.response.ReservationTimeResponse;
|
||||||
import roomescape.reservation.service.ReservationService;
|
import roomescape.reservation.service.ReservationService;
|
||||||
import roomescape.reservation.service.ReservationTimeService;
|
import roomescape.reservation.service.ReservationTimeService;
|
||||||
import roomescape.system.exception.RoomEscapeException;
|
import roomescape.common.exception.RoomescapeException;
|
||||||
import roomescape.theme.domain.Theme;
|
import roomescape.theme.domain.Theme;
|
||||||
import roomescape.theme.domain.repository.ThemeRepository;
|
import roomescape.theme.domain.repository.ThemeRepository;
|
||||||
import roomescape.theme.dto.ThemeRequest;
|
import roomescape.theme.dto.ThemeRequest;
|
||||||
@ -73,7 +73,7 @@ class ThemeServiceTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThatThrownBy(() -> themeService.findThemeById(notExistId))
|
assertThatThrownBy(() -> themeService.findThemeById(notExistId))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -128,7 +128,7 @@ class ThemeServiceTest {
|
|||||||
|
|
||||||
// then
|
// then
|
||||||
assertThatThrownBy(() -> themeService.addTheme(invalidRequest))
|
assertThatThrownBy(() -> themeService.addTheme(invalidRequest))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@ -159,6 +159,6 @@ class ThemeServiceTest {
|
|||||||
|
|
||||||
// when & then
|
// when & then
|
||||||
assertThatThrownBy(() -> themeService.removeThemeById(theme.getId()))
|
assertThatThrownBy(() -> themeService.removeThemeById(theme.getId()))
|
||||||
.isInstanceOf(RoomEscapeException.class);
|
.isInstanceOf(RoomescapeException.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
package roomescape.common
|
package roomescape.util
|
||||||
|
|
||||||
import roomescape.member.infrastructure.persistence.Member
|
import roomescape.member.infrastructure.persistence.Member
|
||||||
import roomescape.member.infrastructure.persistence.Role
|
import roomescape.member.infrastructure.persistence.Role
|
||||||
import roomescape.system.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
import roomescape.system.auth.web.LoginRequest
|
import roomescape.auth.web.LoginRequest
|
||||||
import java.util.concurrent.atomic.AtomicLong
|
import java.util.concurrent.atomic.AtomicLong
|
||||||
|
|
||||||
object MemberFixture {
|
object MemberFixture {
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.common
|
package roomescape.util
|
||||||
|
|
||||||
import io.kotest.core.config.AbstractProjectConfig
|
import io.kotest.core.config.AbstractProjectConfig
|
||||||
import io.kotest.extensions.spring.SpringExtension
|
import io.kotest.extensions.spring.SpringExtension
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.common
|
package roomescape.util
|
||||||
|
|
||||||
import com.ninjasquad.springmockk.MockkBean
|
import com.ninjasquad.springmockk.MockkBean
|
||||||
import io.kotest.core.spec.style.BehaviorSpec
|
import io.kotest.core.spec.style.BehaviorSpec
|
||||||
@ -14,9 +14,9 @@ import org.springframework.data.repository.findByIdOrNull
|
|||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import roomescape.member.infrastructure.persistence.Member
|
import roomescape.member.infrastructure.persistence.Member
|
||||||
import roomescape.member.infrastructure.persistence.MemberRepository
|
import roomescape.member.infrastructure.persistence.MemberRepository
|
||||||
import roomescape.system.auth.infrastructure.jwt.JwtHandler
|
import roomescape.auth.infrastructure.jwt.JwtHandler
|
||||||
import roomescape.system.exception.ErrorType
|
import roomescape.common.exception.ErrorType
|
||||||
import roomescape.system.exception.RoomEscapeException
|
import roomescape.common.exception.RoomescapeException
|
||||||
|
|
||||||
const val NOT_LOGGED_IN_USERID: Long = 0;
|
const val NOT_LOGGED_IN_USERID: Long = 0;
|
||||||
|
|
||||||
@ -84,7 +84,7 @@ class RoomescapeApiTest(
|
|||||||
jwtHandler.getMemberIdFromToken(any())
|
jwtHandler.getMemberIdFromToken(any())
|
||||||
} returns NOT_LOGGED_IN_USERID
|
} returns NOT_LOGGED_IN_USERID
|
||||||
|
|
||||||
every { memberRepository.existsById(NOT_LOGGED_IN_USERID) } throws RoomEscapeException(
|
every { memberRepository.existsById(NOT_LOGGED_IN_USERID) } throws RoomescapeException(
|
||||||
ErrorType.LOGIN_REQUIRED,
|
ErrorType.LOGIN_REQUIRED,
|
||||||
HttpStatus.FORBIDDEN
|
HttpStatus.FORBIDDEN
|
||||||
)
|
)
|
||||||
@ -1,4 +1,4 @@
|
|||||||
package roomescape.common
|
package roomescape.util
|
||||||
|
|
||||||
import org.springframework.test.context.TestPropertySource
|
import org.springframework.test.context.TestPropertySource
|
||||||
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
package roomescape.view.controller
|
package roomescape.view
|
||||||
|
|
||||||
import org.hamcrest.Matchers.containsString
|
import org.hamcrest.Matchers
|
||||||
import roomescape.common.RoomescapeApiTest
|
import roomescape.util.RoomescapeApiTest
|
||||||
|
|
||||||
class PageControllerTest() : RoomescapeApiTest() {
|
class PageControllerTest() : RoomescapeApiTest() {
|
||||||
|
|
||||||
@ -54,7 +54,7 @@ class PageControllerTest() : RoomescapeApiTest() {
|
|||||||
then("로그인 페이지로 이동한다.") {
|
then("로그인 페이지로 이동한다.") {
|
||||||
runGetTest(it) {
|
runGetTest(it) {
|
||||||
statusCode(200)
|
statusCode(200)
|
||||||
body(containsString("<title>Login</title>"))
|
body(Matchers.containsString("<title>Login</title>"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -86,7 +86,7 @@ class PageControllerTest() : RoomescapeApiTest() {
|
|||||||
|
|
||||||
runGetTest(it) {
|
runGetTest(it) {
|
||||||
statusCode(200)
|
statusCode(200)
|
||||||
body(containsString("<title>Login</title>"))
|
body(Matchers.containsString("<title>Login</title>"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user