From 243394acd7c67ce46fa38d24777bb05626337618 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 17 Sep 2026 20:17:28 +0900 Subject: [PATCH] =?UTF-8?q?feat(content-preference):=20=EC=A1=B0=ED=9A=8C?= =?UTF-8?q?=EC=9A=A9=20=EC=84=B1=EC=9D=B8=20=EB=85=B8=EC=B6=9C=20=EC=A0=95?= =?UTF-8?q?=EC=B1=85=EC=9D=84=20=ED=86=B5=ED=95=A9=ED=95=9C=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../MemberContentPreferenceService.kt | 8 +++ .../MemberContentPreferenceServiceTest.kt | 56 ++++++++++++++++++- 2 files changed, 62 insertions(+), 2 deletions(-) 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 d7759feb..a7554525 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,6 +157,14 @@ class MemberContentPreferenceService( return getStoredPreference(member).isAdult } + fun isAdultVisibleForQuery(member: Member, isAdultContentVisible: Boolean): Boolean { + return calculateIsAdultForQuery( + member = member, + countryCode = resolveCountryCode(member), + isAdultContentVisible = isAdultContentVisible + ) + } + fun resolveCountryCode(member: Member?): String { if (member != null) requireMemberId(member) return resolveCountryCodeWithForcedMapping(member, countryContext.countryCode) diff --git a/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceServiceTest.kt b/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceServiceTest.kt index 60a7c413..914d70fc 100644 --- a/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceServiceTest.kt +++ b/src/test/kotlin/kr/co/vividnext/sodalive/member/contentpreference/MemberContentPreferenceServiceTest.kt @@ -61,10 +61,10 @@ class MemberContentPreferenceServiceTest { @Test @DisplayName("회원 ID 강제 매핑(JP)이 헤더보다 우선 적용된다") fun shouldResolveCountryCodeByForcedJapanMappingFirst() { - val member = createMember(id = 2L) + val member = createMember(id = 29721L) val preference = createPreference(member) countryContext.setCountryCode("US") - Mockito.`when`(repository.findByMemberId(2L)).thenReturn(preference) + Mockito.`when`(repository.findByMemberId(29721L)).thenReturn(preference) val result = service.getStoredPreference(member) @@ -449,6 +449,58 @@ class MemberContentPreferenceServiceTest { assertTrue(service.calculateIsAdultForQuery(noAuthMember, "US", true)) } + @Test + @DisplayName("로그인 회원의 접속 국가 코드는 공백과 소문자를 정규화하고 없으면 KR로 계산된다") + fun shouldNormalizeCountryCodeForLoggedInMember() { + val member = createMember(id = 2400L) + + countryContext.setCountryCode(" us ") + assertEquals("US", service.resolveCountryCode(member)) + + countryContext.setCountryCode(" ") + assertEquals("KR", service.resolveCountryCode(member)) + + countryContext.setCountryCode(null) + assertEquals("KR", service.resolveCountryCode(member)) + } + + @Test + @DisplayName("조회용 성인 노출 여부는 접속 국가와 인증 여부로 계산된다") + fun shouldCalculateIsAdultVisibleForQueryByCountryAndAuth() { + val noAuthMember = createMember(id = 2300L, withAuth = false) + val authMember = createMember(id = 2301L, withAuth = true) + + countryContext.setCountryCode("KR") + assertFalse(service.isAdultVisibleForQuery(noAuthMember, isAdultContentVisible = true)) + assertTrue(service.isAdultVisibleForQuery(authMember, isAdultContentVisible = true)) + + countryContext.setCountryCode("US") + assertTrue(service.isAdultVisibleForQuery(noAuthMember, isAdultContentVisible = true)) + assertFalse(service.isAdultVisibleForQuery(authMember, isAdultContentVisible = false)) + } + + @Test + @DisplayName("비KR 요청에서는 회원의 저장 국가와 무관하게 전달한 성인 노출값을 사용한다") + fun shouldIgnoreStoredCountryCodeWhenRequestCountryIsNotKr() { + val member = createMember(id = 2401L, withAuth = false).apply { + countryCode = "KR" + } + countryContext.setCountryCode("US") + + assertEquals("US", service.resolveCountryCode(member)) + assertTrue(service.isAdultVisibleForQuery(member, isAdultContentVisible = true)) + assertFalse(service.isAdultVisibleForQuery(member, isAdultContentVisible = false)) + } + + @Test + @DisplayName("조회용 성인 노출 여부도 회원 ID 강제 매핑이 헤더보다 우선 적용된다") + fun shouldApplyForcedCountryMappingForIsAdultVisibleForQuery() { + val forcedKrMember = createMember(id = 16L, withAuth = false) + countryContext.setCountryCode("US") + + assertFalse(service.isAdultVisibleForQuery(forcedKrMember, isAdultContentVisible = true)) + } + @Test @DisplayName("성인 콘텐츠 조회 가능 여부는 저장 preference의 조회용 성인 정책 결과를 반환한다") fun shouldReturnStoredPreferenceAdultPolicyForCanViewAdultContent() {