diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt index 3c38eef..5400225 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendController.kt @@ -5,11 +5,13 @@ 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("/live/recommend") class LiveRecommendController(private val service: LiveRecommendService) { - @GetMapping("/live/recommend") + @GetMapping fun getRecommendLive( @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { @@ -18,7 +20,7 @@ class LiveRecommendController(private val service: LiveRecommendService) { ApiResponse.ok(service.getRecommendLive(member)) } - @GetMapping("/live/recommend/channel") + @GetMapping("/channel") fun getRecommendChannelList( @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { @@ -26,4 +28,13 @@ class LiveRecommendController(private val service: LiveRecommendService) { ApiResponse.ok(service.getRecommendChannelList(member)) } + + @GetMapping("/following/channel/list") + fun getFollowingChannelList( + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.getFollowingChannelList(member)) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendRepository.kt index 7f12513..5a7c1c5 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendRepository.kt @@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.live.recommend.QRecommendLiveCreatorBanner.recom import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.QMember.member +import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing import org.springframework.beans.factory.annotation.Value import org.springframework.stereotype.Repository import java.time.LocalDateTime @@ -106,4 +107,79 @@ class LiveRecommendRepository( .limit(limit) .fetch() } + + fun getOnAirFollowingChannelList( + memberId: Long, + isBlocked: (Long) -> Boolean, + isAdult: Boolean + ): List { + var where = member.role.eq(MemberRole.CREATOR) + .and(member.isActive.isTrue) + + if (!isAdult) { + where = where.and(liveRoom.isAdult.isFalse) + } + + return queryFactory + .select( + Projections.constructor( + GetRecommendChannelResponse::class.java, + member.id, + member.nickname, + member.profileImage.prepend("/").prepend(cloudFrontHost), + Expressions.asBoolean(true) + ) + ) + .from(liveRoom, creatorFollowing) + .rightJoin(liveRoom.member, member) + .innerJoin(creatorFollowing.creator, member) + .where( + where + .and(liveRoom.member.id.eq(creatorFollowing.creator.id)) + .and(creatorFollowing.isActive.isTrue) + .and(creatorFollowing.member.id.eq(memberId)) + .and(liveRoom.isActive.isTrue) + .and(liveRoom.channelName.isNotNull) + .and(liveRoom.channelName.isNotEmpty) + ) + .groupBy(member.id) + .orderBy(Expressions.numberTemplate(Double::class.java, "function('rand')").asc()) + .limit(20) + .fetch() + .asSequence() + .filter { !isBlocked(it.creatorId) } + .toList() + } + + fun getFollowingChannelList( + memberId: Long, + withOutCreatorList: List, + limit: Long, + isBlocked: (Long) -> Boolean + ): List { + val where = member.role.eq(MemberRole.CREATOR) + .and(member.isActive.isTrue) + + return queryFactory + .select( + Projections.constructor( + GetRecommendChannelResponse::class.java, + member.id, + member.nickname, + member.profileImage.prepend("/").prepend(cloudFrontHost), + Expressions.asBoolean(false) + ) + ) + .from(creatorFollowing) + .innerJoin(creatorFollowing.creator, member) + .where( + where + .and(member.id.notIn(withOutCreatorList)) + .and(creatorFollowing.isActive.isTrue) + .and(creatorFollowing.member.id.eq(memberId)) + ) + .orderBy(Expressions.numberTemplate(Double::class.java, "function('rand')").asc()) + .limit(limit) + .fetch() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt index 5ffe915..279718e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/recommend/LiveRecommendService.kt @@ -41,4 +41,29 @@ class LiveRecommendService( return onAirChannelList + notOnAirCreatorList } + + fun getFollowingChannelList(member: Member): List { + val onAirFollowingChannelList = repository.getOnAirFollowingChannelList( + memberId = member.id!!, + isBlocked = { blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it) }, + isAdult = member.auth != null + ) + + if (onAirFollowingChannelList.size >= 20) { + return onAirFollowingChannelList + } + + val onAirCreatorIdList = onAirFollowingChannelList.asSequence() + .map { it.creatorId } + .toList() + + val notOnAirFollowingChannelList = repository.getFollowingChannelList( + memberId = member.id!!, + withOutCreatorList = onAirCreatorIdList, + limit = (20 - onAirCreatorIdList.size).toLong(), + isBlocked = { blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it) } + ) + + return onAirFollowingChannelList + notOnAirFollowingChannelList + } }