test #208
| @@ -111,6 +111,8 @@ interface AudioContentQueryRepository { | ||||
|     fun getAudioContentCurationList(isAdult: Boolean, offset: Long, limit: Long): List<AudioContentCuration> | ||||
|  | ||||
|     fun getNotReleaseContentId(): List<Long> | ||||
|  | ||||
|     fun isContentCreator(contentId: Long, memberId: Long): Boolean | ||||
| } | ||||
|  | ||||
| @Repository | ||||
| @@ -721,4 +723,19 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) | ||||
|             .where(where) | ||||
|             .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 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -492,6 +492,8 @@ class AudioContentService( | ||||
|             commentRepository.findByContentId( | ||||
|                 cloudFrontHost = coverImageHost, | ||||
|                 contentId = audioContent.id!!, | ||||
|                 memberId = member.id!!, | ||||
|                 isContentCreator = creatorId == member.id!!, | ||||
|                 timezone = timezone, | ||||
|                 offset = 0, | ||||
|                 limit = 1 | ||||
| @@ -502,7 +504,11 @@ class AudioContentService( | ||||
|  | ||||
|         // 댓글 수 | ||||
|         val commentCount = if (audioContent.isCommentAvailable) { | ||||
|             commentRepository.totalCountCommentByContentId(contentId = audioContent.id!!) | ||||
|             commentRepository.totalCountCommentByContentId( | ||||
|                 contentId = audioContent.id!!, | ||||
|                 memberId = member.id!!, | ||||
|                 isContentCreator = creatorId == member.id!! | ||||
|             ) | ||||
|         } else { | ||||
|             0 | ||||
|         } | ||||
| @@ -666,7 +672,11 @@ class AudioContentService( | ||||
|         val items = audioContentList | ||||
|             .map { | ||||
|                 val commentCount = commentRepository | ||||
|                     .totalCountCommentByContentId(it.contentId) | ||||
|                     .totalCountCommentByContentId( | ||||
|                         it.contentId, | ||||
|                         memberId = member.id!!, | ||||
|                         isContentCreator = creatorId == member.id!! | ||||
|                     ) | ||||
|                 it.commentCount = commentCount | ||||
|  | ||||
|                 val likeCount = audioContentLikeRepository | ||||
|   | ||||
| @@ -18,6 +18,7 @@ data class AudioContentComment( | ||||
|     var comment: String, | ||||
|     @Column(nullable = true) | ||||
|     var donationCan: Int? = null, | ||||
|     val isSecret: Boolean = false, | ||||
|     var isActive: Boolean = true | ||||
| ) : BaseEntity() { | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|   | ||||
| @@ -27,6 +27,7 @@ class AudioContentCommentController(private val service: AudioContentCommentServ | ||||
|                 comment = request.comment, | ||||
|                 audioContentId = request.contentId, | ||||
|                 parentId = request.parentId, | ||||
|                 isSecret = request.isSecret, | ||||
|                 member = member | ||||
|             ) | ||||
|         ) | ||||
| @@ -54,6 +55,7 @@ class AudioContentCommentController(private val service: AudioContentCommentServ | ||||
|         ApiResponse.ok( | ||||
|             service.getCommentList( | ||||
|                 audioContentId = audioContentId, | ||||
|                 memberId = member.id!!, | ||||
|                 timezone = timezone, | ||||
|                 pageable = pageable | ||||
|             ) | ||||
|   | ||||
| @@ -16,12 +16,14 @@ interface AudioContentCommentQueryRepository { | ||||
|     fun findByContentId( | ||||
|         cloudFrontHost: String, | ||||
|         contentId: Long, | ||||
|         memberId: Long, | ||||
|         isContentCreator: Boolean, | ||||
|         timezone: String, | ||||
|         offset: Long, | ||||
|         limit: Int | ||||
|     ): List<GetAudioContentCommentListItem> | ||||
|  | ||||
|     fun totalCountCommentByContentId(contentId: Long): Int | ||||
|     fun totalCountCommentByContentId(contentId: Long, memberId: Long, isContentCreator: Boolean): Int | ||||
|     fun commentReplyCountByAudioContentCommentId(commentId: Long): Int | ||||
|     fun getAudioContentCommentReplyList( | ||||
|         cloudFrontHost: String, | ||||
| @@ -45,21 +47,32 @@ class AudioContentCommentQueryRepositoryImpl( | ||||
|     override fun findByContentId( | ||||
|         cloudFrontHost: String, | ||||
|         contentId: Long, | ||||
|         memberId: Long, | ||||
|         isContentCreator: Boolean, | ||||
|         timezone: String, | ||||
|         offset: Long, | ||||
|         limit: Int | ||||
|     ): List<GetAudioContentCommentListItem> { | ||||
|         return queryFactory.selectFrom(audioContentComment) | ||||
|             .where( | ||||
|                 audioContentComment.audioContent.id.eq(contentId) | ||||
|                     .and(audioContentComment.isActive.isTrue) | ||||
|                     .and(audioContentComment.parent.isNull) | ||||
|         var where = audioContentComment.audioContent.id.eq(contentId) | ||||
|             .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) | ||||
|             .limit(limit.toLong()) | ||||
|             .orderBy(audioContentComment.createdAt.desc()) | ||||
|             .fetch() | ||||
|             .asSequence() | ||||
|             .map { | ||||
|                 val date = it.createdAt!! | ||||
|                     .atZone(ZoneId.of("UTC")) | ||||
| @@ -75,22 +88,32 @@ class AudioContentCommentQueryRepositoryImpl( | ||||
|                         "$cloudFrontHost/profile/default-profile.png" | ||||
|                     }, | ||||
|                     comment = it.comment, | ||||
|                     isSecret = it.isSecret, | ||||
|                     donationCan = it.donationCan ?: 0, | ||||
|                     date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), | ||||
|                     replyCount = commentReplyCountByAudioContentCommentId(it.id!!) | ||||
|                 ) | ||||
|             } | ||||
|             .toList() | ||||
|     } | ||||
|  | ||||
|     override fun totalCountCommentByContentId(contentId: Long): Int { | ||||
|         return queryFactory.select(audioContentComment.id) | ||||
|             .from(audioContentComment) | ||||
|             .where( | ||||
|                 audioContentComment.audioContent.id.eq(contentId) | ||||
|                     .and(audioContentComment.parent.isNull) | ||||
|                     .and(audioContentComment.isActive.isTrue) | ||||
|     override fun totalCountCommentByContentId(contentId: Long, memberId: Long, isContentCreator: Boolean): Int { | ||||
|         var where = audioContentComment.audioContent.id.eq(contentId) | ||||
|             .and(audioContentComment.isActive.isTrue) | ||||
|             .and(audioContentComment.parent.isNull) | ||||
|  | ||||
|         if (!isContentCreator) { | ||||
|             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() | ||||
|             .size | ||||
|     } | ||||
| @@ -140,6 +163,7 @@ class AudioContentCommentQueryRepositoryImpl( | ||||
|                         "$cloudFrontHost/profile/default-profile.png" | ||||
|                     }, | ||||
|                     comment = it.comment, | ||||
|                     isSecret = it.isSecret, | ||||
|                     donationCan = it.donationCan ?: 0, | ||||
|                     date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), | ||||
|                     replyCount = 0 | ||||
|   | ||||
| @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.content.comment | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| 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.FcmEventType | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| @@ -20,12 +21,19 @@ class AudioContentCommentService( | ||||
|     private val blockMemberRepository: BlockMemberRepository, | ||||
|     private val audioContentRepository: AudioContentRepository, | ||||
|     private val applicationEventPublisher: ApplicationEventPublisher, | ||||
|     private val orderRepository: OrderRepository, | ||||
|  | ||||
|     @Value("\${cloud.aws.cloud-front.host}") | ||||
|     private val cloudFrontHost: String | ||||
| ) { | ||||
|     @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) | ||||
|             ?: throw SodaException("잘못된 콘텐츠 입니다.\n다시 시도해 주세요.") | ||||
|  | ||||
| @@ -33,7 +41,16 @@ class AudioContentCommentService( | ||||
|         val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = creator.id!!) | ||||
|         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.member = member | ||||
|  | ||||
| @@ -90,16 +107,27 @@ class AudioContentCommentService( | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun getCommentList(audioContentId: Long, timezone: String, pageable: Pageable): GetAudioContentCommentListResponse { | ||||
|         val commentList = | ||||
|             repository.findByContentId( | ||||
|                 cloudFrontHost = cloudFrontHost, | ||||
|                 contentId = audioContentId, | ||||
|                 timezone = timezone, | ||||
|                 offset = pageable.offset, | ||||
|                 limit = pageable.pageSize | ||||
|             ) | ||||
|         val totalCount = repository.totalCountCommentByContentId(audioContentId) | ||||
|     fun getCommentList( | ||||
|         audioContentId: Long, | ||||
|         memberId: Long, | ||||
|         timezone: String, | ||||
|         pageable: Pageable | ||||
|     ): GetAudioContentCommentListResponse { | ||||
|         val isContentCreator = audioContentRepository.isContentCreator(audioContentId, memberId) | ||||
|         val commentList = repository.findByContentId( | ||||
|             cloudFrontHost = cloudFrontHost, | ||||
|             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) | ||||
|     } | ||||
|   | ||||
| @@ -1,16 +1,19 @@ | ||||
| package kr.co.vividnext.sodalive.content.comment | ||||
|  | ||||
| import com.querydsl.core.annotations.QueryProjection | ||||
|  | ||||
| data class GetAudioContentCommentListResponse( | ||||
|     val totalCount: Int, | ||||
|     val items: List<GetAudioContentCommentListItem> | ||||
| ) | ||||
|  | ||||
| data class GetAudioContentCommentListItem( | ||||
| data class GetAudioContentCommentListItem @QueryProjection constructor( | ||||
|     val id: Long, | ||||
|     val writerId: Long, | ||||
|     val nickname: String, | ||||
|     val profileUrl: String, | ||||
|     val comment: String, | ||||
|     val isSecret: Boolean, | ||||
|     val donationCan: Int, | ||||
|     val date: String, | ||||
|     val replyCount: Int | ||||
|   | ||||
| @@ -1,3 +1,8 @@ | ||||
| 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 | ||||
| ) | ||||
|   | ||||
| @@ -10,6 +10,7 @@ data class GetAudioContentOrderListResponse( | ||||
| data class GetAudioContentOrderListItem @QueryProjection constructor( | ||||
|     val contentId: Long, | ||||
|     val coverImageUrl: String, | ||||
|     val creatorId: Long, | ||||
|     val creatorNickname: String, | ||||
|     val title: String, | ||||
|     val themeStr: String, | ||||
|   | ||||
| @@ -126,6 +126,7 @@ class OrderQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Orde | ||||
|                 QGetAudioContentOrderListItem( | ||||
|                     audioContent.id, | ||||
|                     audioContent.coverImage.prepend("/").prepend(coverImageHost), | ||||
|                     audioContent.member.id, | ||||
|                     audioContent.member.nickname, | ||||
|                     audioContent.title, | ||||
|                     audioContent.theme.theme, | ||||
|   | ||||
| @@ -98,10 +98,13 @@ class OrderService( | ||||
|             offset = offset, | ||||
|             limit = limit | ||||
|         ) | ||||
|             .asSequence() | ||||
|             .map { | ||||
|                 val commentCount = audioContentCommentQueryRepository | ||||
|                     .totalCountCommentByContentId(it.contentId) | ||||
|                     .totalCountCommentByContentId( | ||||
|                         it.contentId, | ||||
|                         memberId = member.id!!, | ||||
|                         isContentCreator = it.creatorId == member.id!! | ||||
|                     ) | ||||
|  | ||||
|                 val likeCount = audioContentLikeQueryRepository | ||||
|                     .totalCountAudioContentLike(it.contentId) | ||||
| @@ -110,7 +113,6 @@ class OrderService( | ||||
|                 it.likeCount = likeCount | ||||
|                 it | ||||
|             } | ||||
|             .toList() | ||||
|  | ||||
|         return GetAudioContentOrderListResponse( | ||||
|             totalCount = totalCount, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user