feat(creator): 채널 홈 API 모델을 추가한다
This commit is contained in:
@@ -0,0 +1,15 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.creator.channel.data
|
||||||
|
|
||||||
|
import io.reactivex.rxjava3.core.Single
|
||||||
|
import kr.co.vividnext.sodalive.common.ApiResponse
|
||||||
|
import retrofit2.http.GET
|
||||||
|
import retrofit2.http.Header
|
||||||
|
import retrofit2.http.Path
|
||||||
|
|
||||||
|
interface CreatorChannelHomeApi {
|
||||||
|
@GET("/api/v2/creator-channels/{creatorId}/home")
|
||||||
|
fun getHome(
|
||||||
|
@Path("creatorId") creatorId: Long,
|
||||||
|
@Header("Authorization") authHeader: String
|
||||||
|
): Single<ApiResponse<CreatorChannelHomeResponse>>
|
||||||
|
}
|
||||||
@@ -0,0 +1,144 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.creator.channel.data
|
||||||
|
|
||||||
|
import androidx.annotation.Keep
|
||||||
|
import com.google.gson.annotations.SerializedName
|
||||||
|
import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelHomeResponse(
|
||||||
|
@SerializedName("creator") val creator: CreatorChannelCreatorResponse,
|
||||||
|
@SerializedName("currentLive") val currentLive: CreatorChannelLiveResponse?,
|
||||||
|
@SerializedName("latestAudioContent") val latestAudioContent: CreatorChannelAudioContentResponse?,
|
||||||
|
@SerializedName("channelDonations") val channelDonations: List<CreatorChannelDonationResponse>,
|
||||||
|
@SerializedName("notices") val notices: List<CreatorChannelCommunityPostResponse>,
|
||||||
|
@SerializedName("schedules") val schedules: List<CreatorChannelScheduleResponse>,
|
||||||
|
@SerializedName("audioContents") val audioContents: List<CreatorChannelAudioContentResponse>,
|
||||||
|
@SerializedName("series") val series: List<CreatorChannelSeriesResponse>,
|
||||||
|
@SerializedName("communities") val communities: List<CreatorChannelCommunityPostResponse>,
|
||||||
|
@SerializedName("fanTalk") val fanTalk: CreatorChannelFanTalkSummaryResponse,
|
||||||
|
@SerializedName("introduce") val introduce: String,
|
||||||
|
@SerializedName("activity") val activity: CreatorChannelActivityResponse,
|
||||||
|
@SerializedName("sns") val sns: CreatorChannelSnsResponse
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelCreatorResponse(
|
||||||
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
|
@SerializedName("characterId") val characterId: Long?,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("profileImageUrl") val profileImageUrl: String,
|
||||||
|
@SerializedName("followerCount") val followerCount: Int,
|
||||||
|
@SerializedName("isAiChatAvailable") val isAiChatAvailable: Boolean,
|
||||||
|
@SerializedName("isDmAvailable") val isDmAvailable: Boolean,
|
||||||
|
@SerializedName("isFollow") val isFollow: Boolean,
|
||||||
|
@SerializedName("isNotify") val isNotify: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelLiveResponse(
|
||||||
|
@SerializedName("liveId") val liveId: Long,
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("coverImageUrl") val coverImageUrl: String?,
|
||||||
|
@SerializedName("beginDateTimeUtc") val beginDateTimeUtc: String,
|
||||||
|
@SerializedName("price") val price: Int,
|
||||||
|
@SerializedName("isAdult") val isAdult: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelAudioContentResponse(
|
||||||
|
@SerializedName("audioContentId") val audioContentId: Long,
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("duration") val duration: String?,
|
||||||
|
@SerializedName("imageUrl") val imageUrl: String?,
|
||||||
|
@SerializedName("price") val price: Int,
|
||||||
|
@SerializedName("isPointAvailable") val isPointAvailable: Boolean,
|
||||||
|
@SerializedName("isFirstContent") val isFirstContent: Boolean,
|
||||||
|
@SerializedName("seriesName") val seriesName: String?,
|
||||||
|
@SerializedName("isOriginalSeries") val isOriginalSeries: Boolean?
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelDonationResponse(
|
||||||
|
@SerializedName("donationId") val donationId: Long,
|
||||||
|
@SerializedName("memberId") val memberId: Long,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("profileImageUrl") val profileImageUrl: String,
|
||||||
|
@SerializedName("can") val can: Int,
|
||||||
|
@SerializedName("isSecret") val isSecret: Boolean,
|
||||||
|
@SerializedName("message") val message: String,
|
||||||
|
@SerializedName("createdAtUtc") val createdAtUtc: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelScheduleResponse(
|
||||||
|
@SerializedName("scheduledAtUtc") val scheduledAtUtc: String,
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("type") val type: CreatorActivityType,
|
||||||
|
@SerializedName("targetId") val targetId: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelSeriesResponse(
|
||||||
|
@SerializedName("seriesId") val seriesId: Long,
|
||||||
|
@SerializedName("title") val title: String,
|
||||||
|
@SerializedName("coverImageUrl") val coverImageUrl: String,
|
||||||
|
@SerializedName("publishedDaysOfWeek") val publishedDaysOfWeek: String,
|
||||||
|
@SerializedName("isComplete") val isComplete: Boolean,
|
||||||
|
@SerializedName("numberOfContent") val numberOfContent: Int,
|
||||||
|
@SerializedName("isNew") val isNew: Boolean,
|
||||||
|
@SerializedName("isPopular") val isPopular: Boolean,
|
||||||
|
@SerializedName("isOriginal") val isOriginal: Boolean
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelCommunityPostResponse(
|
||||||
|
@SerializedName("postId") val postId: Long,
|
||||||
|
@SerializedName("creatorId") val creatorId: Long,
|
||||||
|
@SerializedName("creatorNickname") val creatorNickname: String,
|
||||||
|
@SerializedName("creatorProfileUrl") val creatorProfileUrl: String,
|
||||||
|
@SerializedName("imageUrl") val imageUrl: String?,
|
||||||
|
@SerializedName("audioUrl") val audioUrl: String?,
|
||||||
|
@SerializedName("content") val content: String,
|
||||||
|
@SerializedName("price") val price: Int,
|
||||||
|
@SerializedName("dateUtc") val dateUtc: String,
|
||||||
|
@SerializedName("existOrdered") val existOrdered: Boolean,
|
||||||
|
@SerializedName("likeCount") val likeCount: Int,
|
||||||
|
@SerializedName("commentCount") val commentCount: Int
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelFanTalkSummaryResponse(
|
||||||
|
@SerializedName("totalCount") val totalCount: Int,
|
||||||
|
@SerializedName("latestFanTalk") val latestFanTalk: CreatorChannelFanTalkResponse?
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelFanTalkResponse(
|
||||||
|
@SerializedName("fanTalkId") val fanTalkId: Long,
|
||||||
|
@SerializedName("memberId") val memberId: Long,
|
||||||
|
@SerializedName("nickname") val nickname: String,
|
||||||
|
@SerializedName("profileImageUrl") val profileImageUrl: String,
|
||||||
|
@SerializedName("content") val content: String,
|
||||||
|
@SerializedName("languageCode") val languageCode: String?,
|
||||||
|
@SerializedName("createdAtUtc") val createdAtUtc: String
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelActivityResponse(
|
||||||
|
@SerializedName("debutDateUtc") val debutDateUtc: String?,
|
||||||
|
@SerializedName("dDay") val dDay: String,
|
||||||
|
@SerializedName("liveCount") val liveCount: Long,
|
||||||
|
@SerializedName("liveDurationHours") val liveDurationHours: Long,
|
||||||
|
@SerializedName("liveContributorCount") val liveContributorCount: Long,
|
||||||
|
@SerializedName("audioContentCount") val audioContentCount: Long,
|
||||||
|
@SerializedName("seriesCount") val seriesCount: Long
|
||||||
|
)
|
||||||
|
|
||||||
|
@Keep
|
||||||
|
data class CreatorChannelSnsResponse(
|
||||||
|
@SerializedName("instagramUrl") val instagramUrl: String,
|
||||||
|
@SerializedName("fancimmUrl") val fancimmUrl: String,
|
||||||
|
@SerializedName("xUrl") val xUrl: String,
|
||||||
|
@SerializedName("youtubeUrl") val youtubeUrl: String,
|
||||||
|
@SerializedName("kakaoOpenChatUrl") val kakaoOpenChatUrl: String
|
||||||
|
)
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
package kr.co.vividnext.sodalive.v2.creator.channel
|
||||||
|
|
||||||
|
import com.google.gson.Gson
|
||||||
|
import kr.co.vividnext.sodalive.v2.common.CreatorActivityType
|
||||||
|
import kr.co.vividnext.sodalive.v2.creator.channel.data.CreatorChannelHomeResponse
|
||||||
|
import org.junit.Assert.assertEquals
|
||||||
|
import org.junit.Assert.assertNull
|
||||||
|
import org.junit.Test
|
||||||
|
|
||||||
|
class CreatorChannelHomeModelsTest {
|
||||||
|
private val gson = Gson()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `home response parses schedule type to creator activity type`() {
|
||||||
|
val response = gson.fromJson(homeJson(scheduleType = "LIVE_REPLAY"), CreatorChannelHomeResponse::class.java)
|
||||||
|
|
||||||
|
assertEquals(CreatorActivityType.LiveReplay, response.schedules.single().type)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `home response preserves nullable fields`() {
|
||||||
|
val response = gson.fromJson(homeJson(scheduleType = "AUDIO"), CreatorChannelHomeResponse::class.java)
|
||||||
|
|
||||||
|
assertNull(response.creator.characterId)
|
||||||
|
assertNull(response.currentLive)
|
||||||
|
assertNull(response.latestAudioContent)
|
||||||
|
assertNull(response.fanTalk.latestFanTalk)
|
||||||
|
assertNull(response.activity.debutDateUtc)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun homeJson(scheduleType: String): String = """
|
||||||
|
{
|
||||||
|
"creator": {
|
||||||
|
"creatorId": 1,
|
||||||
|
"characterId": null,
|
||||||
|
"nickname": "creator",
|
||||||
|
"profileImageUrl": "https://example.com/profile.png",
|
||||||
|
"followerCount": 10,
|
||||||
|
"isAiChatAvailable": true,
|
||||||
|
"isDmAvailable": true,
|
||||||
|
"isFollow": false,
|
||||||
|
"isNotify": false
|
||||||
|
},
|
||||||
|
"currentLive": null,
|
||||||
|
"latestAudioContent": null,
|
||||||
|
"channelDonations": [],
|
||||||
|
"notices": [],
|
||||||
|
"schedules": [
|
||||||
|
{
|
||||||
|
"scheduledAtUtc": "2026-06-12T00:00:00Z",
|
||||||
|
"title": "schedule",
|
||||||
|
"type": "$scheduleType",
|
||||||
|
"targetId": 11
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"audioContents": [],
|
||||||
|
"series": [],
|
||||||
|
"communities": [],
|
||||||
|
"fanTalk": {
|
||||||
|
"totalCount": 0,
|
||||||
|
"latestFanTalk": null
|
||||||
|
},
|
||||||
|
"introduce": "intro",
|
||||||
|
"activity": {
|
||||||
|
"debutDateUtc": null,
|
||||||
|
"dDay": "D+1",
|
||||||
|
"liveCount": 1,
|
||||||
|
"liveDurationHours": 2,
|
||||||
|
"liveContributorCount": 3,
|
||||||
|
"audioContentCount": 4,
|
||||||
|
"seriesCount": 5
|
||||||
|
},
|
||||||
|
"sns": {
|
||||||
|
"instagramUrl": "",
|
||||||
|
"fancimmUrl": "",
|
||||||
|
"xUrl": "",
|
||||||
|
"youtubeUrl": "",
|
||||||
|
"kakaoOpenChatUrl": ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""".trimIndent()
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user