feat: 푸시 토큰 - 한 사람이 여러개의 디바이스로 로그인 해도 모든 푸시 토큰이 기록되어 있어서 모든 디바이스에 푸시가 가도록 수정

This commit is contained in:
2025-04-28 21:40:20 +09:00
parent 73edc0515f
commit 8a924bd5be
7 changed files with 172 additions and 65 deletions

View File

@@ -3,6 +3,7 @@ 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.QPushToken.pushToken
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
@@ -26,7 +27,6 @@ interface MemberRepository : JpaRepository<Member, Long>, MemberQueryRepository
}
interface MemberQueryRepository {
fun findByPushToken(pushToken: String): List<Member>
fun findByNicknameAndOtherCondition(nickname: String, member: Member): List<Member>
fun findCreatorByIdOrNull(memberId: Long): Member?
fun getAllRecipientPushTokens(isAuth: Boolean?, container: String): List<List<String>>
@@ -74,13 +74,6 @@ class MemberQueryRepositoryImpl(
@Value("\${cloud.aws.cloud-front.host}")
private val cloudFrontHost: String
) : MemberQueryRepository {
override fun findByPushToken(pushToken: String): List<Member> {
return queryFactory
.selectFrom(member)
.where(member.pushToken.eq(pushToken))
.fetch()
}
override fun findByNicknameAndOtherCondition(nickname: String, member: Member): List<Member> {
var where = QMember.member.nickname.containsIgnoreCase(nickname)
.and(QMember.member.id.ne(member.id))
@@ -111,8 +104,7 @@ class MemberQueryRepositoryImpl(
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))
.and(member.pushToken.isNotNull)
.and(pushToken.deviceType.eq(container))
if (isAuth != null) {
where = if (isAuth) {
@@ -123,8 +115,9 @@ class MemberQueryRepositoryImpl(
}
return queryFactory
.select(member.pushToken)
.select(pushToken.token)
.from(member)
.innerJoin(pushToken).on(member.id.eq(pushToken.member.id))
.leftJoin(member.auth, auth)
.where(where)
.fetch()
@@ -142,18 +135,18 @@ class MemberQueryRepositoryImpl(
val creator = QMember.member
var where = creatorFollowing.isActive.isTrue
.and(creatorFollowing.member.isActive.isTrue)
.and(creatorFollowing.creator.id.eq(creatorId))
.and(creatorFollowing.member.notification.live.isTrue)
.and(creatorFollowing.member.container.eq(container))
.and(creatorFollowing.member.email.notIn("admin@sodalive.net"))
.and(
creatorFollowing.member.id.notIn(
blockMemberRepository.getBlockedMemberIdList(creatorId)
)
)
.and(creatorFollowing.member.pushToken.isNotNull)
.and(creatorFollowing.isNotify.isTrue)
.or(member.id.eq(4).and(member.pushToken.isNotNull))
.and(pushToken.deviceType.eq(container))
.or(member.id.eq(4))
if (isAuth) {
where = where.and(auth.isNotNull)
@@ -164,11 +157,12 @@ class MemberQueryRepositoryImpl(
}
return queryFactory
.select(creatorFollowing.member.pushToken)
.select(pushToken.token)
.from(creatorFollowing)
.innerJoin(creatorFollowing.creator, creator)
.innerJoin(creatorFollowing.member, member)
.innerJoin(creatorFollowing.member.notification, memberNotification)
.innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id))
.leftJoin(creatorFollowing.member.auth, auth)
.where(where)
.fetch()
@@ -187,18 +181,18 @@ class MemberQueryRepositoryImpl(
val creator = QMember.member
var where = creatorFollowing.isActive.isTrue
.and(creatorFollowing.member.isActive.isTrue)
.and(creatorFollowing.creator.id.eq(creatorId))
.and(creatorFollowing.member.notification.live.isTrue)
.and(creatorFollowing.member.container.eq(container))
.and(creatorFollowing.member.email.notIn("admin@sodalive.net"))
.and(
creatorFollowing.member.id.notIn(
blockMemberRepository.getBlockedMemberIdList(creatorId)
)
)
.and(creatorFollowing.member.pushToken.isNotNull)
.and(creatorFollowing.isNotify.isTrue)
.or(creatorFollowing.member.id.eq(4).and(member.pushToken.isNotNull))
.and(pushToken.deviceType.eq(container))
.or(creatorFollowing.member.id.eq(4))
if (isAuth) {
where = where.and(auth.isNotNull)
@@ -209,36 +203,37 @@ class MemberQueryRepositoryImpl(
}
val followingMemberPushToken = queryFactory
.select(creatorFollowing.member.pushToken)
.select(pushToken.token)
.from(creatorFollowing)
.innerJoin(creatorFollowing.creator, creator)
.innerJoin(creatorFollowing.member, member)
.innerJoin(creatorFollowing.member.notification, memberNotification)
.innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id))
.leftJoin(creatorFollowing.member.auth, auth)
.where(where)
.fetch()
where = liveReservation.isActive.isTrue
.and(liveReservation.member.notification.live.isTrue)
.and(liveReservation.member.container.eq(container))
.and(liveReservation.member.email.notIn("admin@sodalive.net"))
.and(liveReservation.member.pushToken.isNotNull)
.and(liveReservation.room.id.eq(roomId))
.and(
liveReservation.member.id.notIn(
blockMemberRepository.getBlockedMemberIdList(creatorId)
)
)
.and(pushToken.deviceType.eq(container))
if (isAuth) {
where = where.and(auth.isNotNull)
}
val reservationMemberPushToken = queryFactory
.select(liveReservation.member.pushToken)
.select(pushToken.token)
.from(liveReservation)
.innerJoin(liveReservation.member, member)
.innerJoin(liveReservation.member.notification, memberNotification)
.innerJoin(pushToken).on(liveReservation.member.id.eq(pushToken.member.id))
.leftJoin(liveReservation.member.auth, auth)
.where(where)
.fetch()
@@ -259,27 +254,27 @@ class MemberQueryRepositoryImpl(
var where = creatorFollowing.isActive.isTrue
.and(creatorFollowing.creator.id.eq(creatorId))
.and(creatorFollowing.member.email.notIn("admin@sodalive.net"))
.and(creatorFollowing.member.container.eq(container))
.and(creatorFollowing.member.notification.uploadContent.isTrue)
.and(
creatorFollowing.member.id.notIn(
blockMemberRepository.getBlockedMemberIdList(creatorId)
)
)
.and(creatorFollowing.member.pushToken.isNotNull)
.and(creatorFollowing.isNotify.isTrue)
.or(member.id.eq(4).and(member.pushToken.isNotNull))
.and(pushToken.deviceType.eq(container))
.or(member.id.eq(4))
if (isAuth) {
where = where.and(auth.isNotNull)
}
return queryFactory
.select(creatorFollowing.member.pushToken)
.select(pushToken.token)
.from(creatorFollowing)
.innerJoin(creatorFollowing.creator, creator)
.innerJoin(creatorFollowing.member, member)
.innerJoin(member.notification, memberNotification)
.innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id))
.leftJoin(member.auth, auth)
.where(where)
.fetch()
@@ -291,16 +286,16 @@ class MemberQueryRepositoryImpl(
return queryFactory
.select(
QGetMessageRecipientPushTokenResponse(
member.pushToken,
member.container
pushToken.token,
pushToken.deviceType
)
)
.from(message)
.innerJoin(message.recipient, member)
.innerJoin(member.notification, memberNotification)
.innerJoin(pushToken).on(member.id.eq(pushToken.member.id))
.where(
message.id.eq(messageId)
.and(member.pushToken.isNotNull)
.and(memberNotification.message.isTrue)
)
.fetchFirst()
@@ -313,7 +308,6 @@ class MemberQueryRepositoryImpl(
var where = member.isActive.isTrue
.and(member.email.notIn("admin@sodalive.net"))
.and(member.id.`in`(*recipients.toTypedArray()))
.and(member.pushToken.isNotNull)
if (isAuth != null) {
where = if (isAuth) {
@@ -324,19 +318,21 @@ class MemberQueryRepositoryImpl(
}
val aosPushTokens = queryFactory
.select(member.pushToken)
.select(pushToken.token)
.from(member)
.innerJoin(pushToken).on(member.id.eq(pushToken.member.id))
.leftJoin(member.auth, auth)
.where(where.and(member.container.eq("aos")))
.where(where.and(pushToken.deviceType.eq("aos")))
.fetch()
.toSet()
.chunked(500)
val iosPushTokens = queryFactory
.select(member.pushToken)
.select(pushToken.token)
.from(member)
.innerJoin(pushToken).on(member.id.eq(pushToken.member.id))
.leftJoin(member.auth, auth)
.where(where.and(member.container.eq("ios")))
.where(where.and(pushToken.deviceType.eq("ios")))
.fetch()
.toSet()
.chunked(500)
@@ -373,6 +369,7 @@ class MemberQueryRepositoryImpl(
val creator = QMember.member
val where = creatorFollowing.isActive.isTrue
.and(creatorFollowing.member.isActive.isTrue)
.and(creatorFollowing.creator.id.eq(creatorId))
.and(creatorFollowing.member.email.notIn("admin@sodalive.net"))
.and(
@@ -380,25 +377,26 @@ class MemberQueryRepositoryImpl(
blockMemberRepository.getBlockedMemberIdList(creatorId)
)
)
.and(creatorFollowing.member.pushToken.isNotNull)
.and(creatorFollowing.isNotify.isTrue)
val aosPushTokens = queryFactory
.select(creatorFollowing.member.pushToken)
.select(pushToken.token)
.from(creatorFollowing)
.innerJoin(creatorFollowing.creator, creator)
.innerJoin(creatorFollowing.member, member)
.where(where.and(member.container.eq("aos")))
.innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id))
.where(where.and(pushToken.deviceType.eq("aos")))
.fetch()
.toSet()
.chunked(500)
val iosPushTokens = queryFactory
.select(creatorFollowing.member.pushToken)
.select(pushToken.token)
.from(creatorFollowing)
.innerJoin(creatorFollowing.creator, creator)
.innerJoin(creatorFollowing.member, member)
.where(where.and(member.container.eq("ios")))
.innerJoin(pushToken).on(creatorFollowing.member.id.eq(pushToken.member.id))
.where(where.and(pushToken.deviceType.eq("ios")))
.fetch()
.toSet()
.chunked(500)
@@ -411,21 +409,22 @@ class MemberQueryRepositoryImpl(
.and(liveReservation.isActive.isTrue)
val aosPushTokens = queryFactory
.select(liveReservation.member.pushToken)
.select(pushToken.token)
.from(liveReservation)
.innerJoin(liveReservation.room, liveRoom)
.innerJoin(liveReservation.member, member)
.where(where.and(member.container.eq("aos")))
.innerJoin(pushToken).on(member.id.eq(pushToken.member.id))
.where(where.and(pushToken.deviceType.eq("aos")))
.fetch()
.toSet()
.chunked(500)
val iosPushTokens = queryFactory
.select(liveReservation.member.pushToken)
.select(pushToken.token)
.from(liveReservation)
.innerJoin(liveReservation.room, liveRoom)
.innerJoin(liveReservation.member, member)
.where(where.and(member.container.eq("ios")))
.where(where.and(pushToken.deviceType.eq("aos")))
.fetch()
.toSet()
.chunked(500)
@@ -435,28 +434,29 @@ class MemberQueryRepositoryImpl(
override fun getAuditionNoticeRecipientPushTokens(isAuth: Boolean): Map<String, List<List<String>>> {
var where = memberNotification.audition.isTrue
.and(member.pushToken.isNotNull)
if (isAuth) {
where = where.and(auth.isNotNull)
}
val aosPushTokens = queryFactory
.select(member.pushToken)
.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(member.container.eq("aos")))
.where(where.and(pushToken.deviceType.eq("aos")))
.fetch()
.toSet()
.chunked(500)
val iosPushTokens = queryFactory
.select(member.pushToken)
.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(member.container.eq("ios")))
.where(where.and(pushToken.deviceType.eq("ios")))
.fetch()
.toSet()
.chunked(500)

View File

@@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.common.ApiResponse
import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.content.order.OrderService
import kr.co.vividnext.sodalive.email.SendEmailService
import kr.co.vividnext.sodalive.fcm.PushTokenService
import kr.co.vividnext.sodalive.jwt.TokenProvider
import kr.co.vividnext.sodalive.live.reservation.LiveReservationRepository
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser
@@ -82,6 +83,7 @@ class MemberService(
private val orderService: OrderService,
private val emailService: SendEmailService,
private val pushTokenService: PushTokenService,
private val canPaymentService: CanPaymentService,
private val nicknameGenerateService: NicknameGenerateService,
private val memberNotificationService: MemberNotificationService,
@@ -127,7 +129,6 @@ class MemberService(
gender = Gender.NONE,
container = request.container
)
member.pushToken = request.pushToken
if (!request.marketingPid.isNullOrBlank()) {
member.activePid = request.marketingPid
@@ -137,6 +138,14 @@ class MemberService(
repository.save(member)
agreeTermsOfServiceAndPrivacyPolicy(member, stipulationTermsOfService, stipulationPrivacyPolicy)
if (request.pushToken != null) {
pushTokenService.registerToken(
memberId = member.id!!,
token = request.pushToken,
deviceType = request.container
)
}
return SignUpResponse(
memberId = member.id!!,
marketingPid = request.marketingPid,
@@ -235,16 +244,11 @@ class MemberService(
@Transactional
fun updatePushToken(memberId: Long, pushToken: String, container: String) {
val existsHavePushTokenMemberList = repository.findByPushToken(pushToken = pushToken)
for (existsHavePushTokenMember in existsHavePushTokenMemberList) {
existsHavePushTokenMember.pushToken = null
}
val member = repository.findByIdOrNull(id = memberId)
?: throw SodaException("로그인 정보를 확인해주세요.")
member.pushToken = pushToken
member.container = container
pushTokenService.registerToken(
memberId = memberId,
token = pushToken,
deviceType = container
)
}
@Transactional
@@ -551,6 +555,7 @@ class MemberService(
?: throw SodaException("로그인 정보를 확인해주세요.")
member.pushToken = null
pushTokenService.logout(memberId = memberId)
val lock = getOrCreateLock(memberId = memberId)
lock.write {
@@ -568,6 +573,7 @@ class MemberService(
?: throw SodaException("로그인 정보를 확인해주세요.")
member.pushToken = null
pushTokenService.logout(memberId = memberId)
val lock = getOrCreateLock(memberId = memberId)
lock.write { tokenRepository.deleteById(memberId) }