diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/event/EventService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/event/EventService.kt index 1a99eff6..b103cd2a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/event/EventService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/event/EventService.kt @@ -78,7 +78,9 @@ class EventService( startDateString: String, endDateString: String ): Long { - if (detail == null && link.isNullOrBlank()) throw SodaException("상세이미지 혹은 링크를 등록하세요") + if (detail == null && link.isNullOrBlank()) { + throw SodaException(messageKey = "event.detail_or_link_required") + } val dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd") val startDate = LocalDate.parse(startDateString, dateTimeFormatter).atTime(0, 0) @@ -146,7 +148,7 @@ class EventService( event.detailImage = detailImagePath event.popupImage = popupImagePath - return event.id ?: throw SodaException("이벤트 등록을 하지 못했습니다.") + return event.id ?: throw SodaException(messageKey = "event.save_failed") } @Transactional @@ -162,10 +164,10 @@ class EventService( startDateString: String? = null, endDateString: String? = null ) { - if (id <= 0) throw SodaException("잘못된 요청입니다.") + if (id <= 0) throw SodaException(messageKey = "common.error.invalid_request") val event = repository.findByIdOrNull(id) - ?: throw SodaException("잘못된 요청입니다.") + ?: throw SodaException(messageKey = "common.error.invalid_request") if (thumbnail != null) { val metadata = ObjectMetadata() @@ -234,9 +236,9 @@ class EventService( @Transactional fun delete(id: Long) { - if (id <= 0) throw SodaException("잘못된 요청입니다.") + if (id <= 0) throw SodaException(messageKey = "common.error.invalid_request") val event = repository.findByIdOrNull(id) - ?: throw SodaException("잘못된 요청입니다.") + ?: throw SodaException(messageKey = "common.error.invalid_request") event.isActive = false } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/faq/FaqService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/faq/FaqService.kt index 5912d4a9..3e418f34 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/faq/FaqService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/faq/FaqService.kt @@ -12,12 +12,12 @@ class FaqService( ) { @Transactional fun save(request: CreateFaqRequest): Long { - if (request.question.isBlank()) throw SodaException("질문을 입력하세요.") - if (request.answer.isBlank()) throw SodaException("답변을 입력하세요.") - if (request.category.isBlank()) throw SodaException("카테고리를 선택하세요.") + if (request.question.isBlank()) throw SodaException(messageKey = "faq.question_required") + if (request.answer.isBlank()) throw SodaException(messageKey = "faq.answer_required") + if (request.category.isBlank()) throw SodaException(messageKey = "faq.category_required") val category = queryRepository.getCategory(request.category) - ?: throw SodaException("잘못된 카테고리 입니다.") + ?: throw SodaException(messageKey = "faq.invalid_category") val faq = Faq(request.question, request.answer) faq.category = category @@ -28,30 +28,31 @@ class FaqService( @Transactional fun modify(request: ModifyFaqRequest) { val faq = queryRepository.getFaq(request.id) - ?: throw SodaException("잘못된 요청입니다.") + ?: throw SodaException(messageKey = "common.error.invalid_request") if (request.question != null) { - if (request.question.isBlank()) throw SodaException("질문을 입력하세요.") + if (request.question.isBlank()) throw SodaException(messageKey = "faq.question_required") faq.question = request.question } if (request.answer != null) { - if (request.answer.isBlank()) throw SodaException("답변을 입력하세요.") + if (request.answer.isBlank()) throw SodaException(messageKey = "faq.answer_required") faq.answer = request.answer } if (request.category != null) { - if (request.category.isBlank()) throw SodaException("카테고리를 선택하세요.") - val category = queryRepository.getCategory(request.category) ?: throw SodaException("잘못된 카테고리 입니다.") + if (request.category.isBlank()) throw SodaException(messageKey = "faq.category_required") + val category = queryRepository.getCategory(request.category) + ?: throw SodaException(messageKey = "faq.invalid_category") faq.category = category } } @Transactional fun delete(id: Long) { - if (id <= 0) throw SodaException("잘못된 요청입니다.") + if (id <= 0) throw SodaException(messageKey = "common.error.invalid_request") val faq = repository.findByIdOrNull(id) - ?: throw SodaException("잘못된 요청입니다.") + ?: throw SodaException(messageKey = "common.error.invalid_request") faq.isActive = false } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/i18n/SodaMessageSource.kt b/src/main/kotlin/kr/co/vividnext/sodalive/i18n/SodaMessageSource.kt index 8e7d95dd..bffaaf79 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/i18n/SodaMessageSource.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/i18n/SodaMessageSource.kt @@ -626,6 +626,75 @@ class SodaMessageSource { ) ) + private val eventMessages = mapOf( + "event.detail_or_link_required" to mapOf( + Lang.KO to "상세이미지 혹은 링크를 등록하세요", + Lang.EN to "Please register a detail image or link.", + Lang.JA to "詳細画像またはリンクを登録してください。" + ), + "event.save_failed" to mapOf( + Lang.KO to "이벤트 등록을 하지 못했습니다.", + Lang.EN to "Failed to register the event.", + Lang.JA to "イベントの登録に失敗しました。" + ) + ) + + private val faqMessages = mapOf( + "faq.question_required" to mapOf( + Lang.KO to "질문을 입력하세요.", + Lang.EN to "Please enter a question.", + Lang.JA to "質問を入力してください。" + ), + "faq.answer_required" to mapOf( + Lang.KO to "답변을 입력하세요.", + Lang.EN to "Please enter an answer.", + Lang.JA to "回答を入力してください。" + ), + "faq.category_required" to mapOf( + Lang.KO to "카테고리를 선택하세요.", + Lang.EN to "Please select a category.", + Lang.JA to "カテゴリーを選択してください。" + ), + "faq.invalid_category" to mapOf( + Lang.KO to "잘못된 카테고리 입니다.", + Lang.EN to "Invalid category.", + Lang.JA to "不正なカテゴリーです。" + ) + ) + + private val liveReservationMessages = mapOf( + "live.reservation.invalid_request_retry" to mapOf( + Lang.KO to "잘못된 요청입니다.\n다시 시도해 주세요.", + Lang.EN to "Invalid request.\nPlease try again.", + Lang.JA to "不正なリクエストです。\nもう一度やり直してください。" + ), + "live.reservation.already_reserved" to mapOf( + Lang.KO to "이미 예약한 라이브 입니다.", + Lang.EN to "You have already reserved this live.", + Lang.JA to "すでに予約済みのライブです。" + ), + "live.reservation.invalid_reservation" to mapOf( + Lang.KO to "잘못된 예약정보 입니다.", + Lang.EN to "Invalid reservation information.", + Lang.JA to "不正な予約情報です。" + ), + "live.reservation.cancel_not_allowed_within_4_hours" to mapOf( + Lang.KO to "라이브 시작 4시간 이내에는 예약취소가 불가능 합니다.", + Lang.EN to "Reservations cannot be canceled within 4 hours of the live start.", + Lang.JA to "ライブ開始4時間以内は予約をキャンセルできません。" + ), + "live.reservation.price_free" to mapOf( + Lang.KO to "무료", + Lang.EN to "Free", + Lang.JA to "無料" + ), + "live.reservation.datetime_format" to mapOf( + Lang.KO to "yyyy년 M월 d일 (E), a hh:mm", + Lang.EN to "yyyy MMM d (EEE), h:mm a", + Lang.JA to "yyyy年 M月 d日 (E) a hh:mm" + ) + ) + private val liveRouletteMessages = mapOf( "live.roulette.unavailable" to mapOf( Lang.KO to "룰렛을 사용할 수 없습니다.", @@ -949,7 +1018,10 @@ class SodaMessageSource { memberMessages, memberValidationMessages, memberSocialMessages, + eventMessages, + faqMessages, liveRouletteMessages, + liveReservationMessages, liveTagMessages, liveRoomMessages, liveRoomMenuMessages, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/jwt/TokenProvider.kt b/src/main/kotlin/kr/co/vividnext/sodalive/jwt/TokenProvider.kt index 0ec16ac6..f851665a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/jwt/TokenProvider.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/jwt/TokenProvider.kt @@ -85,12 +85,14 @@ class TokenProvider( val authorities = claims[AUTHORITIES_KEY].toString().split(",").map { SimpleGrantedAuthority(it) } val memberToken = tokenRepository.findByIdOrNull(id = claims.subject.toLong()) - ?: throw SodaException("로그인 정보를 확인해주세요.") + ?: throw SodaException(messageKey = "common.error.bad_credentials") - if (!memberToken.tokenSet.contains(token)) throw SodaException("로그인 정보를 확인해주세요.") + if (!memberToken.tokenSet.contains(token)) { + throw SodaException(messageKey = "common.error.bad_credentials") + } val member = repository.findByIdOrNull(id = claims.subject.toLong()) - ?: throw SodaException("로그인 정보를 확인해주세요.") + ?: throw SodaException(messageKey = "common.error.bad_credentials") val principal = MemberAdapter(member) return UsernamePasswordAuthenticationToken(principal, token, authorities) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt index 3b8a2521..d1b7280a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt @@ -30,7 +30,7 @@ class LiveRecommendController(private val service: LiveRecommendService) { fun getFollowingChannelList( @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { - if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + if (member == null) throw SodaException(messageKey = "common.error.bad_credentials") ApiResponse.ok(service.getFollowingChannelList(member)) } @@ -40,7 +40,7 @@ class LiveRecommendController(private val service: LiveRecommendService) { @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, pageable: Pageable ) = run { - if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + if (member == null) throw SodaException(messageKey = "common.error.bad_credentials") ApiResponse.ok(service.getFollowingAllChannelList(member, pageable)) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationController.kt index ead7b722..45507782 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationController.kt @@ -21,7 +21,7 @@ class LiveReservationController(private val service: LiveReservationService) { @RequestBody request: MakeLiveReservationRequest, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { - if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + if (member == null) throw SodaException(messageKey = "common.error.bad_credentials") ApiResponse.ok(service.makeReservation(request, member.id!!)) } @@ -32,7 +32,7 @@ class LiveReservationController(private val service: LiveReservationService) { @RequestParam(value = "timezone") timezone: String, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { - if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + if (member == null) throw SodaException(messageKey = "common.error.bad_credentials") ApiResponse.ok(service.getReservationList(member.id!!, isActive, timezone)) } @@ -42,7 +42,7 @@ class LiveReservationController(private val service: LiveReservationService) { @RequestParam(value = "timezone") timezone: String, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { - if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + if (member == null) throw SodaException(messageKey = "common.error.bad_credentials") ApiResponse.ok(service.getReservation(id, member.id!!, timezone)) } @@ -51,7 +51,7 @@ class LiveReservationController(private val service: LiveReservationService) { @RequestBody request: CancelLiveReservationRequest, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { - if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + if (member == null) throw SodaException(messageKey = "common.error.bad_credentials") ApiResponse.ok(service.cancelReservation(request, member.id!!)) } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationService.kt index df2a75df..2e80924c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/reservation/LiveReservationService.kt @@ -3,6 +3,8 @@ package kr.co.vividnext.sodalive.live.reservation import kr.co.vividnext.sodalive.can.payment.CanPaymentService import kr.co.vividnext.sodalive.can.use.CanUsage import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.i18n.LangContext +import kr.co.vividnext.sodalive.i18n.SodaMessageSource import kr.co.vividnext.sodalive.live.room.LiveRoomRepository import kr.co.vividnext.sodalive.live.room.LiveRoomType import kr.co.vividnext.sodalive.member.MemberRepository @@ -21,32 +23,36 @@ class LiveReservationService( private val memberRepository: MemberRepository, private val canPaymentService: CanPaymentService, private val liveReservationCancelRepository: LiveReservationCancelRepository, + private val messageSource: SodaMessageSource, + private val langContext: LangContext, @Value("\${cloud.aws.cloud-front.host}") private val cloudFrontHost: String ) { fun makeReservation(request: MakeLiveReservationRequest, memberId: Long): MakeLiveReservationResponse { val room = liveRoomRepository.findByIdOrNull(id = request.roomId) - ?: throw SodaException(message = "잘못된 요청입니다.\n다시 시도해 주세요.") + ?: throw SodaException(messageKey = "live.reservation.invalid_request_retry") val member = memberRepository.findByIdOrNull(id = memberId) - ?: throw SodaException(message = "로그인 정보를 확인해주세요.") + ?: throw SodaException(messageKey = "common.error.bad_credentials") if ( room.member!!.id!! != memberId && room.type == LiveRoomType.PRIVATE && (request.password == null || request.password != room.password) ) { - throw SodaException("비밀번호가 일치하지 않습니다.\n다시 확인 후 입력해주세요.") + throw SodaException(messageKey = "live.room.password_mismatch") } if (repository.isExistsReservation(roomId = request.roomId, memberId = memberId)) { - throw SodaException("이미 예약한 라이브 입니다.") + throw SodaException(messageKey = "live.reservation.already_reserved") } val haveCan = member.getChargeCan(request.container) + member.getRewardCan(request.container) if (haveCan < room.price) { - throw SodaException("${room.price - haveCan}캔이 부족합니다. 충전 후 이용해 주세요.") + val messageTemplate = messageSource.getMessage("live.room.insufficient_can", langContext.lang).orEmpty() + val message = String.format(messageTemplate, room.price - haveCan) + throw SodaException(message = message) } if (room.price > 0) { @@ -67,16 +73,21 @@ class LiveReservationService( val beginDateTime = room.beginDateTime .atZone(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of(request.timezone)) + val reservationDateFormat = messageSource.getMessage( + "live.reservation.datetime_format", + langContext.lang + ).orEmpty() return MakeLiveReservationResponse( reservationId = reservation.id!!, nickname = room.member!!.nickname, title = room.title, - beginDateString = beginDateTime.format(DateTimeFormatter.ofPattern("yyyy년 M월 d일 (E), a hh:mm")), + beginDateString = beginDateTime.format(DateTimeFormatter.ofPattern(reservationDateFormat)), price = if (room.price > 0) { - "${room.price} 캔" + val priceTemplate = messageSource.getMessage("live.room.can_title", langContext.lang).orEmpty() + String.format(priceTemplate, room.price) } else { - "무료" + messageSource.getMessage("live.reservation.price_free", langContext.lang).orEmpty() }, haveCan = haveCan, useCan = room.price, @@ -85,6 +96,10 @@ class LiveReservationService( } fun getReservationList(memberId: Long, active: Boolean, timezone: String): List { + val detailDateFormat = messageSource.getMessage( + "live.room.datetime_format_detail", + langContext.lang + ).orEmpty() return repository .getReservationListByMemberId(memberId, active) .asSequence() @@ -105,7 +120,7 @@ class LiveReservationService( price = it.room!!.price, masterNickname = it.room!!.member!!.nickname, beginDateTime = beginDateTime.format( - DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a") + DateTimeFormatter.ofPattern(detailDateFormat) ), cancelable = beginDateTime.minusHours(4).isAfter( LocalDateTime.now() @@ -119,8 +134,12 @@ class LiveReservationService( fun getReservation(reservationId: Long, memberId: Long, timezone: String): GetLiveReservationResponse { val reservation = repository.getReservationByReservationAndMemberId(reservationId, memberId) - ?: throw SodaException("잘못된 예약정보 입니다.") + ?: throw SodaException(messageKey = "live.reservation.invalid_reservation") + val detailDateFormat = messageSource.getMessage( + "live.room.datetime_format_detail", + langContext.lang + ).orEmpty() val beginDateTime = reservation.room!!.beginDateTime .atZone(ZoneId.of("UTC")) .withZoneSameInstant(ZoneId.of(timezone)) @@ -137,7 +156,7 @@ class LiveReservationService( price = reservation.room!!.price, masterNickname = reservation.room!!.member!!.nickname, beginDateTime = beginDateTime.format( - DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a") + DateTimeFormatter.ofPattern(detailDateFormat) ), cancelable = beginDateTime.minusHours(4).isAfter( LocalDateTime.now() @@ -150,22 +169,22 @@ class LiveReservationService( @Transactional fun cancelReservation(request: CancelLiveReservationRequest, memberId: Long) { if (request.reason.isBlank()) { - throw SodaException("취소사유를 입력하세요.") + throw SodaException(messageKey = "live.room.cancel_reason_required") } val reservation = repository.findByIdOrNull(request.reservationId) - ?: throw SodaException("잘못된 예약정보 입니다.") + ?: throw SodaException(messageKey = "live.reservation.invalid_reservation") if (reservation.member == null || reservation.member!!.id!! != memberId) { - throw SodaException("잘못된 예약정보 입니다.") + throw SodaException(messageKey = "live.reservation.invalid_reservation") } if (reservation.room == null || reservation.room?.id == null) { - throw SodaException("잘못된 예약정보 입니다.") + throw SodaException(messageKey = "live.reservation.invalid_reservation") } if (reservation.room!!.beginDateTime.isBefore(LocalDateTime.now().plusHours(4))) { - throw SodaException("라이브 시작 4시간 이내에는 예약취소가 불가능 합니다.") + throw SodaException(messageKey = "live.reservation.cancel_not_allowed_within_4_hours") } if (reservation.room!!.price > 0) {