refactor(creator-channel): 홈 repository 커뮤니티 조회 책임을 제거한다

This commit is contained in:
2026-06-21 23:19:52 +09:00
parent 6ab3c50c32
commit 014511668a
3 changed files with 0 additions and 544 deletions

View File

@@ -4,8 +4,6 @@ import com.querydsl.core.types.Projections
import com.querydsl.core.types.dsl.BooleanExpression
import com.querydsl.core.types.dsl.Expressions
import com.querydsl.jpa.impl.JPAQueryFactory
import kr.co.vividnext.sodalive.can.use.CanUsage
import kr.co.vividnext.sodalive.can.use.QUseCan.useCan
import kr.co.vividnext.sodalive.chat.character.QChatCharacter.chatCharacter
import kr.co.vividnext.sodalive.content.ContentType
import kr.co.vividnext.sodalive.content.QAudioContent.audioContent
@@ -15,9 +13,6 @@ import kr.co.vividnext.sodalive.creator.admin.content.series.QSeries.series
import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent
import kr.co.vividnext.sodalive.explorer.profile.QCreatorCheers.creatorCheers
import kr.co.vividnext.sodalive.explorer.profile.channelDonation.QChannelDonationMessage.channelDonationMessage
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommunity.creatorCommunity
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.QCreatorCommunityComment.creatorCommunityComment
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.QCreatorCommunityLike.creatorCommunityLike
import kr.co.vividnext.sodalive.extensions.removeDeletedNicknamePrefix
import kr.co.vividnext.sodalive.live.room.GenderRestriction
import kr.co.vividnext.sodalive.live.room.QLiveRoom.liveRoom
@@ -30,7 +25,6 @@ import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollow
import kr.co.vividnext.sodalive.v2.common.domain.CreatorActivityType
import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelActivityRecord
import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelAudioContentRecord
import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelCommunityPostRecord
import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelCreatorRecord
import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelDonationRecord
import kr.co.vividnext.sodalive.v2.creator.channel.home.port.out.CreatorChannelFanTalkRecord
@@ -207,90 +201,6 @@ class DefaultCreatorChannelHomeQueryRepository(
.fetch()
}
override fun findCommunityPosts(
creatorId: Long,
viewerId: Long?,
isFixed: Boolean,
canViewAdultContent: Boolean,
limit: Int
): List<CreatorChannelCommunityPostRecord> {
val posts = queryFactory
.select(
creatorCommunity.id,
creatorCommunity.member.id,
creatorCommunity.member.nickname,
creatorCommunity.member.profileImage,
creatorCommunity.imagePath,
creatorCommunity.audioPath,
creatorCommunity.content,
creatorCommunity.price,
creatorCommunity.createdAt,
creatorCommunity.fixedAt,
creatorCommunity.isFixed,
creatorCommunity.isCommentAvailable
)
.from(creatorCommunity)
.where(
creatorCommunity.member.id.eq(creatorId),
creatorCommunity.member.isActive.isTrue,
visibleCommunityPostCondition(viewerId),
creatorCommunity.isFixed.eq(isFixed),
fixedNoticeCondition(isFixed),
adultCommunityCondition(canViewAdultContent)
)
.orderBy(
if (isFixed) creatorCommunity.fixedAt.desc() else creatorCommunity.createdAt.desc(),
creatorCommunity.id.desc()
)
.limit(limit.toLong())
.fetch()
val postIds = posts.map { it.get(creatorCommunity.id)!! }
val orderedPostIds = orderedCommunityPostIds(creatorId, viewerId, postIds)
val likeCounts = communityLikeCounts(postIds)
val commentCounts = communityCommentCounts(
postIds = posts.filter { it.get(creatorCommunity.isCommentAvailable)!! }.map { it.get(creatorCommunity.id)!! },
viewerId = viewerId,
isContentCreator = viewerId == creatorId
)
return posts
.map {
val postId = it.get(creatorCommunity.id)!!
val postCreatorId = it.get(creatorCommunity.member.id)!!
val isFixedPost = it.get(creatorCommunity.isFixed)!!
val price = it.get(creatorCommunity.price)!!
val existOrdered = postId in orderedPostIds
val canAccessPaidContent = canAccessPaidCommunityContent(
price = price,
viewerId = viewerId,
creatorId = postCreatorId,
existOrdered = existOrdered
)
CreatorChannelCommunityPostRecord(
postId = postId,
creatorId = postCreatorId,
creatorNickname = it.get(creatorCommunity.member.nickname)!!,
creatorProfilePath = it.get(creatorCommunity.member.profileImage),
imagePath = it.get(creatorCommunity.imagePath),
audioPath = if (canAccessPaidContent) it.get(creatorCommunity.audioPath) else null,
content = maskPaidCommunityContent(
content = it.get(creatorCommunity.content)!!,
canAccessPaidContent = canAccessPaidContent
),
price = price,
date = if (isFixedPost) {
it.get(creatorCommunity.fixedAt) ?: it.get(creatorCommunity.createdAt)!!
} else {
it.get(creatorCommunity.createdAt)!!
},
existOrdered = existOrdered,
likeCount = likeCounts[postId] ?: 0,
commentCount = commentCounts[postId] ?: 0
)
}
}
override fun findSchedules(
creatorId: Long,
now: LocalDateTime,
@@ -639,103 +549,6 @@ class DefaultCreatorChannelHomeQueryRepository(
.fetchFirst()
}
private fun orderedCommunityPostIds(creatorId: Long, viewerId: Long?, postIds: List<Long>): Set<Long> {
if (viewerId == null || postIds.isEmpty()) return emptySet()
if (viewerId == creatorId) return postIds.toSet()
return queryFactory
.select(useCan.communityPost.id)
.from(useCan)
.where(
useCan.member.id.eq(viewerId),
useCan.communityPost.id.`in`(postIds),
useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST),
useCan.isRefund.isFalse
)
.fetch()
.toSet()
}
private fun communityLikeCounts(postIds: List<Long>): Map<Long, Int> {
if (postIds.isEmpty()) return emptyMap()
return queryFactory
.select(creatorCommunityLike.creatorCommunity.id, creatorCommunityLike.id.count())
.from(creatorCommunityLike)
.where(creatorCommunityLike.creatorCommunity.id.`in`(postIds), creatorCommunityLike.isActive.isTrue)
.groupBy(creatorCommunityLike.creatorCommunity.id)
.fetch()
.associate {
it.get(creatorCommunityLike.creatorCommunity.id)!! to
(it.get(creatorCommunityLike.id.count())?.toInt() ?: 0)
}
}
private fun communityCommentCounts(postIds: List<Long>, viewerId: Long?, isContentCreator: Boolean): Map<Long, Int> {
if (postIds.isEmpty()) return emptyMap()
var where = creatorCommunityComment.creatorCommunity.id.`in`(postIds)
.and(creatorCommunityComment.isActive.isTrue)
.and(creatorCommunityComment.parent.isNull)
if (viewerId != null) {
where = where
.and(creatorCommunityComment.member.id.notIn(blockedMemberIdSubQuery(viewerId)))
.and(creatorCommunityComment.member.id.notIn(blockingMemberIdSubQuery(viewerId)))
}
if (!isContentCreator) {
where = where.and(
creatorCommunityComment.isSecret.isFalse.or(
viewerId?.let { creatorCommunityComment.member.id.eq(it) }
?: creatorCommunityComment.isSecret.isFalse
)
)
}
return queryFactory
.select(creatorCommunityComment.creatorCommunity.id, creatorCommunityComment.id.count())
.from(creatorCommunityComment)
.where(where)
.groupBy(creatorCommunityComment.creatorCommunity.id)
.fetch()
.associate {
it.get(creatorCommunityComment.creatorCommunity.id)!! to
(it.get(creatorCommunityComment.id.count())?.toInt() ?: 0)
}
}
private fun blockedMemberIdSubQuery(viewerId: Long) = QBlockMember("communityCommentViewerBlock").let { viewerBlock ->
queryFactory
.select(viewerBlock.blockedMember.id)
.from(viewerBlock)
.where(viewerBlock.member.id.eq(viewerId), viewerBlock.isActive.isTrue)
}
private fun blockingMemberIdSubQuery(viewerId: Long) = QBlockMember("communityCommentWriterBlock").let { writerBlock ->
queryFactory
.select(writerBlock.member.id)
.from(writerBlock)
.where(writerBlock.blockedMember.id.eq(viewerId), writerBlock.isActive.isTrue)
}
private fun canAccessPaidCommunityContent(
price: Int,
viewerId: Long?,
creatorId: Long,
existOrdered: Boolean
): Boolean {
return price <= 0 || viewerId == creatorId || existOrdered
}
private fun maskPaidCommunityContent(content: String, canAccessPaidContent: Boolean): String {
if (canAccessPaidContent) return content
val length = content.codePointCount(0, content.length)
val endIndex = if (length > 15) {
content.offsetByCodePoints(0, 15)
} else {
content.offsetByCodePoints(0, length / 2)
}
return content.substring(0, endIndex).plus("...")
}
private fun firstAudioDebutAt(creatorId: Long, now: LocalDateTime): LocalDateTime? {
val firstThreeUploads = queryFactory
.select(audioContent.releaseDate, audioContent.createdAt)
@@ -793,31 +606,6 @@ class DefaultCreatorChannelHomeQueryRepository(
return liveRoom.isAvailableJoinCreator.isTrue.or(liveRoom.member.id.eq(viewerId))
}
private fun adultCommunityCondition(canViewAdultContent: Boolean): BooleanExpression? {
return if (canViewAdultContent) null else creatorCommunity.isAdult.isFalse
}
private fun fixedNoticeCondition(isFixed: Boolean): BooleanExpression? {
return if (isFixed) creatorCommunity.fixedAt.isNotNull else null
}
private fun visibleCommunityPostCondition(viewerId: Long?): BooleanExpression {
val activePost = creatorCommunity.isActive.isTrue
if (viewerId == null) return activePost
return activePost.or(
queryFactory
.select(useCan.id)
.from(useCan)
.where(
useCan.member.id.eq(viewerId),
useCan.communityPost.id.eq(creatorCommunity.id),
useCan.canUsage.eq(CanUsage.PAID_COMMUNITY_POST),
useCan.isRefund.isFalse
)
.exists()
)
}
private fun adultSeriesCondition(canViewAdultContent: Boolean): BooleanExpression? {
return if (canViewAdultContent) null else series.isAdult.isFalse
}

View File

@@ -34,14 +34,6 @@ interface CreatorChannelHomeQueryPort {
limit: Int = 8
): List<CreatorChannelDonationRecord>
fun findCommunityPosts(
creatorId: Long,
viewerId: Long?,
isFixed: Boolean,
canViewAdultContent: Boolean,
limit: Int = 3
): List<CreatorChannelCommunityPostRecord>
fun findSchedules(
creatorId: Long,
now: LocalDateTime,
@@ -140,21 +132,6 @@ data class CreatorChannelSeriesRecord(
val isOriginal: Boolean
)
data class CreatorChannelCommunityPostRecord(
val postId: Long,
val creatorId: Long,
val creatorNickname: String,
val creatorProfilePath: String?,
val imagePath: String?,
val audioPath: String?,
val content: String,
val price: Int,
val date: LocalDateTime,
val existOrdered: Boolean,
val likeCount: Int,
val commentCount: Int
)
data class CreatorChannelFanTalkSummaryRecord(
val totalCount: Int,
val latestFanTalk: CreatorChannelFanTalkRecord?