푸시메시지 기능 추가 - 전체, 개별, 라이브 생성, 라이브 시작, 메시지 전송, 콘텐츠 업로드
This commit is contained in:
parent
771dbeced0
commit
705bf0b6b2
|
@ -55,6 +55,9 @@ dependencies {
|
||||||
implementation("org.json:json:20230227")
|
implementation("org.json:json:20230227")
|
||||||
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
implementation("com.google.code.findbugs:jsr305:3.0.2")
|
||||||
|
|
||||||
|
// firebase admin sdk
|
||||||
|
implementation("com.google.firebase:firebase-admin:9.2.0")
|
||||||
|
|
||||||
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
developmentOnly("org.springframework.boot:spring-boot-devtools")
|
||||||
runtimeOnly("com.h2database:h2")
|
runtimeOnly("com.h2database:h2")
|
||||||
runtimeOnly("com.mysql:mysql-connector-j")
|
runtimeOnly("com.mysql:mysql-connector-j")
|
||||||
|
|
|
@ -0,0 +1,25 @@
|
||||||
|
package kr.co.vividnext.sodalive.configs
|
||||||
|
|
||||||
|
import com.google.auth.oauth2.GoogleCredentials
|
||||||
|
import com.google.firebase.FirebaseApp
|
||||||
|
import com.google.firebase.FirebaseOptions
|
||||||
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.context.annotation.Configuration
|
||||||
|
import java.io.FileInputStream
|
||||||
|
import javax.annotation.PostConstruct
|
||||||
|
|
||||||
|
@Configuration
|
||||||
|
class FirebaseConfig(
|
||||||
|
@Value("\${firebase.secret-key-path}")
|
||||||
|
private val secretKeyPath: String
|
||||||
|
) {
|
||||||
|
|
||||||
|
@PostConstruct
|
||||||
|
fun initialize() {
|
||||||
|
FirebaseOptions.builder()
|
||||||
|
.setCredentials(GoogleCredentials.fromStream(FileInputStream(secretKeyPath)))
|
||||||
|
.build()
|
||||||
|
|
||||||
|
FirebaseApp.initializeApp()
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,10 +17,13 @@ import kr.co.vividnext.sodalive.content.order.OrderRepository
|
||||||
import kr.co.vividnext.sodalive.content.order.OrderType
|
import kr.co.vividnext.sodalive.content.order.OrderType
|
||||||
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository
|
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
|
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
|
||||||
|
import kr.co.vividnext.sodalive.fcm.FcmEvent
|
||||||
|
import kr.co.vividnext.sodalive.fcm.FcmEventType
|
||||||
import kr.co.vividnext.sodalive.member.Member
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||||
import kr.co.vividnext.sodalive.utils.generateFileName
|
import kr.co.vividnext.sodalive.utils.generateFileName
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
import org.springframework.transaction.annotation.Transactional
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
@ -45,6 +48,7 @@ class AudioContentService(
|
||||||
private val s3Uploader: S3Uploader,
|
private val s3Uploader: S3Uploader,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val audioContentCloudFront: AudioContentCloudFront,
|
private val audioContentCloudFront: AudioContentCloudFront,
|
||||||
|
private val applicationEventPublisher: ApplicationEventPublisher,
|
||||||
|
|
||||||
@Value("\${cloud.aws.s3.content-bucket}")
|
@Value("\${cloud.aws.s3.content-bucket}")
|
||||||
private val audioContentBucket: String,
|
private val audioContentBucket: String,
|
||||||
|
@ -260,6 +264,17 @@ class AudioContentService(
|
||||||
audioContent.isActive = true
|
audioContent.isActive = true
|
||||||
audioContent.content = content
|
audioContent.content = content
|
||||||
audioContent.duration = duration
|
audioContent.duration = duration
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.UPLOAD_CONTENT,
|
||||||
|
title = audioContent.member!!.nickname,
|
||||||
|
message = "콘텐츠를 업로드 하였습니다. - ${audioContent.title}",
|
||||||
|
isAuth = audioContent.isAdult,
|
||||||
|
contentId = contentId,
|
||||||
|
creatorId = audioContent.member!!.id
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getDetail(id: Long, member: Member, timezone: String): GetAudioContentDetailResponse {
|
fun getDetail(id: Long, member: Member, timezone: String): GetAudioContentDetailResponse {
|
||||||
|
|
|
@ -0,0 +1,47 @@
|
||||||
|
package kr.co.vividnext.sodalive.fcm
|
||||||
|
|
||||||
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
|
import org.springframework.security.access.prepost.PreAuthorize
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/push")
|
||||||
|
@PreAuthorize("hasRole('ADMIN')")
|
||||||
|
class FcmController(private val applicationEventPublisher: ApplicationEventPublisher) {
|
||||||
|
@PostMapping
|
||||||
|
fun send(
|
||||||
|
@RequestBody request: PushRequest
|
||||||
|
) = run {
|
||||||
|
if (request.memberIds.isNotEmpty()) {
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.INDIVIDUAL,
|
||||||
|
title = request.title,
|
||||||
|
message = request.message,
|
||||||
|
recipients = request.memberIds
|
||||||
|
)
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.ALL,
|
||||||
|
title = request.title,
|
||||||
|
message = request.message,
|
||||||
|
container = "ios"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.ALL,
|
||||||
|
title = request.title,
|
||||||
|
message = request.message,
|
||||||
|
container = "aos"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
package kr.co.vividnext.sodalive.fcm
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||||
|
import org.springframework.context.event.EventListener
|
||||||
|
import org.springframework.stereotype.Component
|
||||||
|
|
||||||
|
enum class FcmEventType {
|
||||||
|
ALL, INDIVIDUAL, CREATE_LIVE, START_LIVE, UPLOAD_CONTENT, SEND_MESSAGE
|
||||||
|
}
|
||||||
|
|
||||||
|
class FcmEvent(
|
||||||
|
val type: FcmEventType,
|
||||||
|
val title: String,
|
||||||
|
val message: String,
|
||||||
|
val container: String = "",
|
||||||
|
val recipients: List<Long> = listOf(),
|
||||||
|
val isAuth: Boolean = false,
|
||||||
|
val roomId: Long? = null,
|
||||||
|
val contentId: Long? = null,
|
||||||
|
val messageId: Long? = null,
|
||||||
|
val creatorId: Long? = null
|
||||||
|
)
|
||||||
|
|
||||||
|
@Component
|
||||||
|
class FcmSendListener(
|
||||||
|
private val pushService: FcmService,
|
||||||
|
private val memberRepository: MemberRepository
|
||||||
|
) {
|
||||||
|
@EventListener
|
||||||
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FcmEventType.INDIVIDUAL -> {
|
||||||
|
if (fcmEvent.recipients.isNotEmpty()) {
|
||||||
|
val pushTokens = memberRepository.getIndividualRecipientPushTokens(
|
||||||
|
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 = fcmEvent.container
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (aosPushToken != null) {
|
||||||
|
for (tokens in aosPushToken) {
|
||||||
|
pushService.send(
|
||||||
|
tokens = tokens,
|
||||||
|
title = fcmEvent.title,
|
||||||
|
message = fcmEvent.message,
|
||||||
|
container = fcmEvent.container
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FcmEventType.CREATE_LIVE, FcmEventType.START_LIVE -> {
|
||||||
|
if (fcmEvent.container.isNotBlank()) {
|
||||||
|
val pushTokens = memberRepository.getCreateLiveRoomNotificationRecipientPushTokens(
|
||||||
|
creatorId = fcmEvent.creatorId!!,
|
||||||
|
isAuth = fcmEvent.isAuth,
|
||||||
|
container = fcmEvent.container
|
||||||
|
)
|
||||||
|
|
||||||
|
for (tokens in pushTokens) {
|
||||||
|
pushService.send(
|
||||||
|
tokens = tokens,
|
||||||
|
title = fcmEvent.title,
|
||||||
|
message = fcmEvent.message,
|
||||||
|
container = fcmEvent.container,
|
||||||
|
roomId = fcmEvent.roomId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FcmEventType.UPLOAD_CONTENT -> {
|
||||||
|
if (fcmEvent.container.isNotBlank()) {
|
||||||
|
val pushTokens = memberRepository.getUploadContentNotificationRecipientPushTokens(
|
||||||
|
creatorId = fcmEvent.creatorId!!,
|
||||||
|
isAuth = fcmEvent.isAuth,
|
||||||
|
container = fcmEvent.container
|
||||||
|
)
|
||||||
|
|
||||||
|
for (tokens in pushTokens) {
|
||||||
|
pushService.send(
|
||||||
|
tokens = tokens,
|
||||||
|
title = fcmEvent.title,
|
||||||
|
message = fcmEvent.message,
|
||||||
|
container = fcmEvent.container,
|
||||||
|
contentId = fcmEvent.contentId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
FcmEventType.SEND_MESSAGE -> {
|
||||||
|
val response = memberRepository.getMessageRecipientPushToken(messageId = fcmEvent.messageId!!)
|
||||||
|
|
||||||
|
pushService.send(
|
||||||
|
tokens = listOf(response.pushToken),
|
||||||
|
title = fcmEvent.title,
|
||||||
|
message = fcmEvent.message,
|
||||||
|
container = response.container,
|
||||||
|
messageId = fcmEvent.messageId
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,39 @@
|
||||||
|
package kr.co.vividnext.sodalive.fcm
|
||||||
|
|
||||||
|
import com.google.firebase.messaging.FirebaseMessaging
|
||||||
|
import com.google.firebase.messaging.MulticastMessage
|
||||||
|
import org.springframework.scheduling.annotation.Async
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
|
||||||
|
@Service
|
||||||
|
class FcmService {
|
||||||
|
@Async
|
||||||
|
fun send(
|
||||||
|
tokens: List<String>,
|
||||||
|
title: String,
|
||||||
|
message: String,
|
||||||
|
container: String,
|
||||||
|
roomId: Long? = null,
|
||||||
|
messageId: Long? = null,
|
||||||
|
contentId: Long? = null
|
||||||
|
) {
|
||||||
|
val multicastMessage = MulticastMessage.builder()
|
||||||
|
.putData("title", title)
|
||||||
|
.putData("message", message)
|
||||||
|
.addAllTokens(tokens)
|
||||||
|
|
||||||
|
if (roomId != null) {
|
||||||
|
multicastMessage.putData("room_id", roomId.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (messageId != null) {
|
||||||
|
multicastMessage.putData("message_id", messageId.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
if (contentId != null) {
|
||||||
|
multicastMessage.putData("content_id", contentId.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
FirebaseMessaging.getInstance().sendEachForMulticast(multicastMessage.build())
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
package kr.co.vividnext.sodalive.fcm
|
||||||
|
|
||||||
|
import com.querydsl.core.annotations.QueryProjection
|
||||||
|
|
||||||
|
data class GetMessageRecipientPushTokenResponse @QueryProjection constructor(
|
||||||
|
val pushToken: String,
|
||||||
|
val container: String
|
||||||
|
)
|
|
@ -0,0 +1,7 @@
|
||||||
|
package kr.co.vividnext.sodalive.fcm
|
||||||
|
|
||||||
|
data class PushRequest(
|
||||||
|
val memberIds: List<Long>,
|
||||||
|
val title: String,
|
||||||
|
val message: String
|
||||||
|
)
|
|
@ -19,6 +19,8 @@ import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
|
import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
|
||||||
import kr.co.vividnext.sodalive.extensions.convertLocalDateTime
|
import kr.co.vividnext.sodalive.extensions.convertLocalDateTime
|
||||||
|
import kr.co.vividnext.sodalive.fcm.FcmEvent
|
||||||
|
import kr.co.vividnext.sodalive.fcm.FcmEventType
|
||||||
import kr.co.vividnext.sodalive.live.reservation.LiveReservationRepository
|
import kr.co.vividnext.sodalive.live.reservation.LiveReservationRepository
|
||||||
import kr.co.vividnext.sodalive.live.room.cancel.CancelLiveRequest
|
import kr.co.vividnext.sodalive.live.room.cancel.CancelLiveRequest
|
||||||
import kr.co.vividnext.sodalive.live.room.cancel.LiveRoomCancel
|
import kr.co.vividnext.sodalive.live.room.cancel.LiveRoomCancel
|
||||||
|
@ -45,6 +47,7 @@ import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||||
import kr.co.vividnext.sodalive.utils.generateFileName
|
import kr.co.vividnext.sodalive.utils.generateFileName
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
import org.springframework.data.domain.Pageable
|
import org.springframework.data.domain.Pageable
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -66,6 +69,7 @@ class LiveRoomService(
|
||||||
private val kickOutService: LiveRoomKickOutService,
|
private val kickOutService: LiveRoomKickOutService,
|
||||||
private val blockMemberRepository: BlockMemberRepository,
|
private val blockMemberRepository: BlockMemberRepository,
|
||||||
|
|
||||||
|
private val applicationEventPublisher: ApplicationEventPublisher,
|
||||||
private val useCanCalculateRepository: UseCanCalculateRepository,
|
private val useCanCalculateRepository: UseCanCalculateRepository,
|
||||||
private val reservationRepository: LiveReservationRepository,
|
private val reservationRepository: LiveReservationRepository,
|
||||||
private val explorerQueryRepository: ExplorerQueryRepository,
|
private val explorerQueryRepository: ExplorerQueryRepository,
|
||||||
|
@ -231,6 +235,21 @@ class LiveRoomService(
|
||||||
room.bgImage = request.coverImageUrl
|
room.bgImage = request.coverImageUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.CREATE_LIVE,
|
||||||
|
title = createdRoom.member!!.nickname,
|
||||||
|
message = if (createdRoom.channelName != null) {
|
||||||
|
"라이브를 시작했습니다. - ${createdRoom.title}"
|
||||||
|
} else {
|
||||||
|
"라이브를 개설했습니다. - ${createdRoom.title}"
|
||||||
|
},
|
||||||
|
isAuth = createdRoom.isAdult,
|
||||||
|
roomId = createdRoom.id,
|
||||||
|
creatorId = createdRoom.member!!.id
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
return CreateLiveRoomResponse(createdRoom.id, createdRoom.channelName)
|
return CreateLiveRoomResponse(createdRoom.id, createdRoom.channelName)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -351,6 +370,17 @@ class LiveRoomService(
|
||||||
room.channelName = "SODA_LIVE_CHANNEL_" +
|
room.channelName = "SODA_LIVE_CHANNEL_" +
|
||||||
"${member.id}_${dateTime.year}_${dateTime.month}_${dateTime.dayOfMonth}_" +
|
"${member.id}_${dateTime.year}_${dateTime.month}_${dateTime.dayOfMonth}_" +
|
||||||
"${dateTime.hour}_${dateTime.minute}"
|
"${dateTime.hour}_${dateTime.minute}"
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.START_LIVE,
|
||||||
|
title = room.member!!.nickname,
|
||||||
|
message = "라이브를 시작했습니다 - ${room.title}",
|
||||||
|
isAuth = room.isAdult,
|
||||||
|
roomId = room.id,
|
||||||
|
creatorId = room.member!!.id
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@Transactional
|
@Transactional
|
||||||
|
|
|
@ -1,7 +1,14 @@
|
||||||
package kr.co.vividnext.sodalive.member
|
package kr.co.vividnext.sodalive.member
|
||||||
|
|
||||||
import com.querydsl.jpa.impl.JPAQueryFactory
|
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.member.QMember.member
|
import kr.co.vividnext.sodalive.member.QMember.member
|
||||||
|
import kr.co.vividnext.sodalive.member.auth.QAuth.auth
|
||||||
|
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||||
|
import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing
|
||||||
|
import kr.co.vividnext.sodalive.member.notification.QMemberNotification.memberNotification
|
||||||
|
import kr.co.vividnext.sodalive.message.QMessage.message
|
||||||
import org.springframework.data.jpa.repository.JpaRepository
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
import org.springframework.stereotype.Repository
|
import org.springframework.stereotype.Repository
|
||||||
|
|
||||||
|
@ -15,10 +22,28 @@ interface MemberQueryRepository {
|
||||||
fun findByPushToken(pushToken: String): List<Member>
|
fun findByPushToken(pushToken: String): List<Member>
|
||||||
fun findByNicknameAndOtherCondition(nickname: String, memberId: Long): List<Member>
|
fun findByNicknameAndOtherCondition(nickname: String, memberId: Long): List<Member>
|
||||||
fun findCreatorByIdOrNull(memberId: Long): Member?
|
fun findCreatorByIdOrNull(memberId: Long): Member?
|
||||||
|
fun getAllRecipientPushTokens(isAuth: Boolean, container: String): List<List<String>>
|
||||||
|
fun getCreateLiveRoomNotificationRecipientPushTokens(
|
||||||
|
creatorId: Long,
|
||||||
|
isAuth: Boolean,
|
||||||
|
container: String
|
||||||
|
): List<List<String>>
|
||||||
|
|
||||||
|
fun getUploadContentNotificationRecipientPushTokens(
|
||||||
|
creatorId: Long,
|
||||||
|
isAuth: Boolean,
|
||||||
|
container: String
|
||||||
|
): List<List<String>>
|
||||||
|
|
||||||
|
fun getMessageRecipientPushToken(messageId: Long): GetMessageRecipientPushTokenResponse
|
||||||
|
fun getIndividualRecipientPushTokens(recipients: List<Long>, isAuth: Boolean): Map<String, List<List<String>>>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class MemberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : MemberQueryRepository {
|
class MemberQueryRepositoryImpl(
|
||||||
|
private val queryFactory: JPAQueryFactory,
|
||||||
|
private val blockMemberRepository: BlockMemberRepository
|
||||||
|
) : MemberQueryRepository {
|
||||||
override fun findByPushToken(pushToken: String): List<Member> {
|
override fun findByPushToken(pushToken: String): List<Member> {
|
||||||
return queryFactory
|
return queryFactory
|
||||||
.selectFrom(member)
|
.selectFrom(member)
|
||||||
|
@ -47,4 +72,141 @@ class MemberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Mem
|
||||||
)
|
)
|
||||||
.fetchFirst()
|
.fetchFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getAllRecipientPushTokens(isAuth: Boolean, container: String): List<List<String>> {
|
||||||
|
var where = member.isActive.isTrue
|
||||||
|
.and(member.email.notIn("admin@sodalive.net"))
|
||||||
|
.and(member.container.eq(container))
|
||||||
|
|
||||||
|
if (isAuth) {
|
||||||
|
where = where.and(member.auth.isNotNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryFactory
|
||||||
|
.select(member.pushToken)
|
||||||
|
.from(member)
|
||||||
|
.leftJoin(member.auth, auth)
|
||||||
|
.where(where)
|
||||||
|
.fetch()
|
||||||
|
.toSet()
|
||||||
|
.chunked(500)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getCreateLiveRoomNotificationRecipientPushTokens(
|
||||||
|
creatorId: Long,
|
||||||
|
isAuth: Boolean,
|
||||||
|
container: String
|
||||||
|
): List<List<String>> {
|
||||||
|
val member = QMember.member
|
||||||
|
val creator = QMember.member
|
||||||
|
|
||||||
|
var where = creatorFollowing.isActive.isTrue
|
||||||
|
.and(creator.id.eq(creatorId))
|
||||||
|
.and(member.email.notIn("admin@sodalive.net"))
|
||||||
|
.and(member.container.eq(container))
|
||||||
|
.and(memberNotification.live.isTrue)
|
||||||
|
.and(
|
||||||
|
member.id.notIn(
|
||||||
|
blockMemberRepository.getBlockedMemberList(creatorId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isAuth) {
|
||||||
|
where = where.and(member.auth.isNotNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryFactory
|
||||||
|
.select(member.pushToken)
|
||||||
|
.from(creatorFollowing)
|
||||||
|
.innerJoin(creatorFollowing.creator, creator)
|
||||||
|
.innerJoin(creatorFollowing.member, member)
|
||||||
|
.innerJoin(member.notification, memberNotification)
|
||||||
|
.leftJoin(member.auth, auth)
|
||||||
|
.where(where)
|
||||||
|
.fetch()
|
||||||
|
.toSet()
|
||||||
|
.chunked(500)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getUploadContentNotificationRecipientPushTokens(
|
||||||
|
creatorId: Long,
|
||||||
|
isAuth: Boolean,
|
||||||
|
container: String
|
||||||
|
): List<List<String>> {
|
||||||
|
val member = QMember.member
|
||||||
|
val creator = QMember.member
|
||||||
|
|
||||||
|
var where = creatorFollowing.isActive.isTrue
|
||||||
|
.and(creator.id.eq(creatorId))
|
||||||
|
.and(member.email.notIn("admin@sodalive.net"))
|
||||||
|
.and(member.container.eq(container))
|
||||||
|
.and(memberNotification.uploadContent.isTrue)
|
||||||
|
.and(
|
||||||
|
member.id.notIn(
|
||||||
|
blockMemberRepository.getBlockedMemberList(creatorId)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (isAuth) {
|
||||||
|
where = where.and(member.auth.isNotNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryFactory
|
||||||
|
.select(member.pushToken)
|
||||||
|
.from(creatorFollowing)
|
||||||
|
.innerJoin(creatorFollowing.creator, creator)
|
||||||
|
.innerJoin(creatorFollowing.member, member)
|
||||||
|
.innerJoin(member.notification, memberNotification)
|
||||||
|
.leftJoin(member.auth, auth)
|
||||||
|
.where(where)
|
||||||
|
.fetch()
|
||||||
|
.toSet()
|
||||||
|
.chunked(500)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getMessageRecipientPushToken(messageId: Long): GetMessageRecipientPushTokenResponse {
|
||||||
|
return queryFactory
|
||||||
|
.select(
|
||||||
|
QGetMessageRecipientPushTokenResponse(
|
||||||
|
member.pushToken,
|
||||||
|
member.container
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.from(message)
|
||||||
|
.innerJoin(message.recipient, member)
|
||||||
|
.where(message.id.eq(messageId))
|
||||||
|
.fetchFirst()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getIndividualRecipientPushTokens(
|
||||||
|
recipients: List<Long>,
|
||||||
|
isAuth: Boolean
|
||||||
|
): Map<String, List<List<String>>> {
|
||||||
|
var where = member.isActive.isTrue
|
||||||
|
.and(member.email.notIn("admin@sodalive.net"))
|
||||||
|
|
||||||
|
if (isAuth) {
|
||||||
|
where = where.and(member.auth.isNotNull)
|
||||||
|
}
|
||||||
|
|
||||||
|
val aosPushTokens = queryFactory
|
||||||
|
.select(member.pushToken)
|
||||||
|
.from(member)
|
||||||
|
.leftJoin(member.auth, auth)
|
||||||
|
.where(where.and(member.container.eq("aos")))
|
||||||
|
.fetch()
|
||||||
|
.toSet()
|
||||||
|
.chunked(500)
|
||||||
|
|
||||||
|
val iosPushTokens = queryFactory
|
||||||
|
.select(member.pushToken)
|
||||||
|
.from(member)
|
||||||
|
.leftJoin(member.auth, auth)
|
||||||
|
.where(where.and(member.container.eq("ios")))
|
||||||
|
.fetch()
|
||||||
|
.toSet()
|
||||||
|
.chunked(500)
|
||||||
|
|
||||||
|
return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ interface BlockMemberRepository : JpaRepository<BlockMember, Long>, BlockMemberQ
|
||||||
interface BlockMemberQueryRepository {
|
interface BlockMemberQueryRepository {
|
||||||
fun getBlockAccount(blockedMemberId: Long, memberId: Long): BlockMember?
|
fun getBlockAccount(blockedMemberId: Long, memberId: Long): BlockMember?
|
||||||
fun isBlocked(blockedMemberId: Long, memberId: Long): Boolean
|
fun isBlocked(blockedMemberId: Long, memberId: Long): Boolean
|
||||||
|
fun getBlockedMemberList(creatorId: Long): List<Long>
|
||||||
}
|
}
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
|
@ -39,4 +40,15 @@ class BlockMemberQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
|
||||||
|
|
||||||
return blockedAccount != null
|
return blockedAccount != null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun getBlockedMemberList(creatorId: Long): List<Long> {
|
||||||
|
return queryFactory
|
||||||
|
.select(blockMember.blockedMemberId)
|
||||||
|
.from(blockMember)
|
||||||
|
.where(
|
||||||
|
blockMember.memberId.eq(creatorId)
|
||||||
|
.and(blockMember.isActive.isTrue)
|
||||||
|
)
|
||||||
|
.fetch()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,11 +4,14 @@ import com.amazonaws.services.s3.model.ObjectMetadata
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper
|
import com.fasterxml.jackson.databind.ObjectMapper
|
||||||
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
import kr.co.vividnext.sodalive.aws.s3.S3Uploader
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
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.member.Member
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
import kr.co.vividnext.sodalive.member.MemberRepository
|
import kr.co.vividnext.sodalive.member.MemberRepository
|
||||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
|
||||||
import kr.co.vividnext.sodalive.utils.generateFileName
|
import kr.co.vividnext.sodalive.utils.generateFileName
|
||||||
import org.springframework.beans.factory.annotation.Value
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.context.ApplicationEventPublisher
|
||||||
import org.springframework.data.domain.Pageable
|
import org.springframework.data.domain.Pageable
|
||||||
import org.springframework.data.repository.findByIdOrNull
|
import org.springframework.data.repository.findByIdOrNull
|
||||||
import org.springframework.stereotype.Service
|
import org.springframework.stereotype.Service
|
||||||
|
@ -24,6 +27,7 @@ class MessageService(
|
||||||
private val memberRepository: MemberRepository,
|
private val memberRepository: MemberRepository,
|
||||||
private val blockMemberRepository: BlockMemberRepository,
|
private val blockMemberRepository: BlockMemberRepository,
|
||||||
|
|
||||||
|
private val applicationEventPublisher: ApplicationEventPublisher,
|
||||||
private val objectMapper: ObjectMapper,
|
private val objectMapper: ObjectMapper,
|
||||||
private val s3Uploader: S3Uploader,
|
private val s3Uploader: S3Uploader,
|
||||||
|
|
||||||
|
@ -56,6 +60,15 @@ class MessageService(
|
||||||
message.recipient = recipient
|
message.recipient = recipient
|
||||||
|
|
||||||
repository.save(message)
|
repository.save(message)
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.SEND_MESSAGE,
|
||||||
|
title = "메시지",
|
||||||
|
message = "${sender.nickname}님으로 부터 문자메시지가 도착했습니다.",
|
||||||
|
messageId = message.id
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSentTextMessages(member: Member, pageable: Pageable, timezone: String): GetTextMessageResponse {
|
fun getSentTextMessages(member: Member, pageable: Pageable, timezone: String): GetTextMessageResponse {
|
||||||
|
@ -115,6 +128,15 @@ class MessageService(
|
||||||
)
|
)
|
||||||
|
|
||||||
message.voiceMessage = messagePath
|
message.voiceMessage = messagePath
|
||||||
|
|
||||||
|
applicationEventPublisher.publishEvent(
|
||||||
|
FcmEvent(
|
||||||
|
type = FcmEventType.SEND_MESSAGE,
|
||||||
|
title = "메시지",
|
||||||
|
message = "${sender.nickname}님으로 부터 음성메시지가 도착했습니다.",
|
||||||
|
messageId = message.id
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getSentVoiceMessages(member: Member, pageable: Pageable, timezone: String): GetVoiceMessageResponse {
|
fun getSentVoiceMessages(member: Member, pageable: Pageable, timezone: String): GetVoiceMessageResponse {
|
||||||
|
|
|
@ -20,6 +20,9 @@ agora:
|
||||||
appId: ${AGORA_APP_ID}
|
appId: ${AGORA_APP_ID}
|
||||||
appCertificate: ${AGORA_APP_CERTIFICATE}
|
appCertificate: ${AGORA_APP_CERTIFICATE}
|
||||||
|
|
||||||
|
firebase:
|
||||||
|
secretKeyPath: ${GOOGLE_APPLICATION_CREDENTIALS}
|
||||||
|
|
||||||
cloud:
|
cloud:
|
||||||
aws:
|
aws:
|
||||||
credentials:
|
credentials:
|
||||||
|
|
Loading…
Reference in New Issue