From 9b5c0696b19b0e101b9d0ae2ad04f1b9947b4242 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Tue, 7 May 2024 16:10:21 +0900
Subject: [PATCH 1/2] =?UTF-8?q?=EC=B6=94=EC=B2=9C=EC=8B=9C=EB=A6=AC?=
 =?UTF-8?q?=EC=A6=88=20API=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../content/series/ContentSeriesController.kt |   9 ++
 .../content/series/ContentSeriesRepository.kt |  18 +++
 .../content/series/ContentSeriesService.kt    | 111 ++++++++++++------
 3 files changed, 102 insertions(+), 36 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesController.kt
index 13cdc3a..5811af9 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesController.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesController.kt
@@ -64,4 +64,13 @@ class ContentSeriesController(private val service: ContentSeriesService) {
             )
         )
     }
+
+    @GetMapping("/recommend")
+    fun getRecommendSeriesList(
+        @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?
+    ) = run {
+        if (member == null) throw SodaException("로그인 정보를 확인해주세요.")
+
+        ApiResponse.ok(service.getRecommendSeriesList(member = member))
+    }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt
index cc763bc..cae0c84 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesRepository.kt
@@ -1,5 +1,6 @@
 package kr.co.vividnext.sodalive.content.series
 
+import com.querydsl.core.types.dsl.Expressions
 import com.querydsl.jpa.impl.JPAQueryFactory
 import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
 import kr.co.vividnext.sodalive.content.hashtag.QHashTag.hashTag
@@ -26,6 +27,7 @@ interface ContentSeriesQueryRepository {
     fun getSeriesDetail(seriesId: Long, isAuth: Boolean): Series?
     fun getKeywordList(seriesId: Long): List<String>
     fun getSeriesContentMinMaxPrice(seriesId: Long): GetSeriesContentMinMaxPriceResponse
+    fun getRecommendSeriesList(memberId: Long, isAuth: Boolean, limit: Long): List<Series>
 }
 
 class ContentSeriesQueryRepositoryImpl(
@@ -108,4 +110,20 @@ class ContentSeriesQueryRepositoryImpl(
             .where(series.id.eq(seriesId))
             .fetchFirst()
     }
+
+    override fun getRecommendSeriesList(memberId: Long, isAuth: Boolean, limit: Long): List<Series> {
+        var where = series.isActive.isTrue
+
+        if (!isAuth) {
+            where = where.and(series.isAdult.isFalse)
+        }
+
+        return queryFactory
+            .selectFrom(series)
+            .where(where)
+            .orderBy(Expressions.numberTemplate(Double::class.java, "function('rand')").asc())
+            .offset(0)
+            .limit(limit)
+            .fetch()
+    }
 }
diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt
index 27fe4fb..3173e21 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt
@@ -5,11 +5,13 @@ import kr.co.vividnext.sodalive.content.order.OrderRepository
 import kr.co.vividnext.sodalive.content.order.OrderType
 import kr.co.vividnext.sodalive.content.series.content.ContentSeriesContentRepository
 import kr.co.vividnext.sodalive.content.series.content.GetSeriesContentListResponse
+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.SeriesSortType
 import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesState
 import kr.co.vividnext.sodalive.explorer.ExplorerQueryRepository
 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 java.time.LocalDateTime
@@ -20,6 +22,7 @@ import java.time.format.DateTimeFormatter
 class ContentSeriesService(
     private val repository: ContentSeriesRepository,
     private val orderRepository: OrderRepository,
+    private val blockMemberRepository: BlockMemberRepository,
     private val explorerQueryRepository: ExplorerQueryRepository,
     private val seriesContentRepository: ContentSeriesContentRepository,
 
@@ -40,43 +43,9 @@ class ContentSeriesService(
             isAuth = member.auth != null,
             offset = offset,
             limit = limit
-        )
+        ).filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.member!!.id!!) }
 
-        val items = rawItems
-            .map {
-                GetSeriesListResponse.SeriesListItem(
-                    seriesId = it.id!!,
-                    title = it.title,
-                    coverImage = "$coverImageHost/${it.coverImage!!}",
-                    publishedDaysOfWeek = publishedDaysOfWeekText(it.publishedDaysOfWeek),
-                    isComplete = it.state == SeriesState.COMPLETE,
-                    creator = GetSeriesListResponse.SeriesListItemCreator(
-                        creatorId = it.member!!.id!!,
-                        nickname = it.member!!.nickname,
-                        profileImage = "$coverImageHost/${it.member!!.profileImage!!}"
-                    )
-                )
-            }
-            .map {
-                it.numberOfContent = seriesContentRepository.getContentCount(
-                    seriesId = it.seriesId,
-                    isAdult = member.auth != null
-                )
-
-                it
-            }
-            .map {
-                val nowDateTime = LocalDateTime.now()
-
-                it.isNew = seriesContentRepository.isNewContent(
-                    seriesId = it.seriesId,
-                    isAdult = member.auth == null,
-                    fromDate = nowDateTime.minusDays(7),
-                    nowDate = nowDateTime
-                )
-
-                it
-            }
+        val items = seriesToSeriesListItem(seriesList = rawItems, isAdult = member.auth != null)
 
         return GetSeriesListResponse(totalCount, items)
     }
