test #426
@@ -0,0 +1,140 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.creator.channel.audio.application
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||||
|
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||||
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
|
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||||
|
import kr.co.vividnext.sodalive.member.contentpreference.isAdultVisibleByPolicy
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioQueryPolicy
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTab
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTheme
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioContentRecord
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioCreatorRecord
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioQueryPort
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioThemeRecord
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.common.domain.CreatorChannelAudioContent
|
||||||
|
import org.springframework.beans.factory.ObjectProvider
|
||||||
|
import org.springframework.beans.factory.annotation.Value
|
||||||
|
import org.springframework.stereotype.Service
|
||||||
|
import org.springframework.transaction.annotation.Transactional
|
||||||
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
|
@Service
|
||||||
|
@Transactional(readOnly = true)
|
||||||
|
class CreatorChannelAudioQueryService(
|
||||||
|
private val queryPortProvider: ObjectProvider<CreatorChannelAudioQueryPort>,
|
||||||
|
private val queryPolicy: CreatorChannelAudioQueryPolicy,
|
||||||
|
private val memberContentPreferenceService: MemberContentPreferenceService,
|
||||||
|
private val messageSource: SodaMessageSource,
|
||||||
|
private val langContext: LangContext,
|
||||||
|
@Value("\${cloud.aws.cloud-front.host}")
|
||||||
|
private val cloudFrontHost: String
|
||||||
|
) {
|
||||||
|
fun getAudioTab(
|
||||||
|
creatorId: Long,
|
||||||
|
viewer: Member,
|
||||||
|
sort: String?,
|
||||||
|
themeId: Long?,
|
||||||
|
page: Int?,
|
||||||
|
size: Int?,
|
||||||
|
now: LocalDateTime = LocalDateTime.now()
|
||||||
|
): CreatorChannelAudioTab {
|
||||||
|
val resolvedSort = queryPolicy.resolveSort(sort)
|
||||||
|
val audioPage = queryPolicy.createPage(page, size)
|
||||||
|
val queryPort = queryPortProvider.getObject()
|
||||||
|
val viewerId = viewer.id!!
|
||||||
|
val creator = queryPort.findCreator(creatorId, viewerId)
|
||||||
|
?: throw SodaException(messageKey = "member.validation.user_not_found")
|
||||||
|
|
||||||
|
if (queryPort.existsBlockedBetween(viewerId, creatorId)) {
|
||||||
|
val messageTemplate = messageSource
|
||||||
|
.getMessage("explorer.creator.blocked_access", langContext.lang)
|
||||||
|
.orEmpty()
|
||||||
|
throw SodaException(message = String.format(messageTemplate, creator.nickname))
|
||||||
|
}
|
||||||
|
|
||||||
|
validateCreatorRole(creator)
|
||||||
|
|
||||||
|
val preference = memberContentPreferenceService.getStoredPreference(viewer)
|
||||||
|
val canViewAdultContent = isAdultVisibleByPolicy(viewer, preference.isAdultContentVisible)
|
||||||
|
val resolvedThemeId = themeId?.let(queryPort::findActiveThemeId)
|
||||||
|
val locale = langContext.lang.code
|
||||||
|
val fetchedContents = queryPort.findAudioContents(
|
||||||
|
creatorId = creatorId,
|
||||||
|
viewerId = viewerId,
|
||||||
|
themeId = resolvedThemeId,
|
||||||
|
now = now,
|
||||||
|
canViewAdultContent = canViewAdultContent,
|
||||||
|
sort = resolvedSort,
|
||||||
|
locale = locale,
|
||||||
|
offset = audioPage.offset,
|
||||||
|
limit = audioPage.fetchLimit
|
||||||
|
)
|
||||||
|
val paidAudioContentCount = queryPort.countPaidAudioContents(
|
||||||
|
creatorId = creatorId,
|
||||||
|
themeId = resolvedThemeId,
|
||||||
|
now = now,
|
||||||
|
canViewAdultContent = canViewAdultContent
|
||||||
|
)
|
||||||
|
val purchasedAudioContentCount = queryPort.countPurchasedAudioContents(
|
||||||
|
creatorId = creatorId,
|
||||||
|
viewerId = viewerId,
|
||||||
|
themeId = resolvedThemeId,
|
||||||
|
now = now,
|
||||||
|
canViewAdultContent = canViewAdultContent
|
||||||
|
)
|
||||||
|
|
||||||
|
return CreatorChannelAudioTab(
|
||||||
|
audioContentCount = queryPort.countAudioContents(
|
||||||
|
creatorId = creatorId,
|
||||||
|
themeId = resolvedThemeId,
|
||||||
|
now = now,
|
||||||
|
canViewAdultContent = canViewAdultContent
|
||||||
|
),
|
||||||
|
paidAudioContentCount = paidAudioContentCount,
|
||||||
|
purchasedAudioContentCount = purchasedAudioContentCount,
|
||||||
|
purchasedAudioContentRate = queryPolicy.purchaseRate(paidAudioContentCount, purchasedAudioContentCount),
|
||||||
|
themes = queryPort.findAudioThemes(locale).map { it.toDomain() },
|
||||||
|
audioContents = queryPolicy.limitItems(fetchedContents, audioPage).map { it.toDomain() },
|
||||||
|
sort = resolvedSort,
|
||||||
|
themeId = resolvedThemeId,
|
||||||
|
page = audioPage,
|
||||||
|
hasNext = queryPolicy.hasNext(fetchedContents, audioPage)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun validateCreatorRole(creator: CreatorChannelAudioCreatorRecord) {
|
||||||
|
when (creator.role) {
|
||||||
|
MemberRole.CREATOR -> return
|
||||||
|
else -> throw SodaException(messageKey = "member.validation.creator_not_found")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun CreatorChannelAudioThemeRecord.toDomain() = CreatorChannelAudioTheme(
|
||||||
|
themeId = themeId,
|
||||||
|
themeName = themeName
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun CreatorChannelAudioContentRecord.toDomain() = CreatorChannelAudioContent(
|
||||||
|
audioContentId = audioContentId,
|
||||||
|
title = title,
|
||||||
|
duration = duration,
|
||||||
|
imageUrl = imagePath.toCdnUrl(),
|
||||||
|
price = price,
|
||||||
|
isAdult = isAdult,
|
||||||
|
isPointAvailable = isPointAvailable,
|
||||||
|
isFirstContent = isFirstContent,
|
||||||
|
seriesName = seriesName,
|
||||||
|
isOriginalSeries = isOriginalSeries,
|
||||||
|
isOwned = isOwned,
|
||||||
|
isRented = isRented
|
||||||
|
)
|
||||||
|
|
||||||
|
private fun String?.toCdnUrl(): String? {
|
||||||
|
if (isNullOrBlank()) return null
|
||||||
|
if (startsWith("https://") || startsWith("http://")) return this
|
||||||
|
return "$cloudFrontHost/$this"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,123 +1,263 @@
|
|||||||
package kr.co.vividnext.sodalive.v2.creator.channel.audio.application
|
package kr.co.vividnext.sodalive.v2.creator.channel.audio.application
|
||||||
|
|
||||||
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
|
import kr.co.vividnext.sodalive.content.ContentType
|
||||||
|
import kr.co.vividnext.sodalive.i18n.Lang
|
||||||
|
import kr.co.vividnext.sodalive.i18n.LangContext
|
||||||
|
import kr.co.vividnext.sodalive.i18n.SodaMessageSource
|
||||||
|
import kr.co.vividnext.sodalive.member.Member
|
||||||
|
import kr.co.vividnext.sodalive.member.MemberProvider
|
||||||
import kr.co.vividnext.sodalive.member.MemberRole
|
import kr.co.vividnext.sodalive.member.MemberRole
|
||||||
|
import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService
|
||||||
|
import kr.co.vividnext.sodalive.member.contentpreference.ViewerContentPreference
|
||||||
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
import kr.co.vividnext.sodalive.v2.common.domain.ContentSort
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTab
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioQueryPolicy
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.audio.domain.CreatorChannelAudioTheme
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioContentRecord
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioContentRecord
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioCreatorRecord
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioCreatorRecord
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioQueryPort
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioQueryPort
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioThemeRecord
|
import kr.co.vividnext.sodalive.v2.creator.channel.audio.port.out.CreatorChannelAudioThemeRecord
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.common.domain.CreatorChannelAudioContent
|
|
||||||
import kr.co.vividnext.sodalive.v2.creator.channel.live.domain.CreatorChannelPage
|
|
||||||
import org.junit.jupiter.api.Assertions.assertEquals
|
import org.junit.jupiter.api.Assertions.assertEquals
|
||||||
|
import org.junit.jupiter.api.Assertions.assertNull
|
||||||
|
import org.junit.jupiter.api.Assertions.assertThrows
|
||||||
|
import org.junit.jupiter.api.Assertions.assertTrue
|
||||||
import org.junit.jupiter.api.DisplayName
|
import org.junit.jupiter.api.DisplayName
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
import org.mockito.Mockito
|
||||||
|
import org.springframework.beans.factory.ObjectProvider
|
||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
|
|
||||||
class CreatorChannelAudioQueryServiceTest {
|
class CreatorChannelAudioQueryServiceTest {
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("오디오 탭 domain model과 port 계약을 사용할 수 있다")
|
@DisplayName("오디오 탭 서비스는 요청 fallback과 조회 컨텍스트를 port에 전달하고 탭을 조립한다")
|
||||||
fun shouldUseAudioTabDomainModelAndPortContract() {
|
fun shouldResolveRequestFallbacksAndAssembleAudioTab() {
|
||||||
val page = CreatorChannelPage(page = 0, size = 20)
|
val port = FakeCreatorChannelAudioQueryPort().apply {
|
||||||
val tab = CreatorChannelAudioTab(
|
activeThemeId = null
|
||||||
audioContentCount = 1,
|
paidAudioContentCount = 4
|
||||||
paidAudioContentCount = 1,
|
purchasedAudioContentCount = 3
|
||||||
purchasedAudioContentCount = 1,
|
audioContents = (1L..51L).map { audioContentRecord(it) }
|
||||||
purchasedAudioContentRate = 100.0,
|
}
|
||||||
themes = listOf(CreatorChannelAudioTheme(themeId = 10L, themeName = "theme")),
|
val service = createService(port, canViewAdultContent = false)
|
||||||
audioContents = listOf(audioContent()),
|
val viewer = createMember(id = 10L)
|
||||||
sort = ContentSort.LATEST,
|
val now = LocalDateTime.of(2026, 6, 19, 10, 0)
|
||||||
themeId = 10L,
|
|
||||||
page = page,
|
|
||||||
hasNext = false
|
|
||||||
)
|
|
||||||
val port = FakeCreatorChannelAudioQueryPort()
|
|
||||||
|
|
||||||
assertEquals(1, tab.audioContentCount)
|
val tab = service.getAudioTab(
|
||||||
assertEquals(10L, tab.themes.first().themeId)
|
creatorId = 1L,
|
||||||
assertEquals(100L, tab.audioContents.first().audioContentId)
|
viewer = viewer,
|
||||||
assertEquals(MemberRole.CREATOR, port.findCreator(creatorId = 1L, viewerId = 2L)?.role)
|
sort = "UNKNOWN",
|
||||||
|
themeId = 999L,
|
||||||
|
page = -1,
|
||||||
|
size = 100,
|
||||||
|
now = now
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(ContentSort.LATEST, tab.sort)
|
||||||
|
assertNull(tab.themeId)
|
||||||
|
assertEquals(0, tab.page.page)
|
||||||
|
assertEquals(50, tab.page.size)
|
||||||
|
assertEquals(0L, port.listOffset)
|
||||||
|
assertEquals(51, port.listLimit)
|
||||||
|
assertEquals(ContentSort.LATEST, port.listSort)
|
||||||
|
assertNull(port.listThemeId)
|
||||||
|
assertEquals("en", port.listLocale)
|
||||||
|
assertEquals(false, port.listCanViewAdultContent)
|
||||||
|
assertEquals(75.0, tab.purchasedAudioContentRate)
|
||||||
|
assertEquals(50, tab.audioContents.size)
|
||||||
|
assertTrue(tab.hasNext)
|
||||||
|
assertEquals("https://cdn.test/audio/1.png", tab.audioContents.first().imageUrl)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun audioContent(): CreatorChannelAudioContent {
|
@Test
|
||||||
return CreatorChannelAudioContent(
|
@DisplayName("유료 오디오 콘텐츠가 없으면 소장률은 0.0이다")
|
||||||
audioContentId = 100L,
|
fun shouldReturnZeroPurchaseRateWhenPaidContentCountIsZero() {
|
||||||
title = "audio",
|
val port = FakeCreatorChannelAudioQueryPort().apply {
|
||||||
duration = "00:01:00",
|
paidAudioContentCount = 0
|
||||||
imageUrl = null,
|
purchasedAudioContentCount = 3
|
||||||
price = 10,
|
}
|
||||||
isAdult = false,
|
val service = createService(port)
|
||||||
isPointAvailable = true,
|
val viewer = createMember(id = 10L)
|
||||||
isFirstContent = true,
|
|
||||||
seriesName = null,
|
val tab = service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||||
isOriginalSeries = null,
|
|
||||||
isOwned = true,
|
assertEquals(0.0, tab.purchasedAudioContentRate)
|
||||||
isRented = false
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private class FakeCreatorChannelAudioQueryPort : CreatorChannelAudioQueryPort {
|
@Test
|
||||||
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelAudioCreatorRecord? {
|
@DisplayName("creatorId에 해당하는 회원이 없으면 user_not_found 예외를 던진다")
|
||||||
return CreatorChannelAudioCreatorRecord(
|
fun shouldThrowUserNotFoundWhenCreatorMemberDoesNotExist() {
|
||||||
creatorId = creatorId,
|
val port = FakeCreatorChannelAudioQueryPort().apply { creator = null }
|
||||||
role = MemberRole.CREATOR,
|
val service = createService(port)
|
||||||
nickname = "creator"
|
val viewer = createMember(id = 10L)
|
||||||
|
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("member.validation.user_not_found", exception.messageKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("대상 회원 role이 CREATOR가 아니면 creator_not_found 예외를 던진다")
|
||||||
|
fun shouldThrowCreatorNotFoundWhenMemberIsNotCreator() {
|
||||||
|
val port = FakeCreatorChannelAudioQueryPort().apply { creator = creator?.copy(role = MemberRole.USER) }
|
||||||
|
val service = createService(port)
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertEquals("member.validation.creator_not_found", exception.messageKey)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("차단 관계가 있으면 기존 차단 메시지 예외를 던진다")
|
||||||
|
fun shouldThrowBlockedAccessWhenViewerAndTargetAreBlocked() {
|
||||||
|
val port = FakeCreatorChannelAudioQueryPort().apply { blocked = true }
|
||||||
|
val service = createService(port)
|
||||||
|
val viewer = createMember(id = 10L)
|
||||||
|
|
||||||
|
val exception = assertThrows(SodaException::class.java) {
|
||||||
|
service.getAudioTab(1L, viewer, null, null, null, null, LocalDateTime.of(2026, 6, 19, 10, 0))
|
||||||
|
}
|
||||||
|
|
||||||
|
assertNull(exception.messageKey)
|
||||||
|
assertEquals("Channel access is restricted at creator's request.", exception.message)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createService(
|
||||||
|
port: FakeCreatorChannelAudioQueryPort,
|
||||||
|
canViewAdultContent: Boolean = true
|
||||||
|
): CreatorChannelAudioQueryService {
|
||||||
|
val preferenceService = Mockito.mock(MemberContentPreferenceService::class.java)
|
||||||
|
Mockito.`when`(
|
||||||
|
preferenceService.getStoredPreference(Mockito.any(Member::class.java) ?: createMember(id = 0L))
|
||||||
|
).thenReturn(
|
||||||
|
ViewerContentPreference(
|
||||||
|
countryCode = "US",
|
||||||
|
isAdultContentVisible = canViewAdultContent,
|
||||||
|
contentType = ContentType.ALL,
|
||||||
|
isAdult = canViewAdultContent
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
|
val langContext = LangContext()
|
||||||
|
langContext.setLang(Lang.EN)
|
||||||
|
return CreatorChannelAudioQueryService(
|
||||||
|
queryPortProvider = FixedCreatorChannelAudioQueryPortProvider(port),
|
||||||
|
queryPolicy = CreatorChannelAudioQueryPolicy(),
|
||||||
|
memberContentPreferenceService = preferenceService,
|
||||||
|
messageSource = SodaMessageSource(),
|
||||||
|
langContext = langContext,
|
||||||
|
cloudFrontHost = "https://cdn.test"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean {
|
private fun createMember(id: Long): Member {
|
||||||
return false
|
return Member(
|
||||||
}
|
email = "member$id@test.com",
|
||||||
|
password = "password",
|
||||||
override fun findActiveThemeId(themeId: Long): Long? {
|
nickname = "member$id",
|
||||||
return themeId
|
provider = MemberProvider.EMAIL
|
||||||
}
|
).apply { this.id = id }
|
||||||
|
|
||||||
override fun findAudioThemes(locale: String): List<CreatorChannelAudioThemeRecord> {
|
|
||||||
return listOf(CreatorChannelAudioThemeRecord(themeId = 10L, themeName = locale))
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun countAudioContents(
|
|
||||||
creatorId: Long,
|
|
||||||
themeId: Long?,
|
|
||||||
now: LocalDateTime,
|
|
||||||
canViewAdultContent: Boolean
|
|
||||||
): Int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun countPaidAudioContents(
|
|
||||||
creatorId: Long,
|
|
||||||
themeId: Long?,
|
|
||||||
now: LocalDateTime,
|
|
||||||
canViewAdultContent: Boolean
|
|
||||||
): Int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun countPurchasedAudioContents(
|
|
||||||
creatorId: Long,
|
|
||||||
viewerId: Long,
|
|
||||||
themeId: Long?,
|
|
||||||
now: LocalDateTime,
|
|
||||||
canViewAdultContent: Boolean
|
|
||||||
): Int {
|
|
||||||
return 1
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun findAudioContents(
|
|
||||||
creatorId: Long,
|
|
||||||
viewerId: Long,
|
|
||||||
themeId: Long?,
|
|
||||||
now: LocalDateTime,
|
|
||||||
canViewAdultContent: Boolean,
|
|
||||||
sort: ContentSort,
|
|
||||||
locale: String,
|
|
||||||
offset: Long,
|
|
||||||
limit: Int
|
|
||||||
): List<CreatorChannelAudioContentRecord> {
|
|
||||||
return emptyList()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class FixedCreatorChannelAudioQueryPortProvider(
|
||||||
|
private val port: CreatorChannelAudioQueryPort
|
||||||
|
) : ObjectProvider<CreatorChannelAudioQueryPort> {
|
||||||
|
override fun getObject(vararg args: Any?): CreatorChannelAudioQueryPort = port
|
||||||
|
|
||||||
|
override fun getIfAvailable(): CreatorChannelAudioQueryPort = port
|
||||||
|
|
||||||
|
override fun getIfUnique(): CreatorChannelAudioQueryPort = port
|
||||||
|
|
||||||
|
override fun getObject(): CreatorChannelAudioQueryPort = port
|
||||||
|
}
|
||||||
|
|
||||||
|
private class FakeCreatorChannelAudioQueryPort : CreatorChannelAudioQueryPort {
|
||||||
|
var creator: CreatorChannelAudioCreatorRecord? = CreatorChannelAudioCreatorRecord(
|
||||||
|
creatorId = 1L,
|
||||||
|
role = MemberRole.CREATOR,
|
||||||
|
nickname = "creator"
|
||||||
|
)
|
||||||
|
var blocked = false
|
||||||
|
var activeThemeId: Long? = 10L
|
||||||
|
var audioContentCount = 60
|
||||||
|
var paidAudioContentCount = 4
|
||||||
|
var purchasedAudioContentCount = 3
|
||||||
|
var audioContents = (1L..21L).map { audioContentRecord(it) }
|
||||||
|
var listThemeId: Long? = null
|
||||||
|
var listSort: ContentSort? = null
|
||||||
|
var listLocale: String? = null
|
||||||
|
var listOffset: Long? = null
|
||||||
|
var listLimit: Int? = null
|
||||||
|
var listCanViewAdultContent: Boolean? = null
|
||||||
|
|
||||||
|
override fun findCreator(creatorId: Long, viewerId: Long?): CreatorChannelAudioCreatorRecord? = creator
|
||||||
|
|
||||||
|
override fun existsBlockedBetween(viewerId: Long, creatorId: Long): Boolean = blocked
|
||||||
|
|
||||||
|
override fun findActiveThemeId(themeId: Long): Long? = activeThemeId
|
||||||
|
|
||||||
|
override fun findAudioThemes(locale: String): List<CreatorChannelAudioThemeRecord> {
|
||||||
|
return listOf(CreatorChannelAudioThemeRecord(themeId = 10L, themeName = locale))
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun countAudioContents(
|
||||||
|
creatorId: Long,
|
||||||
|
themeId: Long?,
|
||||||
|
now: LocalDateTime,
|
||||||
|
canViewAdultContent: Boolean
|
||||||
|
): Int = audioContentCount
|
||||||
|
|
||||||
|
override fun countPaidAudioContents(
|
||||||
|
creatorId: Long,
|
||||||
|
themeId: Long?,
|
||||||
|
now: LocalDateTime,
|
||||||
|
canViewAdultContent: Boolean
|
||||||
|
): Int = paidAudioContentCount
|
||||||
|
|
||||||
|
override fun countPurchasedAudioContents(
|
||||||
|
creatorId: Long,
|
||||||
|
viewerId: Long,
|
||||||
|
themeId: Long?,
|
||||||
|
now: LocalDateTime,
|
||||||
|
canViewAdultContent: Boolean
|
||||||
|
): Int = purchasedAudioContentCount
|
||||||
|
|
||||||
|
override fun findAudioContents(
|
||||||
|
creatorId: Long,
|
||||||
|
viewerId: Long,
|
||||||
|
themeId: Long?,
|
||||||
|
now: LocalDateTime,
|
||||||
|
canViewAdultContent: Boolean,
|
||||||
|
sort: ContentSort,
|
||||||
|
locale: String,
|
||||||
|
offset: Long,
|
||||||
|
limit: Int
|
||||||
|
): List<CreatorChannelAudioContentRecord> {
|
||||||
|
listThemeId = themeId
|
||||||
|
listSort = sort
|
||||||
|
listLocale = locale
|
||||||
|
listOffset = offset
|
||||||
|
listLimit = limit
|
||||||
|
listCanViewAdultContent = canViewAdultContent
|
||||||
|
return audioContents
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun audioContentRecord(audioContentId: Long): CreatorChannelAudioContentRecord {
|
||||||
|
return CreatorChannelAudioContentRecord(
|
||||||
|
audioContentId = audioContentId,
|
||||||
|
title = "audio-$audioContentId",
|
||||||
|
duration = "00:10:00",
|
||||||
|
imagePath = "audio/$audioContentId.png",
|
||||||
|
price = 10,
|
||||||
|
isAdult = false,
|
||||||
|
isPointAvailable = true,
|
||||||
|
isFirstContent = audioContentId == 1L,
|
||||||
|
seriesName = "series",
|
||||||
|
isOriginalSeries = true,
|
||||||
|
isOwned = audioContentId == 1L,
|
||||||
|
isRented = audioContentId == 2L
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user