콘텐츠 랭킹 추가 #44

Merged
klaus merged 5 commits from test into main 2023-10-14 19:37:56 +00:00
6 changed files with 166 additions and 2 deletions

View File

@ -148,4 +148,20 @@ class AudioContentController(private val service: AudioContentService) {
ApiResponse.ok(service.audioContentLike(request, member))
}
@GetMapping("/ranking")
fun getAudioContentRanking(
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?,
pageable: Pageable
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(
service.getAudioContentRanking(
member = member,
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
)
}
}

View File

@ -2,15 +2,19 @@ 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.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
import kr.co.vividnext.sodalive.content.main.banner.QAudioContentBanner.audioContentBanner
import kr.co.vividnext.sodalive.content.main.curation.AudioContentCuration
import kr.co.vividnext.sodalive.content.main.curation.QAudioContentCuration.audioContentCuration
import kr.co.vividnext.sodalive.content.order.QOrder.order
import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme
import kr.co.vividnext.sodalive.event.QEvent.event
import kr.co.vividnext.sodalive.member.QMember.member
@ -78,6 +82,15 @@ interface AudioContentQueryRepository {
cloudfrontHost: String,
isAdult: Boolean
): List<GetAudioContentMainItem>
fun getAudioContentRanking(
cloudfrontHost: String,
isAdult: Boolean,
startDate: LocalDateTime,
endDate: LocalDateTime,
offset: Long = 0,
limit: Long = 12
): List<GetAudioContentRankingItem>
}
@Repository
@ -424,4 +437,48 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
.orderBy(audioContent.id.desc())
.fetch()
}
override fun getAudioContentRanking(
cloudfrontHost: String,
isAdult: Boolean,
startDate: LocalDateTime,
endDate: LocalDateTime,
offset: Long,
limit: Long
): List<GetAudioContentRankingItem> {
var where = audioContent.isActive.isTrue
.and(audioContent.member.isNotNull)
.and(audioContent.duration.isNotNull)
.and(audioContent.member.isActive.isTrue)
.and(useCan.createdAt.goe(startDate))
.and(useCan.createdAt.lt(endDate))
if (!isAdult) {
where = where.and(audioContent.isAdult.isFalse)
}
return queryFactory
.select(
QGetAudioContentRankingItem(
audioContent.id,
audioContent.title,
audioContent.coverImage.prepend("/").prepend(cloudfrontHost),
audioContentTheme.theme,
audioContent.price,
audioContent.duration,
member.id,
member.nickname
)
)
.from(useCan)
.innerJoin(useCan.order, order)
.innerJoin(order.audioContent, audioContent)
.innerJoin(audioContent.member, member)
.innerJoin(audioContent.theme, audioContentTheme)
.where(where)
.groupBy(audioContent.id)
.orderBy(order.can.sum().desc())
.limit(limit)
.fetch()
}
}

View File

@ -13,6 +13,7 @@ import kr.co.vividnext.sodalive.content.like.AudioContentLike
import kr.co.vividnext.sodalive.content.like.AudioContentLikeRepository
import kr.co.vividnext.sodalive.content.like.PutAudioContentLikeRequest
import kr.co.vividnext.sodalive.content.like.PutAudioContentLikeResponse
import kr.co.vividnext.sodalive.content.main.GetAudioContentRanking
import kr.co.vividnext.sodalive.content.order.OrderRepository
import kr.co.vividnext.sodalive.content.order.OrderType
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository
@ -29,9 +30,11 @@ 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
@ -573,4 +576,39 @@ class AudioContentService(
)
}
}
fun getAudioContentRanking(
member: Member,
offset: Long,
limit: Long
): 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일")
val contentRankingItemList = repository
.getAudioContentRanking(
cloudfrontHost = coverImageHost,
startDate = startDate,
endDate = endDate,
isAdult = member.auth != null,
offset = offset,
limit = limit
)
return GetAudioContentRanking(
startDate = startDate.format(startDateFormatter),
endDate = endDate.minusDays(1).format(endDateFormatter),
items = contentRankingItemList
)
}
}

View File

@ -12,6 +12,10 @@ import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import org.springframework.beans.factory.annotation.Value
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(
@ -126,13 +130,41 @@ class AudioContentMainService(
.filter { it.contents.isNotEmpty() }
.toList()
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 contentRankingItemList = repository
.getAudioContentRanking(
cloudfrontHost = imageHost,
startDate = startDate,
endDate = endDate,
isAdult = isAdult
)
val contentRanking = GetAudioContentRanking(
startDate = startDate.format(startDateFormatter),
endDate = endDate.minusDays(1).format(endDateFormatter),
contentRankingItemList
)
return GetAudioContentMainResponse(
newContentUploadCreatorList = newContentUploadCreatorList,
bannerList = bannerList,
orderList = orderList,
themeList = themeList,
newContentList = newContentList,
curationList = curationList
curationList = curationList,
contentRanking = contentRanking
)
}

View File

@ -9,5 +9,6 @@ data class GetAudioContentMainResponse(
val orderList: List<GetAudioContentMainItem>,
val themeList: List<String>,
val newContentList: List<GetAudioContentMainItem>,
val curationList: List<GetAudioContentCurationResponse>
val curationList: List<GetAudioContentCurationResponse>,
val contentRanking: GetAudioContentRanking
)

View File

@ -0,0 +1,20 @@
package kr.co.vividnext.sodalive.content.main
import com.querydsl.core.annotations.QueryProjection
data class GetAudioContentRanking(
val startDate: String,
val endDate: String,
val items: List<GetAudioContentRankingItem>
)
data class GetAudioContentRankingItem @QueryProjection constructor(
val contentId: Long,
val title: String,
val coverImageUrl: String,
val themeStr: String,
val price: Int,
val duration: String,
val creatorId: Long,
val creatorNickname: String
)