콘텐츠 메인
- 홈 탭 API
This commit is contained in:
		@@ -6,9 +6,9 @@ import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
 | 
			
		||||
import kr.co.vividnext.sodalive.content.category.QCategoryContent.categoryContent
 | 
			
		||||
import kr.co.vividnext.sodalive.content.comment.QAudioContentComment.audioContentComment
 | 
			
		||||
import kr.co.vividnext.sodalive.content.like.QAudioContentLike.audioContentLike
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.ContentCreatorResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.GetAudioContentRankingItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.GetNewContentUploadCreator
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.QGetAudioContentMainItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.QGetAudioContentRankingItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBanner
 | 
			
		||||
@@ -98,7 +98,7 @@ interface AudioContentQueryRepository {
 | 
			
		||||
    fun getNewContentUploadCreatorList(
 | 
			
		||||
        cloudfrontHost: String,
 | 
			
		||||
        isAdult: Boolean = false
 | 
			
		||||
    ): List<GetNewContentUploadCreator>
 | 
			
		||||
    ): List<ContentCreatorResponse>
 | 
			
		||||
 | 
			
		||||
    fun getAudioContentMainBannerList(isAdult: Boolean): List<AudioContentBanner>
 | 
			
		||||
    fun getAudioContentCurations(isAdult: Boolean): List<AudioContentCuration>
 | 
			
		||||
