fix(content): 무료 콘텐츠 포인트 사용 조건을 보정한다
This commit is contained in:
+8
-4
@@ -339,7 +339,8 @@ class AiCharacterAdminAudioContentControllerTest @Autowired constructor(
|
||||
val content = saveAudioContent(
|
||||
owner = character.creatorMember!!,
|
||||
title = "target night walk",
|
||||
contentPath = "private/target-night-walk.mp3"
|
||||
contentPath = "private/target-night-walk.mp3",
|
||||
price = 0
|
||||
)
|
||||
val otherCharacter = chatCharacterService.createChatCharacterWithDetails(
|
||||
characterUUID = "v2-audio-other-character",
|
||||
@@ -374,6 +375,7 @@ class AiCharacterAdminAudioContentControllerTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.totalCount").value(1))
|
||||
.andExpect(jsonPath("$.data.items[0].audioContentId").value(content.id))
|
||||
.andExpect(jsonPath("$.data.items[0].title").value("target night walk"))
|
||||
.andExpect(jsonPath("$.data.items[0].isPointAvailable").value(true))
|
||||
.andExpect(
|
||||
jsonPath("$.data.items[0].contentUrl").value(
|
||||
"https://signed.example.com/private/target-night-walk.mp3?Expires=1"
|
||||
@@ -495,7 +497,8 @@ class AiCharacterAdminAudioContentControllerTest @Autowired constructor(
|
||||
val content = saveAudioContent(
|
||||
owner = character.creatorMember!!,
|
||||
title = "detail night walk",
|
||||
contentPath = "private/detail-night-walk.mp3"
|
||||
contentPath = "private/detail-night-walk.mp3",
|
||||
price = 0
|
||||
)
|
||||
entityManager.flush()
|
||||
Mockito.`when`(audioContentCloudFront.generateSignedURL(Mockito.anyString(), Mockito.anyLong()))
|
||||
@@ -899,7 +902,8 @@ class AiCharacterAdminAudioContentControllerTest @Autowired constructor(
|
||||
owner: Member,
|
||||
title: String,
|
||||
contentPath: String,
|
||||
releaseDate: LocalDateTime = Instant.now().minusSeconds(60).atOffset(ZoneOffset.UTC).toLocalDateTime()
|
||||
releaseDate: LocalDateTime = Instant.now().minusSeconds(60).atOffset(ZoneOffset.UTC).toLocalDateTime(),
|
||||
price: Int = 100
|
||||
): AudioContent {
|
||||
val theme = AudioContentTheme(theme = "theme-$title", image = "theme.png")
|
||||
entityManager.persist(theme)
|
||||
@@ -907,7 +911,7 @@ class AiCharacterAdminAudioContentControllerTest @Autowired constructor(
|
||||
title = title,
|
||||
detail = "detail",
|
||||
languageCode = "ko",
|
||||
price = 100,
|
||||
price = price,
|
||||
isAdult = false,
|
||||
isPointAvailable = true,
|
||||
isCommentAvailable = true
|
||||
|
||||
+21
@@ -94,6 +94,27 @@ class MainContentAllEndToEndTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.audios.length()").value(1))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("전체 탭 POINT API는 무료 포인트 콘텐츠를 목록과 페이징 후보에서 제외한다")
|
||||
fun shouldExcludeFreePointAudioContentsForPointType() {
|
||||
val fixture = createAudioFixture("main-all-point-paid-e2e", freeControl = true)
|
||||
|
||||
mockMvc.perform(
|
||||
get("/api/v2/audio/contents")
|
||||
.param("type", "POINT")
|
||||
.param("sort", "LATEST")
|
||||
.param("page", "0")
|
||||
.param("size", "1")
|
||||
)
|
||||
.andExpect(status().isOk)
|
||||
.andExpect(jsonPath("$.data.type").value("POINT"))
|
||||
.andExpect(jsonPath("$.data.totalCount").value(1))
|
||||
.andExpect(jsonPath("$.data.audios.length()").value(1))
|
||||
.andExpect(jsonPath("$.data.audios[0].audioContentId").value(fixture.audioContentId))
|
||||
.andExpect(jsonPath("$.data.audios[0].price").value(100))
|
||||
.andExpect(jsonPath("$.data.hasNext").value(false))
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("전체 탭 SERIES API는 dayOfWeek 조건으로 시리즈 응답과 빈 audios를 반환한다")
|
||||
fun shouldReturnSeriesContentsFilteredByDayOfWeekThroughControllerServiceAndRepository() {
|
||||
|
||||
+24
@@ -67,6 +67,28 @@ class MainContentAllTabResponseTest {
|
||||
isFirstContent = true,
|
||||
isOriginalSeries = false,
|
||||
creatorNickname = "creator"
|
||||
),
|
||||
MainContentAllAudio(
|
||||
audioContentId = 2L,
|
||||
title = "free audio",
|
||||
imageUrl = "https://cdn/free-audio.jpg",
|
||||
price = 0,
|
||||
isAdult = false,
|
||||
isPointAvailable = true,
|
||||
isFirstContent = false,
|
||||
isOriginalSeries = false,
|
||||
creatorNickname = "creator"
|
||||
),
|
||||
MainContentAllAudio(
|
||||
audioContentId = 3L,
|
||||
title = "point unavailable audio",
|
||||
imageUrl = "https://cdn/point-unavailable-audio.jpg",
|
||||
price = 100,
|
||||
isAdult = false,
|
||||
isPointAvailable = false,
|
||||
isFirstContent = false,
|
||||
isOriginalSeries = false,
|
||||
creatorNickname = "creator"
|
||||
)
|
||||
),
|
||||
series = emptyList(),
|
||||
@@ -83,6 +105,8 @@ class MainContentAllTabResponseTest {
|
||||
assertEquals(true, json["audios"][0]["isPointAvailable"].asBoolean())
|
||||
assertEquals(true, json["audios"][0]["isFirstContent"].asBoolean())
|
||||
assertEquals(false, json["audios"][0]["isOriginalSeries"].asBoolean())
|
||||
assertEquals(false, json["audios"][1]["isPointAvailable"].asBoolean())
|
||||
assertEquals(false, json["audios"][2]["isPointAvailable"].asBoolean())
|
||||
assertEquals(true, json["hasNext"].asBoolean())
|
||||
assertFalse(json["audios"][0].has("duration"))
|
||||
assertFalse(json["series"].any { it.has("publishedDaysOfWeek") })
|
||||
|
||||
+70
@@ -1,8 +1,11 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.content.overview.dto
|
||||
|
||||
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
|
||||
import kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioCard
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeFirstAudioContentRecord
|
||||
import org.junit.jupiter.api.Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
@@ -77,4 +80,71 @@ class ContentOverviewPageResponseTest {
|
||||
assertEquals(true, response.isAdult)
|
||||
assertEquals(true, response.isOriginalSeries)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("NEW_AND_HOT 응답은 무료 콘텐츠의 포인트 가능 여부를 false로 보정한다")
|
||||
fun shouldNormalizePointAvailabilityForFreeNewAndHotAudio() {
|
||||
val freeAudio = audioCard(price = 0, isPointAvailable = true)
|
||||
val paidAudio = audioCard(price = 100, isPointAvailable = true)
|
||||
val paidUnavailableAudio = audioCard(price = 100, isPointAvailable = false)
|
||||
|
||||
assertFalse(ContentOverviewItemResponse.fromNewAndHot(freeAudio).isPointAvailable)
|
||||
assertTrue(ContentOverviewItemResponse.fromNewAndHot(paidAudio).isPointAvailable)
|
||||
assertFalse(ContentOverviewItemResponse.fromNewAndHot(paidUnavailableAudio).isPointAvailable)
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("첫 오디오 응답은 무료 콘텐츠의 포인트 가능 여부를 false로 보정한다")
|
||||
fun shouldNormalizePointAvailabilityForFreeFirstAudioContent() {
|
||||
val freeAudio = firstAudio(price = 0, isPointAvailable = true)
|
||||
val paidAudio = firstAudio(price = 100, isPointAvailable = true)
|
||||
val paidUnavailableAudio = firstAudio(price = 100, isPointAvailable = false)
|
||||
|
||||
assertFalse(
|
||||
ContentOverviewItemResponse.fromFirstAudioContent(freeAudio, "https://cdn.test/free.png", false, false)
|
||||
.isPointAvailable
|
||||
)
|
||||
assertTrue(
|
||||
ContentOverviewItemResponse.fromFirstAudioContent(paidAudio, "https://cdn.test/paid.png", false, false)
|
||||
.isPointAvailable
|
||||
)
|
||||
assertFalse(
|
||||
ContentOverviewItemResponse.fromFirstAudioContent(
|
||||
paidUnavailableAudio,
|
||||
"https://cdn.test/paid-unavailable.png",
|
||||
false,
|
||||
false
|
||||
).isPointAvailable
|
||||
)
|
||||
}
|
||||
|
||||
private fun audioCard(price: Int, isPointAvailable: Boolean): AudioCard {
|
||||
return AudioCard(
|
||||
audioContentId = price.toLong() + 1,
|
||||
title = "audio",
|
||||
duration = "00:01",
|
||||
imageUrl = "https://cdn.test/audio.png",
|
||||
price = price,
|
||||
isAdult = false,
|
||||
isPointAvailable = isPointAvailable,
|
||||
isFirstContent = true,
|
||||
isOriginalSeries = false,
|
||||
creatorNickname = "creator"
|
||||
)
|
||||
}
|
||||
|
||||
private fun firstAudio(price: Int, isPointAvailable: Boolean): HomeFirstAudioContentRecord {
|
||||
return HomeFirstAudioContentRecord(
|
||||
contentId = price.toLong() + 1,
|
||||
creatorId = 10L,
|
||||
creatorNickname = "creator",
|
||||
creatorProfileImage = null,
|
||||
title = "first audio",
|
||||
price = price,
|
||||
coverImage = "cover/audio.png",
|
||||
isPointAvailable = isPointAvailable,
|
||||
isAdult = false,
|
||||
isOriginalSeries = false
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+17
-5
@@ -54,6 +54,9 @@ class AudioRecommendationEndToEndTest @Autowired constructor(
|
||||
.andExpect(jsonPath("$.data.latestAudios[0].isOriginalSeries").value(true))
|
||||
.andExpect(jsonPath("$.data.recommendedAudios").isArray)
|
||||
.andExpect(jsonPath("$.data.recommendedAudios[0].audioContentId").value(fixture.audioContentId))
|
||||
.andExpect(jsonPath("$.data.pointAudios.length()").value(1))
|
||||
.andExpect(jsonPath("$.data.pointAudios[0].audioContentId").value(fixture.paidPointAudioContentId))
|
||||
.andExpect(jsonPath("$.data.pointAudios[0].price").value(100))
|
||||
.andExpect(jsonPath("$.data.mostCommentedAudios[0].latestComment").value("latest e2e comment"))
|
||||
.andExpect(
|
||||
jsonPath("$.data.mostCommentedAudios[0].latestCommentWriterProfileImageUrl")
|
||||
@@ -68,6 +71,7 @@ class AudioRecommendationEndToEndTest @Autowired constructor(
|
||||
val writer = saveMember("audio-recommendation-e2e-writer", MemberRole.USER, profileImage = "comment-writer.png")
|
||||
val theme = saveTheme()
|
||||
val audio = saveAudio(creator, theme, now)
|
||||
val paidPointAudio = saveAudio(creator, theme, now.minusMinutes(10), "paid-point", 100)
|
||||
val series = saveSeries(creator)
|
||||
saveSeriesContent(series, audio)
|
||||
saveComment(audio, writer, "latest e2e comment", now.plusMinutes(10))
|
||||
@@ -79,7 +83,8 @@ class AudioRecommendationEndToEndTest @Autowired constructor(
|
||||
|
||||
Fixture(
|
||||
seriesId = series.id!!,
|
||||
audioContentId = audio.id!!
|
||||
audioContentId = audio.id!!,
|
||||
paidPointAudioContentId = paidPointAudio.id!!
|
||||
)
|
||||
}!!
|
||||
}
|
||||
@@ -102,14 +107,20 @@ class AudioRecommendationEndToEndTest @Autowired constructor(
|
||||
return theme
|
||||
}
|
||||
|
||||
private fun saveAudio(creator: Member, theme: AudioContentTheme, releaseDate: LocalDateTime): AudioContent {
|
||||
private fun saveAudio(
|
||||
creator: Member,
|
||||
theme: AudioContentTheme,
|
||||
releaseDate: LocalDateTime,
|
||||
title: String = "audio-recommendation-e2e",
|
||||
price: Int = 0
|
||||
): AudioContent {
|
||||
val audio = AudioContent(
|
||||
title = "audio-recommendation-e2e",
|
||||
title = title,
|
||||
detail = "detail",
|
||||
languageCode = "ko",
|
||||
releaseDate = releaseDate,
|
||||
isAdult = false,
|
||||
price = 0,
|
||||
price = price,
|
||||
isPointAvailable = true
|
||||
)
|
||||
audio.member = creator
|
||||
@@ -174,6 +185,7 @@ class AudioRecommendationEndToEndTest @Autowired constructor(
|
||||
|
||||
private data class Fixture(
|
||||
val seriesId: Long,
|
||||
val audioContentId: Long
|
||||
val audioContentId: Long,
|
||||
val paidPointAudioContentId: Long
|
||||
)
|
||||
}
|
||||
|
||||
+6
-3
@@ -33,10 +33,13 @@ class AudioRecommendationFacadeTest {
|
||||
assertEquals(1, response.mostCommentedAudios.size)
|
||||
assertEquals(1, response.recommendedAudios.size)
|
||||
assertEquals(false, response.latestAudios[0].isOriginalSeries)
|
||||
assertEquals(false, response.latestAudios[0].isPointAvailable)
|
||||
assertEquals(true, response.newAndHotAudios[0].isPointAvailable)
|
||||
assertEquals(false, response.recommendedAudios[0].isPointAvailable)
|
||||
|
||||
val json = objectMapper.readTree(objectMapper.writeValueAsString(response))
|
||||
assertEquals(false, json["latestAudios"][0]["isAdult"].asBoolean())
|
||||
assertEquals(true, json["latestAudios"][0]["isPointAvailable"].asBoolean())
|
||||
assertEquals(false, json["latestAudios"][0]["isPointAvailable"].asBoolean())
|
||||
assertEquals(true, json["latestAudios"][0]["isFirstContent"].asBoolean())
|
||||
assertEquals(false, json["latestAudios"][0]["isOriginalSeries"].asBoolean())
|
||||
assertEquals(false, json["latestAudios"][0].has("adult"))
|
||||
@@ -61,7 +64,7 @@ class AudioRecommendationFacadeTest {
|
||||
banners = listOf(RecommendationBanner("https://cdn.test/banner.png", null, null, null, "https://link.test")),
|
||||
originalSeries = listOf(OriginalSeries(2L, "https://cdn.test/series.png")),
|
||||
latestAudios = listOf(card),
|
||||
newAndHotAudios = listOf(card.copy(audioContentId = 3L)),
|
||||
newAndHotAudios = listOf(card.copy(audioContentId = 3L, price = 100)),
|
||||
freeAudios = listOf(card.copy(audioContentId = 4L)),
|
||||
pointAudios = listOf(card.copy(audioContentId = 5L)),
|
||||
mostCommentedAudios = listOf(
|
||||
@@ -73,7 +76,7 @@ class AudioRecommendationFacadeTest {
|
||||
latestCommentWriterProfileImageUrl = "https://cdn.test/profile.png"
|
||||
)
|
||||
),
|
||||
recommendedAudios = listOf(card.copy(audioContentId = 7L))
|
||||
recommendedAudios = listOf(card.copy(audioContentId = 7L, price = 100, isPointAvailable = false))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+38
@@ -0,0 +1,38 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.creator.channel.common.dto
|
||||
|
||||
import kr.co.vividnext.sodalive.v2.creator.channel.common.domain.CreatorChannelAudioContent
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
|
||||
class CreatorChannelAudioContentResponseTest {
|
||||
@Test
|
||||
@DisplayName("크리에이터 채널 오디오 응답은 무료 콘텐츠의 포인트 가능 여부를 false로 보정한다")
|
||||
fun shouldNormalizePointAvailabilityForFreeAudioContent() {
|
||||
val freeAudio = audioContent(price = 0, isPointAvailable = true)
|
||||
val paidAudio = audioContent(price = 100, isPointAvailable = true)
|
||||
val paidUnavailableAudio = audioContent(price = 100, isPointAvailable = false)
|
||||
|
||||
assertFalse(CreatorChannelAudioContentResponse.from(freeAudio).isPointAvailable)
|
||||
assertTrue(CreatorChannelAudioContentResponse.from(paidAudio).isPointAvailable)
|
||||
assertFalse(CreatorChannelAudioContentResponse.from(paidUnavailableAudio).isPointAvailable)
|
||||
}
|
||||
|
||||
private fun audioContent(price: Int, isPointAvailable: Boolean): CreatorChannelAudioContent {
|
||||
return CreatorChannelAudioContent(
|
||||
audioContentId = price.toLong() + 1,
|
||||
title = "audio",
|
||||
duration = "00:10:00",
|
||||
imageUrl = "audio.png",
|
||||
price = price,
|
||||
isAdult = false,
|
||||
isPointAvailable = isPointAvailable,
|
||||
isFirstContent = true,
|
||||
seriesName = "series",
|
||||
isOriginalSeries = true,
|
||||
isOwned = false,
|
||||
isRented = false
|
||||
)
|
||||
}
|
||||
}
|
||||
+163
@@ -0,0 +1,163 @@
|
||||
package kr.co.vividnext.sodalive.v2.api.home.application
|
||||
|
||||
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryService
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeAiCharacterRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeBannerRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeCheerCreatorRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeFirstAudioContentRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeGenreCreatorRecommendationGroup
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeLiveRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomePopularCommunityRecommendationRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeRecommendationQueryPort
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecentDebutCreatorRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecentlyActiveCreatorRecord
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecommendationSnapshotPort
|
||||
import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecommendationSnapshotRecord
|
||||
import org.junit.jupiter.api.Assertions.assertFalse
|
||||
import org.junit.jupiter.api.Assertions.assertTrue
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import org.junit.jupiter.api.Test
|
||||
import org.mockito.Mockito
|
||||
import java.time.LocalDateTime
|
||||
|
||||
class HomeRecommendationFacadeTest {
|
||||
private val queryPort = FakeHomeRecommendationQueryPort()
|
||||
private val queryService = HomeRecommendationQueryService(queryPort, EmptyRecommendationSnapshotPort())
|
||||
private val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||
private val facade = HomeRecommendationFacade(queryService, preferenceService, "https://cdn.test")
|
||||
|
||||
@Test
|
||||
@DisplayName("홈 첫 오디오 응답은 무료 콘텐츠의 포인트 가능 여부를 false로 보정한다")
|
||||
fun shouldNormalizePointAvailabilityForFreeFirstAudioContent() {
|
||||
queryPort.firstAudioContents = listOf(
|
||||
firstAudio(price = 0, isPointAvailable = true),
|
||||
firstAudio(price = 100, isPointAvailable = true),
|
||||
firstAudio(price = 100, isPointAvailable = false)
|
||||
)
|
||||
|
||||
val response = facade.getHomeRecommendations(null)
|
||||
|
||||
assertFalse(response.firstAudioContents[0].isPointAvailable)
|
||||
assertTrue(response.firstAudioContents[1].isPointAvailable)
|
||||
assertFalse(response.firstAudioContents[2].isPointAvailable)
|
||||
}
|
||||
|
||||
private fun firstAudio(price: Int, isPointAvailable: Boolean): HomeFirstAudioContentRecord {
|
||||
return HomeFirstAudioContentRecord(
|
||||
contentId = price.toLong() + 1,
|
||||
creatorId = 10L,
|
||||
creatorNickname = "creator",
|
||||
creatorProfileImage = null,
|
||||
title = "first audio",
|
||||
price = price,
|
||||
coverImage = "cover/audio.png",
|
||||
isPointAvailable = isPointAvailable,
|
||||
isAdult = false,
|
||||
isOriginalSeries = false
|
||||
)
|
||||
}
|
||||
|
||||
private class FakeHomeRecommendationQueryPort : HomeRecommendationQueryPort {
|
||||
var firstAudioContents: List<HomeFirstAudioContentRecord> = emptyList()
|
||||
|
||||
override fun findLiveRecommendations(
|
||||
offset: Long,
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultLives: Boolean
|
||||
): List<HomeLiveRecommendationRecord> = emptyList()
|
||||
|
||||
override fun findHomeBanners(limit: Int, memberId: Long?): List<HomeBannerRecommendationRecord> = emptyList()
|
||||
|
||||
override fun findRecentlyActiveCreators(
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultActivities: Boolean
|
||||
): List<RecentlyActiveCreatorRecord> = emptyList()
|
||||
|
||||
override fun findRecentDebutCreators(
|
||||
now: LocalDateTime,
|
||||
offset: Long,
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultContents: Boolean
|
||||
): List<RecentDebutCreatorRecord> = emptyList()
|
||||
|
||||
override fun findFirstAudioContents(
|
||||
now: LocalDateTime,
|
||||
offset: Long,
|
||||
limit: Int,
|
||||
memberId: Long?,
|
||||
includeAdultContents: Boolean
|
||||
): List<HomeFirstAudioContentRecord> = firstAudioContents
|
||||
|
||||
override fun findAiCharacterSnapshots(
|
||||
windowStart: LocalDateTime,
|
||||
windowEndExclusive: LocalDateTime,
|
||||
limit: Int
|
||||
): List<RecommendationSnapshotRecord> = emptyList()
|
||||
|
||||
override fun findCheerCreatorSnapshots(
|
||||
windowStart: LocalDateTime,
|
||||
windowEndExclusive: LocalDateTime,
|
||||
limit: Int
|
||||
): List<RecommendationSnapshotRecord> = emptyList()
|
||||
|
||||
override fun findPopularCommunitySnapshots(
|
||||
windowStart: LocalDateTime,
|
||||
windowEndExclusive: LocalDateTime,
|
||||
limit: Int
|
||||
): List<RecommendationSnapshotRecord> = emptyList()
|
||||
|
||||
override fun findAiCharacterRecommendationDetails(
|
||||
characterIds: List<Long>
|
||||
): List<HomeAiCharacterRecommendationRecord> = emptyList()
|
||||
|
||||
override fun findRandomAiCharacterRecommendationIds(excludeCharacterIds: List<Long>, limit: Int): List<Long> = emptyList()
|
||||
|
||||
override fun findCheerCreatorRecommendationDetails(
|
||||
creatorIds: List<Long>,
|
||||
memberId: Long?
|
||||
): List<HomeCheerCreatorRecommendationRecord> = emptyList()
|
||||
|
||||
override fun findPopularCommunityRecommendationDetails(
|
||||
communityIds: List<Long>,
|
||||
memberId: Long?,
|
||||
includeAdultCommunities: Boolean
|
||||
): List<HomePopularCommunityRecommendationRecord> = emptyList()
|
||||
|
||||
override fun findGenreCreatorRecommendations(
|
||||
memberId: Long?,
|
||||
includeAdultGenres: Boolean,
|
||||
genreLimit: Int,
|
||||
creatorLimit: Int
|
||||
): List<HomeGenreCreatorRecommendationGroup> = emptyList()
|
||||
}
|
||||
|
||||
private class EmptyRecommendationSnapshotPort : RecommendationSnapshotPort {
|
||||
override fun findLatestSnapshots(
|
||||
sectionType: RecommendedSectionType,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
): List<RecommendationSnapshotRecord> = emptyList()
|
||||
|
||||
override fun findSnapshots(
|
||||
sectionType: RecommendedSectionType,
|
||||
snapshotAt: LocalDateTime,
|
||||
offset: Long,
|
||||
limit: Int
|
||||
): List<RecommendationSnapshotRecord> = emptyList()
|
||||
|
||||
override fun existsLatestSnapshot(sectionType: RecommendedSectionType): Boolean = true
|
||||
|
||||
override fun existsSnapshot(sectionType: RecommendedSectionType, snapshotAt: LocalDateTime): Boolean = true
|
||||
|
||||
override fun replaceSnapshots(
|
||||
sectionType: RecommendedSectionType,
|
||||
snapshotAt: LocalDateTime,
|
||||
newSnapshots: List<RecommendationSnapshotRecord>
|
||||
) = Unit
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user