test #312
| @@ -4,6 +4,7 @@ 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.QPushToken.pushToken | ||||
| import kr.co.vividnext.sodalive.member.QMember.member | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
| import org.springframework.stereotype.Repository | ||||
| @@ -204,25 +205,27 @@ class AudioContentCommentQueryRepositoryImpl( | ||||
|             queryFactory | ||||
|                 .select( | ||||
|                     QFindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse( | ||||
|                         member.pushToken.coalesce(""), | ||||
|                         member.container | ||||
|                         pushToken.token, | ||||
|                         pushToken.deviceType | ||||
|                     ) | ||||
|                 ) | ||||
|                 .from(audioContentComment) | ||||
|                 .innerJoin(audioContentComment.audioContent, audioContent) | ||||
|                 .innerJoin(audioContentComment.member, member) | ||||
|                 .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) | ||||
|                 .where(where) | ||||
|                 .fetch() | ||||
|         } else { | ||||
|             queryFactory | ||||
|                 .select( | ||||
|                     QFindPushTokenByContentIdAndCommentParentIdMyMemberIdResponse( | ||||
|                         member.pushToken.coalesce(""), | ||||
|                         member.container | ||||
|                         pushToken.token, | ||||
|                         pushToken.deviceType | ||||
|                     ) | ||||
|                 ) | ||||
|                 .from(audioContent) | ||||
|                 .innerJoin(audioContent.member, member) | ||||
|                 .innerJoin(pushToken).on(member.id.eq(pushToken.member.id)) | ||||
|                 .where(where) | ||||
|                 .fetch() | ||||
|         } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.creator.admin.member | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.ApiResponse | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.fcm.PushTokenService | ||||
| import kr.co.vividnext.sodalive.jwt.TokenProvider | ||||
| import kr.co.vividnext.sodalive.member.MemberRepository | ||||
| import kr.co.vividnext.sodalive.member.MemberRole | ||||
| @@ -25,6 +26,8 @@ class CreatorAdminMemberService( | ||||
|     private val tokenProvider: TokenProvider, | ||||
|     private val authenticationManagerBuilder: AuthenticationManagerBuilder, | ||||
|  | ||||
|     private val pushTokenService: PushTokenService, | ||||
|  | ||||
|     @Value("\${cloud.aws.cloud-front.host}") | ||||
|     private val cloudFrontHost: String | ||||
| ) { | ||||
| @@ -44,6 +47,7 @@ class CreatorAdminMemberService( | ||||
|             ?: throw SodaException("로그인 정보를 확인해주세요.") | ||||
|  | ||||
|         member.pushToken = null | ||||
|         pushTokenService.logout(memberId = memberId) | ||||
|  | ||||
|         val lock = getOrCreateLock(memberId = memberId) | ||||
|         lock.write { | ||||
|   | ||||
| @@ -14,7 +14,7 @@ import org.springframework.scheduling.annotation.Async | ||||
| import org.springframework.stereotype.Service | ||||
|  | ||||
| @Service | ||||
| class FcmService { | ||||
| class FcmService(private val pushTokenService: PushTokenService) { | ||||
|     private val logger = LoggerFactory.getLogger(this::class.java) | ||||
|  | ||||
|     @Async | ||||
| @@ -100,7 +100,8 @@ class FcmService { | ||||
|  | ||||
|                     if (exception?.messagingErrorCode == MessagingErrorCode.UNREGISTERED) { | ||||
|                         logger.error("[FCM] ❌ UNREGISTERED → $token") | ||||
|                         // 필요 시 DB에서 삭제 | ||||
|                         // DB에서 삭제 | ||||
|                         pushTokenService.unregisterInvalidToken(token) | ||||
|                     } else { | ||||
|                         logger.error("[FCM] ❌ 실패: $token / ${exception?.messagingErrorCode}") | ||||
|                         failedTokens.add(token) | ||||
| @@ -148,6 +149,8 @@ class FcmService { | ||||
|                 // "registration-token-not-registered" 예외 코드 확인 | ||||
|                 if (e.messagingErrorCode == MessagingErrorCode.UNREGISTERED) { | ||||
|                     logger.error("[FCM] ❌ 실패: 토큰이 등록되지 않음 (등록 해제됨) → 재시도 안함") | ||||
|                     // DB에서 삭제 | ||||
|                     pushTokenService.unregisterInvalidToken(token) | ||||
|                     return | ||||
|                 } | ||||
|  | ||||
|   | ||||
							
								
								
									
										18
									
								
								src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/main/kotlin/kr/co/vividnext/sodalive/fcm/PushToken.kt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,18 @@ | ||||
| package kr.co.vividnext.sodalive.fcm | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import javax.persistence.Entity | ||||
| import javax.persistence.FetchType | ||||
| import javax.persistence.JoinColumn | ||||
| import javax.persistence.ManyToOne | ||||
|  | ||||
| @Entity | ||||
| data class PushToken( | ||||
|     var token: String, | ||||
|     var deviceType: String | ||||
| ) : BaseEntity() { | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "member_id", nullable = true) | ||||
|     var member: Member? = null | ||||
| } | ||||
| @@ -0,0 +1,30 @@ | ||||
| package kr.co.vividnext.sodalive.fcm | ||||
|  | ||||
| import com.querydsl.jpa.impl.JPAQueryFactory | ||||
| import kr.co.vividnext.sodalive.fcm.QPushToken.pushToken | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
|  | ||||
| interface PushTokenRepository : JpaRepository<PushToken, Long>, PushTokenQueryRepository | ||||
|  | ||||
| interface PushTokenQueryRepository { | ||||
|     fun findByToken(token: String): PushToken? | ||||
|     fun findByMemberId(memberId: Long): List<PushToken> | ||||
| } | ||||
|  | ||||
| class PushTokenQueryRepositoryImpl( | ||||
|     private val queryFactory: JPAQueryFactory | ||||
| ) : PushTokenQueryRepository { | ||||
|     override fun findByToken(token: String): PushToken? { | ||||
|         return queryFactory | ||||
|             .selectFrom(pushToken) | ||||
|             .where(pushToken.token.eq(token)) | ||||
|             .fetchFirst() | ||||
|     } | ||||
|  | ||||
|     override fun findByMemberId(memberId: Long): List<PushToken> { | ||||
|         return queryFactory | ||||
|             .selectFrom(pushToken) | ||||
|             .where(pushToken.member.id.eq(memberId)) | ||||
|             .fetch() | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| package kr.co.vividnext.sodalive.fcm | ||||
|  | ||||
| import kr.co.vividnext.sodalive.member.MemberRepository | ||||
| import org.springframework.data.repository.findByIdOrNull | ||||
| import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | ||||
|  | ||||
| @Service | ||||
| class PushTokenService( | ||||
|     private val repository: PushTokenRepository, | ||||
|     private val memberRepository: MemberRepository | ||||
| ) { | ||||
|     @Transactional | ||||
|     fun registerToken(memberId: Long, token: String, deviceType: String) { | ||||
|         val member = memberRepository.findByIdOrNull(memberId) | ||||
|  | ||||
|         if (member != null) { | ||||
|             val existing = repository.findByToken(token) | ||||
|             if (existing != null) { | ||||
|                 existing.member = member | ||||
|                 existing.token = token | ||||
|                 existing.deviceType = deviceType | ||||
|             } else { | ||||
|                 val newToken = PushToken(token, deviceType) | ||||
|                 newToken.member = member | ||||
|                 repository.save(newToken) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun logout(memberId: Long) { | ||||
|         val tokens = repository.findByMemberId(memberId) | ||||
|  | ||||
|         for (token in tokens) { | ||||
|             token.member = null | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun unregisterInvalidToken(token: String) { | ||||
|         val existing = repository.findByToken(token) | ||||
|         if (existing != null) { | ||||
|             repository.delete(existing) | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -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) | ||||
|   | ||||
| @@ -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) } | ||||
| @@ -824,7 +830,14 @@ class MemberService( | ||||
|             provider = MemberProvider.GOOGLE, | ||||
|             container = container | ||||
|         ) | ||||
|         member.pushToken = pushToken | ||||
|  | ||||
|         if (pushToken != null) { | ||||
|             pushTokenService.registerToken( | ||||
|                 memberId = member.id!!, | ||||
|                 token = pushToken, | ||||
|                 deviceType = container | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         if (!marketingPid.isNullOrBlank()) { | ||||
|             member.activePid = marketingPid | ||||
| @@ -873,7 +886,14 @@ class MemberService( | ||||
|             provider = MemberProvider.KAKAO, | ||||
|             container = container | ||||
|         ) | ||||
|         member.pushToken = pushToken | ||||
|  | ||||
|         if (pushToken != null) { | ||||
|             pushTokenService.registerToken( | ||||
|                 memberId = member.id!!, | ||||
|                 token = pushToken, | ||||
|                 deviceType = container | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         if (!marketingPid.isNullOrBlank()) { | ||||
|             member.activePid = marketingPid | ||||
|   | ||||
		Reference in New Issue
	
	Block a user