@@ -533,7 +533,7 @@ class AudioContentQueryRepositoryImpl(
 | 
			
		||||
    override fun getNewContentUploadCreatorList(
 | 
			
		||||
        cloudfrontHost: String,
 | 
			
		||||
        isAdult: Boolean
 | 
			
		||||
    ): List<GetNewContentUploadCreator> {
 | 
			
		||||
    ): List<ContentCreatorResponse> {
 | 
			
		||||
        var where = audioContent.releaseDate.after(LocalDateTime.now().minusWeeks(2))
 | 
			
		||||
            .and(audioContent.isActive.isTrue)
 | 
			
		||||
            .and(audioContent.duration.isNotNull)
 | 
			
		||||
@@ -552,7 +552,7 @@ class AudioContentQueryRepositoryImpl(
 | 
			
		||||
            .limit(20)
 | 
			
		||||
            .fetch()
 | 
			
		||||
            .map {
 | 
			
		||||
                GetNewContentUploadCreator(
 | 
			
		||||
                ContentCreatorResponse(
 | 
			
		||||
                    it.id!!,
 | 
			
		||||
                    it.nickname,
 | 
			
		||||
                    creatorProfileImageUrl = if (it.profileImage != null) {
 | 
			
		||||
 
 | 
			
		||||
@@ -80,7 +80,7 @@ class AudioContentMainService(
 | 
			
		||||
 | 
			
		||||
    @Transactional(readOnly = true)
 | 
			
		||||
    @Cacheable(cacheNames = ["default"], key = "'newContentUploadCreatorList:' + #memberId + ':' + #isAdult")
 | 
			
		||||
    fun getNewContentUploadCreatorList(memberId: Long, isAdult: Boolean): List<GetNewContentUploadCreator> {
 | 
			
		||||
    fun getNewContentUploadCreatorList(memberId: Long, isAdult: Boolean): List<ContentCreatorResponse> {
 | 
			
		||||
        return repository.getNewContentUploadCreatorList(
 | 
			
		||||
            cloudfrontHost = imageHost,
 | 
			
		||||
            isAdult = isAdult
 | 
			
		||||
 
 | 
			
		||||
@@ -3,7 +3,7 @@ package kr.co.vividnext.sodalive.content.main
 | 
			
		||||
import com.fasterxml.jackson.annotation.JsonProperty
 | 
			
		||||
import com.querydsl.core.annotations.QueryProjection
 | 
			
		||||
 | 
			
		||||
data class GetNewContentUploadCreator @QueryProjection constructor(
 | 
			
		||||
data class ContentCreatorResponse @QueryProjection constructor(
 | 
			
		||||
    @JsonProperty("creatorId") val creatorId: Long,
 | 
			
		||||
    @JsonProperty("creatorNickname") val creatorNickname: String,
 | 
			
		||||
    @JsonProperty("creatorProfileImageUrl") val creatorProfileImageUrl: String
 | 
			
		||||
@@ -0,0 +1,41 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.content.main.banner
 | 
			
		||||
 | 
			
		||||
import com.querydsl.jpa.impl.JPAQueryFactory
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.banner.QAudioContentBanner.audioContentBanner
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.tab.QAudioContentMainTab.audioContentMainTab
 | 
			
		||||
import kr.co.vividnext.sodalive.event.QEvent.event
 | 
			
		||||
import kr.co.vividnext.sodalive.member.QMember.member
 | 
			
		||||
import org.springframework.data.jpa.repository.JpaRepository
 | 
			
		||||
 | 
			
		||||
interface AudioContentBannerRepository : JpaRepository<AudioContentBanner, Long>, AudioContentBannerQueryRepository
 | 
			
		||||
 | 
			
		||||
interface AudioContentBannerQueryRepository {
 | 
			
		||||
    fun getAudioContentMainBannerList(tabId: Long, isAdult: Boolean): List<AudioContentBanner>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
class AudioContentBannerQueryRepositoryImpl(
 | 
			
		||||
    private val queryFactory: JPAQueryFactory
 | 
			
		||||
) : AudioContentBannerQueryRepository {
 | 
			
		||||
    override fun getAudioContentMainBannerList(tabId: Long, isAdult: Boolean): List<AudioContentBanner> {
 | 
			
		||||
        var where = audioContentBanner.isActive.isTrue
 | 
			
		||||
 | 
			
		||||
        where = if (tabId == 1L) {
 | 
			
		||||
            where.and(audioContentBanner.tab.isNull)
 | 
			
		||||
        } else {
 | 
			
		||||
            where.and(audioContentBanner.tab.id.eq(tabId))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!isAdult) {
 | 
			
		||||
            where = where.and(audioContentBanner.isAdult.isFalse)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return queryFactory
 | 
			
		||||
            .selectFrom(audioContentBanner)
 | 
			
		||||
            .leftJoin(audioContentBanner.tab, audioContentMainTab)
 | 
			
		||||
            .leftJoin(audioContentBanner.event, event)
 | 
			
		||||
            .leftJoin(audioContentBanner.creator, member)
 | 
			
		||||
            .where(where)
 | 
			
		||||
            .orderBy(audioContentBanner.orders.asc())
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,67 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.content.main.banner
 | 
			
		||||
 | 
			
		||||
import kr.co.vividnext.sodalive.event.EventItem
 | 
			
		||||
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value
 | 
			
		||||
import org.springframework.stereotype.Service
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
class AudioContentBannerService(
 | 
			
		||||
    private val repository: AudioContentBannerRepository,
 | 
			
		||||
    private val blockMemberRepository: BlockMemberRepository,
 | 
			
		||||
 | 
			
		||||
    @Value("\${cloud.aws.cloud-front.host}")
 | 
			
		||||
    private val imageHost: String
 | 
			
		||||
) {
 | 
			
		||||
    fun getBannerList(tabId: Long, memberId: Long, isAdult: Boolean): List<GetAudioContentBannerResponse> {
 | 
			
		||||
        return repository.getAudioContentMainBannerList(tabId, isAdult)
 | 
			
		||||
            .filter {
 | 
			
		||||
                if (it.type == AudioContentBannerType.CREATOR && it.creator != null) {
 | 
			
		||||
                    !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = it.creator!!.id!!)
 | 
			
		||||
                } else if (it.type == AudioContentBannerType.SERIES && it.series != null) {
 | 
			
		||||
                    !blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = it.series!!.member!!.id!!)
 | 
			
		||||
                } else {
 | 
			
		||||
                    true
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .map {
 | 
			
		||||
                GetAudioContentBannerResponse(
 | 
			
		||||
                    type = it.type,
 | 
			
		||||
                    thumbnailImageUrl = "$imageHost/${it.thumbnailImage}",
 | 
			
		||||
                    eventItem = if (it.type == AudioContentBannerType.EVENT && it.event != null) {
 | 
			
		||||
                        EventItem(
 | 
			
		||||
                            id = it.event!!.id!!,
 | 
			
		||||
                            thumbnailImageUrl = if (!it.event!!.thumbnailImage.startsWith("https://")) {
 | 
			
		||||
                                "$imageHost/${it.event!!.thumbnailImage}"
 | 
			
		||||
                            } else {
 | 
			
		||||
                                it.event!!.thumbnailImage
 | 
			
		||||
                            },
 | 
			
		||||
                            detailImageUrl = if (
 | 
			
		||||
                                it.event!!.detailImage != null &&
 | 
			
		||||
                                !it.event!!.detailImage!!.startsWith("https://")
 | 
			
		||||
                            ) {
 | 
			
		||||
                                "$imageHost/${it.event!!.detailImage}"
 | 
			
		||||
                            } else {
 | 
			
		||||
                                it.event!!.detailImage
 | 
			
		||||
                            },
 | 
			
		||||
                            popupImageUrl = null,
 | 
			
		||||
                            link = it.event!!.link
 | 
			
		||||
                        )
 | 
			
		||||
                    } else {
 | 
			
		||||
                        null
 | 
			
		||||
                    },
 | 
			
		||||
                    creatorId = if (it.type == AudioContentBannerType.CREATOR && it.creator != null) {
 | 
			
		||||
                        it.creator!!.id
 | 
			
		||||
                    } else {
 | 
			
		||||
                        null
 | 
			
		||||
                    },
 | 
			
		||||
                    seriesId = if (it.type == AudioContentBannerType.SERIES && it.series != null) {
 | 
			
		||||
                        it.series!!.id
 | 
			
		||||
                    } else {
 | 
			
		||||
                        null
 | 
			
		||||
                    },
 | 
			
		||||
                    link = it.link
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,22 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.content.main.tab.home
 | 
			
		||||
 | 
			
		||||
import kr.co.vividnext.sodalive.common.ApiResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.common.SodaException
 | 
			
		||||
import kr.co.vividnext.sodalive.member.Member
 | 
			
		||||
import org.springframework.security.core.annotation.AuthenticationPrincipal
 | 
			
		||||
import org.springframework.web.bind.annotation.GetMapping
 | 
			
		||||
import org.springframework.web.bind.annotation.RequestMapping
 | 
			
		||||
import org.springframework.web.bind.annotation.RestController
 | 
			
		||||
 | 
			
		||||
@RestController
 | 
			
		||||
@RequestMapping("/v2/audio-content/main/home")
 | 
			
		||||
class AudioContentMainTabHomeController(private val service: AudioContentMainTabHomeService) {
 | 
			
		||||
    @GetMapping
 | 
			
		||||
    fun fetchContentMainHome(
 | 
			
		||||
        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
 | 
			
		||||
    ) = run {
 | 
			
		||||
        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
 | 
			
		||||
 | 
			
		||||
        ApiResponse.ok(service.fetchData(member))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,109 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.content.main.tab.home
 | 
			
		||||
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerService
 | 
			
		||||
import kr.co.vividnext.sodalive.event.EventService
 | 
			
		||||
import kr.co.vividnext.sodalive.member.Member
 | 
			
		||||
import kr.co.vividnext.sodalive.notice.ServiceNoticeService
 | 
			
		||||
import kr.co.vividnext.sodalive.rank.RankingService
 | 
			
		||||
import org.springframework.stereotype.Service
 | 
			
		||||
import java.time.DayOfWeek
 | 
			
		||||
import java.time.LocalDateTime
 | 
			
		||||
import java.time.format.DateTimeFormatter
 | 
			
		||||
import java.time.temporal.TemporalAdjusters
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
class AudioContentMainTabHomeService(
 | 
			
		||||
    private val noticeService: ServiceNoticeService,
 | 
			
		||||
    private val bannerService: AudioContentBannerService,
 | 
			
		||||
    private val rankingService: RankingService,
 | 
			
		||||
    private val eventService: EventService
 | 
			
		||||
) {
 | 
			
		||||
    fun fetchData(member: Member): GetContentMainTabHomeResponse {
 | 
			
		||||
        // 주간 랭킹 기간
 | 
			
		||||
        val currentDateTime = LocalDateTime.now()
 | 
			
		||||
        val startDate = currentDateTime
 | 
			
		||||
            .withHour(15)
 | 
			
		||||
            .withMinute(0)
 | 
			
		||||
            .withSecond(0)
 | 
			
		||||
            .minusWeeks(1)
 | 
			
		||||
            .with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))
 | 
			
		||||
        val endDate = startDate
 | 
			
		||||
            .plusDays(7)
 | 
			
		||||
 | 
			
		||||
        val startDateFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일")
 | 
			
		||||
        val endDateFormatter = DateTimeFormatter.ofPattern("MM월 dd일")
 | 
			
		||||
 | 
			
		||||
        val formattedLastMonday = startDate.format(startDateFormatter)
 | 
			
		||||
        val formattedLastSunday = endDate.format(endDateFormatter)
 | 
			
		||||
 | 
			
		||||
        // 최근 공지사항
 | 
			
		||||
        val latestNotice = noticeService.getLatestNotice()
 | 
			
		||||
 | 
			
		||||
        // 메인 배너 (홈)
 | 
			
		||||
        val contentBannerList = bannerService.getBannerList(
 | 
			
		||||
            tabId = 1,
 | 
			
		||||
            memberId = member.id!!,
 | 
			
		||||
            isAdult = member.auth != null
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // 인기 크리에이터
 | 
			
		||||
        val rankCreatorList = rankingService.getCreatorRanking(
 | 
			
		||||
            memberId = member.id!!,
 | 
			
		||||
            rankingDate = "$formattedLastMonday ~ $formattedLastSunday"
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // 인기 시리즈
 | 
			
		||||
        val rankSeriesList = rankingService.getSeriesRanking(
 | 
			
		||||
            memberId = member.id!!,
 | 
			
		||||
            isAdult = member.auth != null,
 | 
			
		||||
            startDate = startDate.minusDays(1),
 | 
			
		||||
            endDate = endDate.minusDays(1)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // 인기 콘텐츠
 | 
			
		||||
        val rankContentList = rankingService.getContentRanking(
 | 
			
		||||
            memberId = member.id!!,
 | 
			
		||||
            isAdult = member.auth != null,
 | 
			
		||||
            startDate = startDate.minusDays(1),
 | 
			
		||||
            endDate = endDate.minusDays(1)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        // 이벤트 배너
 | 
			
		||||
        val eventBannerList = eventService.getEventList(isAdult = member.auth != null)
 | 
			
		||||
 | 
			
		||||
        /* 채널별 인기 콘텐츠
 | 
			
		||||
         * - 콘텐츠를 4개 이상 등록한 채널
 | 
			
		||||
         * - 주간 콘텐츠 매출 Top 20 채널
 | 
			
		||||
         * - 해당 채널의 누적 매출 Top 2
 | 
			
		||||
         * - 해당 채널의 누적 판매 개수 Top 2
 | 
			
		||||
         */
 | 
			
		||||
        val contentRankCreatorList = rankingService.fetchCreatorByContentRevenueRankTop20(
 | 
			
		||||
            memberId = member.id!!,
 | 
			
		||||
            startDate = startDate.minusDays(1),
 | 
			
		||||
            endDate = endDate.minusDays(1)
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val salesRankContentList = rankingService.fetchCreatorContentBySalesTop2(
 | 
			
		||||
            creatorId = contentRankCreatorList[0].creatorId,
 | 
			
		||||
            isAdult = member.auth != null
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        val salesCountRankContentList = rankingService.fetchCreatorContentBySalesCountTop2(
 | 
			
		||||
            creatorId = contentRankCreatorList[0].creatorId,
 | 
			
		||||
            isAdult = member.auth != null
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        return GetContentMainTabHomeResponse(
 | 
			
		||||
            latestNotice = latestNotice,
 | 
			
		||||
            bannerList = contentBannerList,
 | 
			
		||||
            rankCreatorList = rankCreatorList,
 | 
			
		||||
            rankSeriesList = rankSeriesList,
 | 
			
		||||
            rankSortTypeList = listOf("매출", "댓글", "좋아요"),
 | 
			
		||||
            rankContentList = rankContentList,
 | 
			
		||||
            eventBannerList = eventBannerList,
 | 
			
		||||
            contentRankCreatorList = contentRankCreatorList,
 | 
			
		||||
            salesRankContentList = salesRankContentList,
 | 
			
		||||
            salesCountRankContentList = salesCountRankContentList
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -0,0 +1,23 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.content.main.tab.home
 | 
			
		||||
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.ContentCreatorResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.GetAudioContentRankingItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.banner.GetAudioContentBannerResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.content.series.GetSeriesListResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.event.GetEventResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.explorer.GetExplorerSectionResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.notice.NoticeTitleItem
 | 
			
		||||
 | 
			
		||||
data class GetContentMainTabHomeResponse(
 | 
			
		||||
    val tabId: Long = 1,
 | 
			
		||||
    val latestNotice: NoticeTitleItem?,
 | 
			
		||||
    val bannerList: List<GetAudioContentBannerResponse>,
 | 
			
		||||
    val rankCreatorList: GetExplorerSectionResponse,
 | 
			
		||||
    val rankSeriesList: List<GetSeriesListResponse.SeriesListItem>,
 | 
			
		||||
    val rankSortTypeList: List<String>,
 | 
			
		||||
    val rankContentList: List<GetAudioContentRankingItem>,
 | 
			
		||||
    val eventBannerList: GetEventResponse,
 | 
			
		||||
    val contentRankCreatorList: List<ContentCreatorResponse>,
 | 
			
		||||
    val salesRankContentList: List<GetAudioContentRankingItem>,
 | 
			
		||||
    val salesCountRankContentList: List<GetAudioContentRankingItem>
 | 
			
		||||
)
 | 
			
		||||
@@ -1,5 +1,7 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.notice
 | 
			
		||||
 | 
			
		||||
import com.querydsl.core.annotations.QueryProjection
 | 
			
		||||
 | 
			
		||||
data class GetNoticeResponse(
 | 
			
		||||
    val totalCount: Int,
 | 
			
		||||
    val noticeList: List<NoticeItem>
 | 
			
		||||
@@ -11,3 +13,8 @@ data class NoticeItem(
 | 
			
		||||
    val content: String,
 | 
			
		||||
    val date: String
 | 
			
		||||
)
 | 
			
		||||
 | 
			
		||||
data class NoticeTitleItem @QueryProjection constructor(
 | 
			
		||||
    val id: Long,
 | 
			
		||||
    val title: String
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
@@ -63,4 +63,8 @@ class ServiceNoticeService(private val repository: ServiceServiceNoticeRepositor
 | 
			
		||||
 | 
			
		||||
        return GetNoticeResponse(totalCount, noticeList)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getLatestNotice(): NoticeTitleItem? {
 | 
			
		||||
        return repository.getLatestNotice()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -12,6 +12,7 @@ interface ServiceServiceNoticeRepository : JpaRepository<ServiceNotice, Long>, S
 | 
			
		||||
interface ServiceNoticeQueryRepository {
 | 
			
		||||
    fun getNoticeTotalCount(): Int
 | 
			
		||||
    fun getNoticeList(pageable: Pageable): List<ServiceNotice>
 | 
			
		||||
    fun getLatestNotice(): NoticeTitleItem?
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
@@ -34,4 +35,18 @@ class ServiceNoticeQueryRepositoryImpl(private val queryFactory: JPAQueryFactory
 | 
			
		||||
            .orderBy(serviceNotice.id.desc())
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    override fun getLatestNotice(): NoticeTitleItem? {
 | 
			
		||||
        return queryFactory
 | 
			
		||||
            .select(
 | 
			
		||||
                QNoticeTitleItem(
 | 
			
		||||
                    serviceNotice.id,
 | 
			
		||||
                    serviceNotice.title
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
            .from(serviceNotice)
 | 
			
		||||
            .where(serviceNotice.isActive.isTrue)
 | 
			
		||||
            .orderBy(serviceNotice.id.desc())
 | 
			
		||||
            .fetchFirst()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -0,0 +1,318 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.rank
 | 
			
		||||
 | 
			
		||||
import com.querydsl.jpa.impl.JPAQueryFactory
 | 
			
		||||
import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
 | 
			
		||||
import kr.co.vividnext.sodalive.content.comment.QAudioContentComment.audioContentComment
 | 
			
		||||
import kr.co.vividnext.sodalive.content.like.QAudioContentLike.audioContentLike
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.ContentCreatorResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.GetAudioContentRankingItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.QContentCreatorResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.QGetAudioContentRankingItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.order.QOrder.order
 | 
			
		||||
import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme
 | 
			
		||||
import kr.co.vividnext.sodalive.creator.admin.content.series.QSeries.series
 | 
			
		||||
import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent
 | 
			
		||||
import kr.co.vividnext.sodalive.creator.admin.content.series.Series
 | 
			
		||||
import kr.co.vividnext.sodalive.explorer.QCreatorRanking.creatorRanking
 | 
			
		||||
import kr.co.vividnext.sodalive.member.Member
 | 
			
		||||
import kr.co.vividnext.sodalive.member.MemberRole
 | 
			
		||||
import kr.co.vividnext.sodalive.member.QMember.member
 | 
			
		||||
import kr.co.vividnext.sodalive.member.block.QBlockMember.blockMember
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value
 | 
			
		||||
import org.springframework.stereotype.Repository
 | 
			
		||||
import java.time.LocalDateTime
 | 
			
		||||
 | 
			
		||||
@Repository
 | 
			
		||||
class RankingRepository(
 | 
			
		||||
    private val queryFactory: JPAQueryFactory,
 | 
			
		||||
 | 
			
		||||
    @Value("\${cloud.aws.cloud-front.host}")
 | 
			
		||||
    private val imageHost: String
 | 
			
		||||
) {
 | 
			
		||||
    fun getCreatorRankings(): List<Member> {
 | 
			
		||||
        return queryFactory
 | 
			
		||||
            .select(member)
 | 
			
		||||
            .from(creatorRanking)
 | 
			
		||||
            .innerJoin(creatorRanking.member, member)
 | 
			
		||||
            .orderBy(creatorRanking.ranking.asc())
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getAudioContentRanking(
 | 
			
		||||
        memberId: Long,
 | 
			
		||||
        isAdult: Boolean,
 | 
			
		||||
        startDate: LocalDateTime,
 | 
			
		||||
        endDate: LocalDateTime,
 | 
			
		||||
        offset: Long,
 | 
			
		||||
        limit: Long,
 | 
			
		||||
        sortType: String
 | 
			
		||||
    ): List<GetAudioContentRankingItem> {
 | 
			
		||||
        val blockMemberCondition = blockMember.member.id.eq(member.id)
 | 
			
		||||
            .and(blockMember.isActive.isTrue)
 | 
			
		||||
            .and(blockMember.blockedMember.id.eq(memberId))
 | 
			
		||||
 | 
			
		||||
        var where = audioContent.isActive.isTrue
 | 
			
		||||
            .and(audioContent.member.isActive.isTrue)
 | 
			
		||||
            .and(audioContent.member.isNotNull)
 | 
			
		||||
            .and(audioContent.member.role.eq(MemberRole.CREATOR))
 | 
			
		||||
            .and(audioContent.duration.isNotNull)
 | 
			
		||||
            .and(audioContentTheme.isActive.isTrue)
 | 
			
		||||
            .and(audioContent.limited.isNull)
 | 
			
		||||
            .and(blockMember.id.isNull)
 | 
			
		||||
 | 
			
		||||
        if (!isAdult) {
 | 
			
		||||
            where = where.and(audioContent.isAdult.isFalse)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        var select = queryFactory
 | 
			
		||||
            .select(
 | 
			
		||||
                QGetAudioContentRankingItem(
 | 
			
		||||
                    audioContent.id,
 | 
			
		||||
                    audioContent.title,
 | 
			
		||||
                    audioContent.coverImage.prepend("/").prepend(imageHost),
 | 
			
		||||
                    audioContentTheme.theme,
 | 
			
		||||
                    audioContent.price,
 | 
			
		||||
                    audioContent.duration,
 | 
			
		||||
                    member.id,
 | 
			
		||||
                    member.nickname
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        select = when (sortType) {
 | 
			
		||||
            "후원" -> {
 | 
			
		||||
                select
 | 
			
		||||
                    .from(audioContentComment)
 | 
			
		||||
                    .innerJoin(audioContentComment.audioContent, audioContent)
 | 
			
		||||
                    .innerJoin(audioContent.member, member)
 | 
			
		||||
                    .innerJoin(audioContent.theme, audioContentTheme)
 | 
			
		||||
                    .leftJoin(blockMember).on(blockMemberCondition)
 | 
			
		||||
                    .where(
 | 
			
		||||
                        where
 | 
			
		||||
                            .and(audioContentComment.isActive.isTrue)
 | 
			
		||||
                            .and(audioContentComment.donationCan.gt(0))
 | 
			
		||||
                            .and(audioContentComment.createdAt.goe(startDate))
 | 
			
		||||
                            .and(audioContentComment.createdAt.lt(endDate))
 | 
			
		||||
                    )
 | 
			
		||||
                    .groupBy(audioContent.id)
 | 
			
		||||
                    .orderBy(audioContentComment.donationCan.sum().desc(), audioContent.createdAt.asc())
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            "댓글" -> {
 | 
			
		||||
                select
 | 
			
		||||
                    .from(audioContentComment)
 | 
			
		||||
                    .innerJoin(audioContentComment.audioContent, audioContent)
 | 
			
		||||
                    .innerJoin(audioContent.member, member)
 | 
			
		||||
                    .innerJoin(audioContent.theme, audioContentTheme)
 | 
			
		||||
                    .leftJoin(blockMember).on(blockMemberCondition)
 | 
			
		||||
                    .where(
 | 
			
		||||
                        where
 | 
			
		||||
                            .and(audioContentComment.isActive.isTrue)
 | 
			
		||||
                            .and(audioContentComment.createdAt.goe(startDate))
 | 
			
		||||
                            .and(audioContentComment.createdAt.lt(endDate))
 | 
			
		||||
                    )
 | 
			
		||||
                    .groupBy(audioContentComment.audioContent.id)
 | 
			
		||||
                    .orderBy(audioContentComment.id.count().desc(), audioContent.createdAt.asc())
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            "좋아요" -> {
 | 
			
		||||
                select
 | 
			
		||||
                    .from(audioContentLike)
 | 
			
		||||
                    .innerJoin(audioContentLike.audioContent, audioContent)
 | 
			
		||||
                    .innerJoin(audioContent.member, member)
 | 
			
		||||
                    .innerJoin(audioContent.theme, audioContentTheme)
 | 
			
		||||
                    .leftJoin(blockMember).on(blockMemberCondition)
 | 
			
		||||
                    .where(
 | 
			
		||||
                        where
 | 
			
		||||
                            .and(audioContentLike.isActive.isTrue)
 | 
			
		||||
                            .and(audioContentLike.createdAt.goe(startDate))
 | 
			
		||||
                            .and(audioContentLike.createdAt.lt(endDate))
 | 
			
		||||
                    )
 | 
			
		||||
                    .groupBy(audioContentLike.audioContent.id)
 | 
			
		||||
                    .orderBy(audioContentLike.id.count().desc(), audioContent.createdAt.asc())
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            else -> {
 | 
			
		||||
                select
 | 
			
		||||
                    .from(order)
 | 
			
		||||
                    .innerJoin(order.audioContent, audioContent)
 | 
			
		||||
                    .innerJoin(audioContent.member, member)
 | 
			
		||||
                    .innerJoin(audioContent.theme, audioContentTheme)
 | 
			
		||||
                    .leftJoin(blockMember).on(blockMemberCondition)
 | 
			
		||||
                    .where(
 | 
			
		||||
                        where
 | 
			
		||||
                            .and(order.isActive.isTrue)
 | 
			
		||||
                            .and(order.createdAt.goe(startDate))
 | 
			
		||||
                            .and(order.createdAt.lt(endDate))
 | 
			
		||||
                    )
 | 
			
		||||
                    .groupBy(audioContent.id)
 | 
			
		||||
                    .orderBy(order.can.sum().desc(), audioContent.createdAt.asc())
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return select
 | 
			
		||||
            .offset(offset)
 | 
			
		||||
            .limit(limit)
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getSeriesRanking(
 | 
			
		||||
        memberId: Long,
 | 
			
		||||
        isAdult: Boolean,
 | 
			
		||||
        startDate: LocalDateTime,
 | 
			
		||||
        endDate: LocalDateTime
 | 
			
		||||
    ): List<Series> {
 | 
			
		||||
        val blockMemberCondition = blockMember.member.id.eq(member.id)
 | 
			
		||||
            .and(blockMember.isActive.isTrue)
 | 
			
		||||
            .and(blockMember.blockedMember.id.eq(memberId))
 | 
			
		||||
 | 
			
		||||
        var where = series.isActive.isTrue
 | 
			
		||||
            .and(audioContent.isActive.isTrue)
 | 
			
		||||
            .and(member.isActive.isTrue)
 | 
			
		||||
            .and(member.isNotNull)
 | 
			
		||||
            .and(member.role.eq(MemberRole.CREATOR))
 | 
			
		||||
            .and(audioContent.duration.isNotNull)
 | 
			
		||||
            .and(audioContent.limited.isNull)
 | 
			
		||||
            .and(blockMember.id.isNull)
 | 
			
		||||
            .and(order.isActive.isTrue)
 | 
			
		||||
            .and(order.createdAt.goe(startDate))
 | 
			
		||||
            .and(order.createdAt.lt(endDate))
 | 
			
		||||
 | 
			
		||||
        if (!isAdult) {
 | 
			
		||||
            where = where.and(series.isAdult.isFalse)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return queryFactory
 | 
			
		||||
            .select(series)
 | 
			
		||||
            .from(seriesContent)
 | 
			
		||||
            .innerJoin(seriesContent.series, series)
 | 
			
		||||
            .innerJoin(seriesContent.content, audioContent)
 | 
			
		||||
            .innerJoin(series.member, member)
 | 
			
		||||
            .innerJoin(order).on(audioContent.id.eq(order.audioContent.id))
 | 
			
		||||
            .leftJoin(blockMember).on(blockMemberCondition)
 | 
			
		||||
            .where(where)
 | 
			
		||||
            .groupBy(series.id)
 | 
			
		||||
            .orderBy(order.can.sum().desc(), series.createdAt.asc())
 | 
			
		||||
            .offset(0)
 | 
			
		||||
            .limit(10)
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun fetchCreatorByContentRevenueRankTop20(
 | 
			
		||||
        memberId: Long,
 | 
			
		||||
        startDate: LocalDateTime,
 | 
			
		||||
        endDate: LocalDateTime
 | 
			
		||||
    ): List<ContentCreatorResponse> {
 | 
			
		||||
        val blockMemberCondition = blockMember.member.id.eq(member.id)
 | 
			
		||||
            .and(blockMember.isActive.isTrue)
 | 
			
		||||
            .and(blockMember.blockedMember.id.eq(memberId))
 | 
			
		||||
 | 
			
		||||
        val ordersCondition = order.audioContent.id.eq(audioContent.id)
 | 
			
		||||
            .and(order.isActive.isTrue)
 | 
			
		||||
            .and(order.createdAt.goe(startDate))
 | 
			
		||||
            .and(order.createdAt.lt(startDate))
 | 
			
		||||
 | 
			
		||||
        val where = member.isActive.isTrue
 | 
			
		||||
            .and(member.role.eq(MemberRole.CREATOR))
 | 
			
		||||
            .and(audioContent.isActive.isTrue)
 | 
			
		||||
            .and(audioContent.duration.isNotNull)
 | 
			
		||||
            .and(audioContent.limited.isNull)
 | 
			
		||||
            .and(blockMember.id.isNull)
 | 
			
		||||
 | 
			
		||||
        return queryFactory
 | 
			
		||||
            .select(
 | 
			
		||||
                QContentCreatorResponse(
 | 
			
		||||
                    member.id,
 | 
			
		||||
                    member.nickname,
 | 
			
		||||
                    member.profileImage.prepend("/").prepend(imageHost)
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
            .from(member)
 | 
			
		||||
            .innerJoin(audioContent).on(member.id.eq(audioContent.member.id))
 | 
			
		||||
            .leftJoin(order).on(ordersCondition)
 | 
			
		||||
            .leftJoin(blockMember).on(blockMemberCondition)
 | 
			
		||||
            .where(where)
 | 
			
		||||
            .groupBy(member.id)
 | 
			
		||||
            .having(
 | 
			
		||||
                audioContent.id.count().goe(4)
 | 
			
		||||
                    .and(order.can.sum().gt(0))
 | 
			
		||||
            )
 | 
			
		||||
            .orderBy(order.can.sum().desc())
 | 
			
		||||
            .offset(0)
 | 
			
		||||
            .limit(20)
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun fetchCreatorContentBySalesTop2(creatorId: Long, isAdult: Boolean): List<GetAudioContentRankingItem> {
 | 
			
		||||
        var where = member.isActive.isTrue
 | 
			
		||||
            .and(member.role.eq(MemberRole.CREATOR))
 | 
			
		||||
            .and(audioContent.isActive.isTrue)
 | 
			
		||||
            .and(audioContent.duration.isNotNull)
 | 
			
		||||
            .and(audioContent.limited.isNull)
 | 
			
		||||
            .and(order.isActive.isTrue)
 | 
			
		||||
            .and(member.id.eq(creatorId))
 | 
			
		||||
 | 
			
		||||
        if (!isAdult) {
 | 
			
		||||
            where = where.and(series.isAdult.isFalse)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return queryFactory
 | 
			
		||||
            .select(
 | 
			
		||||
                QGetAudioContentRankingItem(
 | 
			
		||||
                    audioContent.id,
 | 
			
		||||
                    audioContent.title,
 | 
			
		||||
                    audioContent.coverImage.prepend("/").prepend(imageHost),
 | 
			
		||||
                    audioContentTheme.theme,
 | 
			
		||||
                    audioContent.price,
 | 
			
		||||
                    audioContent.duration,
 | 
			
		||||
                    member.id,
 | 
			
		||||
                    member.nickname
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
            .from(order)
 | 
			
		||||
            .innerJoin(order.audioContent, audioContent)
 | 
			
		||||
            .innerJoin(audioContent.member, member)
 | 
			
		||||
            .where(where)
 | 
			
		||||
            .groupBy(audioContent.id)
 | 
			
		||||
            .orderBy(order.can.sum().desc())
 | 
			
		||||
            .offset(0)
 | 
			
		||||
            .limit(2)
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun fetchCreatorContentBySalesCountTop2(creatorId: Long, isAdult: Boolean): List<GetAudioContentRankingItem> {
 | 
			
		||||
        var where = member.isActive.isTrue
 | 
			
		||||
            .and(member.role.eq(MemberRole.CREATOR))
 | 
			
		||||
            .and(audioContent.isActive.isTrue)
 | 
			
		||||
            .and(audioContent.duration.isNotNull)
 | 
			
		||||
            .and(audioContent.limited.isNull)
 | 
			
		||||
            .and(order.isActive.isTrue)
 | 
			
		||||
            .and(member.id.eq(creatorId))
 | 
			
		||||
 | 
			
		||||
        if (!isAdult) {
 | 
			
		||||
            where = where.and(series.isAdult.isFalse)
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return queryFactory
 | 
			
		||||
            .select(
 | 
			
		||||
                QGetAudioContentRankingItem(
 | 
			
		||||
                    audioContent.id,
 | 
			
		||||
                    audioContent.title,
 | 
			
		||||
                    audioContent.coverImage.prepend("/").prepend(imageHost),
 | 
			
		||||
                    audioContentTheme.theme,
 | 
			
		||||
                    audioContent.price,
 | 
			
		||||
                    audioContent.duration,
 | 
			
		||||
                    member.id,
 | 
			
		||||
                    member.nickname
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
            .from(order)
 | 
			
		||||
            .innerJoin(order.audioContent, audioContent)
 | 
			
		||||
            .innerJoin(audioContent.member, member)
 | 
			
		||||
            .where(where)
 | 
			
		||||
            .groupBy(audioContent.id)
 | 
			
		||||
            .orderBy(order.id.count().desc())
 | 
			
		||||
            .offset(0)
 | 
			
		||||
            .limit(2)
 | 
			
		||||
            .fetch()
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										151
									
								
								src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingService.kt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										151
									
								
								src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingService.kt
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,151 @@
 | 
			
		||||
package kr.co.vividnext.sodalive.rank
 | 
			
		||||
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.ContentCreatorResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.content.main.GetAudioContentRankingItem
 | 
			
		||||
import kr.co.vividnext.sodalive.content.series.GetSeriesListResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.content.series.content.ContentSeriesContentRepository
 | 
			
		||||
import kr.co.vividnext.sodalive.creator.admin.content.series.Series
 | 
			
		||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesPublishedDaysOfWeek
 | 
			
		||||
import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesState
 | 
			
		||||
import kr.co.vividnext.sodalive.explorer.GetExplorerSectionResponse
 | 
			
		||||
import kr.co.vividnext.sodalive.member.MemberService
 | 
			
		||||
import org.springframework.beans.factory.annotation.Value
 | 
			
		||||
import org.springframework.stereotype.Service
 | 
			
		||||
import java.time.LocalDateTime
 | 
			
		||||
 | 
			
		||||
@Service
 | 
			
		||||
class RankingService(
 | 
			
		||||
    private val repository: RankingRepository,
 | 
			
		||||
    private val memberService: MemberService,
 | 
			
		||||
    private val seriesContentRepository: ContentSeriesContentRepository,
 | 
			
		||||
 | 
			
		||||
    @Value("\${cloud.aws.cloud-front.host}")
 | 
			
		||||
    private val imageHost: String
 | 
			
		||||
) {
 | 
			
		||||
    fun getCreatorRanking(memberId: Long, rankingDate: String): GetExplorerSectionResponse {
 | 
			
		||||
        val creatorRankings = repository
 | 
			
		||||
            .getCreatorRankings()
 | 
			
		||||
            .filter { !memberService.isBlocked(blockedMemberId = memberId, memberId = it.id!!) }
 | 
			
		||||
            .map { it.toExplorerSectionCreator(imageHost) }
 | 
			
		||||
 | 
			
		||||
        return GetExplorerSectionResponse(
 | 
			
		||||
            title = "인기 크리에이터",
 | 
			
		||||
            coloredTitle = "인기",
 | 
			
		||||
            color = "FF5C49",
 | 
			
		||||
            desc = rankingDate,
 | 
			
		||||
            creators = creatorRankings
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getContentRanking(
 | 
			
		||||
        memberId: Long,
 | 
			
		||||
        isAdult: Boolean,
 | 
			
		||||
        startDate: LocalDateTime,
 | 
			
		||||
        endDate: LocalDateTime,
 | 
			
		||||
        offset: Long = 0,
 | 
			
		||||
        limit: Long = 12,
 | 
			
		||||
        sortType: String = "매출"
 | 
			
		||||
    ): List<GetAudioContentRankingItem> {
 | 
			
		||||
        return repository.getAudioContentRanking(
 | 
			
		||||
            memberId = memberId,
 | 
			
		||||
            isAdult = isAdult,
 | 
			
		||||
            startDate = startDate,
 | 
			
		||||
            endDate = endDate,
 | 
			
		||||
            offset = offset,
 | 
			
		||||
            limit = limit,
 | 
			
		||||
            sortType = sortType
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun getSeriesRanking(
 | 
			
		||||
        memberId: Long,
 | 
			
		||||
        isAdult: Boolean,
 | 
			
		||||
        startDate: LocalDateTime,
 | 
			
		||||
        endDate: LocalDateTime
 | 
			
		||||
    ): List<GetSeriesListResponse.SeriesListItem> {
 | 
			
		||||
        val seriesList = repository.getSeriesRanking(memberId, isAdult, startDate, endDate)
 | 
			
		||||
        return seriesToSeriesListItem(seriesList = seriesList, isAdult = isAdult)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun seriesToSeriesListItem(
 | 
			
		||||
        seriesList: List<Series>,
 | 
			
		||||
        isAdult: Boolean
 | 
			
		||||
    ): List<GetSeriesListResponse.SeriesListItem> {
 | 
			
		||||
        return seriesList
 | 
			
		||||
            .map {
 | 
			
		||||
                GetSeriesListResponse.SeriesListItem(
 | 
			
		||||
                    seriesId = it.id!!,
 | 
			
		||||
                    title = it.title,
 | 
			
		||||
                    coverImage = "$imageHost/${it.coverImage!!}",
 | 
			
		||||
                    publishedDaysOfWeek = publishedDaysOfWeekText(it.publishedDaysOfWeek),
 | 
			
		||||
                    isComplete = it.state == SeriesState.COMPLETE,
 | 
			
		||||
                    creator = GetSeriesListResponse.SeriesListItemCreator(
 | 
			
		||||
                        creatorId = it.member!!.id!!,
 | 
			
		||||
                        nickname = it.member!!.nickname,
 | 
			
		||||
                        profileImage = "$imageHost/${it.member!!.profileImage!!}"
 | 
			
		||||
                    )
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            .map {
 | 
			
		||||
                it.numberOfContent = seriesContentRepository.getContentCount(
 | 
			
		||||
                    seriesId = it.seriesId,
 | 
			
		||||
                    isAdult = isAdult
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                it
 | 
			
		||||
            }
 | 
			
		||||
            .map {
 | 
			
		||||
                val nowDateTime = LocalDateTime.now()
 | 
			
		||||
 | 
			
		||||
                it.isNew = seriesContentRepository.isNewContent(
 | 
			
		||||
                    seriesId = it.seriesId,
 | 
			
		||||
                    isAdult = isAdult,
 | 
			
		||||
                    fromDate = nowDateTime.minusDays(7),
 | 
			
		||||
                    nowDate = nowDateTime
 | 
			
		||||
                )
 | 
			
		||||
 | 
			
		||||
                it
 | 
			
		||||
            }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private fun publishedDaysOfWeekText(publishedDaysOfWeek: Set<SeriesPublishedDaysOfWeek>): String {
 | 
			
		||||
        val dayOfWeekText = publishedDaysOfWeek.toList().sortedBy { it.ordinal }
 | 
			
		||||
            .map {
 | 
			
		||||
                when (it) {
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.SUN -> "일"
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.MON -> "월"
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.TUE -> "화"
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.WED -> "수"
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.THU -> "목"
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.FRI -> "금"
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.SAT -> "토"
 | 
			
		||||
                    SeriesPublishedDaysOfWeek.RANDOM -> "랜덤"
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            .joinToString(", ") { it }
 | 
			
		||||
 | 
			
		||||
        return if (publishedDaysOfWeek.contains(SeriesPublishedDaysOfWeek.RANDOM)) {
 | 
			
		||||
            dayOfWeekText
 | 
			
		||||
        } else if (publishedDaysOfWeek.size < 7) {
 | 
			
		||||
            "매주 $dayOfWeekText"
 | 
			
		||||
        } else {
 | 
			
		||||
            "매일"
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun fetchCreatorByContentRevenueRankTop20(
 | 
			
		||||
        memberId: Long,
 | 
			
		||||
        startDate: LocalDateTime,
 | 
			
		||||
        endDate: LocalDateTime
 | 
			
		||||
    ): List<ContentCreatorResponse> {
 | 
			
		||||
        return repository.fetchCreatorByContentRevenueRankTop20(memberId, startDate, endDate)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun fetchCreatorContentBySalesTop2(creatorId: Long, isAdult: Boolean): List<GetAudioContentRankingItem> {
 | 
			
		||||
        return repository.fetchCreatorContentBySalesTop2(creatorId, isAdult)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    fun fetchCreatorContentBySalesCountTop2(creatorId: Long, isAdult: Boolean): List<GetAudioContentRankingItem> {
 | 
			
		||||
        return repository.fetchCreatorContentBySalesCountTop2(creatorId, isAdult)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user