From 8205e83b4ae28467ede5559de8a09bf05b5bd259 Mon Sep 17 00:00:00 2001 From: pricelees Date: Mon, 15 Sep 2025 12:08:46 +0900 Subject: [PATCH] =?UTF-8?q?refactor:=20DTO=20=EB=AA=85=EB=AA=85=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/src/api/theme/themeAPI.ts | 2 +- .../roomescape/theme/business/ThemeService.kt | 6 +-- .../kotlin/roomescape/theme/docs/ThemeApi.kt | 4 +- .../theme/web/AdminThemeController.kt | 2 +- .../roomescape/theme/web/AdminThemeDto.kt | 36 ++++------------ .../kotlin/roomescape/theme/ThemeApiTest.kt | 41 ++++++++++--------- 6 files changed, 38 insertions(+), 53 deletions(-) diff --git a/frontend/src/api/theme/themeAPI.ts b/frontend/src/api/theme/themeAPI.ts index 3db475d2..7282709c 100644 --- a/frontend/src/api/theme/themeAPI.ts +++ b/frontend/src/api/theme/themeAPI.ts @@ -34,5 +34,5 @@ export const fetchUserThemes = async (): Promise => { }; export const findThemesByIds = async (request: ThemeIdListResponse): Promise => { - return await apiClient.post('/themes/retrieve', request); + return await apiClient.post('/themes/batch', request); }; diff --git a/src/main/kotlin/roomescape/theme/business/ThemeService.kt b/src/main/kotlin/roomescape/theme/business/ThemeService.kt index e641a533..81f96d37 100644 --- a/src/main/kotlin/roomescape/theme/business/ThemeService.kt +++ b/src/main/kotlin/roomescape/theme/business/ThemeService.kt @@ -42,7 +42,7 @@ class ThemeService( } @Transactional(readOnly = true) - fun findThemesByIds(request: ThemeIdListResponse): ThemeInfoListResponse { + fun findThemesByIds(request: ThemeIdListRequest): ThemeInfoListResponse { log.info { "[ThemeService.findThemesByIds] 예약 페이지에서의 테마 목록 조회 시작: themeIds=${request.themeIds}" } val result: MutableList = mutableListOf() @@ -86,7 +86,7 @@ class ThemeService( } @Transactional - fun createTheme(request: ThemeCreateRequest): ThemeCreateResponseV2 { + fun createTheme(request: ThemeCreateRequest): ThemeCreateResponse { log.info { "[ThemeService.createTheme] 테마 생성 시작: name=${request.name}" } themeValidator.validateCanCreate(request) @@ -95,7 +95,7 @@ class ThemeService( request.toEntity(tsidFactory.next()) ) - return ThemeCreateResponseV2(theme.id).also { + return ThemeCreateResponse(theme.id).also { log.info { "[ThemeService.createTheme] 테마 생성 완료: id=${theme.id}, name=${theme.name}" } } } diff --git a/src/main/kotlin/roomescape/theme/docs/ThemeApi.kt b/src/main/kotlin/roomescape/theme/docs/ThemeApi.kt index 94d68e63..e0d8db6f 100644 --- a/src/main/kotlin/roomescape/theme/docs/ThemeApi.kt +++ b/src/main/kotlin/roomescape/theme/docs/ThemeApi.kt @@ -30,7 +30,7 @@ interface HQAdminThemeAPI { @AdminOnly(type = AdminType.HQ, privilege = Privilege.CREATE) @Operation(summary = "테마 추가", tags = ["관리자 로그인이 필요한 API"]) @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) - fun createTheme(@Valid @RequestBody themeCreateRequest: ThemeCreateRequest): ResponseEntity> + fun createTheme(@Valid @RequestBody themeCreateRequest: ThemeCreateRequest): ResponseEntity> @AdminOnly(type = AdminType.HQ, privilege = Privilege.DELETE) @Operation(summary = "테마 삭제", tags = ["관리자 로그인이 필요한 API"]) @@ -57,7 +57,7 @@ interface PublicThemeAPI { @Public @Operation(summary = "입력된 모든 ID에 대한 테마 조회") @ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true)) - fun findThemesByIds(request: ThemeIdListResponse): ResponseEntity> + fun findThemesByIds(request: ThemeIdListRequest): ResponseEntity> @Public @Operation(summary = "입력된 테마 ID에 대한 정보 조회") diff --git a/src/main/kotlin/roomescape/theme/web/AdminThemeController.kt b/src/main/kotlin/roomescape/theme/web/AdminThemeController.kt index 5554ac16..e0412600 100644 --- a/src/main/kotlin/roomescape/theme/web/AdminThemeController.kt +++ b/src/main/kotlin/roomescape/theme/web/AdminThemeController.kt @@ -27,7 +27,7 @@ class HQAdminThemeController( } @PostMapping("/admin/themes") - override fun createTheme(themeCreateRequest: ThemeCreateRequest): ResponseEntity> { + override fun createTheme(themeCreateRequest: ThemeCreateRequest): ResponseEntity> { val response = themeService.createTheme(themeCreateRequest) return ResponseEntity.created(URI.create("/admin/themes/${response.id}")) diff --git a/src/main/kotlin/roomescape/theme/web/AdminThemeDto.kt b/src/main/kotlin/roomescape/theme/web/AdminThemeDto.kt index 3306d22e..ef6d0cf2 100644 --- a/src/main/kotlin/roomescape/theme/web/AdminThemeDto.kt +++ b/src/main/kotlin/roomescape/theme/web/AdminThemeDto.kt @@ -31,7 +31,7 @@ data class ThemeCreateRequest( val isActive: Boolean ) -data class ThemeCreateResponseV2( +data class ThemeCreateResponse( val id: Long ) @@ -145,38 +145,20 @@ fun ThemeEntity.toAdminThemeDetailResponse(createdBy: OperatorInfo, updatedBy: O // Store Admin DTO // ======================================== -data class ThemeInfoResponse( +data class SimpleActiveThemeResponse( val id: Long, - val name: String, - val thumbnailUrl: String, - val description: String, - val difficulty: Difficulty, - val price: Int, - val minParticipants: Short, - val maxParticipants: Short, - val availableMinutes: Short, - val expectedMinutesFrom: Short, - val expectedMinutesTo: Short + val name: String ) -fun ThemeEntity.toSummaryResponse() = ThemeInfoResponse( +fun ThemeEntity.toSimpleActiveThemeResponse() = SimpleActiveThemeResponse( id = this.id, - name = this.name, - thumbnailUrl = this.thumbnailUrl, - description = this.description, - difficulty = this.difficulty, - price = this.price, - minParticipants = this.minParticipants, - maxParticipants = this.maxParticipants, - availableMinutes = this.availableMinutes, - expectedMinutesFrom = this.expectedMinutesFrom, - expectedMinutesTo = this.expectedMinutesTo + name = this.name ) -data class ThemeInfoListResponse( - val themes: List +data class SimpleActiveThemeListResponse( + val themes: List ) -fun List.toListResponse() = ThemeInfoListResponse( - themes = this.map { it.toSummaryResponse() } +fun List.toSimpleActiveThemeResponse() = SimpleActiveThemeListResponse( + themes = this.map { it.toSimpleActiveThemeResponse() } ) diff --git a/src/test/kotlin/roomescape/theme/ThemeApiTest.kt b/src/test/kotlin/roomescape/theme/ThemeApiTest.kt index e07aa933..4007516a 100644 --- a/src/test/kotlin/roomescape/theme/ThemeApiTest.kt +++ b/src/test/kotlin/roomescape/theme/ThemeApiTest.kt @@ -19,7 +19,7 @@ import roomescape.theme.business.MIN_PRICE import roomescape.theme.exception.ThemeErrorCode import roomescape.theme.infrastructure.persistence.ThemeEntity import roomescape.theme.infrastructure.persistence.ThemeRepository -import roomescape.theme.web.ThemeIdListResponse +import roomescape.theme.web.ThemeIdListRequest import roomescape.theme.web.ThemeUpdateRequest import roomescape.supports.* import roomescape.supports.ThemeFixture.createRequest @@ -311,10 +311,10 @@ class ThemeApiTest( runTest( token = authUtil.defaultUserLogin(), using = { - body(ThemeIdListResponse(themeIds)) + body(ThemeIdListRequest(themeIds)) }, on = { - post("/themes/retrieve") + post("/themes/batch") }, expect = { statusCode(HttpStatus.OK.value()) @@ -337,10 +337,10 @@ class ThemeApiTest( runTest( token = authUtil.defaultUserLogin(), using = { - body(ThemeIdListResponse(themeIds)) + body(ThemeIdListRequest(themeIds)) }, on = { - post("/themes/retrieve") + post("/themes/batch") }, expect = { statusCode(HttpStatus.OK.value()) @@ -411,35 +411,38 @@ class ThemeApiTest( } } - context("예약 페이지에서 테마를 조회한다.") { - test("공개된 테마의 전체 정보가 조회된다.") { - val token = authUtil.defaultHqAdminLogin() - listOf( - createRequest.copy(name = "open", isOpen = true), - createRequest.copy(name = "close", isOpen = false) - ).forEach { - dummyInitializer.createTheme(token, it) - } + context("ID로 테마 정보를 조회한다.") { + test("성공 응답") { + val createdTheme: ThemeEntity = dummyInitializer.createTheme( + adminToken = authUtil.defaultHqAdminLogin(), + request = createRequest + ) runTest( - token = authUtil.defaultUserLogin(), on = { - get("/themes") + get("/themes/${createdTheme.id}") }, expect = { - body("data.themes.size()", equalTo(1)) - body("data.themes[0].name", equalTo("open")) + body("data.id", equalTo(createdTheme.id)) + body("data.name", equalTo(createdTheme.name)) assertProperties( props = setOf( "id", "name", "thumbnailUrl", "description", "difficulty", "price", "minParticipants", "maxParticipants", "availableMinutes", "expectedMinutesFrom", "expectedMinutesTo" ), - propsNameIfList = "themes", ) } ) } + + test("테마가 없으면 실패한다.") { + runExceptionTest( + method = HttpMethod.GET, + endpoint = "/themes/$INVALID_PK", + expectedErrorCode = ThemeErrorCode.THEME_NOT_FOUND + ) + } } context("관리자 페이지에서 특정 테마의 상세 정보를 조회한다.") {