generated from pricelees/issue-pr-template
refactor: theme 내 DTO, Mapper 패키지 분리
This commit is contained in:
parent
038381424c
commit
c4604ccdde
@ -7,7 +7,7 @@ import com.sangdol.roomescape.reservation.exception.ReservationException
|
||||
import com.sangdol.roomescape.reservation.web.PendingReservationCreateRequest
|
||||
import com.sangdol.roomescape.schedule.infrastructure.persistence.ScheduleStatus
|
||||
import com.sangdol.roomescape.schedule.web.ScheduleSummaryResponse
|
||||
import com.sangdol.roomescape.theme.web.ThemeInfoResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoResponse
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@ -0,0 +1,136 @@
|
||||
package com.sangdol.roomescape.theme.business
|
||||
|
||||
import com.sangdol.common.persistence.IDGenerator
|
||||
import com.sangdol.roomescape.admin.business.AdminService
|
||||
import com.sangdol.roomescape.common.types.AuditingInfo
|
||||
import com.sangdol.roomescape.theme.dto.ThemeDetailResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeSummaryListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeNameListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.theme.dto.ThemeCreateResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeUpdateRequest
|
||||
import com.sangdol.roomescape.theme.exception.ThemeErrorCode
|
||||
import com.sangdol.roomescape.theme.exception.ThemeException
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||
import com.sangdol.roomescape.theme.mapper.toDetailResponse
|
||||
import com.sangdol.roomescape.theme.mapper.toSummaryListResponse
|
||||
import com.sangdol.roomescape.theme.mapper.toEntity
|
||||
import com.sangdol.roomescape.theme.mapper.toNameListResponse
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
@Service
|
||||
class AdminThemeService(
|
||||
private val themeRepository: ThemeRepository,
|
||||
private val themeValidator: ThemeValidator,
|
||||
private val idGenerator: IDGenerator,
|
||||
private val adminService: AdminService
|
||||
) {
|
||||
@Transactional(readOnly = true)
|
||||
fun findThemeSummaries(): ThemeSummaryListResponse {
|
||||
log.info { "[findAdminThemes] 관리자 페이지에서의 테마 목록 조회 시작" }
|
||||
|
||||
return themeRepository.findAll()
|
||||
.toSummaryListResponse()
|
||||
.also { log.info { "[findAdminThemes] ${it.themes.size}개 테마 조회 완료" } }
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun findThemeDetail(id: Long): ThemeDetailResponse {
|
||||
log.info { "[findAdminThemeDetail] 관리자 페이지에서의 테마 상세 정보 조회 시작: id=${id}" }
|
||||
|
||||
val theme: ThemeEntity = findOrThrow(id)
|
||||
|
||||
val createdBy = adminService.findOperatorOrUnknown(theme.createdBy)
|
||||
val updatedBy = adminService.findOperatorOrUnknown(theme.updatedBy)
|
||||
val audit = AuditingInfo(theme.createdAt, createdBy, theme.updatedAt, updatedBy)
|
||||
|
||||
return theme.toDetailResponse(audit)
|
||||
.also { log.info { "[findAdminThemeDetail] 테마 상세 조회 완료: id=$id, name=${theme.name}" } }
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun findActiveThemes(): ThemeNameListResponse {
|
||||
log.info { "[findActiveThemes] open 상태인 모든 테마 조회 시작" }
|
||||
|
||||
return themeRepository.findActiveThemes()
|
||||
.toNameListResponse()
|
||||
.also {
|
||||
log.info { "[findActiveThemes] ${it.themes.size}개 테마 조회 완료" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
fun createTheme(request: ThemeCreateRequest): ThemeCreateResponse {
|
||||
log.info { "[createTheme] 테마 생성 시작: name=${request.name}" }
|
||||
|
||||
themeValidator.validateCanCreate(request)
|
||||
|
||||
val theme: ThemeEntity = request.toEntity(id = idGenerator.create())
|
||||
.also { themeRepository.save(it) }
|
||||
|
||||
return ThemeCreateResponse(theme.id).also {
|
||||
log.info { "[createTheme] 테마 생성 완료: id=${theme.id}, name=${theme.name}" }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Transactional
|
||||
fun deleteTheme(id: Long) {
|
||||
log.info { "[deleteTheme] 테마 삭제 시작: id=${id}" }
|
||||
|
||||
val theme: ThemeEntity = findOrThrow(id)
|
||||
|
||||
themeRepository.delete(theme).also {
|
||||
log.info { "[deleteTheme] 테마 삭제 완료: id=$id, name=${theme.name}" }
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun updateTheme(id: Long, request: ThemeUpdateRequest) {
|
||||
log.info { "[updateTheme] 테마 수정 시작: id=${id}, request=${request}" }
|
||||
|
||||
if (request.isAllParamsNull()) {
|
||||
log.info { "[updateTheme] 테마 변경 사항 없음: id=${id}" }
|
||||
return
|
||||
}
|
||||
|
||||
themeValidator.validateCanUpdate(request)
|
||||
|
||||
val theme: ThemeEntity = findOrThrow(id)
|
||||
|
||||
theme.modifyIfNotNull(
|
||||
request.name,
|
||||
request.description,
|
||||
request.thumbnailUrl,
|
||||
request.difficulty,
|
||||
request.price,
|
||||
request.minParticipants,
|
||||
request.maxParticipants,
|
||||
request.availableMinutes,
|
||||
request.expectedMinutesFrom,
|
||||
request.expectedMinutesTo,
|
||||
request.isActive,
|
||||
).also {
|
||||
log.info { "[updateTheme] 테마 수정 완료: id=$id, request=${request}" }
|
||||
}
|
||||
}
|
||||
|
||||
private fun findOrThrow(id: Long): ThemeEntity {
|
||||
log.info { "[findOrThrow] 테마 조회 시작: id=$id" }
|
||||
|
||||
return themeRepository.findByIdOrNull(id)
|
||||
?.also { log.info { "[findOrThrow] 테마 조회 완료: id=$id" } }
|
||||
?: run {
|
||||
log.warn { "[findOrThrow] 테마 조회 실패: id=$id" }
|
||||
throw ThemeException(ThemeErrorCode.THEME_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,11 +0,0 @@
|
||||
package com.sangdol.roomescape.theme.business
|
||||
|
||||
import java.time.DayOfWeek
|
||||
import java.time.LocalDate
|
||||
import java.time.temporal.TemporalAdjusters
|
||||
|
||||
object DateUtils {
|
||||
fun getSundayOfPreviousWeek(date: LocalDate): LocalDate = date
|
||||
.minusWeeks(1)
|
||||
.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))
|
||||
}
|
||||
@ -1,44 +1,38 @@
|
||||
package com.sangdol.roomescape.theme.business
|
||||
|
||||
import com.sangdol.common.persistence.IDGenerator
|
||||
import com.sangdol.common.utils.KoreaDate
|
||||
import com.sangdol.roomescape.admin.business.AdminService
|
||||
import com.sangdol.roomescape.common.types.AuditingInfo
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoResponse
|
||||
import com.sangdol.roomescape.theme.exception.ThemeErrorCode
|
||||
import com.sangdol.roomescape.theme.exception.ThemeException
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||
import com.sangdol.roomescape.theme.web.*
|
||||
import com.sangdol.roomescape.theme.mapper.toInfoResponse
|
||||
import com.sangdol.roomescape.theme.mapper.toListResponse
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import org.springframework.stereotype.Service
|
||||
import org.springframework.transaction.annotation.Transactional
|
||||
import java.time.DayOfWeek
|
||||
import java.time.LocalDate
|
||||
import java.time.temporal.TemporalAdjusters
|
||||
|
||||
private val log: KLogger = KotlinLogging.logger {}
|
||||
|
||||
/**
|
||||
* Structure:
|
||||
* - Public: 모두가 접근 가능한 메서드
|
||||
* - Store Admin: 매장 관리자가 사용하는 메서드
|
||||
* - HQ Admin: 본사 관리자가 사용하는 메서드
|
||||
* - Common: 공통 메서드
|
||||
*/
|
||||
@Service
|
||||
class ThemeService(
|
||||
private val themeRepository: ThemeRepository,
|
||||
private val themeValidator: ThemeValidator,
|
||||
private val idGenerator: IDGenerator,
|
||||
private val adminService: AdminService
|
||||
private val themeRepository: ThemeRepository
|
||||
) {
|
||||
// ========================================
|
||||
// Public (인증 불필요)
|
||||
// ========================================
|
||||
@Transactional(readOnly = true)
|
||||
fun findInfoById(id: Long): ThemeInfoResponse {
|
||||
log.info { "[findInfoById] 테마 조회 시작: id=$id" }
|
||||
|
||||
return findOrThrow(id).toInfoResponse()
|
||||
val theme = themeRepository.findByIdOrNull(id) ?: run {
|
||||
log.warn { "[updateTheme] 테마 조회 실패: id=$id" }
|
||||
throw ThemeException(ThemeErrorCode.THEME_NOT_FOUND)
|
||||
}
|
||||
|
||||
return theme.toInfoResponse()
|
||||
.also { log.info { "[findInfoById] 테마 조회 완료: id=$id" } }
|
||||
}
|
||||
|
||||
@ -54,115 +48,11 @@ class ThemeService(
|
||||
.also {
|
||||
log.info { "[findMostReservedThemeLastWeek] ${it.themes.size} / $count 개의 인기 테마 조회 완료" }
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// HQ Admin (본사)
|
||||
// ========================================
|
||||
@Transactional(readOnly = true)
|
||||
fun findAdminThemes(): AdminThemeSummaryListResponse {
|
||||
log.info { "[findAdminThemes] 관리자 페이지에서의 테마 목록 조회 시작" }
|
||||
|
||||
return themeRepository.findAll()
|
||||
.toAdminThemeSummaryListResponse()
|
||||
.also { log.info { "[findAdminThemes] ${it.themes.size}개 테마 조회 완료" } }
|
||||
}
|
||||
|
||||
@Transactional(readOnly = true)
|
||||
fun findAdminThemeDetail(id: Long): AdminThemeDetailResponse {
|
||||
log.info { "[findAdminThemeDetail] 관리자 페이지에서의 테마 상세 정보 조회 시작: id=${id}" }
|
||||
|
||||
val theme: ThemeEntity = findOrThrow(id)
|
||||
|
||||
val createdBy = adminService.findOperatorOrUnknown(theme.createdBy)
|
||||
val updatedBy = adminService.findOperatorOrUnknown(theme.updatedBy)
|
||||
val audit = AuditingInfo(theme.createdAt, createdBy, theme.updatedAt, updatedBy)
|
||||
|
||||
return theme.toAdminThemeDetailResponse(audit)
|
||||
.also { log.info { "[findAdminThemeDetail] 테마 상세 조회 완료: id=$id, name=${theme.name}" } }
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun createTheme(request: ThemeCreateRequest): ThemeCreateResponse {
|
||||
log.info { "[createTheme] 테마 생성 시작: name=${request.name}" }
|
||||
|
||||
themeValidator.validateCanCreate(request)
|
||||
|
||||
val theme: ThemeEntity = request.toEntity(id = idGenerator.create())
|
||||
.also { themeRepository.save(it) }
|
||||
|
||||
return ThemeCreateResponse(theme.id).also {
|
||||
log.info { "[createTheme] 테마 생성 완료: id=${theme.id}, name=${theme.name}" }
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun deleteTheme(id: Long) {
|
||||
log.info { "[deleteTheme] 테마 삭제 시작: id=${id}" }
|
||||
|
||||
val theme: ThemeEntity = findOrThrow(id)
|
||||
|
||||
themeRepository.delete(theme).also {
|
||||
log.info { "[deleteTheme] 테마 삭제 완료: id=$id, name=${theme.name}" }
|
||||
}
|
||||
}
|
||||
|
||||
@Transactional
|
||||
fun updateTheme(id: Long, request: ThemeUpdateRequest) {
|
||||
log.info { "[updateTheme] 테마 수정 시작: id=${id}, request=${request}" }
|
||||
|
||||
if (request.isAllParamsNull()) {
|
||||
log.info { "[updateTheme] 테마 변경 사항 없음: id=${id}" }
|
||||
return
|
||||
}
|
||||
|
||||
themeValidator.validateCanUpdate(request)
|
||||
|
||||
val theme: ThemeEntity = findOrThrow(id)
|
||||
|
||||
theme.modifyIfNotNull(
|
||||
request.name,
|
||||
request.description,
|
||||
request.thumbnailUrl,
|
||||
request.difficulty,
|
||||
request.price,
|
||||
request.minParticipants,
|
||||
request.maxParticipants,
|
||||
request.availableMinutes,
|
||||
request.expectedMinutesFrom,
|
||||
request.expectedMinutesTo,
|
||||
request.isActive,
|
||||
).also {
|
||||
log.info { "[updateTheme] 테마 수정 완료: id=$id, request=${request}" }
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Store Admin (매장)
|
||||
// ========================================
|
||||
@Transactional(readOnly = true)
|
||||
fun findActiveThemes(): SimpleActiveThemeListResponse {
|
||||
log.info { "[findActiveThemes] open 상태인 모든 테마 조회 시작" }
|
||||
|
||||
return themeRepository.findActiveThemes()
|
||||
.toSimpleActiveThemeResponse()
|
||||
.also {
|
||||
log.info { "[findActiveThemes] ${it.themes.size}개 테마 조회 완료" }
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Common (공통 메서드)
|
||||
// ========================================
|
||||
private fun findOrThrow(id: Long): ThemeEntity {
|
||||
log.info { "[findOrThrow] 테마 조회 시작: id=$id" }
|
||||
|
||||
return themeRepository.findByIdOrNull(id)
|
||||
?.also { log.info { "[findOrThrow] 테마 조회 완료: id=$id" } }
|
||||
?: run {
|
||||
log.warn { "[updateTheme] 테마 조회 실패: id=$id" }
|
||||
throw ThemeException(ThemeErrorCode.THEME_NOT_FOUND)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
object DateUtils {
|
||||
fun getSundayOfPreviousWeek(date: LocalDate): LocalDate = date
|
||||
.minusWeeks(1)
|
||||
.with(TemporalAdjusters.previousOrSame(DayOfWeek.SUNDAY))
|
||||
}
|
||||
|
||||
@ -3,8 +3,8 @@ package com.sangdol.roomescape.theme.business
|
||||
import com.sangdol.roomescape.theme.exception.ThemeErrorCode
|
||||
import com.sangdol.roomescape.theme.exception.ThemeException
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||
import com.sangdol.roomescape.theme.web.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.theme.web.ThemeUpdateRequest
|
||||
import com.sangdol.roomescape.theme.dto.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.theme.dto.ThemeUpdateRequest
|
||||
import io.github.oshai.kotlinlogging.KLogger
|
||||
import io.github.oshai.kotlinlogging.KotlinLogging
|
||||
import org.springframework.stereotype.Component
|
||||
|
||||
@ -5,7 +5,14 @@ import com.sangdol.roomescape.admin.infrastructure.persistence.AdminType
|
||||
import com.sangdol.roomescape.admin.infrastructure.persistence.Privilege
|
||||
import com.sangdol.roomescape.auth.web.support.AdminOnly
|
||||
import com.sangdol.roomescape.auth.web.support.Public
|
||||
import com.sangdol.roomescape.theme.web.*
|
||||
import com.sangdol.roomescape.theme.dto.ThemeDetailResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeSummaryListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeNameListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.theme.dto.ThemeCreateResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeUpdateRequest
|
||||
import io.swagger.v3.oas.annotations.Operation
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponse
|
||||
import io.swagger.v3.oas.annotations.responses.ApiResponses
|
||||
@ -20,12 +27,12 @@ interface AdminThemeAPI {
|
||||
@AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_SUMMARY)
|
||||
@Operation(summary = "모든 테마 조회")
|
||||
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||
fun getAdminThemeSummaries(): ResponseEntity<CommonApiResponse<AdminThemeSummaryListResponse>>
|
||||
fun getAdminThemeSummaries(): ResponseEntity<CommonApiResponse<ThemeSummaryListResponse>>
|
||||
|
||||
@AdminOnly(type = AdminType.HQ, privilege = Privilege.READ_DETAIL)
|
||||
@Operation(summary = "테마 상세 조회")
|
||||
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||
fun findAdminThemeDetail(@PathVariable("id") id: Long): ResponseEntity<CommonApiResponse<AdminThemeDetailResponse>>
|
||||
fun findAdminThemeDetail(@PathVariable("id") id: Long): ResponseEntity<CommonApiResponse<ThemeDetailResponse>>
|
||||
|
||||
@AdminOnly(type = AdminType.HQ, privilege = Privilege.CREATE)
|
||||
@Operation(summary = "테마 추가")
|
||||
@ -48,7 +55,7 @@ interface AdminThemeAPI {
|
||||
@AdminOnly(privilege = Privilege.READ_SUMMARY)
|
||||
@Operation(summary = "현재 활성화 상태인 테마 ID + 이름 목록 조회")
|
||||
@ApiResponses(ApiResponse(responseCode = "200", useReturnTypeSchema = true))
|
||||
fun getActiveThemes(): ResponseEntity<CommonApiResponse<SimpleActiveThemeListResponse>>
|
||||
fun getActiveThemes(): ResponseEntity<CommonApiResponse<ThemeNameListResponse>>
|
||||
}
|
||||
|
||||
interface PublicThemeAPI {
|
||||
|
||||
@ -0,0 +1,31 @@
|
||||
package com.sangdol.roomescape.theme.dto
|
||||
|
||||
import com.sangdol.roomescape.common.types.AuditingInfo
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty
|
||||
|
||||
data class ThemeSummaryResponse(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val difficulty: Difficulty,
|
||||
val price: Int,
|
||||
val isActive: Boolean
|
||||
)
|
||||
|
||||
data class ThemeSummaryListResponse(
|
||||
val themes: List<ThemeSummaryResponse>
|
||||
)
|
||||
|
||||
data class ThemeDetailResponse(
|
||||
val theme: ThemeInfoResponse,
|
||||
val isActive: Boolean,
|
||||
val audit: AuditingInfo
|
||||
)
|
||||
|
||||
data class ThemeNameResponse(
|
||||
val id: Long,
|
||||
val name: String
|
||||
)
|
||||
|
||||
data class ThemeNameListResponse(
|
||||
val themes: List<ThemeNameResponse>
|
||||
)
|
||||
@ -0,0 +1,49 @@
|
||||
package com.sangdol.roomescape.theme.dto
|
||||
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty
|
||||
|
||||
data class ThemeCreateRequest(
|
||||
val name: String,
|
||||
val description: String,
|
||||
val thumbnailUrl: String,
|
||||
val difficulty: Difficulty,
|
||||
val price: Int,
|
||||
val minParticipants: Short,
|
||||
val maxParticipants: Short,
|
||||
val availableMinutes: Short,
|
||||
val expectedMinutesFrom: Short,
|
||||
val expectedMinutesTo: Short,
|
||||
val isActive: Boolean
|
||||
)
|
||||
|
||||
data class ThemeCreateResponse(
|
||||
val id: Long
|
||||
)
|
||||
|
||||
data class ThemeUpdateRequest(
|
||||
val name: String? = null,
|
||||
val description: String? = null,
|
||||
val thumbnailUrl: String? = null,
|
||||
val difficulty: Difficulty? = null,
|
||||
val price: Int? = null,
|
||||
val minParticipants: Short? = null,
|
||||
val maxParticipants: Short? = null,
|
||||
val availableMinutes: Short? = null,
|
||||
val expectedMinutesFrom: Short? = null,
|
||||
val expectedMinutesTo: Short? = null,
|
||||
val isActive: Boolean? = null,
|
||||
) {
|
||||
fun isAllParamsNull(): Boolean {
|
||||
return name == null &&
|
||||
description == null &&
|
||||
thumbnailUrl == null &&
|
||||
difficulty == null &&
|
||||
price == null &&
|
||||
minParticipants == null &&
|
||||
maxParticipants == null &&
|
||||
availableMinutes == null &&
|
||||
expectedMinutesFrom == null &&
|
||||
expectedMinutesTo == null &&
|
||||
isActive == null
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,19 @@
|
||||
package com.sangdol.roomescape.theme.dto
|
||||
|
||||
data class ThemeInfoResponse(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val thumbnailUrl: String,
|
||||
val description: String,
|
||||
val difficulty: String,
|
||||
val price: Int,
|
||||
val minParticipants: Short,
|
||||
val maxParticipants: Short,
|
||||
val availableMinutes: Short,
|
||||
val expectedMinutesFrom: Short,
|
||||
val expectedMinutesTo: Short
|
||||
)
|
||||
|
||||
data class ThemeInfoListResponse(
|
||||
val themes: List<ThemeInfoResponse>
|
||||
)
|
||||
@ -0,0 +1,48 @@
|
||||
package com.sangdol.roomescape.theme.mapper
|
||||
|
||||
import com.sangdol.roomescape.common.types.AuditingInfo
|
||||
import com.sangdol.roomescape.theme.dto.*
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
|
||||
fun ThemeCreateRequest.toEntity(id: Long) = ThemeEntity(
|
||||
id = id,
|
||||
name = this.name,
|
||||
description = this.description,
|
||||
thumbnailUrl = this.thumbnailUrl,
|
||||
difficulty = this.difficulty,
|
||||
price = this.price,
|
||||
minParticipants = this.minParticipants,
|
||||
maxParticipants = this.maxParticipants,
|
||||
availableMinutes = this.availableMinutes,
|
||||
expectedMinutesFrom = this.expectedMinutesFrom,
|
||||
expectedMinutesTo = this.expectedMinutesTo,
|
||||
isActive = this.isActive
|
||||
)
|
||||
|
||||
fun ThemeEntity.toSummaryResponse() = ThemeSummaryResponse(
|
||||
id = this.id,
|
||||
name = this.name,
|
||||
difficulty = this.difficulty,
|
||||
price = this.price,
|
||||
isActive = this.isActive
|
||||
)
|
||||
|
||||
fun ThemeEntity.toDetailResponse(audit: AuditingInfo) =
|
||||
ThemeDetailResponse(
|
||||
theme = this.toInfoResponse(),
|
||||
isActive = this.isActive,
|
||||
audit = audit
|
||||
)
|
||||
|
||||
fun ThemeEntity.toNameResponse() = ThemeNameResponse(
|
||||
id = this.id,
|
||||
name = this.name
|
||||
)
|
||||
|
||||
fun List<ThemeEntity>.toSummaryListResponse() = ThemeSummaryListResponse(
|
||||
themes = this.map { it.toSummaryResponse() }
|
||||
)
|
||||
|
||||
fun List<ThemeEntity>.toNameListResponse() = ThemeNameListResponse(
|
||||
themes = this.map { it.toNameResponse() }
|
||||
)
|
||||
@ -1,23 +1,11 @@
|
||||
package com.sangdol.roomescape.theme.web
|
||||
package com.sangdol.roomescape.theme.mapper
|
||||
|
||||
import com.sangdol.roomescape.theme.business.domain.ThemeInfo
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoResponse
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
|
||||
data class ThemeInfoResponse(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val thumbnailUrl: String,
|
||||
val description: String,
|
||||
val difficulty: String,
|
||||
val price: Int,
|
||||
val minParticipants: Short,
|
||||
val maxParticipants: Short,
|
||||
val availableMinutes: Short,
|
||||
val expectedMinutesFrom: Short,
|
||||
val expectedMinutesTo: Short
|
||||
)
|
||||
|
||||
fun ThemeInfo.toInfoResponse() = ThemeInfoResponse(
|
||||
fun ThemeInfo.toResponse() = ThemeInfoResponse(
|
||||
id = this.id,
|
||||
name = this.name,
|
||||
thumbnailUrl = this.thumbnailUrl,
|
||||
@ -45,10 +33,8 @@ fun ThemeEntity.toInfoResponse() = ThemeInfoResponse(
|
||||
expectedMinutesTo = this.expectedMinutesTo
|
||||
)
|
||||
|
||||
data class ThemeInfoListResponse(
|
||||
val themes: List<ThemeInfoResponse>
|
||||
fun List<ThemeInfo>.toListResponse() = ThemeInfoListResponse(
|
||||
themes = this.map { it.toResponse() }
|
||||
)
|
||||
|
||||
fun List<ThemeInfo>.toListResponse() = ThemeInfoListResponse(
|
||||
themes = this.map { it.toInfoResponse() }
|
||||
)
|
||||
|
||||
@ -1,8 +1,9 @@
|
||||
package com.sangdol.roomescape.theme.web
|
||||
|
||||
import com.sangdol.common.types.web.CommonApiResponse
|
||||
import com.sangdol.roomescape.theme.business.ThemeService
|
||||
import com.sangdol.roomescape.theme.business.AdminThemeService
|
||||
import com.sangdol.roomescape.theme.docs.AdminThemeAPI
|
||||
import com.sangdol.roomescape.theme.dto.*
|
||||
import jakarta.validation.Valid
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
@ -10,19 +11,19 @@ import java.net.URI
|
||||
|
||||
@RestController
|
||||
class AdminThemeController(
|
||||
private val themeService: ThemeService,
|
||||
private val adminThemeService: AdminThemeService,
|
||||
) : AdminThemeAPI {
|
||||
|
||||
@GetMapping("/admin/themes")
|
||||
override fun getAdminThemeSummaries(): ResponseEntity<CommonApiResponse<AdminThemeSummaryListResponse>> {
|
||||
val response = themeService.findAdminThemes()
|
||||
override fun getAdminThemeSummaries(): ResponseEntity<CommonApiResponse<ThemeSummaryListResponse>> {
|
||||
val response = adminThemeService.findThemeSummaries()
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@GetMapping("/admin/themes/{id}")
|
||||
override fun findAdminThemeDetail(@PathVariable id: Long): ResponseEntity<CommonApiResponse<AdminThemeDetailResponse>> {
|
||||
val response = themeService.findAdminThemeDetail(id)
|
||||
override fun findAdminThemeDetail(@PathVariable id: Long): ResponseEntity<CommonApiResponse<ThemeDetailResponse>> {
|
||||
val response = adminThemeService.findThemeDetail(id)
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
@ -31,7 +32,7 @@ class AdminThemeController(
|
||||
override fun createTheme(
|
||||
@Valid @RequestBody themeCreateRequest: ThemeCreateRequest
|
||||
): ResponseEntity<CommonApiResponse<ThemeCreateResponse>> {
|
||||
val response = themeService.createTheme(themeCreateRequest)
|
||||
val response = adminThemeService.createTheme(themeCreateRequest)
|
||||
|
||||
return ResponseEntity.created(URI.create("/admin/themes/${response.id}"))
|
||||
.body(CommonApiResponse(response))
|
||||
@ -39,7 +40,7 @@ class AdminThemeController(
|
||||
|
||||
@DeleteMapping("/admin/themes/{id}")
|
||||
override fun deleteTheme(@PathVariable id: Long): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
themeService.deleteTheme(id)
|
||||
adminThemeService.deleteTheme(id)
|
||||
|
||||
return ResponseEntity.noContent().build()
|
||||
}
|
||||
@ -49,14 +50,14 @@ class AdminThemeController(
|
||||
@PathVariable id: Long,
|
||||
@Valid @RequestBody request: ThemeUpdateRequest
|
||||
): ResponseEntity<CommonApiResponse<Unit>> {
|
||||
themeService.updateTheme(id, request)
|
||||
adminThemeService.updateTheme(id, request)
|
||||
|
||||
return ResponseEntity.ok().build()
|
||||
}
|
||||
|
||||
@GetMapping("/admin/themes/active")
|
||||
override fun getActiveThemes(): ResponseEntity<CommonApiResponse<SimpleActiveThemeListResponse>> {
|
||||
val response = themeService.findActiveThemes()
|
||||
override fun getActiveThemes(): ResponseEntity<CommonApiResponse<ThemeNameListResponse>> {
|
||||
val response = adminThemeService.findActiveThemes()
|
||||
|
||||
return ResponseEntity.ok(CommonApiResponse(response))
|
||||
}
|
||||
|
||||
@ -1,127 +0,0 @@
|
||||
package com.sangdol.roomescape.theme.web
|
||||
|
||||
import com.sangdol.roomescape.common.types.AuditingInfo
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
|
||||
// ========================================
|
||||
// HQ Admin DTO (본사)
|
||||
// ========================================
|
||||
data class ThemeCreateRequest(
|
||||
val name: String,
|
||||
val description: String,
|
||||
val thumbnailUrl: String,
|
||||
val difficulty: Difficulty,
|
||||
val price: Int,
|
||||
val minParticipants: Short,
|
||||
val maxParticipants: Short,
|
||||
val availableMinutes: Short,
|
||||
val expectedMinutesFrom: Short,
|
||||
val expectedMinutesTo: Short,
|
||||
val isActive: Boolean
|
||||
)
|
||||
|
||||
data class ThemeCreateResponse(
|
||||
val id: Long
|
||||
)
|
||||
|
||||
fun ThemeCreateRequest.toEntity(id: Long) = ThemeEntity(
|
||||
id = id,
|
||||
name = this.name,
|
||||
description = this.description,
|
||||
thumbnailUrl = this.thumbnailUrl,
|
||||
difficulty = this.difficulty,
|
||||
price = this.price,
|
||||
minParticipants = this.minParticipants,
|
||||
maxParticipants = this.maxParticipants,
|
||||
availableMinutes = this.availableMinutes,
|
||||
expectedMinutesFrom = this.expectedMinutesFrom,
|
||||
expectedMinutesTo = this.expectedMinutesTo,
|
||||
isActive = this.isActive
|
||||
)
|
||||
|
||||
data class ThemeUpdateRequest(
|
||||
val name: String? = null,
|
||||
val description: String? = null,
|
||||
val thumbnailUrl: String? = null,
|
||||
val difficulty: Difficulty? = null,
|
||||
val price: Int? = null,
|
||||
val minParticipants: Short? = null,
|
||||
val maxParticipants: Short? = null,
|
||||
val availableMinutes: Short? = null,
|
||||
val expectedMinutesFrom: Short? = null,
|
||||
val expectedMinutesTo: Short? = null,
|
||||
val isActive: Boolean? = null,
|
||||
) {
|
||||
fun isAllParamsNull(): Boolean {
|
||||
return name == null &&
|
||||
description == null &&
|
||||
thumbnailUrl == null &&
|
||||
difficulty == null &&
|
||||
price == null &&
|
||||
minParticipants == null &&
|
||||
maxParticipants == null &&
|
||||
availableMinutes == null &&
|
||||
expectedMinutesFrom == null &&
|
||||
expectedMinutesTo == null &&
|
||||
isActive == null
|
||||
}
|
||||
}
|
||||
|
||||
data class AdminThemeSummaryResponse(
|
||||
val id: Long,
|
||||
val name: String,
|
||||
val difficulty: Difficulty,
|
||||
val price: Int,
|
||||
val isActive: Boolean
|
||||
)
|
||||
|
||||
fun ThemeEntity.toAdminThemeSummaryResponse() = AdminThemeSummaryResponse(
|
||||
id = this.id,
|
||||
name = this.name,
|
||||
difficulty = this.difficulty,
|
||||
price = this.price,
|
||||
isActive = this.isActive
|
||||
)
|
||||
|
||||
data class AdminThemeSummaryListResponse(
|
||||
val themes: List<AdminThemeSummaryResponse>
|
||||
)
|
||||
|
||||
fun List<ThemeEntity>.toAdminThemeSummaryListResponse() = AdminThemeSummaryListResponse(
|
||||
themes = this.map { it.toAdminThemeSummaryResponse() }
|
||||
)
|
||||
|
||||
data class AdminThemeDetailResponse(
|
||||
val theme: ThemeInfoResponse,
|
||||
val isActive: Boolean,
|
||||
val audit: AuditingInfo
|
||||
)
|
||||
|
||||
fun ThemeEntity.toAdminThemeDetailResponse(audit: AuditingInfo) =
|
||||
AdminThemeDetailResponse(
|
||||
theme = this.toInfoResponse(),
|
||||
isActive = this.isActive,
|
||||
audit = audit
|
||||
)
|
||||
|
||||
// ========================================
|
||||
// Store Admin DTO
|
||||
// ========================================
|
||||
data class SimpleActiveThemeResponse(
|
||||
val id: Long,
|
||||
val name: String
|
||||
)
|
||||
|
||||
fun ThemeEntity.toSimpleActiveThemeResponse() = SimpleActiveThemeResponse(
|
||||
id = this.id,
|
||||
name = this.name
|
||||
)
|
||||
|
||||
data class SimpleActiveThemeListResponse(
|
||||
val themes: List<SimpleActiveThemeResponse>
|
||||
)
|
||||
|
||||
fun List<ThemeEntity>.toSimpleActiveThemeResponse() = SimpleActiveThemeListResponse(
|
||||
themes = this.map { it.toSimpleActiveThemeResponse() }
|
||||
)
|
||||
@ -3,6 +3,8 @@ package com.sangdol.roomescape.theme.web
|
||||
import com.sangdol.common.types.web.CommonApiResponse
|
||||
import com.sangdol.roomescape.theme.business.ThemeService
|
||||
import com.sangdol.roomescape.theme.docs.PublicThemeAPI
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoListResponse
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoResponse
|
||||
import org.springframework.http.ResponseEntity
|
||||
import org.springframework.web.bind.annotation.*
|
||||
|
||||
|
||||
@ -26,8 +26,8 @@ import com.sangdol.roomescape.store.infrastructure.persistence.StoreRepository
|
||||
import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||
import com.sangdol.roomescape.theme.web.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.theme.web.toEntity
|
||||
import com.sangdol.roomescape.theme.dto.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.theme.mapper.toEntity
|
||||
import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity
|
||||
import org.springframework.data.repository.findByIdOrNull
|
||||
import java.time.Instant
|
||||
|
||||
@ -19,7 +19,7 @@ import com.sangdol.roomescape.store.infrastructure.persistence.StoreStatus
|
||||
import com.sangdol.roomescape.store.web.StoreRegisterRequest
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.Difficulty
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
import com.sangdol.roomescape.theme.web.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.theme.dto.ThemeCreateRequest
|
||||
import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity
|
||||
import com.sangdol.roomescape.user.infrastructure.persistence.UserStatus
|
||||
import com.sangdol.roomescape.user.dto.MIN_PASSWORD_LENGTH
|
||||
|
||||
@ -12,7 +12,7 @@ import com.sangdol.roomescape.theme.business.MIN_PRICE
|
||||
import com.sangdol.roomescape.theme.exception.ThemeErrorCode
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||
import com.sangdol.roomescape.theme.web.ThemeUpdateRequest
|
||||
import com.sangdol.roomescape.theme.dto.ThemeUpdateRequest
|
||||
import io.kotest.matchers.nulls.shouldNotBeNull
|
||||
import io.kotest.matchers.shouldBe
|
||||
import org.hamcrest.CoreMatchers.equalTo
|
||||
|
||||
@ -7,8 +7,8 @@ import com.sangdol.roomescape.theme.business.DateUtils
|
||||
import com.sangdol.roomescape.theme.exception.ThemeErrorCode
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeEntity
|
||||
import com.sangdol.roomescape.theme.infrastructure.persistence.ThemeRepository
|
||||
import com.sangdol.roomescape.theme.web.ThemeInfoResponse
|
||||
import com.sangdol.roomescape.theme.web.toEntity
|
||||
import com.sangdol.roomescape.theme.dto.ThemeInfoResponse
|
||||
import com.sangdol.roomescape.theme.mapper.toEntity
|
||||
import com.sangdol.roomescape.user.infrastructure.persistence.UserEntity
|
||||
import io.kotest.matchers.collections.shouldContainInOrder
|
||||
import io.kotest.matchers.collections.shouldHaveSize
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user