Merge pull request 'test' (#208) from test into main

Reviewed-on: #208
This commit is contained in:
klaus 2024-08-30 09:17:41 +00:00
commit 1e4b47f989
11 changed files with 128 additions and 34 deletions

View File

@ -111,6 +111,8 @@ interface AudioContentQueryRepository {
fun getAudioContentCurationList(isAdult: Boolean, offset: Long, limit: Long): List<AudioContentCuration> fun getAudioContentCurationList(isAdult: Boolean, offset: Long, limit: Long): List<AudioContentCuration>
fun getNotReleaseContentId(): List<Long> fun getNotReleaseContentId(): List<Long>
fun isContentCreator(contentId: Long, memberId: Long): Boolean
} }
@Repository @Repository
@ -721,4 +723,19 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory)
.where(where) .where(where)
.fetch() .fetch()
} }
override fun isContentCreator(contentId: Long, memberId: Long): Boolean {
val foundedContentId = queryFactory
.select(audioContent.id)
.from(audioContent)
.innerJoin(audioContent.member, member)
.where(
audioContent.isActive.isTrue
.and(audioContent.id.eq(contentId))
.and(audioContent.member.id.eq(memberId))
)
.fetchOne()
return foundedContentId != null && foundedContentId == contentId
}
} }

View File

