diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureController.kt index df3115d..22a3ed8 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureController.kt @@ -31,6 +31,7 @@ class CreatorAdminSignatureController(private val service: CreatorAdminSignature @PostMapping fun createSignature( @RequestParam("can") can: Int, + @RequestParam("time") time: Int, @RequestParam("image") image: MultipartFile, @RequestParam("isAdult", required = false) isAdult: Boolean = false, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? @@ -38,7 +39,7 @@ class CreatorAdminSignatureController(private val service: CreatorAdminSignature if (member == null) throw SodaException("로그인 정보를 확인해주세요.") ApiResponse.ok( - service.createSignature(can = can, image = image, isAdult = isAdult, memberId = member.id!!), + service.createSignature(can = can, time = time, image = image, isAdult = isAdult, memberId = member.id!!), "등록되었습니다." ) } @@ -47,13 +48,14 @@ class CreatorAdminSignatureController(private val service: CreatorAdminSignature fun modifySignature( @RequestParam("id") id: Long, @RequestParam("can", required = false) can: Int?, + @RequestParam("time", required = false) time: Int?, @RequestParam("image", required = false) image: MultipartFile?, @RequestParam("isActive", required = false) isActive: Boolean?, @RequestParam("isAdult", required = false) isAdult: Boolean?, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { if (member == null) throw SodaException("로그인 정보를 확인해주세요.") - if (can == null && image == null && isActive == null && isAdult == null) { + if (can == null && time == null && image == null && isActive == null && isAdult == null) { throw SodaException("변경사항이 없습니다.") } @@ -61,6 +63,7 @@ class CreatorAdminSignatureController(private val service: CreatorAdminSignature service.modifySignature( id = id, can = can, + time = time, image = image, isActive = isActive, isAdult = isAdult, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureRepository.kt index 7fcc302..da27d01 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureRepository.kt @@ -40,6 +40,7 @@ class CreatorAdminSignatureQueryRepositoryImpl( QGetSignatureListItem( signatureCan.id, signatureCan.can, + signatureCan.time, signatureCan.image.prepend("/").prepend(imageHost), signatureCan.isAdult, member.nickname diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureService.kt index 9c1f57c..10ae45d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureService.kt @@ -37,11 +37,14 @@ class CreatorAdminSignatureService( } @Transactional - fun createSignature(can: Int, image: MultipartFile, memberId: Long, isAdult: Boolean) { + fun createSignature(can: Int, time: Int, image: MultipartFile, memberId: Long, isAdult: Boolean) { val member = memberRepository.findCreatorByIdOrNull(memberId = memberId) ?: throw SodaException("잘못된 접근입니다.") - val signatureCan = SignatureCan(can = can, isAdult = isAdult) + if (can <= 0) throw SodaException("1캔 이상 설정할 수 있습니다.") + if (time < 3 || time > 20) throw SodaException("시간은 3초 이상 20초 이하로 설정할 수 있습니다.") + + val signatureCan = SignatureCan(can = can, time = time, isAdult = isAdult) signatureCan.creator = member repository.save(signatureCan) @@ -61,6 +64,7 @@ class CreatorAdminSignatureService( fun modifySignature( id: Long, can: Int?, + time: Int?, image: MultipartFile?, isActive: Boolean?, memberId: Long, @@ -70,9 +74,15 @@ class CreatorAdminSignatureService( ?: throw SodaException("잘못된 요청입니다.") if (can != null) { + if (can <= 0) throw SodaException("1캔 이상 설정할 수 있습니다.") signatureCan.can = can } + if (time != null) { + if (time < 3 || time > 20) throw SodaException("시간은 3초 이상 20초 이하로 설정할 수 있습니다.") + signatureCan.time = time + } + if (isActive != null) { signatureCan.isActive = isActive } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/GetSignatureListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/GetSignatureListResponse.kt index 9c8028d..c5f019f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/GetSignatureListResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/GetSignatureListResponse.kt @@ -10,6 +10,7 @@ data class GetSignatureListResponse( data class GetSignatureListItem @QueryProjection constructor( val id: Long, val can: Int, + val time: Int, val image: String, val isAdult: Boolean, val nickname: String 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 b034601..18c3a01 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 @@ -205,6 +205,16 @@ class LiveRoomController( ApiResponse.ok(service.donation(request, member)) } + @PostMapping("/donation/v2") + fun donationV2( + @RequestBody request: LiveRoomDonationRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.donationV2(request, member)) + } + @PostMapping("/donation/refund/{id}") fun refundDonation( @PathVariable id: Long, 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 a4ac5e4..4f9edfe 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 @@ -33,6 +33,7 @@ import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationStatusResp import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationTotalResponse import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationMessage import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationRequest +import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse import kr.co.vividnext.sodalive.live.room.info.GetRoomInfoResponse import kr.co.vividnext.sodalive.live.room.info.LiveRoomInfo import kr.co.vividnext.sodalive.live.room.info.LiveRoomInfoRedisRepository @@ -1059,6 +1060,49 @@ class LiveRoomService( ) } + @Transactional + fun donationV2(request: LiveRoomDonationRequest, member: Member): LiveRoomDonationResponse? { + 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 = request.can, + canUsage = CanUsage.DONATION, + liveRoom = room, + container = request.container + ) + + if (request.message.isNotBlank()) { + val lock = getOrCreateLock(memberId = member.id!!) + lock.write { + val roomInfo = roomInfoRepository.findByIdOrNull(room.id!!) + ?: throw SodaException("해당하는 라이브의 정보가 없습니다.") + + roomInfo.addDonationMessage( + nickname = member.nickname, + can = request.can, + donationMessage = request.message + ) + + roomInfoRepository.save(roomInfo) + } + } + + return signatureCanRepository.findByCreatorIdAndCan( + creatorId = host.id!!, + can = request.can, + imageHost = cloudFrontHost, + isAdult = room.isAdult + ) + } + @Transactional fun refundDonation(roomId: Long, member: Member) { val donator = memberRepository.findByIdOrNull(member.id) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/donation/LiveRoomDonationResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/donation/LiveRoomDonationResponse.kt new file mode 100644 index 0000000..1161080 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/donation/LiveRoomDonationResponse.kt @@ -0,0 +1,5 @@ +package kr.co.vividnext.sodalive.live.room.donation + +import com.querydsl.core.annotations.QueryProjection + +data class LiveRoomDonationResponse @QueryProjection constructor(val imageUrl: String, val time: Int) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt index c9ee36f..108764e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt @@ -10,6 +10,7 @@ import javax.persistence.ManyToOne @Entity data class SignatureCan( var can: Int, + var time: Int = 7, var isAdult: Boolean = false, var isActive: Boolean = true ) : BaseEntity() { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt index 2976998..df2bfe9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt @@ -1,6 +1,8 @@ package kr.co.vividnext.sodalive.live.signature import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.live.room.donation.LiveRoomDonationResponse +import kr.co.vividnext.sodalive.live.room.donation.QLiveRoomDonationResponse import kr.co.vividnext.sodalive.live.signature.QSignatureCan.signatureCan import org.springframework.data.jpa.repository.JpaRepository @@ -8,6 +10,7 @@ interface SignatureCanRepository : JpaRepository, SignatureC interface SignatureCanQueryRepository { fun findImageByCreatorIdAndCan(creatorId: Long, can: Int, imageHost: String, isAdult: Boolean): String? + fun findByCreatorIdAndCan(creatorId: Long, can: Int, imageHost: String, isAdult: Boolean): LiveRoomDonationResponse? } class SignatureCanQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : SignatureCanQueryRepository { @@ -27,4 +30,31 @@ class SignatureCanQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) .orderBy(signatureCan.isAdult.desc()) .fetchFirst() } + + override fun findByCreatorIdAndCan( + creatorId: Long, + can: Int, + imageHost: String, + isAdult: Boolean + ): LiveRoomDonationResponse? { + var where = signatureCan.creator.id.eq(creatorId) + .and(signatureCan.can.eq(can)) + .and(signatureCan.isActive.isTrue) + + if (!isAdult) { + where = where.and(signatureCan.isAdult.isFalse()) + } + + return queryFactory + .select( + QLiveRoomDonationResponse( + signatureCan.image.prepend("/").prepend(imageHost), + signatureCan.time + ) + ) + .from(signatureCan) + .where(where) + .orderBy(signatureCan.isAdult.desc()) + .fetchFirst() + } }