test #63
@@ -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
 | 
			
		||||
            )
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -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<GetAudioContentRankingItem>
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@@ -443,11 +447,11 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
 | 
			
		||||
        startDate: LocalDateTime,
 | 
			
		||||
        endDate: LocalDateTime,
 | 
			
		||||
        offset: Long,
 | 
			
		||||
        limit: Long
 | 
			
		||||
        limit: Long,
 | 
			
		||||
        sortType: String
 | 
			
		||||
    ): List<GetAudioContentRankingItem> {
 | 
			
		||||
        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
 | 
			
		||||
                )
 | 
			
		||||
            )
 | 
			
		||||
 | 
			
		||||
        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)
 | 
			
		||||
                    .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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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<String> {
 | 
			
		||||
        return listOf("매출", "후원", "댓글", "좋아요")
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -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()
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -10,5 +10,6 @@ data class GetAudioContentMainResponse(
 | 
			
		||||
    val themeList: List<String>,
 | 
			
		||||
    val newContentList: List<GetAudioContentMainItem>,
 | 
			
		||||
    val curationList: List<GetAudioContentCurationResponse>,
 | 
			
		||||
    val contentRankingSortTypeList: List<String>,
 | 
			
		||||
    val contentRanking: GetAudioContentRanking
 | 
			
		||||
)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user