test #350
@@ -193,6 +193,11 @@ interface AudioContentQueryRepository {
|
|||||||
offset: Long = 0,
|
offset: Long = 0,
|
||||||
limit: Long = 20
|
limit: Long = 20
|
||||||
): List<GetAudioContentMainItem>
|
): List<GetAudioContentMainItem>
|
||||||
|
|
||||||
|
fun findLatestContentByCreatorId(
|
||||||
|
creatorId: Long,
|
||||||
|
isAdult: Boolean = false
|
||||||
|
): AudioContent?
|
||||||
}
|
}
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
@@ -1416,4 +1421,27 @@ class AudioContentQueryRepositoryImpl(
|
|||||||
.limit(limit)
|
.limit(limit)
|
||||||
.fetch()
|
.fetch()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun findLatestContentByCreatorId(
|
||||||
|
creatorId: Long,
|
||||||
|
isAdult: Boolean
|
||||||
|
): AudioContent? {
|
||||||
|
var where = audioContent.member.id.eq(creatorId)
|
||||||
|
.and(
|
||||||
|
audioContent.isActive.isTrue
|
||||||
|
.and(audioContent.duration.isNotNull)
|
||||||
|
.or(audioContent.releaseDate.isNotNull.and(audioContent.duration.isNotNull))
|
||||||
|
)
|
||||||
|
|
||||||
|
if (!isAdult) {
|
||||||
|
where = where.and(audioContent.isAdult.isFalse)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryFactory
|
||||||
|
.selectFrom(audioContent)
|
||||||
|
.where(where)
|
||||||
|
.orderBy(audioContent.releaseDate.desc())
|
||||||
|
.limit(1)
|
||||||
|
.fetchFirst()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -386,7 +386,7 @@ class AudioContentService(
|
|||||||
|
|
||||||
// Check if the time difference is greater than 30 seconds (30000 milliseconds)
|
// Check if the time difference is greater than 30 seconds (30000 milliseconds)
|
||||||
return date2.time - date1.time
|
return date2.time - date1.time
|
||||||
} catch (e: Exception) {
|
} catch (_: Exception) {
|
||||||
// Handle invalid time formats or parsing errors
|
// Handle invalid time formats or parsing errors
|
||||||
return 0
|
return 0
|
||||||
}
|
}
|
||||||
@@ -749,6 +749,49 @@ class AudioContentService(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getLatestCreatorAudioContent(
|
||||||
|
creatorId: Long,
|
||||||
|
member: Member,
|
||||||
|
isAdultContentVisible: Boolean
|
||||||
|
): GetAudioContentListItem? {
|
||||||
|
val isAdult = member.auth != null && isAdultContentVisible
|
||||||
|
|
||||||
|
val audioContent = repository.findLatestContentByCreatorId(creatorId, isAdult) ?: return null
|
||||||
|
|
||||||
|
val commentCount = commentRepository
|
||||||
|
.totalCountCommentByContentId(
|
||||||
|
audioContent.id!!,
|
||||||
|
memberId = member.id!!,
|
||||||
|
isContentCreator = creatorId == member.id!!
|
||||||
|
)
|
||||||
|
|
||||||
|
val likeCount = audioContentLikeRepository
|
||||||
|
.totalCountAudioContentLike(audioContent.id!!)
|
||||||
|
|
||||||
|
val (isExistsAudioContent, orderType) = orderRepository.isExistOrderedAndOrderType(
|
||||||
|
memberId = member.id!!,
|
||||||
|
contentId = audioContent.id!!
|
||||||
|
)
|
||||||
|
|
||||||
|
return GetAudioContentListItem(
|
||||||
|
contentId = audioContent.id!!,
|
||||||
|
coverImageUrl = "$coverImageHost/${audioContent.coverImage}",
|
||||||
|
title = audioContent.title,
|
||||||
|
price = audioContent.price,
|
||||||
|
themeStr = audioContent.theme!!.theme,
|
||||||
|
duration = audioContent.duration,
|
||||||
|
likeCount = likeCount,
|
||||||
|
commentCount = commentCount,
|
||||||
|
isPin = false,
|
||||||
|
isAdult = audioContent.isAdult,
|
||||||
|
isScheduledToOpen = audioContent.releaseDate != null && audioContent.releaseDate!! >= LocalDateTime.now(),
|
||||||
|
isRented = isExistsAudioContent && orderType == OrderType.RENTAL,
|
||||||
|
isOwned = isExistsAudioContent && orderType == OrderType.KEEP,
|
||||||
|
isSoldOut = audioContent.remaining != null && audioContent.remaining!! <= 0,
|
||||||
|
isPointAvailable = audioContent.isPointAvailable
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
fun getAudioContentList(
|
fun getAudioContentList(
|
||||||
creatorId: Long,
|
creatorId: Long,
|
||||||
sortType: SortType,
|
sortType: SortType,
|
||||||
|
@@ -187,6 +187,7 @@ class OrderQueryRepositoryImpl(
|
|||||||
return queryFactory.select(order.id)
|
return queryFactory.select(order.id)
|
||||||
.from(order)
|
.from(order)
|
||||||
.where(where)
|
.where(where)
|
||||||
|
.distinct()
|
||||||
.fetch()
|
.fetch()
|
||||||
.size
|
.size
|
||||||
}
|
}
|
||||||
|
@@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.can.use.QUseCanCalculate.useCanCalculate
|
|||||||
import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus
|
import kr.co.vividnext.sodalive.can.use.UseCanCalculateStatus
|
||||||
import kr.co.vividnext.sodalive.common.SodaException
|
import kr.co.vividnext.sodalive.common.SodaException
|
||||||
import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
|
import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
|
||||||
|
import kr.co.vividnext.sodalive.content.order.QOrder.order
|
||||||
import kr.co.vividnext.sodalive.explorer.QCreatorRanking.creatorRanking
|
import kr.co.vividnext.sodalive.explorer.QCreatorRanking.creatorRanking
|
||||||
import kr.co.vividnext.sodalive.explorer.follower.GetFollowerListDto
|
import kr.co.vividnext.sodalive.explorer.follower.GetFollowerListDto
|
||||||
import kr.co.vividnext.sodalive.explorer.follower.QGetFollowerListDto
|
import kr.co.vividnext.sodalive.explorer.follower.QGetFollowerListDto
|
||||||
@@ -39,6 +40,7 @@ import java.time.LocalDate
|
|||||||
import java.time.LocalDateTime
|
import java.time.LocalDateTime
|
||||||
import java.time.ZoneId
|
import java.time.ZoneId
|
||||||
import java.time.format.DateTimeFormatter
|
import java.time.format.DateTimeFormatter
|
||||||
|
import java.util.Locale
|
||||||
|
|
||||||
@Repository
|
@Repository
|
||||||
class ExplorerQueryRepository(
|
class ExplorerQueryRepository(
|
||||||
@@ -353,7 +355,6 @@ class ExplorerQueryRepository(
|
|||||||
creatorId: Long,
|
creatorId: Long,
|
||||||
userMember: Member,
|
userMember: Member,
|
||||||
timezone: String,
|
timezone: String,
|
||||||
limit: Int,
|
|
||||||
offset: Long = 0
|
offset: Long = 0
|
||||||
): List<LiveRoomResponse> {
|
): List<LiveRoomResponse> {
|
||||||
var where = liveRoom.member.id.eq(creatorId)
|
var where = liveRoom.member.id.eq(creatorId)
|
||||||
@@ -392,6 +393,14 @@ class ExplorerQueryRepository(
|
|||||||
val beginDateTime = it.beginDateTime
|
val beginDateTime = it.beginDateTime
|
||||||
.atZone(ZoneId.of("UTC"))
|
.atZone(ZoneId.of("UTC"))
|
||||||
.withZoneSameInstant(ZoneId.of(timezone))
|
.withZoneSameInstant(ZoneId.of(timezone))
|
||||||
|
.format(
|
||||||
|
DateTimeFormatter
|
||||||
|
.ofPattern("yyyy년 MM월 dd일 (E) a hh시 mm분")
|
||||||
|
.withLocale(Locale.KOREAN)
|
||||||
|
)
|
||||||
|
|
||||||
|
val beginDateTimeUtc = it.beginDateTime
|
||||||
|
.format(DateTimeFormatter.ISO_LOCAL_DATE_TIME)
|
||||||
|
|
||||||
val isPaid = if (it.channelName != null) {
|
val isPaid = if (it.channelName != null) {
|
||||||
val useCan = queryFactory
|
val useCan = queryFactory
|
||||||
@@ -415,9 +424,8 @@ class ExplorerQueryRepository(
|
|||||||
title = it.title,
|
title = it.title,
|
||||||
content = it.notice,
|
content = it.notice,
|
||||||
isPaid = isPaid,
|
isPaid = isPaid,
|
||||||
beginDateTime = beginDateTime.format(
|
beginDateTime = beginDateTime,
|
||||||
DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")
|
beginDateTimeUtc = beginDateTimeUtc,
|
||||||
),
|
|
||||||
isAdult = it.isAdult,
|
isAdult = it.isAdult,
|
||||||
price = it.price,
|
price = it.price,
|
||||||
channelName = it.channelName,
|
channelName = it.channelName,
|
||||||
@@ -653,6 +661,28 @@ class ExplorerQueryRepository(
|
|||||||
.fetchFirst()
|
.fetchFirst()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun getOwnedContentCount(creatorId: Long, memberId: Long): Long {
|
||||||
|
// 활성 주문 + 대여의 경우 유효기간 내 주문만 포함, 동일 콘텐츠 중복 구매는 1개로 카운트
|
||||||
|
return queryFactory
|
||||||
|
.select(audioContent.id)
|
||||||
|
.from(order)
|
||||||
|
.innerJoin(order.audioContent, audioContent)
|
||||||
|
.where(
|
||||||
|
order.isActive.isTrue,
|
||||||
|
order.member.id.eq(memberId),
|
||||||
|
audioContent.member.id.eq(creatorId),
|
||||||
|
order.type.eq(kr.co.vividnext.sodalive.content.order.OrderType.KEEP)
|
||||||
|
.or(
|
||||||
|
order.type.eq(kr.co.vividnext.sodalive.content.order.OrderType.RENTAL)
|
||||||
|
.and(order.endDate.after(LocalDateTime.now()))
|
||||||
|
)
|
||||||
|
)
|
||||||
|
.distinct()
|
||||||
|
.fetch()
|
||||||
|
.size
|
||||||
|
.toLong()
|
||||||
|
}
|
||||||
|
|
||||||
fun getVisibleDonationRank(creatorId: Long): Boolean {
|
fun getVisibleDonationRank(creatorId: Long): Boolean {
|
||||||
return queryFactory
|
return queryFactory
|
||||||
.select(member.isVisibleDonationRank)
|
.select(member.isVisibleDonationRank)
|
||||||
|
@@ -76,7 +76,7 @@ class ExplorerService(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getExplorer(member: Member, growthRankingCreatorsLimit: Long = 20): GetExplorerResponse {
|
fun getExplorer(member: Member): GetExplorerResponse {
|
||||||
val sections = mutableListOf<GetExplorerSectionResponse>()
|
val sections = mutableListOf<GetExplorerSectionResponse>()
|
||||||
|
|
||||||
// 인기 크리에이터
|
// 인기 크리에이터
|
||||||
@@ -209,8 +209,7 @@ class ExplorerService(
|
|||||||
queryRepository.getLiveRoomList(
|
queryRepository.getLiveRoomList(
|
||||||
creatorId,
|
creatorId,
|
||||||
userMember = member,
|
userMember = member,
|
||||||
timezone = timezone,
|
timezone = timezone
|
||||||
limit = 3
|
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
listOf()
|
listOf()
|
||||||
@@ -231,6 +230,27 @@ class ExplorerService(
|
|||||||
listOf()
|
listOf()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 크리에이터의 최신 오디오 콘텐츠 1개
|
||||||
|
val latestContent = if (isCreator) {
|
||||||
|
audioContentService.getLatestCreatorAudioContent(creatorId, member, isAdultContentVisible)
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
// 크리에이터의 전체 콘텐츠 개수
|
||||||
|
val totalContentCount = if (isCreator) {
|
||||||
|
queryRepository.getContentCount(creatorId) ?: 0
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
// 조회하는 유저가 소장 중인 크리에이터의 콘텐츠 개수
|
||||||
|
val ownedContentCount = if (isCreator) {
|
||||||
|
queryRepository.getOwnedContentCount(creatorId, member.id!!)
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
// 공지사항
|
// 공지사항
|
||||||
val notice = if (isCreator) {
|
val notice = if (isCreator) {
|
||||||
queryRepository.getNoticeString(creatorId)
|
queryRepository.getNoticeString(creatorId)
|
||||||
@@ -311,6 +331,9 @@ class ExplorerService(
|
|||||||
similarCreatorList = similarCreatorList,
|
similarCreatorList = similarCreatorList,
|
||||||
liveRoomList = liveRoomList,
|
liveRoomList = liveRoomList,
|
||||||
contentList = contentList,
|
contentList = contentList,
|
||||||
|
latestContent = latestContent,
|
||||||
|
totalContentCount = totalContentCount,
|
||||||
|
ownedContentCount = ownedContentCount,
|
||||||
notice = notice,
|
notice = notice,
|
||||||
communityPostList = communityPostList,
|
communityPostList = communityPostList,
|
||||||
cheers = cheers,
|
cheers = cheers,
|
||||||
|
@@ -10,6 +10,9 @@ data class GetCreatorProfileResponse(
|
|||||||
val similarCreatorList: List<SimilarCreatorResponse>,
|
val similarCreatorList: List<SimilarCreatorResponse>,
|
||||||
val liveRoomList: List<LiveRoomResponse>,
|
val liveRoomList: List<LiveRoomResponse>,
|
||||||
val contentList: List<GetAudioContentListItem>,
|
val contentList: List<GetAudioContentListItem>,
|
||||||
|
val latestContent: GetAudioContentListItem?,
|
||||||
|
val totalContentCount: Long,
|
||||||
|
val ownedContentCount: Long,
|
||||||
val notice: String,
|
val notice: String,
|
||||||
val communityPostList: List<GetCommunityPostListResponse>,
|
val communityPostList: List<GetCommunityPostListResponse>,
|
||||||
val cheers: GetCheersResponse,
|
val cheers: GetCheersResponse,
|
||||||
|
@@ -1,16 +1,12 @@
|
|||||||
package kr.co.vividnext.sodalive.explorer
|
package kr.co.vividnext.sodalive.explorer
|
||||||
|
|
||||||
data class GetLiveRoomAllResponse(
|
|
||||||
val totalCount: Int,
|
|
||||||
val liveRoomList: List<LiveRoomResponse>
|
|
||||||
)
|
|
||||||
|
|
||||||
data class LiveRoomResponse(
|
data class LiveRoomResponse(
|
||||||
val roomId: Long,
|
val roomId: Long,
|
||||||
val title: String,
|
val title: String,
|
||||||
val content: String,
|
val content: String,
|
||||||
val isPaid: Boolean,
|
val isPaid: Boolean,
|
||||||
val beginDateTime: String,
|
val beginDateTime: String,
|
||||||
|
val beginDateTimeUtc: String,
|
||||||
val coverImageUrl: String,
|
val coverImageUrl: String,
|
||||||
val isAdult: Boolean,
|
val isAdult: Boolean,
|
||||||
val price: Int,
|
val price: Int,
|
||||||
|
Reference in New Issue
Block a user