콘텐츠 메인

- 단편 탭 API
This commit is contained in:
Klaus 2025-02-07 18:29:31 +09:00
parent 0f8fcbcaed
commit c5539bc7e3
6 changed files with 162 additions and 17 deletions

View File

@ -24,6 +24,7 @@ import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentThe
import kr.co.vividnext.sodalive.event.QEvent.event
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.data.jpa.repository.JpaRepository
import org.springframework.stereotype.Repository
@ -61,7 +62,6 @@ interface AudioContentQueryRepository {
): List<OtherContentResponse>
fun findByTheme(
cloudfrontHost: String,
memberId: Long,
theme: String = "",
sortType: SortType = SortType.NEWEST,
@ -334,7 +334,6 @@ class AudioContentQueryRepositoryImpl(
}
override fun findByTheme(
cloudfrontHost: String,
memberId: Long,
theme: String,
sortType: SortType,
@ -343,6 +342,10 @@ class AudioContentQueryRepositoryImpl(
offset: Long,
limit: Long
): List<GetAudioContentMainItem> {
val blockMemberCondition = blockMember.member.id.eq(member.id)
.and(blockMember.isActive.isTrue)
.and(blockMember.blockedMember.id.eq(memberId))
val orderBy = when (sortType) {
SortType.NEWEST -> listOf(audioContent.releaseDate.desc(), audioContent.id.desc())
SortType.PRICE_HIGH -> listOf(
@ -365,6 +368,7 @@ class AudioContentQueryRepositoryImpl(
.or(audioContent.releaseDate.loe(LocalDateTime.now()))
.or(audioContent.member.id.eq(memberId))
)
.and(blockMember.id.isNull)
if (!isAdult) {
where = where.and(audioContent.isAdult.isFalse)
@ -384,10 +388,10 @@ class AudioContentQueryRepositoryImpl(
.select(
QGetAudioContentMainItem(
audioContent.id,
audioContent.coverImage.prepend("/").prepend(cloudfrontHost),
audioContent.coverImage.prepend("/").prepend(imageHost),
audioContent.title,
member.id,
member.profileImage.prepend("/").prepend(cloudfrontHost),
member.profileImage.prepend("/").prepend(imageHost),
member.nickname,
audioContent.price,
audioContent.duration
@ -396,6 +400,7 @@ class AudioContentQueryRepositoryImpl(
.from(audioContent)
.innerJoin(audioContent.member, member)
.innerJoin(audioContent.theme, audioContentTheme)
.leftJoin(blockMember).on(blockMemberCondition)
.where(where)
.offset(offset)
.limit(limit)

View File

@ -39,7 +39,6 @@ class AudioContentMainService(
pageable: Pageable
): List<GetAudioContentMainItem> {
return repository.findByTheme(
cloudfrontHost = imageHost,
memberId = member.id!!,
theme = theme,
isAdult = member.auth != null && isAdultContentVisible,
@ -47,7 +46,6 @@ class AudioContentMainService(
offset = pageable.offset,
limit = pageable.pageSize.toLong()
)
.filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) }
}
@Transactional(readOnly = true)

View File

@ -0,0 +1,22 @@
package kr.co.vividnext.sodalive.content.main.tab.content
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/content")
class AudioContentMainTabContentController(private val service: AudioContentMainTabContentService) {
@GetMapping
fun fetchContentMainTabContent(
@AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
) = run {
if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
ApiResponse.ok(service.fetchData(member))
}
}

View File

@ -0,0 +1,110 @@
package kr.co.vividnext.sodalive.content.main.tab.content
import kr.co.vividnext.sodalive.content.AudioContentRepository
import kr.co.vividnext.sodalive.content.ContentType
import kr.co.vividnext.sodalive.content.main.banner.AudioContentBannerService
import kr.co.vividnext.sodalive.content.theme.AudioContentThemeQueryRepository
import kr.co.vividnext.sodalive.event.EventService
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.rank.RankingService
import org.springframework.stereotype.Service
import java.time.LocalDateTime
@Service
class AudioContentMainTabContentService(
private val bannerService: AudioContentBannerService,
private val audioContentRepository: AudioContentRepository,
private val audioContentThemeRepository: AudioContentThemeQueryRepository,
private val rankingService: RankingService,
private val eventService: EventService
) {
fun fetchData(member: Member): GetContentMainTabContentResponse {
/**
* 새로운 단편
* 일간 랭킹
* 채널별 추천 단편
*/
val memberId = member.id!!
val isAdult = member.auth != null
// 단편 배너
val contentBannerList = bannerService.getBannerList(
tabId = 3,
memberId = memberId,
isAdult = isAdult
)
// 새로운 단편 테마
val themeOfContentList = audioContentThemeRepository.getActiveThemeOfContent(isAdult = isAdult)
// 새로운 단편
val newContentList = if (themeOfContentList.isNotEmpty()) {
audioContentRepository.findByTheme(
memberId = member.id!!,
theme = themeOfContentList[0],
isAdult = member.auth != null,
contentType = ContentType.ALL,
offset = 0,
limit = 10
)
} else {
emptyList()
}
// 일간 랭킹
val currentDateTime = LocalDateTime.now()
val dailyRankingStartDate = currentDateTime
.withHour(15)
.withMinute(0)
.withSecond(0)
.minusDays(2)
val dailyRankingEndDate = dailyRankingStartDate
.plusDays(1)
val rankContentList = rankingService.getContentRanking(
memberId = memberId,
isAdult = isAdult,
startDate = dailyRankingStartDate,
endDate = dailyRankingEndDate
)
// 이벤트 배너
val eventBannerList = eventService.getEventList(isAdult = isAdult)
val contentRankCreatorList = rankingService.fetchCreatorByContentRevenueRankTop20(
memberId = member.id!!,
startDate = dailyRankingStartDate.minusDays(1),
endDate = dailyRankingEndDate
)
val salesRankContentList = if (contentRankCreatorList.isNotEmpty()) {
rankingService.fetchCreatorContentBySalesTop2(
creatorId = contentRankCreatorList[0].creatorId,
isAdult = member.auth != null
)
} else {
emptyList()
}
val salesCountRankContentList = if (contentRankCreatorList.isNotEmpty()) {
rankingService.fetchCreatorContentBySalesCountTop2(
creatorId = contentRankCreatorList[0].creatorId,
isAdult = member.auth != null
)
} else {
emptyList()
}
return GetContentMainTabContentResponse(
bannerList = contentBannerList,
contentThemeList = themeOfContentList,
newContentList = newContentList,
rankSortTypeList = listOf("매출", "댓글", "좋아요"),
rankContentList = rankContentList,
contentRankCreatorList = contentRankCreatorList,
salesRankContentList = salesRankContentList,
salesCountRankContentList = salesCountRankContentList,
eventBannerList = eventBannerList
)
}
}

View File

@ -0,0 +1,20 @@
package kr.co.vividnext.sodalive.content.main.tab.content
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.banner.GetAudioContentBannerResponse
import kr.co.vividnext.sodalive.event.GetEventResponse
data class GetContentMainTabContentResponse(
val tabId: Long = 3,
val bannerList: List<GetAudioContentBannerResponse>,
val contentThemeList: List<String>,
val newContentList: List<GetAudioContentMainItem>,
val rankSortTypeList: List<String>,
val rankContentList: List<GetAudioContentRankingItem>,
val contentRankCreatorList: List<ContentCreatorResponse>,
val salesRankContentList: List<GetAudioContentRankingItem>,
val salesCountRankContentList: List<GetAudioContentRankingItem>,
val eventBannerList: GetEventResponse
)

View File

@ -6,19 +6,13 @@ import kr.co.vividnext.sodalive.content.ContentType
import kr.co.vividnext.sodalive.content.SortType
import kr.co.vividnext.sodalive.content.theme.content.GetContentByThemeResponse
import kr.co.vividnext.sodalive.member.Member
import kr.co.vividnext.sodalive.member.block.BlockMemberRepository
import org.springframework.beans.factory.annotation.Value
import org.springframework.stereotype.Service
import org.springframework.transaction.annotation.Transactional
@Service
class AudioContentThemeService(
private val queryRepository: AudioContentThemeQueryRepository,
private val blockMemberRepository: BlockMemberRepository,
private val contentRepository: AudioContentRepository,
@Value("\${cloud.aws.cloud-front.host}")
private val imageHost: String
private val contentRepository: AudioContentRepository
) {
@Transactional(readOnly = true)
fun getThemes(): List<GetAudioContentThemeResponse> {
@ -46,7 +40,6 @@ class AudioContentThemeService(
)
val items = contentRepository.findByTheme(
cloudfrontHost = imageHost,
memberId = member.id!!,
theme = theme.theme,
sortType = sortType,
@ -55,9 +48,6 @@ class AudioContentThemeService(
offset = offset,
limit = limit
)
.asSequence()
.filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) }
.toList()
return GetContentByThemeResponse(
theme = theme.theme,