| @@ -31,6 +31,10 @@ data class GetCalculateLiveQueryData @QueryProjection constructor( | ||||
|                 "룰렛" | ||||
|             } | ||||
|  | ||||
|             CanUsage.HEART -> { | ||||
|                 "하트" | ||||
|             } | ||||
|  | ||||
|             else -> { | ||||
|                 "후원" | ||||
|             } | ||||
|   | ||||
| @@ -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) { | ||||
|   | ||||
| @@ -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("잘못된 요청입니다.") | ||||
|         } | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.can.use | ||||
|  | ||||
| enum class CanUsage { | ||||
|     LIVE, | ||||
|     HEART, | ||||
|     DONATION, | ||||
|     CHANGE_NICKNAME, | ||||
|     ORDER_CONTENT, | ||||
|   | ||||
| @@ -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)) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -53,6 +53,7 @@ interface LiveRoomQueryRepository { | ||||
|     fun getDonationList(roomId: Long, isLiveCreator: Boolean): List<GetLiveRoomDonationItem> | ||||
|     fun getRoomActiveAndChannelNameIsNotNull(memberId: Long): List<LiveRoom> | ||||
|     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() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,5 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.like | ||||
|  | ||||
| data class GetLiveRoomHeartTotalResponse( | ||||
|     val totalHeartCount: Int | ||||
| ) | ||||
| @@ -0,0 +1,6 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.like | ||||
|  | ||||
| data class LiveRoomLikeHeartRequest( | ||||
|     val roomId: Long, | ||||
|     val container: String | ||||
| ) | ||||
| @@ -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 | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user