From ed2660adc660a79caabc1544bc96617a5e5b638b Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 15 Jan 2026 17:21:22 +0900 Subject: [PATCH] =?UTF-8?q?=ED=91=B8=EC=8B=9C=20=EC=95=8C=EB=A6=BC=20?= =?UTF-8?q?=EC=A0=84=EC=86=A1=20=EC=96=B8=EC=96=B4=20=EC=B2=98=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/audition/AdminAuditionService.kt | 12 +- .../sodalive/admin/live/AdminLiveService.kt | 11 +- .../can/charge/event/ChargeEventService.kt | 16 +- .../sodalive/content/AudioContentService.kt | 38 +-- .../comment/AudioContentCommentRepository.kt | 16 +- .../comment/AudioContentCommentService.kt | 7 +- ...tIdAndCommentParentIdMyMemberIdResponse.kt | 8 - .../sodalive/explorer/ExplorerService.kt | 2 +- .../CreatorCommunityService.kt | 2 +- .../vividnext/sodalive/fcm/FcmController.kt | 11 - .../kr/co/vividnext/sodalive/fcm/FcmEvent.kt | 312 +++++------------- .../GetMessageRecipientPushTokenResponse.kt | 8 - .../kr/co/vividnext/sodalive/fcm/PushToken.kt | 3 +- .../vividnext/sodalive/fcm/PushTokenInfo.kt | 9 + .../sodalive/fcm/PushTokenService.kt | 7 +- .../sodalive/live/room/LiveRoomService.kt | 58 +--- .../sodalive/member/MemberRepository.kt | 225 ++++++------- .../sodalive/message/MessageService.kt | 16 +- 18 files changed, 258 insertions(+), 503 deletions(-) delete mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/comment/FindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse.kt delete mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/fcm/GetMessageRecipientPushTokenResponse.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenInfo.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionService.kt index e362f4f8..a3b6c07d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/audition/AdminAuditionService.kt @@ -7,8 +7,6 @@ import kr.co.vividnext.sodalive.aws.s3.S3Uploader import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.fcm.FcmEvent import kr.co.vividnext.sodalive.fcm.FcmEventType -import kr.co.vividnext.sodalive.i18n.LangContext -import kr.co.vividnext.sodalive.i18n.SodaMessageSource import kr.co.vividnext.sodalive.utils.generateFileName import org.springframework.beans.factory.annotation.Value import org.springframework.context.ApplicationEventPublisher @@ -24,8 +22,6 @@ class AdminAuditionService( private val repository: AdminAuditionRepository, private val roleRepository: AdminAuditionRoleRepository, private val applicationEventPublisher: ApplicationEventPublisher, - private val langContext: LangContext, - private val messageSource: SodaMessageSource, @Value("\${cloud.aws.s3.bucket}") private val bucket: String @@ -92,14 +88,12 @@ class AdminAuditionService( } if (request.status != null && request.status == AuditionStatus.IN_PROGRESS && audition.isActive) { - val title = messageSource.getMessage("admin.audition.fcm.title.new", langContext.lang).orEmpty() - val messageTemplate = messageSource.getMessage("admin.audition.fcm.message.new", langContext.lang).orEmpty() - val message = String.format(messageTemplate, audition.title) applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.IN_PROGRESS_AUDITION, - title = title, - message = message, + titleKey = "admin.audition.fcm.title.new", + messageKey = "admin.audition.fcm.message.new", + args = listOf(audition.title), isAuth = audition.isAdult, auditionId = audition.id ?: -1 ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt index 969ec154..35cb6232 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/AdminLiveService.kt @@ -321,20 +321,17 @@ class AdminLiveService( } // 예약현황 취소 - val pushTokenListMap = memberRepository.getPushTokenFromReservationList(room.id!!) + val pushTokens = memberRepository.getPushTokenFromReservationList(room.id!!) reservationRepository.cancelReservation(roomId = room.id!!) // 라이브 취소 푸시 발송 - val cancelMessageTemplate = messageSource - .getMessage("live.room.fcm.message.canceled", langContext.lang) - .orEmpty() - val cancelMessage = String.format(cancelMessageTemplate, room.title) applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.CANCEL_LIVE, title = room.member!!.nickname, - message = cancelMessage, - recipientsMap = pushTokenListMap + messageKey = "live.room.fcm.message.canceled", + args = listOf(room.title), + pushTokens = pushTokens ) ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt index 625377c1..46038b7a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/charge/event/ChargeEventService.kt @@ -83,10 +83,8 @@ class ChargeEventService( FcmEvent( type = FcmEventType.INDIVIDUAL, title = chargeEvent.title, - message = formatMessage( - "can.charge.event.additional_can_paid", - additionalCan - ), + messageKey = "can.charge.event.additional_can_paid", + args = listOf(additionalCan), recipients = listOf(member.id!!), isAuth = null ) @@ -109,13 +107,9 @@ class ChargeEventService( applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.INDIVIDUAL, - title = messageSource - .getMessage("can.charge.event.first_title", langContext.lang) - .orEmpty(), - message = formatMessage( - "can.charge.event.additional_can_paid", - additionalCan - ), + titleKey = "can.charge.event.first_title", + messageKey = "can.charge.event.additional_can_paid", + args = listOf(additionalCan), recipients = listOf(member.id!!), isAuth = null ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index fdd2fcd9..c3777ed5 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -459,7 +459,7 @@ class AudioContentService( applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.INDIVIDUAL, - title = formatMessage("content.notification.upload_complete_title"), + titleKey = "content.notification.upload_complete_title", message = audioContent.title, recipients = listOf(audioContent.member!!.id!!), isAuth = null, @@ -474,23 +474,11 @@ class AudioContentService( FcmEvent( type = FcmEventType.UPLOAD_CONTENT, title = audioContent.member!!.nickname, - message = formatMessage("content.notification.uploaded_message", audioContent.title), + messageKey = "content.notification.uploaded_message", + args = listOf(audioContent.title), isAuth = audioContent.isAdult, contentId = contentId, - creatorId = audioContent.member!!.id, - container = "ios" - ) - ) - - applicationEventPublisher.publishEvent( - FcmEvent( - type = FcmEventType.UPLOAD_CONTENT, - title = audioContent.member!!.nickname, - message = formatMessage("content.notification.uploaded_message", audioContent.title), - isAuth = audioContent.isAdult, - contentId = contentId, - creatorId = audioContent.member!!.id, - container = "aos" + creatorId = audioContent.member!!.id ) ) } @@ -508,23 +496,11 @@ class AudioContentService( FcmEvent( type = FcmEventType.UPLOAD_CONTENT, title = audioContent.member!!.nickname, - message = "콘텐츠를 업로드 하였습니다. - ${audioContent.title}", + messageKey = "content.notification.uploaded_message", + args = listOf(audioContent.title), isAuth = audioContent.isAdult, contentId = audioContent.id!!, - creatorId = audioContent.member!!.id, - container = "ios" - ) - ) - - applicationEventPublisher.publishEvent( - FcmEvent( - type = FcmEventType.UPLOAD_CONTENT, - title = audioContent.member!!.nickname, - message = "콘텐츠를 업로드 하였습니다. - ${audioContent.title}", - isAuth = audioContent.isAdult, - contentId = audioContent.id!!, - creatorId = audioContent.member!!.id, - container = "aos" + creatorId = audioContent.member!!.id ) ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt index 09ef520e..f4e679bf 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentRepository.kt @@ -4,7 +4,9 @@ import com.querydsl.core.types.dsl.Expressions import com.querydsl.jpa.impl.JPAQueryFactory import kr.co.vividnext.sodalive.content.QAudioContent.audioContent import kr.co.vividnext.sodalive.content.comment.QAudioContentComment.audioContentComment +import kr.co.vividnext.sodalive.fcm.PushTokenInfo import kr.co.vividnext.sodalive.fcm.QPushToken.pushToken +import kr.co.vividnext.sodalive.fcm.QPushTokenInfo import kr.co.vividnext.sodalive.member.QMember.member import org.springframework.data.jpa.repository.JpaRepository import org.springframework.stereotype.Repository @@ -38,7 +40,7 @@ interface AudioContentCommentQueryRepository { contentId: Long, commentParentId: Long?, myMemberId: Long - ): List + ): List } @Repository @@ -191,7 +193,7 @@ class AudioContentCommentQueryRepositoryImpl( contentId: Long, commentParentId: Long?, myMemberId: Long - ): List { + ): List { var where = audioContent.id.eq(contentId) .and(member.id.ne(myMemberId)) @@ -206,9 +208,10 @@ class AudioContentCommentQueryRepositoryImpl( val response = if (commentParentId != null) { queryFactory .select( - QFindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse( + QPushTokenInfo( pushToken.token, - pushToken.deviceType + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") ) ) .from(audioContentComment) @@ -220,9 +223,10 @@ class AudioContentCommentQueryRepositoryImpl( } else { queryFactory .select( - QFindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse( + QPushTokenInfo( pushToken.token, - pushToken.deviceType + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") ) ) .from(audioContent) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentService.kt index 3746b449..401484ed 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/AudioContentCommentService.kt @@ -83,11 +83,12 @@ class AudioContentCommentService( } else { member.nickname }, - message = if (parent != null) { - formatMessage("content.comment.notification.reply", audioContent.title) + messageKey = if (parent != null) { + "content.comment.notification.reply" } else { - formatMessage("content.comment.notification.new", audioContent.title) + "content.comment.notification.new" }, + args = listOf(audioContent.title), contentId = audioContentId, commentParentId = parentId, myMemberId = member.id diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/FindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/FindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse.kt deleted file mode 100644 index 1876da44..00000000 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/comment/FindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package kr.co.vividnext.sodalive.content.comment - -import com.querydsl.core.annotations.QueryProjection - -data class FindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse @QueryProjection constructor( - val pushToken: String, - val container: String -) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt index 71d087ba..bd003ee8 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt @@ -578,7 +578,7 @@ class ExplorerService( FcmEvent( type = FcmEventType.CHANGE_NOTICE, title = member.nickname, - message = messageSource.getMessage("explorer.notice.fcm.message", langContext.lang).orEmpty(), + messageKey = "explorer.notice.fcm.message", creatorId = member.id!! ) ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt index 5a66eba2..cc3be756 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt @@ -123,7 +123,7 @@ class CreatorCommunityService( FcmEvent( type = FcmEventType.CHANGE_NOTICE, title = member.nickname, - message = messageSource.getMessage("creator.community.fcm.new_post", langContext.lang).orEmpty(), + messageKey = "creator.community.fcm.new_post", creatorId = member.id!! ) ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmController.kt index b01d4c99..6040d940 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmController.kt @@ -33,17 +33,6 @@ class FcmController(private val applicationEventPublisher: ApplicationEventPubli type = FcmEventType.ALL, title = request.title, message = request.message, - container = "ios", - isAuth = request.isAuth - ) - ) - - applicationEventPublisher.publishEvent( - FcmEvent( - type = FcmEventType.ALL, - title = request.title, - message = request.message, - container = "aos", isAuth = request.isAuth ) ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmEvent.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmEvent.kt index 6ce30a4e..d054ed3e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmEvent.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/FcmEvent.kt @@ -1,6 +1,8 @@ package kr.co.vividnext.sodalive.fcm import kr.co.vividnext.sodalive.content.comment.AudioContentCommentRepository +import kr.co.vividnext.sodalive.i18n.Lang +import kr.co.vividnext.sodalive.i18n.SodaMessageSource import kr.co.vividnext.sodalive.member.MemberRepository import org.springframework.scheduling.annotation.Async import org.springframework.stereotype.Component @@ -15,11 +17,14 @@ enum class FcmEventType { class FcmEvent( val type: FcmEventType, - val title: String, - val message: String, + val title: String = "", + val message: String = "", + val titleKey: String? = null, + val messageKey: String? = null, + val args: List = listOf(), val container: String = "", val recipients: List = listOf(), - val recipientsMap: Map>>? = null, + val pushTokens: List? = null, val isAuth: Boolean? = null, val roomId: Long? = null, val contentId: Long? = null, @@ -35,7 +40,8 @@ class FcmEvent( class FcmSendListener( private val pushService: FcmService, private val memberRepository: MemberRepository, - private val contentCommentRepository: AudioContentCommentRepository + private val contentCommentRepository: AudioContentCommentRepository, + private val messageSource: SodaMessageSource ) { @Async @TransactionalEventListener @@ -43,21 +49,10 @@ class FcmSendListener( fun send(fcmEvent: FcmEvent) { when (fcmEvent.type) { FcmEventType.ALL -> { - if (fcmEvent.container.isNotBlank()) { - val pushTokens = memberRepository.getAllRecipientPushTokens( - fcmEvent.isAuth, - fcmEvent.container - ) - - for (tokens in pushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = fcmEvent.container - ) - } - } + val pushTokens = memberRepository.getAllRecipientPushTokens( + fcmEvent.isAuth + ) + sendPush(pushTokens, fcmEvent) } FcmEventType.INDIVIDUAL -> { @@ -66,254 +61,117 @@ class FcmSendListener( recipients = fcmEvent.recipients, isAuth = fcmEvent.isAuth ) - - val iosPushTokens = pushTokens["ios"] - val aosPushToken = pushTokens["aos"] - - if (iosPushTokens != null) { - for (tokens in iosPushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "ios", - contentId = fcmEvent.contentId - ) - } - } - - if (aosPushToken != null) { - for (tokens in aosPushToken) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "aos", - contentId = fcmEvent.contentId - ) - } - } + sendPush(pushTokens, fcmEvent) } } FcmEventType.CREATE_LIVE -> { - if (fcmEvent.container.isNotBlank()) { - val pushTokens = memberRepository.getCreateLiveRoomNotificationRecipientPushTokens( - creatorId = fcmEvent.creatorId!!, - isAuth = fcmEvent.isAuth ?: false, - isAvailableJoinCreator = fcmEvent.isAvailableJoinCreator ?: false, - container = fcmEvent.container - ) - - for (tokens in pushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = fcmEvent.container, - roomId = fcmEvent.roomId - ) - } - } + val pushTokens = memberRepository.getCreateLiveRoomNotificationRecipientPushTokens( + creatorId = fcmEvent.creatorId!!, + isAuth = fcmEvent.isAuth ?: false, + isAvailableJoinCreator = fcmEvent.isAvailableJoinCreator ?: false + ) + sendPush(pushTokens, fcmEvent, roomId = fcmEvent.roomId) } FcmEventType.START_LIVE -> { - if (fcmEvent.container.isNotBlank()) { - val pushTokens = memberRepository.getStartLiveRoomNotificationRecipientPushTokens( - creatorId = fcmEvent.creatorId!!, - roomId = fcmEvent.roomId!!, - isAuth = fcmEvent.isAuth ?: false, - isAvailableJoinCreator = fcmEvent.isAvailableJoinCreator ?: false, - container = fcmEvent.container - ) - - for (tokens in pushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = fcmEvent.container, - roomId = fcmEvent.roomId - ) - } - } + val pushTokens = memberRepository.getStartLiveRoomNotificationRecipientPushTokens( + creatorId = fcmEvent.creatorId!!, + roomId = fcmEvent.roomId!!, + isAuth = fcmEvent.isAuth ?: false, + isAvailableJoinCreator = fcmEvent.isAvailableJoinCreator ?: false + ) + sendPush(pushTokens, fcmEvent, roomId = fcmEvent.roomId) } FcmEventType.CANCEL_LIVE -> { - if (fcmEvent.recipientsMap != null) { - val iosPushTokens = fcmEvent.recipientsMap["ios"] - val aosPushToken = fcmEvent.recipientsMap["aos"] - if (iosPushTokens != null) { - for (tokens in iosPushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "ios" - ) - } - } - - if (aosPushToken != null) { - for (tokens in aosPushToken) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "aos" - ) - } - } + if (fcmEvent.pushTokens != null) { + sendPush(fcmEvent.pushTokens, fcmEvent) } } FcmEventType.UPLOAD_CONTENT -> { - if (fcmEvent.container.isNotBlank()) { - val pushTokens = memberRepository.getUploadContentNotificationRecipientPushTokens( - creatorId = fcmEvent.creatorId!!, - isAuth = fcmEvent.isAuth ?: false, - container = fcmEvent.container - ) - - for (tokens in pushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = fcmEvent.container, - contentId = fcmEvent.contentId - ) - } - } + val pushTokens = memberRepository.getUploadContentNotificationRecipientPushTokens( + creatorId = fcmEvent.creatorId!!, + isAuth = fcmEvent.isAuth ?: false + ) + sendPush(pushTokens, fcmEvent, contentId = fcmEvent.contentId) } FcmEventType.SEND_MESSAGE -> { - val response = memberRepository.getMessageRecipientPushToken(messageId = fcmEvent.messageId!!) - - if (response != null) { - pushService.send( - tokens = listOf(response.pushToken), - title = fcmEvent.title, - message = fcmEvent.message, - container = response.container, - messageId = fcmEvent.messageId - ) + val pushToken = memberRepository.getMessageRecipientPushToken(messageId = fcmEvent.messageId!!) + if (pushToken != null) { + sendPush(listOf(pushToken), fcmEvent, messageId = fcmEvent.messageId) } } FcmEventType.CHANGE_NOTICE -> { if (fcmEvent.creatorId != null) { - val pushTokenList = memberRepository.getChangeNoticeRecipientPushTokens(fcmEvent.creatorId) - - val iosPushTokens = pushTokenList["ios"] - val aosPushToken = pushTokenList["aos"] - - if (iosPushTokens != null) { - for (tokens in iosPushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "ios", - creatorId = fcmEvent.creatorId - ) - } - } - - if (aosPushToken != null) { - for (tokens in aosPushToken) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "aos", - creatorId = fcmEvent.creatorId - ) - } - } + val pushTokens = memberRepository.getChangeNoticeRecipientPushTokens(fcmEvent.creatorId) + sendPush(pushTokens, fcmEvent, creatorId = fcmEvent.creatorId) } } FcmEventType.CREATE_CONTENT_COMMENT -> { if (fcmEvent.myMemberId != null && fcmEvent.contentId != null) { - val response = contentCommentRepository.findPushTokenByContentIdAndCommentParentIdMyMemberId( + val pushTokens = contentCommentRepository.findPushTokenByContentIdAndCommentParentIdMyMemberId( contentId = fcmEvent.contentId, commentParentId = fcmEvent.commentParentId, myMemberId = fcmEvent.myMemberId ) - - val iosPushTokens = response - .asSequence() - .distinct() - .filter { it.pushToken.isNotBlank() } - .filter { it.container == "ios" } - .map { it.pushToken } - .toList() - - val aosPushTokens = response - .asSequence() - .distinct() - .filter { it.pushToken.isNotBlank() } - .filter { it.container == "aos" } - .map { it.pushToken } - .toList() - - if (iosPushTokens.isNotEmpty()) { - pushService.send( - tokens = iosPushTokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "ios", - contentId = fcmEvent.contentId - ) - } - - if (aosPushTokens.isNotEmpty()) { - pushService.send( - tokens = aosPushTokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "aos", - contentId = fcmEvent.contentId - ) - } + sendPush(pushTokens, fcmEvent, contentId = fcmEvent.contentId) } } FcmEventType.IN_PROGRESS_AUDITION -> { if (fcmEvent.auditionId != null && fcmEvent.auditionId > 0) { - val pushTokenList = memberRepository.getAuditionNoticeRecipientPushTokens( + val pushTokens = memberRepository.getAuditionNoticeRecipientPushTokens( isAuth = fcmEvent.isAuth ?: false ) - - val iosPushTokens = pushTokenList["ios"] - val aosPushToken = pushTokenList["aos"] - - if (iosPushTokens != null) { - for (tokens in iosPushTokens) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "ios", - auditionId = fcmEvent.auditionId - ) - } - } - - if (aosPushToken != null) { - for (tokens in aosPushToken) { - pushService.send( - tokens = tokens, - title = fcmEvent.title, - message = fcmEvent.message, - container = "aos", - auditionId = fcmEvent.auditionId - ) - } - } + sendPush(pushTokens, fcmEvent, auditionId = fcmEvent.auditionId) } } } } + + private fun sendPush( + pushTokens: List, + fcmEvent: FcmEvent, + roomId: Long? = null, + contentId: Long? = null, + messageId: Long? = null, + creatorId: Long? = null, + auditionId: Long? = null + ) { + val tokensByLang = pushTokens.groupBy { it.languageCode } + + for ((langCode, tokens) in tokensByLang) { + val lang = Lang.fromAcceptLanguage(langCode) + val title = translate(fcmEvent.titleKey, fcmEvent.title, lang, fcmEvent.args) + val message = translate(fcmEvent.messageKey, fcmEvent.message, lang, fcmEvent.args) + + val tokensByOS = tokens.groupBy { it.deviceType } + for ((os, osTokens) in tokensByOS) { + osTokens.map { it.token }.distinct().chunked(500).forEach { batch -> + pushService.send( + tokens = batch, + title = title, + message = message, + container = os, + roomId = roomId ?: fcmEvent.roomId, + contentId = contentId ?: fcmEvent.contentId, + messageId = messageId ?: fcmEvent.messageId, + creatorId = creatorId ?: fcmEvent.creatorId, + auditionId = auditionId ?: fcmEvent.auditionId + ) + } + } + } + } + + private fun translate(key: String?, default: String, lang: Lang, args: List): String { + if (key == null) return default + val template = messageSource.getMessage(key, lang) ?: return default + return String.format(template, *args.toTypedArray()) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/GetMessageRecipientPushTokenResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/GetMessageRecipientPushTokenResponse.kt deleted file mode 100644 index e20dd2e5..00000000 --- a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/GetMessageRecipientPushTokenResponse.kt +++ /dev/null @@ -1,8 +0,0 @@ -package kr.co.vividnext.sodalive.fcm - -import com.querydsl.core.annotations.QueryProjection - -data class GetMessageRecipientPushTokenResponse @QueryProjection constructor( - val pushToken: String, - val container: String -) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt index f442b696..0b5f59b5 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt @@ -10,7 +10,8 @@ import javax.persistence.ManyToOne @Entity data class PushToken( var token: String, - var deviceType: String + var deviceType: String, + var languageCode: String? = null ) : BaseEntity() { @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "member_id", nullable = true) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenInfo.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenInfo.kt new file mode 100644 index 00000000..552ad56a --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenInfo.kt @@ -0,0 +1,9 @@ +package kr.co.vividnext.sodalive.fcm + +import com.querydsl.core.annotations.QueryProjection + +data class PushTokenInfo @QueryProjection constructor( + val token: String, + val deviceType: String, + val languageCode: String +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenService.kt index 1de78b97..5384508f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushTokenService.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.fcm +import kr.co.vividnext.sodalive.i18n.LangContext import kr.co.vividnext.sodalive.member.MemberRepository import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service @@ -8,7 +9,8 @@ import org.springframework.transaction.annotation.Transactional @Service class PushTokenService( private val repository: PushTokenRepository, - private val memberRepository: MemberRepository + private val memberRepository: MemberRepository, + private val langContext: LangContext ) { @Transactional fun registerToken(memberId: Long, token: String, deviceType: String) { @@ -20,8 +22,9 @@ class PushTokenService( existing.member = member existing.token = token existing.deviceType = deviceType + existing.languageCode = langContext.lang.code } else { - val newToken = PushToken(token, deviceType) + val newToken = PushToken(token, deviceType, langContext.lang.code) newToken.member = member repository.save(newToken) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index 00fdbe1f..0d6a9fd7 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -405,35 +405,20 @@ class LiveRoomService( } } - val createdMessage = if (createdRoom.channelName != null) { - formatMessage("live.room.fcm.message.started", createdRoom.title) - } else { - formatMessage("live.room.fcm.message.reserved", createdRoom.title) - } - applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.CREATE_LIVE, title = createdRoom.member!!.nickname, - message = createdMessage, + messageKey = if (createdRoom.channelName != null) { + "live.room.fcm.message.started" + } else { + "live.room.fcm.message.reserved" + }, + args = listOf(createdRoom.title), isAuth = createdRoom.isAdult, isAvailableJoinCreator = createdRoom.isAvailableJoinCreator, roomId = createdRoom.id, - creatorId = createdRoom.member!!.id, - container = "ios" - ) - ) - - applicationEventPublisher.publishEvent( - FcmEvent( - type = FcmEventType.CREATE_LIVE, - title = createdRoom.member!!.nickname, - message = createdMessage, - isAuth = createdRoom.isAdult, - isAvailableJoinCreator = createdRoom.isAvailableJoinCreator, - roomId = createdRoom.id, - creatorId = createdRoom.member!!.id, - container = "aos" + creatorId = createdRoom.member!!.id ) ) @@ -580,30 +565,16 @@ class LiveRoomService( room.beginDateTime = nowDateTime - val startedMessage = formatMessage("live.room.fcm.message.started_now", room.title) applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.START_LIVE, title = room.member!!.nickname, - message = startedMessage, + messageKey = "live.room.fcm.message.started", + args = listOf(room.title), isAuth = room.isAdult, isAvailableJoinCreator = room.isAvailableJoinCreator, roomId = room.id, - creatorId = room.member!!.id, - container = "ios" - ) - ) - - applicationEventPublisher.publishEvent( - FcmEvent( - type = FcmEventType.START_LIVE, - title = room.member!!.nickname, - message = startedMessage, - isAuth = room.isAdult, - isAvailableJoinCreator = room.isAvailableJoinCreator, - roomId = room.id, - creatorId = room.member!!.id, - container = "aos" + creatorId = room.member!!.id ) ) } @@ -660,16 +631,17 @@ class LiveRoomService( } } - val pushTokenListMap = memberRepository.getPushTokenFromReservationList(request.roomId) + val pushTokens = memberRepository.getPushTokenFromReservationList(request.roomId) + reservationRepository.cancelReservation(roomId = room.id!!) - val cancelMessage = formatMessage("live.room.fcm.message.canceled", room.title) applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.CANCEL_LIVE, title = room.member!!.nickname, - message = cancelMessage, - recipientsMap = pushTokenListMap + messageKey = "live.room.fcm.message.canceled", + args = listOf(room.title), + pushTokens = pushTokens ) ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt index 2eb20ef3..9487cdf2 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/MemberRepository.kt @@ -1,9 +1,9 @@ package kr.co.vividnext.sodalive.member import com.querydsl.jpa.impl.JPAQueryFactory -import kr.co.vividnext.sodalive.fcm.GetMessageRecipientPushTokenResponse -import kr.co.vividnext.sodalive.fcm.QGetMessageRecipientPushTokenResponse +import kr.co.vividnext.sodalive.fcm.PushTokenInfo import kr.co.vividnext.sodalive.fcm.QPushToken.pushToken +import kr.co.vividnext.sodalive.fcm.QPushTokenInfo import kr.co.vividnext.sodalive.live.reservation.QLiveReservation.liveReservation import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom import kr.co.vividnext.sodalive.member.QMember.member @@ -29,36 +29,33 @@ interface MemberRepository : JpaRepository, MemberQueryRepository interface MemberQueryRepository { fun findByNicknameAndOtherCondition(nickname: String, member: Member): List fun findCreatorByIdOrNull(memberId: Long): Member? - fun getAllRecipientPushTokens(isAuth: Boolean?, container: String): List> + fun getAllRecipientPushTokens(isAuth: Boolean?): List fun getCreateLiveRoomNotificationRecipientPushTokens( creatorId: Long, isAuth: Boolean, - isAvailableJoinCreator: Boolean, - container: String - ): List> + isAvailableJoinCreator: Boolean + ): List fun getStartLiveRoomNotificationRecipientPushTokens( creatorId: Long, roomId: Long, isAuth: Boolean, - isAvailableJoinCreator: Boolean, - container: String - ): List> + isAvailableJoinCreator: Boolean + ): List fun getUploadContentNotificationRecipientPushTokens( creatorId: Long, - isAuth: Boolean, - container: String - ): List> + isAuth: Boolean + ): List - fun getMessageRecipientPushToken(messageId: Long): GetMessageRecipientPushTokenResponse? - fun getIndividualRecipientPushTokens(recipients: List, isAuth: Boolean?): Map>> + fun getMessageRecipientPushToken(messageId: Long): PushTokenInfo? + fun getIndividualRecipientPushTokens(recipients: List, isAuth: Boolean?): List fun getChangeNicknamePrice(memberId: Long): GetChangeNicknamePriceResponse fun getMemberByEmail(email: String): Member? - fun getChangeNoticeRecipientPushTokens(creatorId: Long): Map>> - fun getPushTokenFromReservationList(roomId: Long): Map>> - fun getAuditionNoticeRecipientPushTokens(isAuth: Boolean): Map>> + fun getChangeNoticeRecipientPushTokens(creatorId: Long): List + fun getPushTokenFromReservationList(roomId: Long): List + fun getAuditionNoticeRecipientPushTokens(isAuth: Boolean): List fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse @@ -103,10 +100,9 @@ class MemberQueryRepositoryImpl( .fetchFirst() } - override fun getAllRecipientPushTokens(isAuth: Boolean?, container: String): List> { + override fun getAllRecipientPushTokens(isAuth: Boolean?): List { var where = member.isActive.isTrue .and(member.email.notIn("admin@sodalive.net")) - .and(pushToken.deviceType.eq(container)) if (isAuth != null) { where = if (isAuth) { @@ -117,22 +113,25 @@ class MemberQueryRepositoryImpl( } return queryFactory - .select(pushToken.token) + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(member) .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) .where(where) .fetch() - .toSet() - .chunked(500) } override fun getCreateLiveRoomNotificationRecipientPushTokens( creatorId: Long, isAuth: Boolean, - isAvailableJoinCreator: Boolean, - container: String - ): List> { + isAvailableJoinCreator: Boolean + ): List { val member = QMember.member val creator = QMember.member @@ -147,7 +146,6 @@ class MemberQueryRepositoryImpl( ) ) .and(creatorFollowing.isNotify.isTrue) - .and(pushToken.deviceType.eq(container)) .or(member.id.eq(4)) if (isAuth) { @@ -159,7 +157,13 @@ class MemberQueryRepositoryImpl( } return queryFactory - .select(pushToken.token) + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) @@ -168,17 +172,14 @@ class MemberQueryRepositoryImpl( .leftJoin(creatorFollowing.member.auth, auth) .where(where) .fetch() - .toSet() - .chunked(500) } override fun getStartLiveRoomNotificationRecipientPushTokens( creatorId: Long, roomId: Long, isAuth: Boolean, - isAvailableJoinCreator: Boolean, - container: String - ): List> { + isAvailableJoinCreator: Boolean + ): List { val member = QMember.member val creator = QMember.member @@ -193,7 +194,6 @@ class MemberQueryRepositoryImpl( ) ) .and(creatorFollowing.isNotify.isTrue) - .and(pushToken.deviceType.eq(container)) .or(creatorFollowing.member.id.eq(4)) if (isAuth) { @@ -205,7 +205,13 @@ class MemberQueryRepositoryImpl( } val followingMemberPushToken = queryFactory - .select(pushToken.token) + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) @@ -224,14 +230,19 @@ class MemberQueryRepositoryImpl( blockMemberRepository.getBlockedMemberIdList(creatorId) ) ) - .and(pushToken.deviceType.eq(container)) if (isAuth) { where = where.and(auth.isNotNull) } val reservationMemberPushToken = queryFactory - .select(pushToken.token) + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(liveReservation) .innerJoin(liveReservation.member, member) .innerJoin(liveReservation.member.notification, memberNotification) @@ -240,16 +251,13 @@ class MemberQueryRepositoryImpl( .where(where) .fetch() - return (followingMemberPushToken + reservationMemberPushToken) - .toSet() - .chunked(500) + return (followingMemberPushToken + reservationMemberPushToken).distinctBy { it.token } } override fun getUploadContentNotificationRecipientPushTokens( creatorId: Long, - isAuth: Boolean, - container: String - ): List> { + isAuth: Boolean + ): List { val member = QMember.member val creator = QMember.member @@ -263,7 +271,6 @@ class MemberQueryRepositoryImpl( ) ) .and(creatorFollowing.isNotify.isTrue) - .and(pushToken.deviceType.eq(container)) .or(member.id.eq(4)) if (isAuth) { @@ -271,7 +278,13 @@ class MemberQueryRepositoryImpl( } return queryFactory - .select(pushToken.token) + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) @@ -280,16 +293,15 @@ class MemberQueryRepositoryImpl( .leftJoin(member.auth, auth) .where(where) .fetch() - .toSet() - .chunked(500) } - override fun getMessageRecipientPushToken(messageId: Long): GetMessageRecipientPushTokenResponse? { + override fun getMessageRecipientPushToken(messageId: Long): PushTokenInfo? { return queryFactory .select( - QGetMessageRecipientPushTokenResponse( + QPushTokenInfo( pushToken.token, - pushToken.deviceType + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") ) ) .from(message) @@ -306,7 +318,7 @@ class MemberQueryRepositoryImpl( override fun getIndividualRecipientPushTokens( recipients: List, isAuth: Boolean? - ): Map>> { + ): List { var where = member.isActive.isTrue .and(member.email.notIn("admin@sodalive.net")) .and(member.id.`in`(*recipients.toTypedArray())) @@ -319,27 +331,19 @@ class MemberQueryRepositoryImpl( } } - val aosPushTokens = queryFactory - .select(pushToken.token) + return queryFactory + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(member) .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) - .where(where.and(pushToken.deviceType.eq("aos"))) + .where(where) .fetch() - .toSet() - .chunked(500) - - val iosPushTokens = queryFactory - .select(pushToken.token) - .from(member) - .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) - .leftJoin(member.auth, auth) - .where(where.and(pushToken.deviceType.eq("ios"))) - .fetch() - .toSet() - .chunked(500) - - return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens) } override fun getChangeNicknamePrice(memberId: Long): GetChangeNicknamePriceResponse { @@ -366,7 +370,7 @@ class MemberQueryRepositoryImpl( .fetchOne() } - override fun getChangeNoticeRecipientPushTokens(creatorId: Long): Map>> { + override fun getChangeNoticeRecipientPushTokens(creatorId: Long): List { val member = QMember.member val creator = QMember.member @@ -381,90 +385,63 @@ class MemberQueryRepositoryImpl( ) .and(creatorFollowing.isNotify.isTrue) - val aosPushTokens = queryFactory - .select(pushToken.token) + return queryFactory + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(creatorFollowing) .innerJoin(creatorFollowing.creator, creator) .innerJoin(creatorFollowing.member, member) .innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id)) - .where(where.and(pushToken.deviceType.eq("aos"))) + .where(where) .fetch() - .toSet() - .chunked(500) - - val iosPushTokens = queryFactory - .select(pushToken.token) - .from(creatorFollowing) - .innerJoin(creatorFollowing.creator, creator) - .innerJoin(creatorFollowing.member, member) - .innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id)) - .where(where.and(pushToken.deviceType.eq("ios"))) - .fetch() - .toSet() - .chunked(500) - - return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens) } - override fun getPushTokenFromReservationList(roomId: Long): Map>> { + override fun getPushTokenFromReservationList(roomId: Long): List { val where = liveRoom.id.eq(roomId) .and(liveReservation.isActive.isTrue) - val aosPushTokens = queryFactory - .select(pushToken.token) + return queryFactory + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(liveReservation) .innerJoin(liveReservation.room, liveRoom) .innerJoin(liveReservation.member, member) .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) - .where(where.and(pushToken.deviceType.eq("aos"))) + .where(where) .fetch() - .toSet() - .chunked(500) - - val iosPushTokens = queryFactory - .select(pushToken.token) - .from(liveReservation) - .innerJoin(liveReservation.room, liveRoom) - .innerJoin(liveReservation.member, member) - .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) - .where(where.and(pushToken.deviceType.eq("ios"))) - .fetch() - .toSet() - .chunked(500) - - return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens) } - override fun getAuditionNoticeRecipientPushTokens(isAuth: Boolean): Map>> { + override fun getAuditionNoticeRecipientPushTokens(isAuth: Boolean): List { var where = memberNotification.audition.isTrue if (isAuth) { where = where.and(auth.isNotNull) } - val aosPushTokens = queryFactory - .select(pushToken.token) + return queryFactory + .select( + QPushTokenInfo( + pushToken.token, + pushToken.deviceType, + pushToken.languageCode.coalesce("ko") + ) + ) .from(member) .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) .leftJoin(member.auth, auth) .leftJoin(memberNotification).on(memberNotification.member.id.eq(member.id)) - .where(where.and(pushToken.deviceType.eq("aos"))) + .where(where) .fetch() - .toSet() - .chunked(500) - - val iosPushTokens = queryFactory - .select(pushToken.token) - .from(member) - .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) - .leftJoin(member.auth, auth) - .leftJoin(memberNotification).on(memberNotification.member.id.eq(member.id)) - .where(where.and(pushToken.deviceType.eq("ios"))) - .fetch() - .toSet() - .chunked(500) - - return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens) } override fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/message/MessageService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/message/MessageService.kt index c968ad61..7a486cec 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/message/MessageService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/message/MessageService.kt @@ -72,11 +72,9 @@ class MessageService( applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.SEND_MESSAGE, - title = messageSource.getMessage("message.fcm.title", langContext.lang).orEmpty(), - message = run { - val messageTemplate = messageSource.getMessage("message.fcm.text_received", langContext.lang).orEmpty() - String.format(messageTemplate, sender.nickname) - }, + titleKey = "message.fcm.title", + messageKey = "message.fcm.text_received", + args = listOf(sender.nickname), messageId = message.id ) ) @@ -147,11 +145,9 @@ class MessageService( applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.SEND_MESSAGE, - title = messageSource.getMessage("message.fcm.title", langContext.lang).orEmpty(), - message = run { - val messageTemplate = messageSource.getMessage("message.fcm.voice_received", langContext.lang).orEmpty() - String.format(messageTemplate, sender.nickname) - }, + titleKey = "message.fcm.title", + messageKey = "message.fcm.voice_received", + args = listOf(sender.nickname), messageId = message.id ) ) -- 2.49.1