diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt index f0b9714e..76273eb6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/api/home/HomeService.kt @@ -22,7 +22,6 @@ import kr.co.vividnext.sodalive.i18n.LangContext import kr.co.vividnext.sodalive.live.room.LiveRoomService import kr.co.vividnext.sodalive.live.room.LiveRoomStatus import kr.co.vividnext.sodalive.member.Member -import kr.co.vividnext.sodalive.member.MemberService import kr.co.vividnext.sodalive.query.recommend.RecommendChannelQueryService import kr.co.vividnext.sodalive.rank.ContentRankingSortType import kr.co.vividnext.sodalive.rank.RankingRepository @@ -37,7 +36,6 @@ import java.time.temporal.TemporalAdjusters @Service class HomeService( - private val memberService: MemberService, private val liveRoomService: LiveRoomService, private val auditionService: AuditionService, private val seriesService: ContentSeriesService, @@ -85,14 +83,7 @@ class HomeService( ) val creatorRanking = rankingRepository - .getCreatorRankings() - .filter { - if (memberId != null) { - !memberService.isBlocked(blockedMemberId = memberId, memberId = it.id!!) - } else { - true - } - } + .getCreatorRankings(memberId = memberId) .map { val followerCount = explorerQueryRepository.getNotificationUserIds(it.id!!).size val follow = if (memberId != null) { @@ -111,17 +102,12 @@ class HomeService( ) val latestContentList = contentService.getLatestContentByTheme( + memberId = memberId, theme = latestContentThemeList, contentType = contentType, isFree = false, isAdult = isAdult - ).filter { - if (memberId != null) { - !memberService.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) - } else { - true - } - } + ) val translatedLatestContentList = getTranslatedContentList(contentList = latestContentList) @@ -237,6 +223,7 @@ class HomeService( } val freeContentList = contentService.getLatestContentByTheme( + memberId = memberId, theme = contentThemeService.getActiveThemeOfContent( isAdult = isAdult, isFree = true, @@ -246,31 +233,20 @@ class HomeService( isFree = true, isAdult = isAdult, orderByRandom = true - ).filter { - if (memberId != null) { - !memberService.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) - } else { - true - } - } + ) val translatedFreeContentList = getTranslatedContentList(contentList = freeContentList) // 포인트 사용가능 콘텐츠 리스트 - 랜덤으로 가져오기 (DB에서 isPointAvailable 조건 적용) val pointAvailableContentList = contentService.getLatestContentByTheme( + memberId = memberId, theme = emptyList(), contentType = contentType, isFree = false, isAdult = isAdult, orderByRandom = true, isPointAvailableOnly = true - ).filter { - if (memberId != null) { - !memberService.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) - } else { - true - } - } + ) val translatedPointAvailableContentList = getTranslatedContentList(contentList = pointAvailableContentList) @@ -326,17 +302,12 @@ class HomeService( } val contentList = contentService.getLatestContentByTheme( + memberId = memberId, theme = themeList, contentType = contentType, isFree = false, isAdult = isAdult - ).filter { - if (memberId != null) { - !memberService.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) - } else { - true - } - } + ) return getTranslatedContentList(contentList = contentList) } @@ -428,6 +399,7 @@ class HomeService( while (attempt < RECOMMEND_MAX_ATTEMPTS && result.size < RECOMMEND_TARGET_SIZE) { attempt += 1 val batch = contentService.getLatestContentByTheme( + memberId = memberId, theme = emptyList(), // 특정 테마에 종속되지 않도록 전체에서 랜덤 조회 contentType = contentType, offset = 0, @@ -435,13 +407,7 @@ class HomeService( isFree = false, isAdult = isAdult, orderByRandom = true - ).filter { - if (memberId != null) { - !memberService.isBlocked(blockedMemberId = memberId, memberId = it.creatorId) - } else { - true - } - } + ) for (item in batch) { if (result.size >= RECOMMEND_TARGET_SIZE) break 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 d30632e9..23a010b1 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt @@ -178,6 +178,7 @@ interface AudioContentQueryRepository { fun findContentIdAndHashTagId(contentId: Long, hashTagId: Int): AudioContentHashTag? fun getLatestContentByTheme( + memberId: Long? = null, theme: List, contentType: ContentType, offset: Long, @@ -1319,6 +1320,7 @@ class AudioContentQueryRepositoryImpl( } override fun getLatestContentByTheme( + memberId: Long?, theme: List, contentType: ContentType, offset: Long, @@ -1329,6 +1331,14 @@ class AudioContentQueryRepositoryImpl( orderByRandom: Boolean, isPointAvailableOnly: Boolean ): List { + val blockMemberCondition = if (memberId != null) { + blockMember.member.id.eq(member.id) + .and(blockMember.isActive.isTrue) + .and(blockMember.blockedMember.id.eq(memberId)) + } else { + null + } + var where = audioContent.isActive.isTrue .and(audioContent.duration.isNotNull) .and( @@ -1366,6 +1376,26 @@ class AudioContentQueryRepositoryImpl( where = where.and(audioContent.isPointAvailable.isTrue) } + var select = queryFactory + .select( + QAudioContentMainItem( + audioContent.id, + member.id, + audioContent.title, + audioContent.coverImage.prepend("/").prepend(imageHost), + member.nickname, + audioContent.isPointAvailable + ) + ) + .from(audioContent) + .innerJoin(audioContent.member, member) + .innerJoin(audioContent.theme, audioContentTheme) + + if (memberId != null) { + where = where.and(blockMember.id.isNull) + select = select.leftJoin(blockMember).on(blockMemberCondition) + } + val orderBy = if (orderByRandom) { Expressions.numberTemplate(Double::class.java, "function('rand')").asc() } else { @@ -1387,20 +1417,7 @@ class AudioContentQueryRepositoryImpl( } } - return queryFactory - .select( - QAudioContentMainItem( - audioContent.id, - member.id, - audioContent.title, - audioContent.coverImage.prepend("/").prepend(imageHost), - member.nickname, - audioContent.isPointAvailable - ) - ) - .from(audioContent) - .innerJoin(audioContent.member, member) - .innerJoin(audioContent.theme, audioContentTheme) + return select .where(where) .offset(offset) .limit(limit) 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 c3777ed5..0a3703cd 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -1198,6 +1198,7 @@ class AudioContentService( @Transactional(readOnly = true) fun getLatestContentByTheme( + memberId: Long? = null, theme: List, contentType: ContentType, offset: Long = 0, @@ -1221,6 +1222,7 @@ class AudioContentService( ) val contentList = repository.getLatestContentByTheme( + memberId = memberId, theme = normalizedTheme, contentType = contentType, offset = offset, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryRepository.kt index 295ed6aa..95208d96 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryRepository.kt @@ -9,6 +9,7 @@ import kr.co.vividnext.sodalive.content.like.QAudioContentLike.audioContentLike import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.QMember.member import kr.co.vividnext.sodalive.member.auth.QAuth.auth +import kr.co.vividnext.sodalive.member.block.QBlockMember.blockMember import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Repository @@ -19,7 +20,19 @@ class RecommendChannelQueryRepository( @Value("\${cloud.aws.cloud-front.host}") private val imageHost: String ) { - fun getRecommendChannelList(isAdult: Boolean, contentType: ContentType): List { + fun getRecommendChannelList( + memberId: Long?, + isAdult: Boolean, + contentType: ContentType + ): List { + val blockMemberCondition = if (memberId != null) { + blockMember.member.id.eq(member.id) + .and(blockMember.isActive.isTrue) + .and(blockMember.blockedMember.id.eq(memberId)) + } else { + null + } + var where = member.role.eq(MemberRole.CREATOR) .and(audioContent.isActive.isTrue) @@ -39,7 +52,7 @@ class RecommendChannelQueryRepository( } } - return queryFactory + var select = queryFactory .select( QRecommendChannelResponse( member.id, @@ -52,6 +65,13 @@ class RecommendChannelQueryRepository( .from(member) .innerJoin(auth).on(auth.member.id.eq(member.id)) .innerJoin(audioContent).on(audioContent.member.id.eq(member.id)) + + if (memberId != null) { + where = where.and(blockMember.id.isNull) + select = select.leftJoin(blockMember).on(blockMemberCondition) + } + + return select .where(where) .groupBy(member.id) .having(audioContent.id.count().goe(3)) @@ -60,14 +80,26 @@ class RecommendChannelQueryRepository( .fetch() } - fun getContentsByCreatorIdLikeDesc(creatorId: Long, isAdult: Boolean): List { + fun getContentsByCreatorIdLikeDesc( + creatorId: Long, + memberId: Long?, + isAdult: Boolean + ): List { + val blockMemberCondition = if (memberId != null) { + blockMember.member.id.eq(audioContent.member.id) + .and(blockMember.isActive.isTrue) + .and(blockMember.blockedMember.id.eq(memberId)) + } else { + null + } + var where = audioContent.member.id.eq(creatorId) if (!isAdult) { where = where.and(audioContent.isAdult.isFalse) } - return queryFactory + var select = queryFactory .select( QRecommendChannelContentItem( audioContent.id, @@ -88,6 +120,13 @@ class RecommendChannelQueryRepository( audioContentComment.audioContent.id.eq(audioContent.id) .and(audioContentComment.isActive.isTrue) ) + + if (memberId != null) { + where = where.and(blockMember.id.isNull) + select = select.leftJoin(blockMember).on(blockMemberCondition) + } + + return select .where(where) .groupBy(audioContent.id) .orderBy(audioContentLike.id.countDistinct().desc()) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryService.kt index 2ad1bc86..4888b1ab 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/query/recommend/RecommendChannelQueryService.kt @@ -18,6 +18,7 @@ class RecommendChannelQueryService(private val repository: RecommendChannelQuery contentType: ContentType ): List { val recommendChannelList = repository.getRecommendChannelList( + memberId = memberId, isAdult = isAdult, contentType = contentType ) @@ -25,6 +26,7 @@ class RecommendChannelQueryService(private val repository: RecommendChannelQuery return recommendChannelList.map { it.contentList = repository.getContentsByCreatorIdLikeDesc( creatorId = it.channelId, + memberId = memberId, isAdult = isAdult ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingRepository.kt index 7e81aa5c..cea4fab0 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingRepository.kt @@ -33,11 +33,29 @@ class RankingRepository( @Value("\${cloud.aws.cloud-front.host}") private val imageHost: String ) { - fun getCreatorRankings(): List { - return queryFactory + fun getCreatorRankings(memberId: Long? = null): List { + val blockMemberCondition = if (memberId != null) { + blockMember.member.id.eq(member.id) + .and(blockMember.isActive.isTrue) + .and(blockMember.blockedMember.id.eq(memberId)) + } else { + null + } + + var select = queryFactory .select(member) .from(creatorRanking) .innerJoin(creatorRanking.member, member) + + if (memberId != null) { + select = select.leftJoin(blockMember).on(blockMemberCondition) + } + + if (memberId != null) { + select = select.where(blockMember.id.isNull) + } + + return select .orderBy(creatorRanking.ranking.asc()) .fetch() } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingService.kt index 3ae4d09d..ea36e7bc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/rank/RankingService.kt @@ -9,7 +9,6 @@ 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 @@ -17,7 +16,6 @@ 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}") @@ -25,14 +23,7 @@ class RankingService( ) { fun getCreatorRanking(memberId: Long?, rankingDate: String): GetExplorerSectionResponse { val creatorRankings = repository - .getCreatorRankings() - .filter { - if (memberId != null) { - !memberService.isBlocked(blockedMemberId = memberId, memberId = it.id!!) - } else { - true - } - } + .getCreatorRankings(memberId = memberId) .map { it.toExplorerSectionCreator(imageHost) } return GetExplorerSectionResponse(