Compare commits

..

4 Commits

6 changed files with 79 additions and 5 deletions

View File

@@ -270,13 +270,15 @@ class HomeRecommendationFacade(
creatorProfileImage = imageUrl(cloudFrontHost, creatorProfileImage),
title = title,
coverImage = imageUrl(cloudFrontHost, coverImage),
releaseDate = releaseDate.toUtcIso()
releaseDate = releaseDate.toUtcIso(),
isPointAvailable = isPointAvailable
)
private fun HomeAiCharacterRecommendationRecord.toItem() = HomeAiCharacterItem(
characterId = characterId,
name = name,
description = description,
profileImage = imageUrl(cloudFrontHost, profileImage),
totalChatCount = totalChatCount,
originalWorkTitle = originalWorkTitle
)

View File

@@ -1,5 +1,6 @@
package kr.co.vividnext.sodalive.v2.api.home.dto
import com.fasterxml.jackson.annotation.JsonProperty
import java.time.LocalDateTime
import java.time.ZoneOffset
@@ -66,13 +67,16 @@ data class HomeFirstAudioContentItem(
val creatorProfileImage: String?,
val title: String,
val coverImage: String?,
val releaseDate: String
val releaseDate: String,
@JsonProperty("isPointAvailable")
val isPointAvailable: Boolean
)
data class HomeAiCharacterItem(
val characterId: Long,
val name: String,
val description: String,
val profileImage: String?,
val totalChatCount: Long,
val originalWorkTitle: String?
)

View File

@@ -395,6 +395,7 @@ class DefaultHomeRecommendationQueryRepository(
ac.cover_image as cover_image,
ac.release_date as release_date,
ac.is_active as is_active,
ac.is_point_available as is_point_available,
row_number() over (
partition by ac.member_id
order by ac.created_at asc, ac.release_date asc, ac.id asc
@@ -421,6 +422,7 @@ class DefaultHomeRecommendationQueryRepository(
ec.title as title,
ec.cover_image as cover_image,
ec.release_date as release_date,
ec.is_point_available as is_point_available,
case
when ec.release_date >= :recency3Start then 100
when ec.release_date >= :recency7Start then 80
@@ -471,8 +473,9 @@ class DefaultHomeRecommendationQueryRepository(
title = row[4] as String,
coverImage = row[5] as String?,
releaseDate = toLocalDateTime(row[6]),
recencyScore = (row[7] as Number).toInt(),
randomTieBreaker = (row[8] as Number).toDouble()
isPointAvailable = row[7] as Boolean,
recencyScore = (row[8] as Number).toInt(),
randomTieBreaker = (row[9] as Number).toDouble()
)
}
}
@@ -708,6 +711,7 @@ class DefaultHomeRecommendationQueryRepository(
chatCharacter.id,
chatCharacter.name,
chatCharacter.description,
chatCharacter.imagePath,
chatMessage.id.count(),
linkedOriginalWork.title
)
@@ -724,7 +728,13 @@ class DefaultHomeRecommendationQueryRepository(
chatMessage.isActive.isTrue
)
.where(chatCharacter.isActive.isTrue, chatCharacter.id.`in`(characterIds))
.groupBy(chatCharacter.id, chatCharacter.name, chatCharacter.description, linkedOriginalWork.title)
.groupBy(
chatCharacter.id,
chatCharacter.name,
chatCharacter.description,
chatCharacter.imagePath,
linkedOriginalWork.title
)
.fetch()
}

View File

@@ -126,6 +126,7 @@ data class HomeFirstAudioContentRecord(
val title: String,
val coverImage: String?,
val releaseDate: LocalDateTime,
val isPointAvailable: Boolean,
val recencyScore: Int,
val randomTieBreaker: Double
)
@@ -134,6 +135,7 @@ data class HomeAiCharacterRecommendationRecord(
val characterId: Long,
val name: String,
val description: String,
val profileImage: String?,
val totalChatCount: Long,
val originalWorkTitle: String?
)

View File

@@ -0,0 +1,51 @@
package kr.co.vividnext.sodalive.v2.api.home.dto
import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertFalse
import org.junit.jupiter.api.Test
class HomeRecommendationResponseTest {
private val objectMapper = jacksonObjectMapper()
@Test
fun shouldSerializeNewHomeRecommendationFields() {
val response = HomeRecommendationResponse(
lives = emptyList(),
banners = emptyList(),
recentlyActiveCreators = emptyList(),
recentDebutCreators = emptyList(),
firstAudioContents = listOf(
HomeFirstAudioContentItem(
contentId = 1L,
creatorId = 2L,
creatorNickname = "creator",
creatorProfileImage = "https://cdn.test/profile/creator.png",
title = "first audio",
coverImage = "https://cdn.test/cover/audio.png",
releaseDate = "2026-06-01T00:00:00Z",
isPointAvailable = true
)
),
aiCharacters = listOf(
HomeAiCharacterItem(
characterId = 3L,
name = "character",
description = "description",
profileImage = "https://cdn.test/profile/character.png",
totalChatCount = 4L,
originalWorkTitle = "original"
)
),
genreCreators = emptyList(),
cheerCreators = emptyList(),
popularCommunities = emptyList()
)
val json = objectMapper.readTree(objectMapper.writeValueAsString(response))
assertEquals(true, json["firstAudioContents"][0]["isPointAvailable"].asBoolean())
assertFalse(json["firstAudioContents"][0].has("pointAvailable"))
assertEquals("https://cdn.test/profile/character.png", json["aiCharacters"][0]["profileImage"].asText())
}
}

View File

@@ -154,6 +154,7 @@ class HomeRecommendationQueryServiceTest {
characterId = 1L,
name = "character-1",
description = "description-1",
profileImage = "profile/character-1.png",
totalChatCount = 3L,
originalWorkTitle = "original-work"
),
@@ -161,6 +162,7 @@ class HomeRecommendationQueryServiceTest {
characterId = 2L,
name = "character-2",
description = "description-2",
profileImage = null,
totalChatCount = 0L,
originalWorkTitle = null
)
@@ -170,6 +172,8 @@ class HomeRecommendationQueryServiceTest {
assertEquals((1L..10L).toList(), port.aiCharacterDetailIds)
assertEquals(listOf(1L, 2L), characters.map { it.characterId })
assertEquals("profile/character-1.png", characters.first().profileImage)
assertEquals(null, characters.last().profileImage)
assertEquals("original-work", characters.first().originalWorkTitle)
assertEquals(null, characters.last().originalWorkTitle)
}
@@ -488,6 +492,7 @@ class HomeRecommendationQueryServiceTest {
title = "first-audio",
coverImage = "first-audio.png",
releaseDate = LocalDateTime.of(2026, 5, 30, 10, 0),
isPointAvailable = true,
recencyScore = 100,
randomTieBreaker = 0.3
)