@ -492,6 +492,8 @@ class AudioContentService(
commentRepository.findByContentId( commentRepository.findByContentId(
cloudFrontHost = coverImageHost, cloudFrontHost = coverImageHost,
contentId = audioContent.id!!, contentId = audioContent.id!!,
memberId = member.id!!,
isContentCreator = creatorId == member.id!!,
timezone = timezone, timezone = timezone,
offset = 0, offset = 0,
limit = 1 limit = 1
@ -502,7 +504,11 @@ class AudioContentService(
// 댓글 수 // 댓글 수
val commentCount = if (audioContent.isCommentAvailable) { val commentCount = if (audioContent.isCommentAvailable) {
commentRepository.totalCountCommentByContentId(contentId = audioContent.id!!) commentRepository.totalCountCommentByContentId(
contentId = audioContent.id!!,
memberId = member.id!!,
isContentCreator = creatorId == member.id!!
)
} else { } else {
0 0
} }
@ -666,7 +672,11 @@ class AudioContentService(
val items = audioContentList val items = audioContentList
.map { .map {
val commentCount = commentRepository val commentCount = commentRepository
.totalCountCommentByContentId(it.contentId) .totalCountCommentByContentId(
it.contentId,
memberId = member.id!!,
isContentCreator = creatorId == member.id!!
)
it.commentCount = commentCount it.commentCount = commentCount
val likeCount = audioContentLikeRepository val likeCount = audioContentLikeRepository

View File

@ -18,6 +18,7 @@ data class AudioContentComment(
var comment: String, var comment: String,
@Column(nullable = true) @Column(nullable = true)
var donationCan: Int? = null, var donationCan: Int? = null,
val isSecret: Boolean = false,
var isActive: Boolean = true var isActive: Boolean = true
) : BaseEntity() { ) : BaseEntity() {
@ManyToOne(fetch = FetchType.LAZY) @ManyToOne(fetch = FetchType.LAZY)

View File

@ -27,6 +27,7 @@ class AudioContentCommentController(private val service: AudioContentCommentServ
comment = request.comment, comment = request.comment,
audioContentId = request.contentId, audioContentId = request.contentId,
parentId = request.parentId, parentId = request.parentId,
isSecret = request.isSecret,
member = member member = member
) )
) )
@ -54,6 +55,7 @@ class AudioContentCommentController(private val service: AudioContentCommentServ
ApiResponse.ok( ApiResponse.ok(
service.getCommentList( service.getCommentList(
audioContentId = audioContentId, audioContentId = audioContentId,
memberId = member.id!!,
timezone = timezone, timezone = timezone,
pageable = pageable pageable = pageable
) )

View File

@ -16,12 +16,14 @@ interface AudioContentCommentQueryRepository {
fun findByContentId( fun findByContentId(
cloudFrontHost: String, cloudFrontHost: String,
contentId: Long, contentId: Long,
memberId: Long,
isContentCreator: Boolean,
timezone: String, timezone: String,
offset: Long, offset: Long,
limit: Int limit: Int
): List<GetAudioContentCommentListItem> ): List<GetAudioContentCommentListItem>
fun totalCountCommentByContentId(contentId: Long): Int fun totalCountCommentByContentId(contentId: Long, memberId: Long, isContentCreator: Boolean): Int
fun commentReplyCountByAudioContentCommentId(commentId: Long): Int fun commentReplyCountByAudioContentCommentId(commentId: Long): Int
fun getAudioContentCommentReplyList( fun getAudioContentCommentReplyList(
cloudFrontHost: String, cloudFrontHost: String,
@ -45,21 +47,32 @@ class AudioContentCommentQueryRepositoryImpl(
override fun findByContentId( override fun findByContentId(
cloudFrontHost: String, cloudFrontHost: String,
contentId: Long, contentId: Long,
memberId: Long,
isContentCreator: Boolean,
timezone: String, timezone: String,
offset: Long, offset: Long,
limit: Int limit: Int
): List<GetAudioContentCommentListItem> { ): List<GetAudioContentCommentListItem> {
return queryFactory.selectFrom(audioContentComment) var where = audioContentComment.audioContent.id.eq(contentId)
.where( .and(audioContentComment.isActive.isTrue)
audioContentComment.audioContent.id.eq(contentId) .and(audioContentComment.parent.isNull)
.and(audioContentComment.isActive.isTrue)
.and(audioContentComment.parent.isNull) if (!isContentCreator) {
where = where.and(
audioContentComment.isSecret.isFalse
.or(audioContentComment.member.id.eq(memberId))
) )
}
return queryFactory
.selectFrom(audioContentComment)
.innerJoin(audioContentComment.audioContent, audioContent)
.innerJoin(audioContentComment.member, member)
.where(where)
.offset(offset) .offset(offset)
.limit(limit.toLong()) .limit(limit.toLong())
.orderBy(audioContentComment.createdAt.desc()) .orderBy(audioContentComment.createdAt.desc())
.fetch() .fetch()
.asSequence()
.map { .map {
val date = it.createdAt!! val date = it.createdAt!!
.atZone(ZoneId.of("UTC")) .atZone(ZoneId.of("UTC"))
@ -75,22 +88,32 @@ class AudioContentCommentQueryRepositoryImpl(
"$cloudFrontHost/profile/default-profile.png" "$cloudFrontHost/profile/default-profile.png"
}, },
comment = it.comment, comment = it.comment,
isSecret = it.isSecret,
donationCan = it.donationCan ?: 0, donationCan = it.donationCan ?: 0,
date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")),
replyCount = commentReplyCountByAudioContentCommentId(it.id!!) replyCount = commentReplyCountByAudioContentCommentId(it.id!!)
) )
} }
.toList()
} }
override fun totalCountCommentByContentId(contentId: Long): Int { override fun totalCountCommentByContentId(contentId: Long, memberId: Long, isContentCreator: Boolean): Int {
return queryFactory.select(audioContentComment.id) var where = audioContentComment.audioContent.id.eq(contentId)
.from(audioContentComment) .and(audioContentComment.isActive.isTrue)
.where( .and(audioContentComment.parent.isNull)
audioContentComment.audioContent.id.eq(contentId)
.and(audioContentComment.parent.isNull) if (!isContentCreator) {
.and(audioContentComment.isActive.isTrue) where = where.and(
audioContentComment.isSecret.isFalse
.or(audioContentComment.member.id.eq(memberId))
) )
}
return queryFactory
.select(audioContentComment.id)
.from(audioContentComment)
.innerJoin(audioContentComment.audioContent, audioContent)
.innerJoin(audioContentComment.member, member)
.where(where)
.fetch() .fetch()
.size .size
} }
@ -140,6 +163,7 @@ class AudioContentCommentQueryRepositoryImpl(
"$cloudFrontHost/profile/default-profile.png" "$cloudFrontHost/profile/default-profile.png"
}, },
comment = it.comment, comment = it.comment,
isSecret = it.isSecret,
donationCan = it.donationCan ?: 0, donationCan = it.donationCan ?: 0,
date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")),
replyCount = 0 replyCount = 0

View File

@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.content.comment
import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.common.SodaException
import kr.co.vividnext.sodalive.content.AudioContentRepository import kr.co.vividnext.sodalive.content.AudioContentRepository
import kr.co.vividnext.sodalive.content.order.OrderRepository
import kr.co.vividnext.sodalive.fcm.FcmEvent import kr.co.vividnext.sodalive.fcm.FcmEvent
import kr.co.vividnext.sodalive.fcm.FcmEventType import kr.co.vividnext.sodalive.fcm.FcmEventType
import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.Member
@ -20,12 +21,19 @@ class AudioContentCommentService(
private val blockMemberRepository: BlockMemberRepository, private val blockMemberRepository: BlockMemberRepository,
private val audioContentRepository: AudioContentRepository, private val audioContentRepository: AudioContentRepository,
private val applicationEventPublisher: ApplicationEventPublisher, private val applicationEventPublisher: ApplicationEventPublisher,
private val orderRepository: OrderRepository,
@Value("\${cloud.aws.cloud-front.host}") @Value("\${cloud.aws.cloud-front.host}")
private val cloudFrontHost: String private val cloudFrontHost: String
) { ) {
@Transactional @Transactional
fun registerComment(member: Member, comment: String, audioContentId: Long, parentId: Long? = null) { fun registerComment(
member: Member,
comment: String,
audioContentId: Long,
parentId: Long? = null,
isSecret: Boolean = false
) {
val audioContent = audioContentRepository.findByIdOrNull(id = audioContentId) val audioContent = audioContentRepository.findByIdOrNull(id = audioContentId)
?: throw SodaException("잘못된 콘텐츠 입니다.\n다시 시도해 주세요.") ?: throw SodaException("잘못된 콘텐츠 입니다.\n다시 시도해 주세요.")
@ -33,7 +41,16 @@ class AudioContentCommentService(
val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = creator.id!!) val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = creator.id!!)
if (isBlocked) throw SodaException("${creator.nickname}님의 요청으로 댓글쓰기가 제한됩니다.") if (isBlocked) throw SodaException("${creator.nickname}님의 요청으로 댓글쓰기가 제한됩니다.")
val audioContentComment = AudioContentComment(comment = comment) val (isExistsAudioContent, _) = orderRepository.isExistOrderedAndOrderType(
memberId = member.id!!,
contentId = audioContent.id!!
)
if (isSecret && !isExistsAudioContent) {
throw SodaException("콘텐츠 구매 후 비밀댓글을 등록할 수 있습니다.")
}
val audioContentComment = AudioContentComment(comment = comment, isSecret = isSecret)
audioContentComment.audioContent = audioContent audioContentComment.audioContent = audioContent
audioContentComment.member = member audioContentComment.member = member
@ -90,16 +107,27 @@ class AudioContentCommentService(
} }
} }
fun getCommentList(audioContentId: Long, timezone: String, pageable: Pageable): GetAudioContentCommentListResponse { fun getCommentList(
val commentList = audioContentId: Long,
repository.findByContentId( memberId: Long,
cloudFrontHost = cloudFrontHost, timezone: String,
contentId = audioContentId, pageable: Pageable
timezone = timezone, ): GetAudioContentCommentListResponse {
offset = pageable.offset, val isContentCreator = audioContentRepository.isContentCreator(audioContentId, memberId)
limit = pageable.pageSize val commentList = repository.findByContentId(
) cloudFrontHost = cloudFrontHost,
val totalCount = repository.totalCountCommentByContentId(audioContentId) contentId = audioContentId,
memberId = memberId,
isContentCreator = isContentCreator,
timezone = timezone,
offset = pageable.offset,
limit = pageable.pageSize
)
val totalCount = repository.totalCountCommentByContentId(
contentId = audioContentId,
memberId = memberId,
isContentCreator = isContentCreator
)
return GetAudioContentCommentListResponse(totalCount, commentList) return GetAudioContentCommentListResponse(totalCount, commentList)
} }

View File

@ -1,16 +1,19 @@
package kr.co.vividnext.sodalive.content.comment package kr.co.vividnext.sodalive.content.comment
import com.querydsl.core.annotations.QueryProjection
data class GetAudioContentCommentListResponse( data class GetAudioContentCommentListResponse(
val totalCount: Int, val totalCount: Int,
val items: List<GetAudioContentCommentListItem> val items: List<GetAudioContentCommentListItem>
) )
data class GetAudioContentCommentListItem( data class GetAudioContentCommentListItem @QueryProjection constructor(
val id: Long, val id: Long,
val writerId: Long, val writerId: Long,
val nickname: String, val nickname: String,
val profileUrl: String, val profileUrl: String,
val comment: String, val comment: String,
val isSecret: Boolean,
val donationCan: Int, val donationCan: Int,
val date: String, val date: String,
val replyCount: Int val replyCount: Int

View File

@ -1,3 +1,8 @@
package kr.co.vividnext.sodalive.content.comment package kr.co.vividnext.sodalive.content.comment
data class RegisterCommentRequest(val comment: String, val contentId: Long, val parentId: Long?) data class RegisterCommentRequest(
val comment: String,
val contentId: Long,
val parentId: Long?,
val isSecret: Boolean = false
)

View File

@ -10,6 +10,7 @@ data class GetAudioContentOrderListResponse(
data class GetAudioContentOrderListItem @QueryProjection constructor( data class GetAudioContentOrderListItem @QueryProjection constructor(
val contentId: Long, val contentId: Long,
val coverImageUrl: String, val coverImageUrl: String,
val creatorId: Long,
val creatorNickname: String, val creatorNickname: String,
val title: String, val title: String,
val themeStr: String, val themeStr: String,

View File

@ -126,6 +126,7 @@ class OrderQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Orde
QGetAudioContentOrderListItem( QGetAudioContentOrderListItem(
audioContent.id, audioContent.id,
audioContent.coverImage.prepend("/").prepend(coverImageHost), audioContent.coverImage.prepend("/").prepend(coverImageHost),
audioContent.member.id,
audioContent.member.nickname, audioContent.member.nickname,
audioContent.title, audioContent.title,
audioContent.theme.theme, audioContent.theme.theme,

View File

@ -98,10 +98,13 @@ class OrderService(
offset = offset, offset = offset,
limit = limit limit = limit
) )
.asSequence()
.map { .map {
val commentCount = audioContentCommentQueryRepository val commentCount = audioContentCommentQueryRepository
.totalCountCommentByContentId(it.contentId) .totalCountCommentByContentId(
it.contentId,
memberId = member.id!!,
isContentCreator = it.creatorId == member.id!!
)
val likeCount = audioContentLikeQueryRepository val likeCount = audioContentLikeQueryRepository
.totalCountAudioContentLike(it.contentId) .totalCountAudioContentLike(it.contentId)
@ -110,7 +113,6 @@ class OrderService(
it.likeCount = likeCount it.likeCount = likeCount
it it
} }
.toList()
return GetAudioContentOrderListResponse( return GetAudioContentOrderListResponse(
totalCount = totalCount, totalCount = totalCount,