diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceCountryResolver.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceCountryResolver.kt index af639e19..c1e4d9d0 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceCountryResolver.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceCountryResolver.kt @@ -5,8 +5,8 @@ import kr.co.vividnext.sodalive.member.Member private val FORCED_KR_MEMBER_IDS = setOf(16L, 17L, 17958L, 44144L) private val FORCED_JP_MEMBER_IDS = setOf(2L, 29721L, 32050L, 37543L, 40850L) -fun resolveCountryCodeWithForcedMapping(member: Member, requestCountryCode: String?): String { - val memberId = member.id +fun resolveCountryCodeWithForcedMapping(member: Member?, requestCountryCode: String?): String { + val memberId = member?.id if (memberId != null && FORCED_KR_MEMBER_IDS.contains(memberId)) { return "KR" } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceService.kt index df330621..d7759feb 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceService.kt @@ -157,8 +157,8 @@ class MemberContentPreferenceService( return getStoredPreference(member).isAdult } - fun resolveCountryCode(member: Member): String { - requireMemberId(member) + fun resolveCountryCode(member: Member?): String { + if (member != null) requireMemberId(member) return resolveCountryCodeWithForcedMapping(member, countryContext.countryCode) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt index 553bd63c..f6fccb19 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacade.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.v2.api.home.application import kr.co.vividnext.sodalive.event.EventItem +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService import kr.co.vividnext.sodalive.v2.api.common.dto.RecommendationBannerResponse @@ -46,6 +47,7 @@ class HomeRecommendationFacade( return runCatching { val now = LocalDateTime.now() val includeAdult = resolveAdultVisibility(member) + val bannerLang = if (memberContentPreferenceService.resolveCountryCode(member) == "JP") Lang.JA else Lang.KO HomeRecommendationResponse( lives = queryService.findLiveRecommendations( @@ -56,7 +58,8 @@ class HomeRecommendationFacade( banners = queryService.findHomeBanners( limit = HOME_BANNER_LIMIT, memberId = member?.id, - includeAdultBanners = includeAdult + includeAdultBanners = includeAdult, + lang = bannerLang ) .map { RecommendationBannerResponse.from(it.toBanner()) }, recentlyActiveCreators = queryService.findRecentlyActiveCreators( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt index 8aa33a36..324f5bbf 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepository.kt @@ -15,6 +15,7 @@ import kr.co.vividnext.sodalive.creator.admin.content.series.QSeries.series import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent import kr.co.vividnext.sodalive.event.EventItem import kr.co.vividnext.sodalive.event.QEvent.event +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.member.QMember import kr.co.vividnext.sodalive.member.QMember.member import kr.co.vividnext.sodalive.member.block.QBlockMember @@ -40,7 +41,12 @@ class DefaultAudioRecommendationQueryRepository( @Value("\${cloud.aws.cloud-front.host}") private val cloudFrontHost: String ) : AudioRecommendationQueryRepository { - override fun findBanners(limit: Int, memberId: Long?, canViewAdultContent: Boolean): List { + override fun findBanners( + limit: Int, + memberId: Long?, + canViewAdultContent: Boolean, + lang: Lang + ): List { val bannerCreator = QMember("audioRecommendationBannerCreator") val seriesOwner = QMember("audioRecommendationSeriesOwner") val randomTieBreaker = Expressions.numberTemplate(Double::class.java, "function('rand')") @@ -64,6 +70,7 @@ class DefaultAudioRecommendationQueryRepository( .where( audioContentBanner.isActive.isTrue, audioContentBanner.tab.id.eq(2L), + audioContentBanner.lang.eq(lang), adultBannerCondition(canViewAdultContent), activeBannerTargetCondition(memberId, bannerCreator, seriesOwner) ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryService.kt index 5f72de82..bac000d5 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryService.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.v2.content.recommendation.application +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService import kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioCard @@ -24,6 +25,7 @@ class AudioRecommendationQueryService( val canViewAdultContent = canViewAdultContent(member) val visibility = if (canViewAdultContent) AudioRecommendationVisibility.ALL else AudioRecommendationVisibility.SAFE val memberId = member?.id + val bannerLang = if (memberContentPreferenceService.resolveCountryCode(member) == "JP") Lang.JA else Lang.KO val newAndHotSectionType = newAndHotSectionType(visibility) val mostCommentedSectionType = mostCommentedSectionType(visibility) val recommendedAudioSectionType = recommendedAudioSectionType(visibility) @@ -44,7 +46,7 @@ class AudioRecommendationQueryService( ) return AudioRecommendations( - banners = queryPort.findBanners(BANNER_LIMIT, memberId, canViewAdultContent), + banners = queryPort.findBanners(BANNER_LIMIT, memberId, canViewAdultContent, bannerLang), originalSeries = queryPort.findOriginalSeries(ORIGINAL_SERIES_LIMIT, memberId, canViewAdultContent, now), latestAudios = queryPort.findLatestAudios(LATEST_AUDIO_LIMIT, memberId, canViewAdultContent, now), newAndHotAudios = queryPort.findAudioCardsByIds( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/port/out/AudioRecommendationQueryPort.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/port/out/AudioRecommendationQueryPort.kt index 12c7b604..5d181dd0 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/port/out/AudioRecommendationQueryPort.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/port/out/AudioRecommendationQueryPort.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.v2.content.recommendation.port.out +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.v2.common.domain.RecommendationBanner import kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioCard import kr.co.vividnext.sodalive.v2.content.recommendation.domain.AudioRecommendationVisibility @@ -9,7 +10,12 @@ import kr.co.vividnext.sodalive.v2.recommendation.port.out.RecommendationSnapsho import java.time.LocalDateTime interface AudioRecommendationQueryPort { - fun findBanners(limit: Int, memberId: Long?, canViewAdultContent: Boolean): List + fun findBanners( + limit: Int, + memberId: Long?, + canViewAdultContent: Boolean, + lang: Lang = Lang.KO + ): List fun findOriginalSeries(limit: Int, memberId: Long?, canViewAdultContent: Boolean, now: LocalDateTime): List fun findLatestAudios(limit: Int, memberId: Long?, canViewAdultContent: Boolean, now: LocalDateTime): List fun findFreeAudios(limit: Int, memberId: Long?, canViewAdultContent: Boolean, now: LocalDateTime): List diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt index edefca60..cfd16a89 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepository.kt @@ -20,6 +20,7 @@ import kr.co.vividnext.sodalive.event.QEvent.event import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommunity.creatorCommunity import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.QCreatorCommunityComment.creatorCommunityComment import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.QCreatorCommunityLike.creatorCommunityLike +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom import kr.co.vividnext.sodalive.member.MemberKind import kr.co.vividnext.sodalive.member.MemberRole @@ -88,7 +89,8 @@ class DefaultHomeRecommendationQueryRepository( override fun findHomeBanners( limit: Int, memberId: Long?, - includeAdultBanners: Boolean + includeAdultBanners: Boolean, + lang: Lang ): List { val bannerCreator = QMember("bannerCreator") val seriesOwner = QMember("seriesOwner") @@ -116,6 +118,7 @@ class DefaultHomeRecommendationQueryRepository( .where( audioContentBanner.isActive.isTrue, audioContentBanner.tab.isNull, + audioContentBanner.lang.eq(lang), includeAdultBannerCondition(includeAdultBanners), activeBannerTargetCondition(memberId, bannerCreator, seriesOwner) ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryService.kt index af617b1e..f225999d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryService.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.v2.recommendation.application +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendationSnapshotWindowPolicy import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType @@ -44,9 +45,10 @@ class HomeRecommendationQueryService( fun findHomeBanners( limit: Int = DEFAULT_BANNER_LIMIT, memberId: Long? = null, - includeAdultBanners: Boolean = false + includeAdultBanners: Boolean = false, + lang: Lang = Lang.KO ): List { - return queryPort.findHomeBanners(limit, memberId, includeAdultBanners) + return queryPort.findHomeBanners(limit, memberId, includeAdultBanners, lang) } fun findRecentlyActiveCreators( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt index 45be5f4c..26578c8e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/v2/recommendation/port/out/HomeRecommendationQueryPort.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.v2.recommendation.port.out +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType import java.time.LocalDateTime @@ -14,7 +15,8 @@ interface HomeRecommendationQueryPort { fun findHomeBanners( limit: Int, memberId: Long? = null, - includeAdultBanners: Boolean = false + includeAdultBanners: Boolean = false, + lang: Lang = Lang.KO ): List fun findRecentlyActiveCreators( diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceIntegrationTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceIntegrationTest.kt index c75ec2ff..6a26bcff 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceIntegrationTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceIntegrationTest.kt @@ -207,6 +207,22 @@ class MemberContentPreferenceIntegrationTest @Autowired constructor( assertEquals("KR", service.resolveCountryCode(member)) } + @Test + @DisplayName("비로그인 사용자의 국가 코드는 접속 국가 헤더를 정규화하고 없으면 KR로 계산된다") + fun shouldResolveCountryCodeForAnonymousUser() { + countryContext.setCountryCode("JP") + assertEquals("JP", service.resolveCountryCode(null)) + + countryContext.setCountryCode(" jp ") + assertEquals("JP", service.resolveCountryCode(null)) + + countryContext.setCountryCode(null) + assertEquals("KR", service.resolveCountryCode(null)) + + countryContext.setCountryCode(" ") + assertEquals("KR", service.resolveCountryCode(null)) + } + private fun saveMember(seed: String): Member { return memberRepository.saveAndFlush( Member( diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacadeTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacadeTest.kt index 494fb245..265b8e57 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacadeTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/api/home/application/HomeRecommendationFacadeTest.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.v2.api.home.application +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService import kr.co.vividnext.sodalive.v2.recommendation.application.HomeRecommendationQueryService @@ -56,6 +57,27 @@ class HomeRecommendationFacadeTest { assertTrue(queryPort.bannerIncludeAdultBanners) } + @Test + @DisplayName("홈 추천은 JP 국가 판정이면 JA 배너 조회를 요청한다") + fun shouldPassJaToHomeBannerQueryForJapan() { + val member = Member(password = "password", nickname = "jp-member").apply { id = 11L } + Mockito.doReturn("JP").`when`(preferenceService).resolveCountryCode(member) + + facade.getHomeRecommendations(member) + + assertTrue(queryPort.bannerLang == Lang.JA) + } + + @Test + @DisplayName("홈 추천은 JP 이외 국가 판정이면 KO 배너 조회를 요청한다") + fun shouldPassKoToHomeBannerQueryForNonJapan() { + Mockito.doReturn("KR").`when`(preferenceService).resolveCountryCode(null) + + facade.getHomeRecommendations(null) + + assertTrue(queryPort.bannerLang == Lang.KO) + } + private fun firstAudio(price: Int, isPointAvailable: Boolean): HomeFirstAudioContentRecord { return HomeFirstAudioContentRecord( contentId = price.toLong() + 1, @@ -74,6 +96,7 @@ class HomeRecommendationFacadeTest { private class FakeHomeRecommendationQueryPort : HomeRecommendationQueryPort { var firstAudioContents: List = emptyList() var bannerIncludeAdultBanners: Boolean = false + var bannerLang: Lang? = null override fun findLiveRecommendations( offset: Long, @@ -85,9 +108,11 @@ class HomeRecommendationFacadeTest { override fun findHomeBanners( limit: Int, memberId: Long?, - includeAdultBanners: Boolean + includeAdultBanners: Boolean, + lang: Lang ): List { bannerIncludeAdultBanners = includeAdultBanners + bannerLang = lang return emptyList() } diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt index 81c60357..acdf8ea2 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/adapter/out/persistence/DefaultAudioRecommendationQueryRepositoryTest.kt @@ -12,6 +12,7 @@ import kr.co.vividnext.sodalive.content.main.tab.AudioContentMainTab import kr.co.vividnext.sodalive.content.theme.AudioContentTheme import kr.co.vividnext.sodalive.creator.admin.content.series.Series import kr.co.vividnext.sodalive.creator.admin.content.series.SeriesContent +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.block.BlockMember @@ -96,6 +97,38 @@ class DefaultAudioRecommendationQueryRepositoryTest @Autowired constructor( assertEquals(visibleCreator.id, safeBanners.first().creatorId) } + @Test + @DisplayName("콘텐츠 추천 배너는 언어 필터를 limit보다 먼저 적용한다") + fun shouldFilterBannersByLangBeforeLimit() { + val recommendationTab = saveContentRecommendationTab() + val koBanner = saveBanner( + "ko-audio-banner.png", + AudioContentBannerType.LINK, + 1, + link = "https://ko.test", + tab = recommendationTab, + lang = Lang.KO + ) + val jaBanner = saveBanner( + "ja-audio-banner.png", + AudioContentBannerType.LINK, + 2, + link = "https://ja.test", + tab = recommendationTab, + lang = Lang.JA + ) + flushAndClear() + + assertEquals( + listOf("https://cdn.test/${koBanner.thumbnailImage}"), + repository.findBanners(1, null, false, Lang.KO).map { it.imageUrl } + ) + assertEquals( + listOf("https://cdn.test/${jaBanner.thumbnailImage}"), + repository.findBanners(1, null, false, Lang.JA).map { it.imageUrl } + ) + } + @Test @DisplayName("오리지널 시리즈는 활성 원본 시리즈를 최신순으로 반환하고 성인/차단 조건을 적용한다") fun shouldFindOriginalSeriesWithVisibilityConditions() { @@ -404,11 +437,13 @@ class DefaultAudioRecommendationQueryRepositoryTest @Autowired constructor( isAdult: Boolean = false, creator: Member? = null, link: String? = null, - tab: AudioContentMainTab? = null + tab: AudioContentMainTab? = null, + lang: Lang = Lang.KO ): AudioContentBanner { val banner = AudioContentBanner( thumbnailImage = thumbnailImage, type = type, + lang = lang, isAdult = isAdult, isActive = isActive, orders = orders diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryServiceTest.kt index 1f258021..af6a3610 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/content/recommendation/application/AudioRecommendationQueryServiceTest.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.v2.content.recommendation.application +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.contentpreference.MemberContentPreferenceService @@ -77,7 +78,7 @@ class AudioRecommendationQueryServiceTest { 0, AudioRecommendationQueryService.RECOMMENDED_AUDIO_LIMIT ) - Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, null, false) + Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, null, false, Lang.KO) Mockito.verify(queryPort).findLatestAudios( eqValue(AudioRecommendationQueryService.LATEST_AUDIO_LIMIT), Mockito.isNull(), @@ -140,6 +141,7 @@ class AudioRecommendationQueryServiceTest { fun shouldUseStoredPreferenceForMemberAdultVisibility() { val member = member(id = 10L) Mockito.doReturn(true).`when`(preferenceService).canViewAdultContent(member) + Mockito.doReturn("JP").`when`(preferenceService).resolveCountryCode(member) stubFallback( RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL, 0, @@ -150,6 +152,7 @@ class AudioRecommendationQueryServiceTest { service.getRecommendations(member) Mockito.verify(preferenceService).canViewAdultContent(member) + Mockito.verify(queryPort).findBanners(AudioRecommendationQueryService.BANNER_LIMIT, member.id, true, Lang.JA) Mockito.verify(preferenceService, Mockito.never()).initializeDefaultPreference(member) verifyFallback( RecommendedSectionType.NEW_AND_HOT_AUDIO_ALL, diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt index 4fa2e799..582b797c 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/adapter/out/persistence/DefaultHomeRecommendationQueryRepositoryTest.kt @@ -262,6 +262,23 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( assertEquals(listOf(homeBanner.thumbnailImage), banners.map { it.thumbnailImage }) } + @Test + @DisplayName("홈 배너는 언어 필터를 limit보다 먼저 적용한다") + fun shouldFilterHomeBannersByLangBeforeLimit() { + val koBanner = saveBanner("ko-home-banner.png", AudioContentBannerType.LINK, 1, true, lang = Lang.KO) + val jaBanner = saveBanner("ja-home-banner.png", AudioContentBannerType.LINK, 2, true, lang = Lang.JA) + flushAndClear() + + assertEquals( + listOf(koBanner.thumbnailImage), + repository.findHomeBanners(limit = 1, lang = Lang.KO).map { it.thumbnailImage } + ) + assertEquals( + listOf(jaBanner.thumbnailImage), + repository.findHomeBanners(limit = 1, lang = Lang.JA).map { it.thumbnailImage } + ) + } + @Test @DisplayName("홈 배너는 성인 콘텐츠 조회가 불가능하면 비성인 배너만 반환한다") fun shouldExcludeAdultHomeBannersWhenAdultContentIsNotVisible() { @@ -2693,12 +2710,13 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor( event: Event? = null, series: Series? = null, tab: AudioContentMainTab? = null, - link: String? = null + link: String? = null, + lang: Lang = Lang.KO ): AudioContentBanner { val banner = AudioContentBanner( thumbnailImage = thumbnailImage, type = type, - lang = Lang.KO, + lang = lang, isAdult = isAdult, isActive = isActive, orders = orders diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt index 1f4cac79..ddd59d3c 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/v2/recommendation/application/HomeRecommendationQueryServiceTest.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.v2.recommendation.application +import kr.co.vividnext.sodalive.i18n.Lang import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType import kr.co.vividnext.sodalive.v2.recommendation.domain.RecommendedSectionType import kr.co.vividnext.sodalive.v2.recommendation.port.out.HomeAiCharacterRecommendationRecord @@ -93,6 +94,16 @@ class HomeRecommendationQueryServiceTest { assertEquals(20, port.bannerLimit) assertEquals(100L, port.bannerMemberId) assertEquals(true, port.bannerIncludeAdultBanners) + assertEquals(Lang.KO, port.bannerLang) + assertEquals(port.banners, banners) + } + + @Test + @DisplayName("홈 배너 추천은 언어 조건을 조회 포트에 위임한다") + fun shouldDelegateHomeBannerLang() { + val banners = service.findHomeBanners(lang = Lang.JA) + + assertEquals(Lang.JA, port.bannerLang) assertEquals(port.banners, banners) } @@ -966,6 +977,7 @@ class HomeRecommendationQueryServiceTest { var bannerLimit: Int? = null var bannerMemberId: Long? = null var bannerIncludeAdultBanners: Boolean? = null + var bannerLang: Lang? = null var activeCreatorLimit: Int? = null var activeCreatorMemberId: Long? = null var activeCreatorIncludeAdultActivities: Boolean? = null @@ -1068,11 +1080,13 @@ class HomeRecommendationQueryServiceTest { override fun findHomeBanners( limit: Int, memberId: Long?, - includeAdultBanners: Boolean + includeAdultBanners: Boolean, + lang: Lang ): List { bannerLimit = limit bannerMemberId = memberId bannerIncludeAdultBanners = includeAdultBanners + bannerLang = lang return banners }