Merge pull request 'test' (#252) from test into main

Reviewed-on: #252
This commit is contained in:
klaus 2025-01-08 14:11:08 +00:00
commit 797666ae0d
9 changed files with 109 additions and 6 deletions

View File

@ -5,8 +5,11 @@ import kr.co.vividnext.sodalive.admin.audition.role.AdminAuditionRoleRepository
import kr.co.vividnext.sodalive.audition.AuditionStatus import kr.co.vividnext.sodalive.audition.AuditionStatus
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.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
@ -18,6 +21,7 @@ class AdminAuditionService(
private val objectMapper: ObjectMapper, private val objectMapper: ObjectMapper,
private val repository: AdminAuditionRepository, private val repository: AdminAuditionRepository,
private val roleRepository: AdminAuditionRoleRepository, private val roleRepository: AdminAuditionRoleRepository,
private val applicationEventPublisher: ApplicationEventPublisher,
@Value("\${cloud.aws.s3.bucket}") @Value("\${cloud.aws.s3.bucket}")
private val bucket: String private val bucket: String
@ -82,6 +86,18 @@ class AdminAuditionService(
if (request.isActive != null) { if (request.isActive != null) {
audition.isActive = request.isActive audition.isActive = request.isActive
} }
if (request.status != null && request.status == AuditionStatus.IN_PROGRESS && audition.isActive) {
applicationEventPublisher.publishEvent(
FcmEvent(
type = FcmEventType.IN_PROGRESS_AUDITION,
title = "새로운 오디션 등록!",
message = "[${audition.title}]이 등록되었습니다. 지금 바로 오리지널 오디오 드라마 오디션에 지원해보세요!",
isAuth = audition.isAdult,
auditionId = audition.id ?: -1
)
)
}
} }
fun getAuditionList(offset: Long, limit: Long): GetAuditionListResponse { fun getAuditionList(offset: Long, limit: Long): GetAuditionListResponse {

View File

@ -10,7 +10,7 @@ import org.springframework.transaction.event.TransactionalEventListener
enum class FcmEventType { enum class FcmEventType {
ALL, INDIVIDUAL, CREATE_LIVE, START_LIVE, CANCEL_LIVE, UPLOAD_CONTENT, SEND_MESSAGE, CHANGE_NOTICE, ALL, INDIVIDUAL, CREATE_LIVE, START_LIVE, CANCEL_LIVE, UPLOAD_CONTENT, SEND_MESSAGE, CHANGE_NOTICE,
CREATE_CONTENT_COMMENT CREATE_CONTENT_COMMENT, IN_PROGRESS_AUDITION
} }
class FcmEvent( class FcmEvent(
@ -25,6 +25,7 @@ class FcmEvent(
val contentId: Long? = null, val contentId: Long? = null,
val messageId: Long? = null, val messageId: Long? = null,
val creatorId: Long? = null, val creatorId: Long? = null,
val auditionId: Long? = null,
val commentParentId: Long? = null, val commentParentId: Long? = null,
val myMemberId: Long? = null, val myMemberId: Long? = null,
val isAvailableJoinCreator: Boolean? = null val isAvailableJoinCreator: Boolean? = null
@ -278,6 +279,41 @@ class FcmSendListener(
} }
} }
} }
FcmEventType.IN_PROGRESS_AUDITION -> {
if (fcmEvent.auditionId != null && fcmEvent.auditionId > 0) {
val pushTokenList = 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
)
}
}
}
}
} }
} }
} }

View File

