diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index 9e020c2..b9314f4 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -150,18 +150,14 @@ class AudioContentService( val theme = themeQueryRepository.findThemeByIdAndActive(id = request.themeId) ?: throw SodaException("잘못된 테마입니다. 다시 선택해 주세요.") - if (request.price in 1..9) throw SodaException("콘텐츠의 최소금액은 10캔 입니다.") + if (request.price <= 4) throw SodaException("콘텐츠의 최소금액은 5캔 입니다.") // DB에 값 추가 val audioContent = AudioContent( title = request.title, detail = request.detail, type = request.type, - price = if (request.price < 0) { - 0 - } else { - request.price - }, + price = request.price, isAdult = request.isAdult, isGeneratePreview = if (request.type == AudioContentType.INDIVIDUAL) { request.isGeneratePreview @@ -311,7 +307,7 @@ class AudioContentService( // 크리에이터(유저) 정보 val creatorId = audioContent.member!!.id!! - val creator = explorerQueryRepository.getAccount(creatorId) + val creator = explorerQueryRepository.getMember(creatorId) ?: throw SodaException("없는 사용자 입니다.") val notificationUserIds = explorerQueryRepository.getNotificationUserIds(creatorId) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/Order.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/Order.kt index 7b778cd..5e0da19 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/Order.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/Order.kt @@ -42,7 +42,7 @@ data class Order( var audioContent: AudioContent? = null set(value) { can = if (type == OrderType.RENTAL) { - ceil(value?.price!! * 0.7).toInt() + ceil(value?.price!! * 0.6).toInt() } else { value?.price!! } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerController.kt index b5d9f7b..8b66af3 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerController.kt @@ -49,6 +49,16 @@ class ExplorerController(private val service: ExplorerService) { ApiResponse.ok(service.getCreatorProfile(creatorId, timezone, member)) } + @GetMapping("/profile/{id}/donation-rank") + fun getCreatorProfileDonationRanking( + @PathVariable("id") creatorId: Long, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, + pageable: Pageable + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + ApiResponse.ok(service.getCreatorProfileDonationRanking(creatorId, pageable, member)) + } + @PostMapping("/profile/cheers") fun writeCheers( @RequestBody request: PostWriteCheersRequest, @@ -86,4 +96,15 @@ class ExplorerController(private val service: ExplorerService) { if (member == null) throw SodaException("로그인 정보를 확인해주세요.") ApiResponse.ok(service.getFollowerList(creatorId, member, pageable)) } + + @GetMapping("/profile/{id}/cheers") + fun getCreatorProfileCheers( + @PathVariable("id") creatorId: Long, + @RequestParam timezone: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, + pageable: Pageable + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + ApiResponse.ok(service.getCreatorProfileCheers(creatorId, timezone, pageable)) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt index d76a4a8..98c4419 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerQueryRepository.kt @@ -6,6 +6,8 @@ import com.querydsl.core.types.dsl.Expressions import com.querydsl.jpa.impl.JPAQueryFactory import kr.co.vividnext.sodalive.can.use.CanUsage import kr.co.vividnext.sodalive.can.use.QUseCan.useCan +import kr.co.vividnext.sodalive.can.use.QUseCanCalculate.useCanCalculate +import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.content.QAudioContent.audioContent import kr.co.vividnext.sodalive.explorer.follower.GetFollowerListDto @@ -55,6 +57,59 @@ class ExplorerQueryRepository( .fetch() } + fun getDonationCoinsDateRange(creatorId: Long, startDate: LocalDateTime, endDate: LocalDateTime): Int? { + val donationCoin = useCanCalculate.can.sum() + + return queryFactory + .select(donationCoin) + .from(useCanCalculate) + .innerJoin(useCanCalculate.useCan, useCan) + .where( + useCanCalculate.status.eq(UseCanCalculateStatus.RECEIVED) + .and(useCan.isRefund.isFalse) + .and(useCanCalculate.recipientCreatorId.eq(creatorId)) + .and( + useCanCalculate.createdAt.goe( + startDate + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + ) + ) + .and( + useCanCalculate.createdAt.lt( + endDate + .atZone(ZoneId.of("Asia/Seoul")) + .withZoneSameInstant(ZoneId.of("UTC")) + .toLocalDateTime() + ) + ) + ) + .fetchOne() + } + + fun getMemberDonationRankingTotal(creatorId: Long): Int { + val creatorMember = QMember("creator") + val userMember = QMember("user") + + val donation = useCan.rewardCan.add(useCan.can).sum() + return queryFactory + .select(userMember.id) + .from(useCan) + .join(useCan.room, liveRoom) + .join(liveRoom.member, creatorMember) + .join(useCan.member, userMember) + .where( + useCan.canUsage.eq(CanUsage.DONATION) + .and(useCan.isRefund.isFalse) + .and(creatorMember.id.eq(creatorId)) + ) + .groupBy(useCan.member.id) + .orderBy(donation.desc()) + .fetch() + .size + } + fun getMemberDonationRanking( creatorId: Long, limit: Long, @@ -161,55 +216,13 @@ class ExplorerQueryRepository( .fetch() } - fun getAccount(userId: Long): Member? { + fun getMember(memberId: Long): Member? { return queryFactory .selectFrom(member) - .where(member.id.eq(userId)) + .where(member.id.eq(memberId)) .fetchFirst() } - fun getUserDonationRanking( - creatorId: Long, - limit: Long, - offset: Long = 0, - withDonationCan: Boolean - ): List { - val creatorMember = QMember("creator") - val userMember = QMember("user") - - val donation = useCan.rewardCan.add(useCan.can).sum() - return queryFactory - .select(userMember, donation) - .from(useCan) - .join(useCan.room, liveRoom) - .join(liveRoom.member, creatorMember) - .join(useCan.member, userMember) - .offset(offset) - .limit(limit) - .where( - useCan.canUsage.eq(CanUsage.DONATION) - .and(useCan.isRefund.isFalse) - .and(creatorMember.id.eq(creatorId)) - ) - .groupBy(useCan.member.id) - .orderBy(donation.desc(), userMember.id.desc()) - .fetch() - .map { - val account = it.get(userMember)!! - val donationCan = it.get(donation)!! - UserDonationRankingResponse( - account.id!!, - account.nickname, - if (account.profileImage != null) { - "$cloudFrontHost/${account.profileImage}" - } else { - "$cloudFrontHost/profile/default-profile.png" - }, - if (withDonationCan) donationCan else 0 - ) - } - } - fun getSimilarCreatorList(creatorId: Long): List { val creator = queryFactory .selectFrom(member) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt index f436dd2..d64d4df 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt @@ -22,6 +22,9 @@ import org.springframework.context.ApplicationEventPublisher import org.springframework.data.domain.Pageable import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional +import java.time.DayOfWeek +import java.time.LocalDate +import java.time.temporal.TemporalAdjusters @Service @Transactional(readOnly = true) @@ -164,7 +167,7 @@ class ExplorerService( fun getCreatorProfile(creatorId: Long, timezone: String, member: Member): GetCreatorProfileResponse { // 크리에이터(유저) 정보 - val creatorAccount = queryRepository.getAccount(creatorId) ?: throw SodaException("없는 사용자 입니다.") + val creatorAccount = queryRepository.getMember(creatorId) ?: throw SodaException("없는 사용자 입니다.") // 차단된 사용자 체크 val isBlocked = memberService.isBlocked(blockedMemberId = member.id!!, memberId = creatorId) @@ -175,7 +178,7 @@ class ExplorerService( val notificationRecipientCount = notificationUserIds.size // 후원랭킹 - val userDonationRanking = queryRepository.getUserDonationRanking( + val memberDonationRanking = queryRepository.getMemberDonationRanking( creatorId, 10, withDonationCan = creatorId == member.id!! @@ -234,7 +237,7 @@ class ExplorerService( isNotification = isNotification, notificationRecipientCount = notificationRecipientCount ), - userDonationRanking = userDonationRanking, + userDonationRanking = memberDonationRanking, similarCreatorList = similarCreatorList, liveRoomList = liveRoomList, contentList = contentList, @@ -250,6 +253,53 @@ class ExplorerService( ) } + fun getCreatorProfileDonationRanking( + creatorId: Long, + pageable: Pageable, + member: Member + ): GetDonationAllResponse { + val currentDate = LocalDate.now().atTime(0, 0, 0) + val firstDayOfLastWeek = currentDate.with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY)).minusDays(7) + val firstDayOfMonth = currentDate.with(TemporalAdjusters.firstDayOfMonth()) + + return GetDonationAllResponse( + accumulatedCansToday = if (creatorId == member.id!!) { + queryRepository.getDonationCoinsDateRange( + creatorId, + currentDate, + currentDate.plusDays(1) + ) ?: 0 + } else { + 0 + }, + accumulatedCansLastWeek = if (creatorId == member.id!!) { + queryRepository.getDonationCoinsDateRange( + creatorId, + firstDayOfLastWeek, + firstDayOfLastWeek.plusDays(7) + ) ?: 0 + } else { + 0 + }, + accumulatedCansThisMonth = if (creatorId == member.id!!) { + queryRepository.getDonationCoinsDateRange( + creatorId, + firstDayOfMonth, + currentDate + ) ?: 0 + } else { + 0 + }, + totalCount = queryRepository.getMemberDonationRankingTotal(creatorId), + userDonationRanking = queryRepository.getMemberDonationRanking( + creatorId, + offset = pageable.offset, + limit = pageable.pageSize.toLong(), + withDonationCan = creatorId == member.id!! + ) + ) + } + fun getFollowerList( creatorId: Long, member: Member, @@ -281,7 +331,7 @@ class ExplorerService( @Transactional fun writeCheers(request: PostWriteCheersRequest, member: Member) { - val creator = queryRepository.getAccount(request.creatorId) ?: throw SodaException("없는 사용자 입니다.") + val creator = queryRepository.getMember(request.creatorId) ?: throw SodaException("없는 사용자 입니다.") val isBlocked = memberService.isBlocked(blockedMemberId = member.id!!, memberId = request.creatorId) if (isBlocked) throw SodaException("${creator.nickname}님의 요청으로 팬토크 작성이 제한됩니다.") @@ -303,6 +353,19 @@ class ExplorerService( cheersRepository.save(cheers) } + fun getCreatorProfileCheers( + creatorId: Long, + timezone: String, + pageable: Pageable + ): GetCheersResponse { + return queryRepository.getCheersList( + creatorId = creatorId, + timezone = timezone, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ) + } + @Transactional fun modifyCheers(request: PutWriteCheersRequest, member: Member) { val cheers = queryRepository.getCheers(request.cheersId, member.id!!) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt index 31aef25..d7f9a83 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt @@ -4,7 +4,7 @@ import kr.co.vividnext.sodalive.content.GetAudioContentListItem data class GetCreatorProfileResponse( val creator: CreatorResponse, - val userDonationRanking: List, + val userDonationRanking: List, val similarCreatorList: List, val liveRoomList: List, val contentList: List, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/MemberDonationRankingResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/MemberDonationRankingResponse.kt index 343c56a..16af1c3 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/MemberDonationRankingResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/MemberDonationRankingResponse.kt @@ -1,5 +1,13 @@ package kr.co.vividnext.sodalive.explorer +data class GetDonationAllResponse( + val accumulatedCansToday: Int, + val accumulatedCansLastWeek: Int, + val accumulatedCansThisMonth: Int, + val totalCount: Int, + val userDonationRanking: List +) + data class MemberDonationRankingResponse( val userId: Long, val nickname: String, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/UserDonationRankingResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/UserDonationRankingResponse.kt deleted file mode 100644 index d68947d..0000000 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/UserDonationRankingResponse.kt +++ /dev/null @@ -1,16 +0,0 @@ -package kr.co.vividnext.sodalive.explorer - -data class GetDonationAllResponse( - val accumulatedCansToday: Int, - val accumulatedCansLastWeek: Int, - val accumulatedCansThisMonth: Int, - val totalCount: Int, - val userDonationRanking: List -) - -data class UserDonationRankingResponse( - val userId: Long, - val nickname: String, - val profileImage: String, - val donationCan: Int -)