feat(home-live): 라이브 추천 조회 정보를 확장한다
This commit is contained in:
@@ -62,7 +62,10 @@ class DefaultHomeRecommendationQueryRepository(
|
|||||||
HomeLiveRecommendationRecord::class.java,
|
HomeLiveRecommendationRecord::class.java,
|
||||||
liveRoom.id,
|
liveRoom.id,
|
||||||
member.nickname,
|
member.nickname,
|
||||||
member.profileImage
|
member.profileImage,
|
||||||
|
liveRoom.title,
|
||||||
|
liveRoom.price,
|
||||||
|
liveRoom.beginDateTime
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
.from(liveRoom)
|
.from(liveRoom)
|
||||||
|
|||||||
@@ -80,7 +80,10 @@ interface HomeRecommendationQueryPort {
|
|||||||
data class HomeLiveRecommendationRecord(
|
data class HomeLiveRecommendationRecord(
|
||||||
val liveRoomId: Long,
|
val liveRoomId: Long,
|
||||||
val creatorNickname: String,
|
val creatorNickname: String,
|
||||||
val creatorProfileImage: String?
|
val creatorProfileImage: String?,
|
||||||
|
val title: String,
|
||||||
|
val price: Int,
|
||||||
|
val beginDateTime: LocalDateTime
|
||||||
)
|
)
|
||||||
|
|
||||||
data class HomeBannerRecommendationRecord(
|
data class HomeBannerRecommendationRecord(
|
||||||
|
|||||||
@@ -106,6 +106,66 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
|||||||
assertEquals(listOf(oldest.id), page1.map { it.liveRoomId })
|
assertEquals(listOf(oldest.id), page1.map { it.liveRoomId })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("라이브 추천 조회는 진행 중인 라이브의 제목, 가격, 시작 시간을 함께 반환한다")
|
||||||
|
fun shouldReturnLiveTitlePriceAndBeginDateTimeForOnAirLiveQuery() {
|
||||||
|
val beginDateTime = LocalDateTime.of(2026, 6, 26, 12, 30)
|
||||||
|
val viewer = saveMember("on-air-viewer", MemberRole.USER)
|
||||||
|
val creator = saveMember("on-air-creator", MemberRole.CREATOR)
|
||||||
|
val live = saveLiveRoom(
|
||||||
|
creator = creator,
|
||||||
|
beginDateTime = beginDateTime,
|
||||||
|
channelName = "channel",
|
||||||
|
title = "paid live",
|
||||||
|
price = 30
|
||||||
|
)
|
||||||
|
flushAndClear()
|
||||||
|
|
||||||
|
val lives = repository.findLiveRecommendations(
|
||||||
|
offset = 0,
|
||||||
|
limit = 1,
|
||||||
|
memberId = viewer.id,
|
||||||
|
includeAdultLives = true
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(listOf(live.id), lives.map { it.liveRoomId })
|
||||||
|
assertEquals("paid live", lives.single().title)
|
||||||
|
assertEquals(30, lives.single().price)
|
||||||
|
assertEquals(beginDateTime, lives.single().beginDateTime)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("진행 중 라이브 조회 정책은 활성 방송자, 채널명, 활성 라이브, 성인 노출, 차단 관계를 적용한다")
|
||||||
|
fun shouldApplyOnAirLiveVisibilityPolicy() {
|
||||||
|
val baseAt = LocalDateTime.of(2026, 6, 26, 12, 0)
|
||||||
|
val viewer = saveMember("policy-viewer", MemberRole.USER)
|
||||||
|
val visibleCreator = saveMember("policy-visible", MemberRole.CREATOR)
|
||||||
|
val inactiveCreator = saveMember("policy-inactive", MemberRole.CREATOR, isActive = false)
|
||||||
|
val viewerBlockedCreator = saveMember("policy-viewer-blocked", MemberRole.CREATOR)
|
||||||
|
val creatorBlockedViewer = saveMember("policy-creator-blocked", MemberRole.CREATOR)
|
||||||
|
val olderVisibleLive = saveLiveRoom(visibleCreator, baseAt, channelName = "older")
|
||||||
|
val newerVisibleLive = saveLiveRoom(visibleCreator, baseAt.plusMinutes(1), channelName = "newer")
|
||||||
|
saveLiveRoom(inactiveCreator, baseAt.plusMinutes(6), channelName = "inactive-creator")
|
||||||
|
saveLiveRoom(visibleCreator, baseAt.plusMinutes(5), channelName = "inactive-live", isActive = false)
|
||||||
|
saveLiveRoom(visibleCreator, baseAt.plusMinutes(5), channelName = null)
|
||||||
|
saveLiveRoom(visibleCreator, baseAt.plusMinutes(4), channelName = "")
|
||||||
|
saveLiveRoom(visibleCreator, baseAt.plusMinutes(3), channelName = "adult", isAdult = true)
|
||||||
|
saveLiveRoom(viewerBlockedCreator, baseAt.plusMinutes(2), channelName = "viewer-blocked")
|
||||||
|
saveLiveRoom(creatorBlockedViewer, baseAt.plusMinutes(2), channelName = "creator-blocked")
|
||||||
|
saveBlock(viewer, viewerBlockedCreator)
|
||||||
|
saveBlock(creatorBlockedViewer, viewer)
|
||||||
|
flushAndClear()
|
||||||
|
|
||||||
|
val lives = repository.findLiveRecommendations(
|
||||||
|
offset = 0,
|
||||||
|
limit = 10,
|
||||||
|
memberId = viewer.id,
|
||||||
|
includeAdultLives = false
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(listOf(newerVisibleLive.id, olderVisibleLive.id), lives.map { it.liveRoomId })
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("라이브 추천은 회원과 크리에이터의 양방향 차단 관계를 제외한다")
|
@DisplayName("라이브 추천은 회원과 크리에이터의 양방향 차단 관계를 제외한다")
|
||||||
fun shouldExcludeBidirectionalBlockedCreatorsFromLiveRecommendations() {
|
fun shouldExcludeBidirectionalBlockedCreatorsFromLiveRecommendations() {
|
||||||
@@ -2082,17 +2142,22 @@ class DefaultHomeRecommendationQueryRepositoryTest @Autowired constructor(
|
|||||||
creator: Member,
|
creator: Member,
|
||||||
beginDateTime: LocalDateTime,
|
beginDateTime: LocalDateTime,
|
||||||
channelName: String?,
|
channelName: String?,
|
||||||
isAdult: Boolean = false
|
isAdult: Boolean = false,
|
||||||
|
title: String = "live-${creator.nickname}-$beginDateTime",
|
||||||
|
price: Int = 0,
|
||||||
|
isActive: Boolean = true
|
||||||
): LiveRoom {
|
): LiveRoom {
|
||||||
val room = LiveRoom(
|
val room = LiveRoom(
|
||||||
title = "live-${creator.nickname}-$beginDateTime",
|
title = title,
|
||||||
notice = "notice",
|
notice = "notice",
|
||||||
beginDateTime = beginDateTime,
|
beginDateTime = beginDateTime,
|
||||||
numberOfPeople = 0,
|
numberOfPeople = 0,
|
||||||
isAdult = isAdult
|
isAdult = isAdult,
|
||||||
|
price = price
|
||||||
)
|
)
|
||||||
room.member = creator
|
room.member = creator
|
||||||
room.channelName = channelName
|
room.channelName = channelName
|
||||||
|
room.isActive = isActive
|
||||||
entityManager.persist(room)
|
entityManager.persist(room)
|
||||||
return room
|
return room
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -65,6 +65,23 @@ class HomeRecommendationQueryServiceTest {
|
|||||||
assertEquals(port.liveRecommendations, recommendations)
|
assertEquals(port.liveRecommendations, recommendations)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@DisplayName("라이브 추천 조회는 paging과 성인 노출 여부를 조회 포트에 그대로 위임한다")
|
||||||
|
fun shouldDelegateLiveRecommendationQueryWithPagingAndAdultFlag() {
|
||||||
|
val recommendations = service.findLiveRecommendations(
|
||||||
|
offset = 40,
|
||||||
|
limit = 21,
|
||||||
|
memberId = 100L,
|
||||||
|
includeAdultLives = true
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(40, port.liveOffset)
|
||||||
|
assertEquals(21, port.liveLimit)
|
||||||
|
assertEquals(100L, port.liveMemberId)
|
||||||
|
assertEquals(true, port.liveIncludeAdultLives)
|
||||||
|
assertEquals(port.liveRecommendations, recommendations)
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@DisplayName("홈 배너 추천은 기본 20개를 활성 배너 조회 포트에 위임한다")
|
@DisplayName("홈 배너 추천은 기본 20개를 활성 배너 조회 포트에 위임한다")
|
||||||
fun shouldFindHomeBannersWithDefaultLimit() {
|
fun shouldFindHomeBannersWithDefaultLimit() {
|
||||||
@@ -628,7 +645,10 @@ class HomeRecommendationQueryServiceTest {
|
|||||||
HomeLiveRecommendationRecord(
|
HomeLiveRecommendationRecord(
|
||||||
liveRoomId = 1L,
|
liveRoomId = 1L,
|
||||||
creatorNickname = "creator",
|
creatorNickname = "creator",
|
||||||
creatorProfileImage = "profile.png"
|
creatorProfileImage = "profile.png",
|
||||||
|
title = "live",
|
||||||
|
price = 10,
|
||||||
|
beginDateTime = LocalDateTime.of(2026, 6, 26, 12, 30)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
val banners = listOf(
|
val banners = listOf(
|
||||||
|
|||||||
Reference in New Issue
Block a user