@ -23,7 +23,8 @@ class FcmService {
roomId: Long? = null, roomId: Long? = null,
messageId: Long? = null, messageId: Long? = null,
contentId: Long? = null, contentId: Long? = null,
creatorId: Long? = null creatorId: Long? = null,
auditionId: Long? = null
) { ) {
if (tokens.isNotEmpty()) { if (tokens.isNotEmpty()) {
logger.info("os: $container") logger.info("os: $container")
@ -76,6 +77,10 @@ class FcmService {
multicastMessage.putData("channel_id", creatorId.toString()) multicastMessage.putData("channel_id", creatorId.toString())
} }
if (auditionId != null) {
multicastMessage.putData("audition_id", auditionId.toString())
}
val response = FirebaseMessaging.getInstance().sendEachForMulticast(multicastMessage.build()) val response = FirebaseMessaging.getInstance().sendEachForMulticast(multicastMessage.build())
logger.info("보내기 성공: ${response.successCount}") logger.info("보내기 성공: ${response.successCount}")
logger.info("보내기 실패: ${response.failureCount}") logger.info("보내기 실패: ${response.failureCount}")

View File

@ -56,6 +56,7 @@ interface MemberQueryRepository {
fun getChangeNoticeRecipientPushTokens(creatorId: Long): Map<String, List<List<String>>> fun getChangeNoticeRecipientPushTokens(creatorId: Long): Map<String, List<List<String>>>
fun getPushTokenFromReservationList(roomId: Long): Map<String, List<List<String>>> fun getPushTokenFromReservationList(roomId: Long): Map<String, List<List<String>>>
fun getAuditionNoticeRecipientPushTokens(isAuth: Boolean): Map<String, List<List<String>>>
fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse
} }
@ -427,6 +428,37 @@ class MemberQueryRepositoryImpl(
return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens) return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens)
} }
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)
.from(member)
.leftJoin(member.auth, auth)
.leftJoin(memberNotification).on(memberNotification.member.id.eq(member.id))
.where(where.and(member.container.eq("aos")))
.fetch()
.toSet()
.chunked(500)
val iosPushTokens = queryFactory
.select(member.pushToken)
.from(member)
.leftJoin(member.auth, auth)
.leftJoin(memberNotification).on(memberNotification.member.id.eq(member.id))
.where(where.and(member.container.eq("ios")))
.fetch()
.toSet()
.chunked(500)
return mapOf("aos" to aosPushTokens, "ios" to iosPushTokens)
}
override fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse { override fun getMemberProfile(memberId: Long, myMemberId: Long): GetMemberProfileResponse {
return queryFactory return queryFactory
.select( .select(

View File

@ -141,7 +141,8 @@ class MemberService(
role = member.role, role = member.role,
messageNotice = member.notification?.message, messageNotice = member.notification?.message,
followingChannelLiveNotice = member.notification?.live, followingChannelLiveNotice = member.notification?.live,
followingChannelUploadContentNotice = member.notification?.uploadContent followingChannelUploadContentNotice = member.notification?.uploadContent,
auditionNotice = member.notification?.audition
) )
} }
@ -151,6 +152,7 @@ class MemberService(
live = request.live, live = request.live,
uploadContent = request.uploadContent, uploadContent = request.uploadContent,
message = request.message, message = request.message,
audition = request.audition,
member = member member = member
) )
} }

View File

@ -8,5 +8,6 @@ data class GetMemberInfoResponse(
val role: MemberRole, val role: MemberRole,
val messageNotice: Boolean?, val messageNotice: Boolean?,
val followingChannelLiveNotice: Boolean?, val followingChannelLiveNotice: Boolean?,
val followingChannelUploadContentNotice: Boolean? val followingChannelUploadContentNotice: Boolean?,
val auditionNotice: Boolean?
) )

View File

@ -17,7 +17,10 @@ data class MemberNotification(
var live: Boolean? = true, var live: Boolean? = true,
@Column(nullable = false) @Column(nullable = false)
var message: Boolean? = true var message: Boolean? = true,
@Column(nullable = false)
var audition: Boolean? = false
) : BaseEntity() { ) : BaseEntity() {
@OneToOne(fetch = FetchType.LAZY) @OneToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", nullable = false) @JoinColumn(name = "member_id", nullable = false)

View File

@ -11,16 +11,23 @@ class MemberNotificationService(private val repository: MemberNotificationReposi
live: Boolean? = null, live: Boolean? = null,
uploadContent: Boolean? = null, uploadContent: Boolean? = null,
message: Boolean? = null, message: Boolean? = null,
audition: Boolean? = null,
member: Member member: Member
) { ) {
var notification = repository.getMemberNotification(memberId = member.id!!) var notification = repository.getMemberNotification(memberId = member.id!!)
if (notification == null) { if (notification == null) {
notification = MemberNotification(uploadContent, live, message) notification = MemberNotification(
uploadContent = uploadContent,
live = live,
message = message,
audition = audition
)
notification.member = member notification.member = member
repository.save(notification) repository.save(notification)
} else { } else {
if (live != null) notification.live = live if (live != null) notification.live = live
if (message != null) notification.message = message if (message != null) notification.message = message
if (audition != null) notification.audition = audition
if (uploadContent != null) notification.uploadContent = uploadContent if (uploadContent != null) notification.uploadContent = uploadContent
} }
} }

View File

@ -3,5 +3,6 @@ package kr.co.vividnext.sodalive.member.notification
data class UpdateNotificationSettingRequest( data class UpdateNotificationSettingRequest(
val live: Boolean?, val live: Boolean?,
val message: Boolean?, val message: Boolean?,
val audition: Boolean?,
val uploadContent: Boolean? val uploadContent: Boolean?
) )