diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateLiveQueryData.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateLiveQueryData.kt index 41b6515..f23d21a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateLiveQueryData.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/GetCalculateLiveQueryData.kt @@ -31,6 +31,10 @@ data class GetCalculateLiveQueryData @QueryProjection constructor( "룰렛" } + CanUsage.HEART -> { + "하트" + } + else -> { "후원" } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt index bfe03fa..87025af 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt @@ -53,7 +53,7 @@ class CanService(private val repository: CanRepository) { } .map { val title: String = when (it.canUsage) { - CanUsage.DONATION, CanUsage.SPIN_ROULETTE -> { + CanUsage.HEART, CanUsage.DONATION, CanUsage.SPIN_ROULETTE -> { if (it.room != null) { "[라이브 후원] ${it.room!!.member!!.nickname}" } else if (it.audioContent != null) { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt index 14479c8..c50f823 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt @@ -100,6 +100,10 @@ class CanPaymentService( useCan.member = member } else if (canUsage == CanUsage.ALARM_SLOT) { useCan.member = member + } else if (canUsage == CanUsage.HEART && liveRoom != null) { + recipientId = liveRoom.member!!.id!! + useCan.room = liveRoom + useCan.member = member } else { throw SodaException("잘못된 요청입니다.") } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt index 667f2b3..6677b8f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.can.use enum class CanUsage { LIVE, + HEART, DONATION, CHANGE_NICKNAME, ORDER_CONTENT, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomController.kt index 02029a5..ebbd3a9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomController.kt @@ -5,6 +5,7 @@ import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.live.room.cancel.CancelLiveRequest import kr.co.vividnext.sodalive.live.room.donation.DeleteLiveRoomDonationMessage import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest +import kr.co.vividnext.sodalive.live.room.like.LiveRoomLikeHeartRequest import kr.co.vividnext.sodalive.live.room.visit.LiveRoomVisitService import kr.co.vividnext.sodalive.member.Member import org.springframework.data.domain.Pageable @@ -262,4 +263,24 @@ class LiveRoomController( ApiResponse.ok(visitService.getRecentVisitRoomUsers(member)) } + + @PostMapping("/like-heart") + fun likeHeart( + @RequestBody request: LiveRoomLikeHeartRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.likeHeart(request, member)) + } + + @GetMapping("/{id}/heart-total") + fun getTotalHeartCount( + @PathVariable("id") roomId: Long, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.getTotalHeartCount(roomId)) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt index 6d2eb3d..7348403 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomRepository.kt @@ -53,6 +53,7 @@ interface LiveRoomQueryRepository { fun getDonationList(roomId: Long, isLiveCreator: Boolean): List fun getRoomActiveAndChannelNameIsNotNull(memberId: Long): List fun getActiveRoomIdList(memberId: Long): Int + fun getTotalHeartCount(roomId: Long): Int? } class LiveRoomQueryRepositoryImpl( @@ -297,4 +298,18 @@ class LiveRoomQueryRepositoryImpl( .fetch() .size } + + override fun getTotalHeartCount(roomId: Long): Int? { + val where = liveRoom.id.eq(roomId) + .and(useCan.canUsage.eq(CanUsage.HEART)) + .and(useCan.isRefund.isFalse) + + return queryFactory + .select(useCanCalculate.can.sum()) + .from(useCanCalculate) + .innerJoin(useCanCalculate.useCan, useCan) + .innerJoin(useCan.room, liveRoom) + .where(where) + .fetchOne() + } } 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 bad1a6d..8d4fcf0 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 @@ -39,6 +39,8 @@ import kr.co.vividnext.sodalive.live.room.info.LiveRoomInfo import kr.co.vividnext.sodalive.live.room.info.LiveRoomInfoRedisRepository import kr.co.vividnext.sodalive.live.room.info.LiveRoomMember import kr.co.vividnext.sodalive.live.room.kickout.LiveRoomKickOutService +import kr.co.vividnext.sodalive.live.room.like.GetLiveRoomHeartTotalResponse +import kr.co.vividnext.sodalive.live.room.like.LiveRoomLikeHeartRequest import kr.co.vividnext.sodalive.live.room.menu.CreateLiveMenuRequest import kr.co.vividnext.sodalive.live.room.menu.LiveRoomMenuService import kr.co.vividnext.sodalive.live.room.menu.UpdateLiveMenuRequest @@ -1221,4 +1223,29 @@ class LiveRoomService( private fun getOrCreateLock(memberId: Long): ReentrantReadWriteLock { return tokenLocks.computeIfAbsent(memberId) { ReentrantReadWriteLock() } } + + @Transactional + fun likeHeart(request: LiveRoomLikeHeartRequest, member: Member) { + val room = repository.findByIdOrNull(request.roomId) + ?: throw SodaException("해당하는 라이브가 없습니다.") + + val host = room.member ?: throw SodaException("잘못된 요청입니다.") + + if (host.role != MemberRole.CREATOR) { + throw SodaException("비비드넥스트와 계약한\n크리에이터에게만 후원을 하실 수 있습니다.") + } + + canPaymentService.spendCan( + memberId = member.id!!, + needCan = 1, + canUsage = CanUsage.HEART, + isSecret = false, + liveRoom = room, + container = request.container + ) + } + + fun getTotalHeartCount(roomId: Long): GetLiveRoomHeartTotalResponse { + return GetLiveRoomHeartTotalResponse(totalHeartCount = repository.getTotalHeartCount(roomId = roomId) ?: 0) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/like/GetLiveRoomHeartTotalResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/like/GetLiveRoomHeartTotalResponse.kt new file mode 100644 index 0000000..b3dbc9d --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/like/GetLiveRoomHeartTotalResponse.kt @@ -0,0 +1,5 @@ +package kr.co.vividnext.sodalive.live.room.like + +data class GetLiveRoomHeartTotalResponse( + val totalHeartCount: Int +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/like/LiveRoomLikeHeartRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/like/LiveRoomLikeHeartRequest.kt new file mode 100644 index 0000000..5b6f73a --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/like/LiveRoomLikeHeartRequest.kt @@ -0,0 +1,6 @@ +package kr.co.vividnext.sodalive.live.room.like + +data class LiveRoomLikeHeartRequest( + val roomId: Long, + val container: String +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt index 6529381..7b273f4 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/roulette/v2/RouletteService.kt @@ -93,15 +93,19 @@ class RouletteService( var activeRoulette = false rouletteList.forEach { - if (request.isActive || it.isActive) { - activeRoulette = true - } - if (it.id == request.id) { it.can = request.can it.items = request.items it.isActive = request.isActive repository.save(it) + + activeRoulette = request.isActive + } else { + if ( + !activeRoulette && (request.isActive || it.isActive) + ) { + activeRoulette = true + } } }