[#34] 회원 / 인증 도메인 재정의 #43

Merged
pricelees merged 73 commits from refactor/#34 into main 2025-09-13 10:13:45 +00:00
4 changed files with 31 additions and 31 deletions
Showing only changes of commit 53d82902ca - Show all commits

View File

@ -7,9 +7,10 @@ import org.springframework.data.repository.findByIdOrNull
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
import roomescape.common.config.next
import roomescape.member.business.MemberService
import roomescape.member.infrastructure.persistence.Role
import roomescape.member.web.MemberSummaryRetrieveResponse
import roomescape.common.dto.CurrentUserContext
import roomescape.common.dto.PrincipalType
import roomescape.member.business.UserService
import roomescape.member.web.UserContactRetrieveResponse
import roomescape.payment.business.PaymentService
import roomescape.payment.web.PaymentRetrieveResponse
import roomescape.reservation.exception.ReservationErrorCode
@ -31,7 +32,7 @@ class ReservationService(
private val reservationRepository: ReservationRepository,
private val reservationValidator: ReservationValidator,
private val scheduleService: ScheduleService,
private val memberService: MemberService,
private val userService: UserService,
private val themeService: ThemeService,
private val canceledReservationRepository: CanceledReservationRepository,
private val tsidFactory: TsidFactory,
@ -40,14 +41,14 @@ class ReservationService(
@Transactional
fun createPendingReservation(
memberId: Long,
user: CurrentUserContext,
request: PendingReservationCreateRequest
): PendingReservationCreateResponse {
log.info { "[ReservationService.createPendingReservation] Pending 예약 생성 시작: schedule=${request.scheduleId}" }
validateCanCreate(request)
val reservation: ReservationEntity = request.toEntity(id = tsidFactory.next(), memberId = memberId)
val reservation: ReservationEntity = request.toEntity(id = tsidFactory.next(), userId = user.id)
return PendingReservationCreateResponse(reservationRepository.save(reservation).id)
.also { "[ReservationService.createPendingReservation] Pending 예약 생성 완료: reservationId=${it}, schedule=${request.scheduleId}" }
@ -70,18 +71,17 @@ class ReservationService(
}
@Transactional
fun cancelReservation(memberId: Long, reservationId: Long, request: ReservationCancelRequest) {
log.info { "[ReservationService.cancelReservation] 예약 취소 시작: memberId=${memberId}, reservationId=${reservationId}" }
fun cancelReservation(user: CurrentUserContext, reservationId: Long, request: ReservationCancelRequest) {
log.info { "[ReservationService.cancelReservation] 예약 취소 시작: userId=${user.id}, reservationId=${reservationId}" }
val reservation: ReservationEntity = findOrThrow(reservationId)
val member: MemberSummaryRetrieveResponse = memberService.findSummaryById(memberId)
run {
scheduleService.updateSchedule(
reservation.scheduleId,
ScheduleUpdateRequest(status = ScheduleStatus.AVAILABLE)
)
saveCanceledReservation(member, reservation, request.cancelReason)
saveCanceledReservation(user, reservation, request.cancelReason)
reservation.cancel()
}.also {
log.info { "[ReservationService.cancelReservation] 예약 취소 완료: reservationId=${reservationId}" }
@ -89,10 +89,10 @@ class ReservationService(
}
@Transactional(readOnly = true)
fun findSummaryByMemberId(memberId: Long): ReservationSummaryRetrieveListResponse {
log.info { "[ReservationService.findSummaryByMemberId] 예약 조회 시작: memberId=${memberId}" }
fun findUserSummaryReservation(user: CurrentUserContext): ReservationSummaryRetrieveListResponse {
log.info { "[ReservationService.findSummaryByMemberId] 예약 조회 시작: userId=${user.id}" }
val reservations: List<ReservationEntity> = reservationRepository.findAllByMemberId(memberId)
val reservations: List<ReservationEntity> = reservationRepository.findAllByUserId(user.id)
return ReservationSummaryRetrieveListResponse(reservations.map {
val schedule: ScheduleSummaryResponse = scheduleService.findSummaryById(it.scheduleId)
@ -106,7 +106,7 @@ class ReservationService(
status = it.status
)
}).also {
log.info { "[ReservationService.findSummaryByMemberId] ${it.reservations.size}개의 예약 조회 완료: memberId=${memberId}" }
log.info { "[ReservationService.findSummaryByMemberId] ${it.reservations.size}개의 예약 조회 완료: userId=${user.id}" }
}
}
@ -115,11 +115,11 @@ class ReservationService(
log.info { "[ReservationService.findDetailById] 예약 상세 조회 시작: reservationId=${id}" }
val reservation: ReservationEntity = findOrThrow(id)
val member: MemberSummaryRetrieveResponse = memberService.findSummaryById(reservation.memberId)
val user: UserContactRetrieveResponse = userService.findContactById(reservation.userId)
val paymentDetail: PaymentRetrieveResponse = paymentService.findDetailByReservationId(id)
return reservation.toReservationDetailRetrieveResponse(
member = member,
user = user,
payment = paymentDetail
).also {
log.info { "[ReservationService.findDetailById] 예약 상세 조회 완료: reservationId=${id}" }
@ -138,19 +138,19 @@ class ReservationService(
}
private fun saveCanceledReservation(
member: MemberSummaryRetrieveResponse,
user: CurrentUserContext,
reservation: ReservationEntity,
cancelReason: String
) {
if (member.role != Role.ADMIN && reservation.memberId != member.id) {
log.warn { "[ReservationService.createCanceledPayment] 예약자 본인 또는 관리자가 아닌 회원의 취소 요청: reservationId=${reservation.id}, memberId=${member.id}" }
if (user.type != PrincipalType.ADMIN && reservation.userId != user.id) {
log.warn { "[ReservationService.createCanceledPayment] 예약자 본인 또는 관리자가 아닌 회원의 취소 요청: reservationId=${reservation.id}, userId=${user.id}" }
throw ReservationException(ReservationErrorCode.NO_PERMISSION_TO_CANCEL_RESERVATION)
}
CanceledReservationEntity(
id = tsidFactory.next(),
reservationId = reservation.id,
canceledBy = member.id,
canceledBy = user.id,
cancelReason = cancelReason,
canceledAt = LocalDateTime.now(),
status = CanceledReservationStatus.PROCESSING

View File

@ -1,16 +1,14 @@
package roomescape.reservation.docs
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.responses.ApiResponse
import io.swagger.v3.oas.annotations.responses.ApiResponses
import jakarta.validation.Valid
import org.springframework.http.ResponseEntity
import org.springframework.web.bind.annotation.PathVariable
import org.springframework.web.bind.annotation.RequestBody
import roomescape.auth.web.support.Authenticated
import roomescape.auth.web.support.CurrentUser
import roomescape.auth.web.support.LoginRequired
import roomescape.auth.web.support.MemberId
import roomescape.auth.web.support.UserOnly
import roomescape.common.dto.CurrentUserContext
import roomescape.common.dto.response.CommonApiResponse
@ -18,6 +16,7 @@ import roomescape.reservation.web.*
interface ReservationAPI {
@UserOnly
@Operation(summary = "결제 대기 예약 저장", tags = ["로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun createPendingReservation(
@ -32,7 +31,7 @@ interface ReservationAPI {
@PathVariable("id") id: Long
): ResponseEntity<CommonApiResponse<Unit>>
@UserOnly
@Authenticated
@Operation(summary = "예약 취소", tags = ["로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun cancelReservation(
@ -41,6 +40,7 @@ interface ReservationAPI {
@Valid @RequestBody request: ReservationCancelRequest
): ResponseEntity<CommonApiResponse<Unit>>
@UserOnly
@Operation(summary = "회원별 예약 요약 목록 조회", tags = ["로그인이 필요한 API"])
@ApiResponses(ApiResponse(responseCode = "200", description = "성공", useReturnTypeSchema = true))
fun findSummaryByMemberId(

View File

@ -19,7 +19,7 @@ class ReservationController(
@CurrentUser user: CurrentUserContext,
@Valid @RequestBody request: PendingReservationCreateRequest
): ResponseEntity<CommonApiResponse<PendingReservationCreateResponse>> {
val response = reservationService.createPendingReservation(user.id, request)
val response = reservationService.createPendingReservation(user, request)
return ResponseEntity.ok(CommonApiResponse(response))
}
@ -39,7 +39,7 @@ class ReservationController(
@PathVariable reservationId: Long,
@Valid @RequestBody request: ReservationCancelRequest
): ResponseEntity<CommonApiResponse<Unit>> {
reservationService.cancelReservation(user.id, reservationId, request)
reservationService.cancelReservation(user, reservationId, request)
return ResponseEntity.ok().body(CommonApiResponse())
}
@ -48,7 +48,7 @@ class ReservationController(
override fun findSummaryByMemberId(
@CurrentUser user: CurrentUserContext,
): ResponseEntity<CommonApiResponse<ReservationSummaryRetrieveListResponse>> {
val response = reservationService.findSummaryByMemberId(user.id)
val response = reservationService.findUserSummaryReservation(user)
return ResponseEntity.ok(CommonApiResponse(response))
}

View File

@ -1,7 +1,7 @@
package roomescape.reservation.web
import jakarta.validation.constraints.NotEmpty
import roomescape.member.web.MemberSummaryRetrieveResponse
import roomescape.member.web.UserContactRetrieveResponse
import roomescape.payment.web.PaymentRetrieveResponse
import roomescape.reservation.infrastructure.persistence.ReservationEntity
import roomescape.reservation.infrastructure.persistence.ReservationStatus
@ -48,18 +48,18 @@ data class ReservationSummaryRetrieveListResponse(
data class ReservationDetailRetrieveResponse(
val id: Long,
val member: MemberSummaryRetrieveResponse,
val user: UserContactRetrieveResponse,
val applicationDateTime: LocalDateTime,
val payment: PaymentRetrieveResponse,
)
fun ReservationEntity.toReservationDetailRetrieveResponse(
member: MemberSummaryRetrieveResponse,
user: UserContactRetrieveResponse,
payment: PaymentRetrieveResponse,
): ReservationDetailRetrieveResponse {
return ReservationDetailRetrieveResponse(
id = this.id,
member = member,
user = user,
applicationDateTime = this.createdAt,
payment = payment,
)