generated from pricelees/issue-pr-template
refactor: 테마 반환 DTO 이름 수정 및 테스트 추가
This commit is contained in:
parent
fc3c6e42b0
commit
ed618e1699
@ -24,17 +24,26 @@ class ThemeService(
|
|||||||
private val themeValidator: ThemeValidator
|
private val themeValidator: ThemeValidator
|
||||||
) {
|
) {
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun findThemesByIds(request: ThemeListRetrieveRequest): ThemeRetrieveListResponse {
|
fun findThemesByIds(request: ThemeListRetrieveRequest): ThemeSummaryListResponse {
|
||||||
log.info { "[ThemeService.findThemesByIds] 예약 페이지에서의 테마 목록 조회 시작: themeIds=${request.themeIds}" }
|
log.info { "[ThemeService.findThemesByIds] 예약 페이지에서의 테마 목록 조회 시작: themeIds=${request.themeIds}" }
|
||||||
|
val result: MutableList<ThemeEntity> = mutableListOf()
|
||||||
|
|
||||||
return request.themeIds
|
for (id in request.themeIds) {
|
||||||
.map { findOrThrow(it) }
|
val theme: ThemeEntity? = themeRepository.findByIdOrNull(id)
|
||||||
.toRetrieveListResponse()
|
if (theme == null) {
|
||||||
.also { log.info { "[ThemeService.findThemesByIds] ${it.themes.size}개 테마 조회 완료" } }
|
log.warn { "[ThemeService.findThemesByIds] id=${id} 인 테마 조회 실패" }
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
result.add(theme)
|
||||||
|
}
|
||||||
|
|
||||||
|
return result.toRetrieveListResponse().also {
|
||||||
|
log.info { "[ThemeService.findThemesByIds] ${it.themes.size} / ${request.themeIds.size} 개 테마 조회 완료" }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun findThemesForReservation(): ThemeRetrieveListResponse {
|
fun findThemesForReservation(): ThemeSummaryListResponse {
|
||||||
log.info { "[ThemeService.findThemesForReservation] 예약 페이지에서의 테마 목록 조회 시작" }
|
log.info { "[ThemeService.findThemesForReservation] 예약 페이지에서의 테마 목록 조회 시작" }
|
||||||
|
|
||||||
return themeRepository.findOpenedThemes()
|
return themeRepository.findOpenedThemes()
|
||||||
@ -65,10 +74,10 @@ class ThemeService(
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Transactional(readOnly = true)
|
@Transactional(readOnly = true)
|
||||||
fun findById(id: Long): ThemeRetrieveResponseV2 {
|
fun findSummaryById(id: Long): ThemeSummaryResponse {
|
||||||
log.info { "[ThemeService.findById] 테마 조회 시작: id=$id" }
|
log.info { "[ThemeService.findById] 테마 조회 시작: id=$id" }
|
||||||
|
|
||||||
return findOrThrow(id).toRetrieveResponse()
|
return findOrThrow(id).toSummaryResponse()
|
||||||
.also { log.info { "[ThemeService.findById] 테마 조회 완료: id=$id" } }
|
.also { log.info { "[ThemeService.findById] 테마 조회 완료: id=$id" } }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -17,7 +17,7 @@ import roomescape.theme.web.ThemeCreateRequest
|
|||||||
import roomescape.theme.web.ThemeCreateResponseV2
|
import roomescape.theme.web.ThemeCreateResponseV2
|
||||||
import roomescape.theme.web.ThemeListRetrieveRequest
|
import roomescape.theme.web.ThemeListRetrieveRequest
|
||||||
import roomescape.theme.web.ThemeUpdateRequest
|
import roomescape.theme.web.ThemeUpdateRequest
|
||||||
import roomescape.theme.web.ThemeRetrieveListResponse
|
import roomescape.theme.web.ThemeSummaryListResponse
|
||||||
|
|
||||||
@Tag(name = "5. 관리자 테마 API", description = "관리자 페이지에서 테마를 조회 / 추가 / 삭제할 때 사용합니다.")
|
@Tag(name = "5. 관리자 테마 API", description = "관리자 페이지에서 테마를 조회 / 추가 / 삭제할 때 사용합니다.")
|
||||||
interface ThemeAPIV2 {
|
interface ThemeAPIV2 {
|
||||||
@ -53,10 +53,10 @@ interface ThemeAPIV2 {
|
|||||||
@LoginRequired
|
@LoginRequired
|
||||||
@Operation(summary = "예약 페이지에서 모든 테마 조회", description = "모든 테마를 조회합니다.", tags = ["로그인이 필요한 API"])
|
@Operation(summary = "예약 페이지에서 모든 테마 조회", description = "모든 테마를 조회합니다.", tags = ["로그인이 필요한 API"])
|
||||||
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
||||||
fun findUserThemes(): ResponseEntity<CommonApiResponse<ThemeRetrieveListResponse>>
|
fun findUserThemes(): ResponseEntity<CommonApiResponse<ThemeSummaryListResponse>>
|
||||||
|
|
||||||
@LoginRequired
|
@LoginRequired
|
||||||
@Operation(summary = "예약 페이지에서 입력한 날짜에 가능한 테마 조회", description = "입력한 날짜에 가능한 테마를 조회합니다.", tags = ["로그인이 필요한 API"])
|
@Operation(summary = "예약 페이지에서 입력한 날짜에 가능한 테마 조회", description = "입력한 날짜에 가능한 테마를 조회합니다.", tags = ["로그인이 필요한 API"])
|
||||||
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
|
||||||
fun findThemesByIds(request: ThemeListRetrieveRequest): ResponseEntity<CommonApiResponse<ThemeRetrieveListResponse>>
|
fun findThemesByIds(request: ThemeListRetrieveRequest): ResponseEntity<CommonApiResponse<ThemeSummaryListResponse>>
|
||||||
}
|
}
|
||||||
|
|||||||
@ -15,14 +15,14 @@ class ThemeController(
|
|||||||
@PostMapping("/themes/retrieve")
|
@PostMapping("/themes/retrieve")
|
||||||
override fun findThemesByIds(
|
override fun findThemesByIds(
|
||||||
@RequestBody request: ThemeListRetrieveRequest
|
@RequestBody request: ThemeListRetrieveRequest
|
||||||
): ResponseEntity<CommonApiResponse<ThemeRetrieveListResponse>> {
|
): ResponseEntity<CommonApiResponse<ThemeSummaryListResponse>> {
|
||||||
val response = themeService.findThemesByIds(request)
|
val response = themeService.findThemesByIds(request)
|
||||||
|
|
||||||
return ResponseEntity.ok(CommonApiResponse(response))
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
}
|
}
|
||||||
|
|
||||||
@GetMapping("/v2/themes")
|
@GetMapping("/v2/themes")
|
||||||
override fun findUserThemes(): ResponseEntity<CommonApiResponse<ThemeRetrieveListResponse>> {
|
override fun findUserThemes(): ResponseEntity<CommonApiResponse<ThemeSummaryListResponse>> {
|
||||||
val response = themeService.findThemesForReservation()
|
val response = themeService.findThemesForReservation()
|
||||||
|
|
||||||
return ResponseEntity.ok(CommonApiResponse(response))
|
return ResponseEntity.ok(CommonApiResponse(response))
|
||||||
|
|||||||
@ -132,7 +132,7 @@ data class ThemeListRetrieveRequest(
|
|||||||
val themeIds: List<Long>
|
val themeIds: List<Long>
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ThemeRetrieveResponseV2(
|
data class ThemeSummaryResponse(
|
||||||
val id: Long,
|
val id: Long,
|
||||||
val name: String,
|
val name: String,
|
||||||
val thumbnailUrl: String,
|
val thumbnailUrl: String,
|
||||||
@ -146,7 +146,7 @@ data class ThemeRetrieveResponseV2(
|
|||||||
val expectedMinutesTo: Short
|
val expectedMinutesTo: Short
|
||||||
)
|
)
|
||||||
|
|
||||||
fun ThemeEntity.toRetrieveResponse() = ThemeRetrieveResponseV2(
|
fun ThemeEntity.toSummaryResponse() = ThemeSummaryResponse(
|
||||||
id = this.id,
|
id = this.id,
|
||||||
name = this.name,
|
name = this.name,
|
||||||
thumbnailUrl = this.thumbnailUrl,
|
thumbnailUrl = this.thumbnailUrl,
|
||||||
@ -160,10 +160,10 @@ fun ThemeEntity.toRetrieveResponse() = ThemeRetrieveResponseV2(
|
|||||||
expectedMinutesTo = this.expectedMinutesTo
|
expectedMinutesTo = this.expectedMinutesTo
|
||||||
)
|
)
|
||||||
|
|
||||||
data class ThemeRetrieveListResponse(
|
data class ThemeSummaryListResponse(
|
||||||
val themes: List<ThemeRetrieveResponseV2>
|
val themes: List<ThemeSummaryResponse>
|
||||||
)
|
)
|
||||||
|
|
||||||
fun List<ThemeEntity>.toRetrieveListResponse() = ThemeRetrieveListResponse(
|
fun List<ThemeEntity>.toRetrieveListResponse() = ThemeSummaryListResponse(
|
||||||
themes = this.map { it.toRetrieveResponse() }
|
themes = this.map { it.toSummaryResponse() }
|
||||||
)
|
)
|
||||||
|
|||||||
@ -4,15 +4,11 @@ import io.kotest.matchers.date.shouldBeAfter
|
|||||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||||
import io.kotest.matchers.shouldBe
|
import io.kotest.matchers.shouldBe
|
||||||
import io.kotest.matchers.shouldNotBe
|
import io.kotest.matchers.shouldNotBe
|
||||||
import io.restassured.module.kotlin.extensions.Extract
|
|
||||||
import io.restassured.module.kotlin.extensions.Given
|
|
||||||
import io.restassured.module.kotlin.extensions.When
|
|
||||||
import io.restassured.response.ValidatableResponse
|
import io.restassured.response.ValidatableResponse
|
||||||
import org.hamcrest.CoreMatchers.equalTo
|
import org.hamcrest.CoreMatchers.equalTo
|
||||||
import org.hamcrest.CoreMatchers.notNullValue
|
import org.hamcrest.CoreMatchers.notNullValue
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.http.HttpStatus
|
import org.springframework.http.HttpStatus
|
||||||
import org.springframework.http.MediaType
|
|
||||||
import roomescape.auth.exception.AuthErrorCode
|
import roomescape.auth.exception.AuthErrorCode
|
||||||
import roomescape.member.infrastructure.persistence.Role
|
import roomescape.member.infrastructure.persistence.Role
|
||||||
import roomescape.theme.business.MIN_DURATION
|
import roomescape.theme.business.MIN_DURATION
|
||||||
@ -21,9 +17,10 @@ import roomescape.theme.business.MIN_PRICE
|
|||||||
import roomescape.theme.exception.ThemeErrorCode
|
import roomescape.theme.exception.ThemeErrorCode
|
||||||
import roomescape.theme.infrastructure.persistence.ThemeEntity
|
import roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||||
import roomescape.theme.infrastructure.persistence.ThemeRepository
|
import roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||||
import roomescape.theme.web.ThemeCreateRequest
|
import roomescape.theme.web.ThemeListRetrieveRequest
|
||||||
import roomescape.theme.web.ThemeUpdateRequest
|
import roomescape.theme.web.ThemeUpdateRequest
|
||||||
import roomescape.util.FunSpecSpringbootTest
|
import roomescape.util.FunSpecSpringbootTest
|
||||||
|
import roomescape.util.INVALID_PK
|
||||||
import roomescape.util.ThemeFixture.createRequest
|
import roomescape.util.ThemeFixture.createRequest
|
||||||
import roomescape.util.assertProperties
|
import roomescape.util.assertProperties
|
||||||
import roomescape.util.runTest
|
import roomescape.util.runTest
|
||||||
@ -105,10 +102,15 @@ class ThemeApiTest(
|
|||||||
|
|
||||||
context("일반 회원도 접근할 수 있다.") {
|
context("일반 회원도 접근할 수 있다.") {
|
||||||
test("테마 조회: GET /v2/themes") {
|
test("테마 조회: GET /v2/themes") {
|
||||||
createDummyTheme(createRequest.copy(name = "test123", isOpen = true))
|
val token = loginUtil.loginAsUser()
|
||||||
|
|
||||||
|
dummyInitializer.createTheme(
|
||||||
|
adminToken = loginUtil.loginAsAdmin(),
|
||||||
|
request = createRequest.copy(name = "test123", isOpen = true)
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = loginUtil.loginAsUser(),
|
token = token,
|
||||||
on = {
|
on = {
|
||||||
get("/v2/themes")
|
get("/v2/themes")
|
||||||
},
|
},
|
||||||
@ -158,7 +160,10 @@ class ThemeApiTest(
|
|||||||
|
|
||||||
test("이미 동일한 이름의 테마가 있으면 실패한다.") {
|
test("이미 동일한 이름의 테마가 있으면 실패한다.") {
|
||||||
val commonName = "test123"
|
val commonName = "test123"
|
||||||
createDummyTheme(createRequest.copy(name = commonName))
|
dummyInitializer.createTheme(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest.copy(name = commonName)
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = token,
|
token = token,
|
||||||
@ -329,15 +334,77 @@ class ThemeApiTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
context("모든 테마를 조회한다.") {
|
context("입력된 모든 ID에 대한 테마를 조회한다.") {
|
||||||
|
val themeIds = mutableListOf<Long>()
|
||||||
|
|
||||||
beforeTest {
|
beforeTest {
|
||||||
createDummyTheme(createRequest.copy(name = "open", isOpen = true))
|
for (i in 1..3) {
|
||||||
createDummyTheme(createRequest.copy(name = "close", isOpen = false))
|
dummyInitializer.createTheme(
|
||||||
|
adminToken = loginUtil.loginAsAdmin(),
|
||||||
|
request = createRequest.copy(name = "test$i")
|
||||||
|
).also {
|
||||||
|
themeIds.add(it.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
afterTest {
|
||||||
|
themeIds.clear()
|
||||||
|
}
|
||||||
|
|
||||||
|
test("정상 응답") {
|
||||||
|
runTest(
|
||||||
|
token = loginUtil.loginAsUser(),
|
||||||
|
using = {
|
||||||
|
body(ThemeListRetrieveRequest(themeIds))
|
||||||
|
},
|
||||||
|
on = {
|
||||||
|
post("/themes/retrieve")
|
||||||
|
},
|
||||||
|
expect = {
|
||||||
|
statusCode(HttpStatus.OK.value())
|
||||||
|
body("data.themes.size()", equalTo(3))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
test("없는 테마가 있으면 생략한다.") {
|
||||||
|
themeIds.add(INVALID_PK)
|
||||||
|
|
||||||
|
runTest(
|
||||||
|
token = loginUtil.loginAsUser(),
|
||||||
|
using = {
|
||||||
|
body(ThemeListRetrieveRequest(themeIds))
|
||||||
|
},
|
||||||
|
on = {
|
||||||
|
post("/themes/retrieve")
|
||||||
|
},
|
||||||
|
expect = {
|
||||||
|
statusCode(HttpStatus.OK.value())
|
||||||
|
body("data.themes.size()", equalTo(3))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
context("모든 테마를 조회한다.") {
|
||||||
|
lateinit var token: String
|
||||||
|
|
||||||
|
beforeTest {
|
||||||
|
token = loginUtil.loginAsAdmin()
|
||||||
|
dummyInitializer.createTheme(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest.copy(name = "open", isOpen = true)
|
||||||
|
)
|
||||||
|
dummyInitializer.createTheme(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest.copy(name = "close", isOpen = false)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
test("관리자 페이지에서는 비공개 테마까지 포함하여 간단한 정보만 조회된다.") {
|
test("관리자 페이지에서는 비공개 테마까지 포함하여 간단한 정보만 조회된다.") {
|
||||||
runTest(
|
runTest(
|
||||||
token = loginUtil.loginAsAdmin(),
|
token = token,
|
||||||
on = {
|
on = {
|
||||||
get("/admin/themes")
|
get("/admin/themes")
|
||||||
},
|
},
|
||||||
@ -375,10 +442,14 @@ class ThemeApiTest(
|
|||||||
|
|
||||||
context("관리자 페이지에서 특정 테마의 상세 정보를 조회한다.") {
|
context("관리자 페이지에서 특정 테마의 상세 정보를 조회한다.") {
|
||||||
test("정상 응답") {
|
test("정상 응답") {
|
||||||
val createdTheme: ThemeEntity = createDummyTheme(createRequest)
|
val token = loginUtil.loginAsAdmin()
|
||||||
|
val createdTheme = dummyInitializer.createTheme(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = loginUtil.loginAsAdmin(),
|
token = token,
|
||||||
on = {
|
on = {
|
||||||
get("/admin/themes/${createdTheme.id}")
|
get("/admin/themes/${createdTheme.id}")
|
||||||
},
|
},
|
||||||
@ -413,10 +484,14 @@ class ThemeApiTest(
|
|||||||
|
|
||||||
context("테마를 삭제한다.") {
|
context("테마를 삭제한다.") {
|
||||||
test("정상 삭제") {
|
test("정상 삭제") {
|
||||||
val createdTheme = createDummyTheme(createRequest)
|
val token = loginUtil.loginAsAdmin()
|
||||||
|
val createdTheme = dummyInitializer.createTheme(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest
|
||||||
|
)
|
||||||
|
|
||||||
runTest(
|
runTest(
|
||||||
token = loginUtil.loginAsAdmin(),
|
token = token,
|
||||||
on = {
|
on = {
|
||||||
delete("/admin/themes/${createdTheme.id}")
|
delete("/admin/themes/${createdTheme.id}")
|
||||||
},
|
},
|
||||||
@ -451,7 +526,10 @@ class ThemeApiTest(
|
|||||||
|
|
||||||
beforeTest {
|
beforeTest {
|
||||||
token = loginUtil.loginAsAdmin()
|
token = loginUtil.loginAsAdmin()
|
||||||
createdTheme = createDummyTheme(createRequest.copy(name = "theme-${Random.nextInt()}"))
|
createdTheme = dummyInitializer.createTheme(
|
||||||
|
adminToken = token,
|
||||||
|
request = createRequest.copy(name = "theme-${Random.nextInt()}")
|
||||||
|
)
|
||||||
apiPath = "/admin/themes/${createdTheme.id}"
|
apiPath = "/admin/themes/${createdTheme.id}"
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -669,19 +747,4 @@ class ThemeApiTest(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun createDummyTheme(request: ThemeCreateRequest): ThemeEntity {
|
|
||||||
val createdThemeId: Long = Given {
|
|
||||||
contentType(MediaType.APPLICATION_JSON_VALUE)
|
|
||||||
header("Authorization", "Bearer ${loginUtil.loginAsAdmin()}")
|
|
||||||
body(request)
|
|
||||||
} When {
|
|
||||||
post("/admin/themes")
|
|
||||||
} Extract {
|
|
||||||
path("data.id")
|
|
||||||
}
|
|
||||||
|
|
||||||
return themeRepository.findByIdOrNull(createdThemeId)
|
|
||||||
?: throw RuntimeException("unreachable line")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user