diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt index 286f232..bddedcd 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt @@ -19,6 +19,9 @@ import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RequestPart import org.springframework.web.bind.annotation.RestController import org.springframework.web.multipart.MultipartFile +import java.time.DayOfWeek +import java.time.LocalDateTime +import java.time.temporal.TemporalAdjusters @RestController @RequestMapping("/audio-content") @@ -152,15 +155,29 @@ class AudioContentController(private val service: AudioContentService) { @GetMapping("/ranking") fun getAudioContentRanking( @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, + @RequestParam("sortType") sortType: String, pageable: Pageable ) = run { if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + 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) + ApiResponse.ok( service.getAudioContentRanking( - member = member, + isAdult = member.auth != null, + startDate = startDate, + endDate = endDate, offset = pageable.offset, - limit = pageable.pageSize.toLong() + limit = pageable.pageSize.toLong(), + sortType = sortType ) ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt index e7bfebe..ee349c7 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt @@ -2,8 +2,11 @@ package kr.co.vividnext.sodalive.content import com.querydsl.core.types.dsl.Expressions import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.can.use.QUseCan.useCan import kr.co.vividnext.sodalive.content.QAudioContent.audioContent import kr.co.vividnext.sodalive.content.QBundleAudioContent.bundleAudioContent +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.GetAudioContentMainItem import kr.co.vividnext.sodalive.content.main.GetAudioContentRankingItem import kr.co.vividnext.sodalive.content.main.GetNewContentUploadCreator @@ -88,7 +91,8 @@ interface AudioContentQueryRepository { startDate: LocalDateTime, endDate: LocalDateTime, offset: Long = 0, - limit: Long = 12 + limit: Long = 12, + sortType: String = "매출" ): List } @@ -443,11 +447,11 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) startDate: LocalDateTime, endDate: LocalDateTime, offset: Long, - limit: Long + limit: Long, + sortType: String ): List { - var where = order.createdAt.goe(startDate) - .and(order.createdAt.lt(endDate)) - .and(audioContent.isActive.isTrue) + var where = audioContent.isActive.isTrue + .and(audioContent.member.id.ne(648)) .and(audioContent.member.isNotNull) .and(audioContent.duration.isNotNull) .and(audioContent.member.isActive.isTrue) @@ -457,7 +461,7 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) where = where.and(audioContent.isAdult.isFalse) } - return queryFactory + var select = queryFactory .select( QGetAudioContentRankingItem( audioContent.id, @@ -470,13 +474,70 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) member.nickname ) ) - .from(order) - .innerJoin(order.audioContent, audioContent) - .innerJoin(audioContent.member, member) - .innerJoin(audioContent.theme, audioContentTheme) - .where(where) - .groupBy(audioContent.id) - .orderBy(order.can.sum().desc(), audioContent.createdAt.asc()) + + select = when (sortType) { + "후원" -> { + select + .from(useCan) + .innerJoin(useCan.audioContent, audioContent) + .innerJoin(audioContent.member, member) + .innerJoin(audioContent.theme, audioContentTheme) + .where( + where + .and(audioContentComment.createdAt.goe(startDate)) + .and(audioContentComment.createdAt.lt(endDate)) + ) + .groupBy(audioContent.id) + .orderBy(useCan.can.add(useCan.rewardCan).sum().desc(), audioContent.createdAt.asc()) + } + + "댓글" -> { + select + .from(audioContentComment) + .innerJoin(audioContentComment.audioContent, audioContent) + .innerJoin(audioContentComment.audioContent.member, member) + .innerJoin(audioContentComment.audioContent.theme, audioContentTheme) + .where( + where + .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(audioContentLike.audioContent.member, member) + .innerJoin(audioContentLike.audioContent.theme, audioContentTheme) + .where( + where + .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) + .where( + where + .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() 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 ea50196..6d12fe6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -24,17 +24,16 @@ import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import kr.co.vividnext.sodalive.utils.generateFileName import org.springframework.beans.factory.annotation.Value +import org.springframework.cache.annotation.Cacheable import org.springframework.context.ApplicationEventPublisher import org.springframework.data.repository.findByIdOrNull import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional import org.springframework.web.multipart.MultipartFile import java.text.SimpleDateFormat -import java.time.DayOfWeek import java.time.LocalDateTime import java.time.ZoneId import java.time.format.DateTimeFormatter -import java.time.temporal.TemporalAdjusters import java.util.Locale @Service @@ -72,11 +71,10 @@ class AudioContentService( ) if (audioContentLike == null) { - audioContentLike = AudioContentLike( - memberId = member.id!!, - contentId = request.contentId - ) + audioContentLike = AudioContentLike(memberId = member.id!!) + val audioContent = repository.findByIdAndActive(request.contentId) + audioContentLike.audioContent = audioContent audioContentLikeRepository.save(audioContentLike) } else { audioContentLike.isActive = !audioContentLike.isActive @@ -579,21 +577,19 @@ class AudioContentService( } } + @Cacheable( + cacheNames = ["cache_ttl_3_days"], + key = "'contentRanking:' + ':' +" + + "#isAdult + ':' + #startDate + ':' + #endDate + ':' + #sortType + ':' + #offset + ':' + #limit" + ) fun getAudioContentRanking( - member: Member, + isAdult: Boolean, + startDate: LocalDateTime, + endDate: LocalDateTime, offset: Long, - limit: Long + limit: Long, + sortType: String = "매출" ): GetAudioContentRanking { - 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일") @@ -602,9 +598,10 @@ class AudioContentService( cloudfrontHost = coverImageHost, startDate = startDate.minusDays(1), endDate = endDate.minusDays(1), - isAdult = member.auth != null, + isAdult = isAdult, offset = offset, - limit = limit + limit = limit, + sortType = sortType ) return GetAudioContentRanking( @@ -613,4 +610,8 @@ class AudioContentService( items = contentRankingItemList ) } + + fun getContentRankingSortTypeList(): List { + return listOf("매출", "후원", "댓글", "좋아요") + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLike.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLike.kt index 5b9b16a..d54c5dd 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLike.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLike.kt @@ -1,20 +1,21 @@ package kr.co.vividnext.sodalive.content.like +import kr.co.vividnext.sodalive.content.AudioContent import java.time.LocalDateTime import javax.persistence.Entity +import javax.persistence.FetchType import javax.persistence.GeneratedValue import javax.persistence.GenerationType import javax.persistence.Id +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne import javax.persistence.PrePersist import javax.persistence.PreUpdate import javax.persistence.Table @Entity @Table(name = "content_like") -data class AudioContentLike( - val memberId: Long, - val contentId: Long -) { +data class AudioContentLike(val memberId: Long) { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) var id: Long? = null @@ -34,4 +35,8 @@ data class AudioContentLike( } var isActive = true + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "content_id", nullable = false) + var audioContent: AudioContent? = null } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLikeRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLikeRepository.kt index db8b1ad..72e9310 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLikeRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/like/AudioContentLikeRepository.kt @@ -20,7 +20,7 @@ class AudioContentLikeQueryRepositoryImpl(private val queryFactory: JPAQueryFact .selectFrom(audioContentLike) .where( audioContentLike.memberId.eq(memberId) - .and(audioContentLike.contentId.eq(contentId)) + .and(audioContentLike.audioContent.id.eq(contentId)) ) .fetchFirst() } @@ -30,7 +30,7 @@ class AudioContentLikeQueryRepositoryImpl(private val queryFactory: JPAQueryFact .select(audioContentLike.id) .from(audioContentLike) .where( - audioContentLike.contentId.eq(contentId) + audioContentLike.audioContent.id.eq(contentId) .and(audioContentLike.isActive.isTrue) ) .fetch() diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/AudioContentMainService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/AudioContentMainService.kt index 56f35f6..4b3fa20 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/AudioContentMainService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/AudioContentMainService.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.content.main import kr.co.vividnext.sodalive.content.AudioContentRepository +import kr.co.vividnext.sodalive.content.AudioContentService import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerType import kr.co.vividnext.sodalive.content.main.banner.GetAudioContentBannerResponse import kr.co.vividnext.sodalive.content.main.curation.GetAudioContentCurationResponse @@ -15,12 +16,12 @@ import org.springframework.data.domain.Pageable 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 AudioContentMainService( private val repository: AudioContentRepository, + private val audioContentService: AudioContentService, private val blockMemberRepository: BlockMemberRepository, private val orderService: OrderService, private val audioContentThemeRepository: AudioContentThemeQueryRepository, @@ -66,7 +67,14 @@ class AudioContentMainService( .withSecond(0) val endDate = startDate.plusDays(7) - val contentRanking = getContentRanking(isAdult = isAdult, startDate = startDate, endDate = endDate) + val contentRankingSortTypeList = audioContentService.getContentRankingSortTypeList() + val contentRanking = audioContentService.getAudioContentRanking( + isAdult = isAdult, + startDate = startDate, + endDate = endDate, + offset = 0, + limit = 12 + ) return GetAudioContentMainResponse( newContentUploadCreatorList = newContentUploadCreatorList, @@ -75,6 +83,7 @@ class AudioContentMainService( themeList = themeList, newContentList = newContentList, curationList = curationList, + contentRankingSortTypeList = contentRankingSortTypeList, contentRanking = contentRanking ) } @@ -192,27 +201,4 @@ class AudioContentMainService( } .filter { it.contents.isNotEmpty() } .toList() - - @Cacheable( - cacheNames = ["cache_ttl_3_days"], - key = "'contentRanking:' + ':' + #isAdult + ':' + #startDate + ':' + #endDate" - ) - fun getContentRanking(isAdult: Boolean, startDate: LocalDateTime, endDate: LocalDateTime): GetAudioContentRanking { - val startDateFormatter = DateTimeFormatter.ofPattern("yyyy년 MM월 dd일") - val endDateFormatter = DateTimeFormatter.ofPattern("MM월 dd일") - - val contentRankingItemList = repository - .getAudioContentRanking( - cloudfrontHost = imageHost, - startDate = startDate.minusDays(1), - endDate = endDate.minusDays(1), - isAdult = isAdult - ) - - return GetAudioContentRanking( - startDate = startDate.format(startDateFormatter), - endDate = endDate.minusDays(1).format(endDateFormatter), - contentRankingItemList - ) - } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainResponse.kt index 9734f21..1cd184c 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainResponse.kt @@ -10,5 +10,6 @@ data class GetAudioContentMainResponse( val themeList: List, val newContentList: List, val curationList: List, + val contentRankingSortTypeList: List, val contentRanking: GetAudioContentRanking )