@@ -87,6 +56,11 @@ class ContentSeriesService(
             isAuth = member.auth != null
         ) ?: throw SodaException("잘못된 시리즈 입니다.\n다시 시도해 주세요")
 
+        val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = series.member!!.id!!)
+        if (isBlocked) {
+            throw SodaException("잘못된 시리즈 입니다.\n다시 시도해 주세요")
+        }
+
         val isFollow = explorerQueryRepository.isFollow(
             creatorId = series.member!!.id!!,
             memberId = member.id!!
@@ -167,6 +141,71 @@ class ContentSeriesService(
         return GetSeriesContentListResponse(totalCount, contentList)
     }
 
+    fun getRecommendSeriesList(member: Member): List<GetSeriesListResponse.SeriesListItem> {
+        val seriesList = repository.getRecommendSeriesList(
+            memberId = member.id!!,
+            isAuth = member.auth != null,
+            limit = 10
+        ).filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.member!!.id!!) }
+
+        while (seriesList.size < 10) {
+            seriesList
+                .toMutableList()
+                .addAll(
+                    repository.getRecommendSeriesList(
+                        memberId = member.id!!,
+                        isAuth = member.auth != null,
+                        limit = 10L - seriesList.size
+                    ).filter {
+                        !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.member!!.id!!)
+                    }
+                )
+        }
+
+        return seriesToSeriesListItem(seriesList = seriesList, isAdult = member.auth != null)
+    }
+
+    private fun seriesToSeriesListItem(
+        seriesList: List<Series>,
+        isAdult: Boolean
+    ): List<GetSeriesListResponse.SeriesListItem> {
+        return seriesList
+            .map {
+                GetSeriesListResponse.SeriesListItem(
+                    seriesId = it.id!!,
+                    title = it.title,
+                    coverImage = "$coverImageHost/${it.coverImage!!}",
+                    publishedDaysOfWeek = publishedDaysOfWeekText(it.publishedDaysOfWeek),
+                    isComplete = it.state == SeriesState.COMPLETE,
+                    creator = GetSeriesListResponse.SeriesListItemCreator(
+                        creatorId = it.member!!.id!!,
+                        nickname = it.member!!.nickname,
+                        profileImage = "$coverImageHost/${it.member!!.profileImage!!}"
+                    )
+                )
+            }
+            .map {
+                it.numberOfContent = seriesContentRepository.getContentCount(
+                    seriesId = it.seriesId,
+                    isAdult = isAdult
+                )
+
+                it
+            }
+            .map {
+                val nowDateTime = LocalDateTime.now()
+
+                it.isNew = seriesContentRepository.isNewContent(
+                    seriesId = it.seriesId,
+                    isAdult = isAdult,
+                    fromDate = nowDateTime.minusDays(7),
+                    nowDate = nowDateTime
+                )
+
+                it
+            }
+    }
+
     private fun publishedDaysOfWeekText(publishedDaysOfWeek: Set<SeriesPublishedDaysOfWeek>): String {
         val dayOfWeekText = publishedDaysOfWeek.toList().sortedBy { it.ordinal }
             .map {

From 849fd9d984de9924ea278aa73970ad088b5b0777 Mon Sep 17 00:00:00 2001
From: Klaus <klaus@vividnext.co.kr>
Date: Tue, 7 May 2024 16:36:22 +0900
Subject: [PATCH 2/2] =?UTF-8?q?=EC=B6=94=EC=B2=9C=EC=8B=9C=EB=A6=AC?=
 =?UTF-8?q?=EC=A6=88=20API=20=EC=B6=94=EA=B0=80?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 .../content/series/ContentSeriesService.kt         | 14 --------------
 1 file changed, 14 deletions(-)

diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt
index 3173e21..1cefd7c 100644
--- a/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt
+++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/series/ContentSeriesService.kt
@@ -148,20 +148,6 @@ class ContentSeriesService(
             limit = 10
         ).filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.member!!.id!!) }
 
-        while (seriesList.size < 10) {
-            seriesList
-                .toMutableList()
-                .addAll(
-                    repository.getRecommendSeriesList(
-                        memberId = member.id!!,
-                        isAuth = member.auth != null,
-                        limit = 10L - seriesList.size
-                    ).filter {
-                        !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.member!!.id!!)
-                    }
-                )
-        }
-
         return seriesToSeriesListItem(seriesList = seriesList, isAdult = member.auth != null)
     }