커뮤니티 게시글 유료화 #182
| @@ -86,7 +86,7 @@ class AdminContentService( | ||||
|             ?: throw SodaException("없는 콘텐츠 입니다.") | ||||
|  | ||||
|         if (request.isDefaultCoverImage) { | ||||
|             audioContent.coverImage = "profile/default_profile.png" | ||||
|             audioContent.coverImage = "`profile/default_profile.png`" | ||||
|         } | ||||
|  | ||||
|         if (request.isActive != null) { | ||||
|   | ||||
| @@ -68,7 +68,8 @@ class CanService(private val repository: CanRepository) { | ||||
|                     } | ||||
|  | ||||
|                     CanUsage.CHANGE_NICKNAME -> "닉네임 변경" | ||||
|                     CanUsage.ORDER_CONTENT -> "콘텐츠 구매" | ||||
|                     CanUsage.ORDER_CONTENT -> "[콘텐츠 구매] ${it.audioContent!!.title}" | ||||
|                     CanUsage.PAID_COMMUNITY_POST -> "[게시글 보기] ${it.communityPost?.member?.nickname ?: ""}" | ||||
|                 } | ||||
|  | ||||
|                 val createdAt = it.createdAt!! | ||||
|   | ||||
| @@ -15,6 +15,7 @@ import kr.co.vividnext.sodalive.can.use.UseCanRepository | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.content.AudioContent | ||||
| import kr.co.vividnext.sodalive.content.order.Order | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity | ||||
| import kr.co.vividnext.sodalive.live.room.LiveRoom | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import kr.co.vividnext.sodalive.member.MemberRepository | ||||
| @@ -38,6 +39,7 @@ class CanPaymentService( | ||||
|         liveRoom: LiveRoom? = null, | ||||
|         order: Order? = null, | ||||
|         audioContent: AudioContent? = null, | ||||
|         communityPost: CreatorCommunity? = null, | ||||
|         container: String | ||||
|     ) { | ||||
|         val member = memberRepository.findByIdOrNull(id = memberId) | ||||
| @@ -90,6 +92,10 @@ class CanPaymentService( | ||||
|             recipientId = liveRoom.member!!.id!! | ||||
|             useCan.room = liveRoom | ||||
|             useCan.member = member | ||||
|         } else if (canUsage == CanUsage.PAID_COMMUNITY_POST && communityPost != null) { | ||||
|             recipientId = communityPost.member!!.id!! | ||||
|             useCan.communityPost = communityPost | ||||
|             useCan.member = member | ||||
|         } else { | ||||
|             throw SodaException("잘못된 요청입니다.") | ||||
|         } | ||||
|   | ||||
| @@ -5,5 +5,6 @@ enum class CanUsage { | ||||
|     DONATION, | ||||
|     CHANGE_NICKNAME, | ||||
|     ORDER_CONTENT, | ||||
|     SPIN_ROULETTE | ||||
|     SPIN_ROULETTE, | ||||
|     PAID_COMMUNITY_POST | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.can.use | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import kr.co.vividnext.sodalive.content.AudioContent | ||||
| import kr.co.vividnext.sodalive.content.order.Order | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity | ||||
| import kr.co.vividnext.sodalive.live.room.LiveRoom | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import javax.persistence.CascadeType | ||||
| @@ -42,10 +43,14 @@ data class UseCan( | ||||
|     @JoinColumn(name = "order_id", nullable = true) | ||||
|     var order: Order? = null | ||||
|  | ||||
|     @OneToOne(fetch = FetchType.LAZY) | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "content_id", nullable = true) | ||||
|     var audioContent: AudioContent? = null | ||||
|  | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "creator_community_id", nullable = true) | ||||
|     var communityPost: CreatorCommunity? = null | ||||
|  | ||||
|     @OneToMany(mappedBy = "useCan", cascade = [CascadeType.ALL]) | ||||
|     val useCanCalculates: MutableList<UseCanCalculate> = mutableListOf() | ||||
| } | ||||
|   | ||||
| @@ -1,7 +1,28 @@ | ||||
| package kr.co.vividnext.sodalive.can.use | ||||
|  | ||||
| import com.querydsl.jpa.impl.JPAQueryFactory | ||||
| import kr.co.vividnext.sodalive.can.use.QUseCan.useCan | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
| import org.springframework.stereotype.Repository | ||||
|  | ||||
| @Repository | ||||
| interface UseCanRepository : JpaRepository<UseCan, Long> | ||||
| interface UseCanRepository : JpaRepository<UseCan, Long>, UseCanQueryRepository | ||||
|  | ||||
| interface UseCanQueryRepository { | ||||
|     fun isExistOrdered(postId: Long, memberId: Long): Boolean | ||||
| } | ||||
|  | ||||
| class UseCanQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : UseCanQueryRepository { | ||||
|     override fun isExistOrdered(postId: Long, memberId: Long): Boolean { | ||||
|         val useCanId = queryFactory.select(useCan.id) | ||||
|             .from(useCan) | ||||
|             .where( | ||||
|                 useCan.member.id.eq(memberId) | ||||
|                     .and(useCan.isRefund.isFalse) | ||||
|                     .and(useCan.communityPost.id.eq(postId)) | ||||
|             ) | ||||
|             .fetchFirst() | ||||
|  | ||||
|         return useCanId != null && useCanId > 0 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,5 +3,6 @@ package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity | ||||
| data class CreateCommunityPostRequest( | ||||
|     val content: String, | ||||
|     val isCommentAvailable: Boolean, | ||||
|     val isAdult: Boolean | ||||
|     val isAdult: Boolean, | ||||
|     val price: Int = 0 | ||||
| ) | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListItem | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import javax.persistence.Column | ||||
| import javax.persistence.Entity | ||||
| @@ -12,6 +13,7 @@ import javax.persistence.ManyToOne | ||||
| data class CreatorCommunity( | ||||
|     @Column(columnDefinition = "TEXT", nullable = false) | ||||
|     var content: String, | ||||
|     var price: Int, | ||||
|     var isCommentAvailable: Boolean, | ||||
|     var isAdult: Boolean, | ||||
|     @Column(nullable = true) | ||||
| @@ -21,4 +23,37 @@ data class CreatorCommunity( | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "member_id", nullable = false) | ||||
|     var member: Member? = null | ||||
|  | ||||
|     fun toCommunityPostListResponse( | ||||
|         imageHost: String, | ||||
|         content: String, | ||||
|         date: String, | ||||
|         isLike: Boolean, | ||||
|         existOrdered: Boolean, | ||||
|         likeCount: Int, | ||||
|         commentCount: Int, | ||||
|         firstComment: GetCommunityPostCommentListItem? | ||||
|     ): GetCommunityPostListResponse { | ||||
|         return GetCommunityPostListResponse( | ||||
|             postId = id!!, | ||||
|             creatorId = member!!.id!!, | ||||
|             creatorNickname = member!!.nickname, | ||||
|             creatorProfileUrl = "$imageHost/${member?.profileImage ?: "profile/default-profile.png"}", | ||||
|             imageUrl = if (imagePath != null) { | ||||
|                 "$imageHost/$imagePath" | ||||
|             } else { | ||||
|                 null | ||||
|             }, | ||||
|             content = content, | ||||
|             price = price, | ||||
|             date = date, | ||||
|             isCommentAvailable = isCommentAvailable, | ||||
|             isAdult = false, | ||||
|             isLike = isLike, | ||||
|             existOrdered = existOrdered, | ||||
|             likeCount = likeCount, | ||||
|             commentCount = commentCount, | ||||
|             firstComment = firstComment | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -195,4 +195,22 @@ class CreatorCommunityController(private val service: CreatorCommunityService) { | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     @PostMapping("/purchase") | ||||
|     fun purchasePost( | ||||
|         @RequestBody request: PurchasePostRequest, | ||||
|         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||
|     ) = run { | ||||
|         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||
|  | ||||
|         ApiResponse.ok( | ||||
|             service.purchasePost( | ||||
|                 postId = request.postId, | ||||
|                 memberId = member.id!!, | ||||
|                 timezone = request.timezone, | ||||
|                 isAdult = member.auth != null, | ||||
|                 container = request.container | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -20,10 +20,12 @@ interface CreatorCommunityQueryRepository { | ||||
|         offset: Long, | ||||
|         limit: Long, | ||||
|         isAdult: Boolean | ||||
|     ): List<CreatorCommunity> | ||||
|     ): List<SelectCommunityPostResponse> | ||||
|  | ||||
|     fun findByIdAndActive(postId: Long, isAdult: Boolean): CreatorCommunity? | ||||
|     fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List<CreatorCommunity> | ||||
|     fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List<SelectCommunityPostResponse> | ||||
|  | ||||
|     fun getCommunityPost(postId: Long, isAdult: Boolean): SelectCommunityPostResponse? | ||||
| } | ||||
|  | ||||
| class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CreatorCommunityQueryRepository { | ||||
| @@ -42,7 +44,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact | ||||
|         offset: Long, | ||||
|         limit: Long, | ||||
|         isAdult: Boolean | ||||
|     ): List<CreatorCommunity> { | ||||
|     ): List<SelectCommunityPostResponse> { | ||||
|         var where = creatorCommunity.member.id.eq(creatorId) | ||||
|             .and(creatorCommunity.isActive.isTrue) | ||||
|  | ||||
| @@ -51,7 +53,20 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact | ||||
|         } | ||||
|  | ||||
|         return queryFactory | ||||
|             .selectFrom(creatorCommunity) | ||||
|             .select( | ||||
|                 QSelectCommunityPostResponse( | ||||
|                     creatorCommunity.id, | ||||
|                     creatorCommunity.member.id, | ||||
|                     creatorCommunity.member.nickname, | ||||
|                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), | ||||
|                     creatorCommunity.imagePath, | ||||
|                     creatorCommunity.content, | ||||
|                     creatorCommunity.createdAt, | ||||
|                     creatorCommunity.isCommentAvailable, | ||||
|                     creatorCommunity.price | ||||
|                 ) | ||||
|             ) | ||||
|             .from(creatorCommunity) | ||||
|             .innerJoin(creatorCommunity.member, member) | ||||
|             .where(where) | ||||
|             .offset(offset) | ||||
| @@ -74,7 +89,10 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact | ||||
|             .fetchFirst() | ||||
|     } | ||||
|  | ||||
|     override fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List<CreatorCommunity> { | ||||
|     override fun getLatestPostListFromCreatorsYouFollow( | ||||
|         memberId: Long, | ||||
|         isAdult: Boolean | ||||
|     ): List<SelectCommunityPostResponse> { | ||||
|         val creatorCommunity = QCreatorCommunity.creatorCommunity | ||||
|         val latest = QCreatorCommunity.creatorCommunity | ||||
|  | ||||
| @@ -110,10 +128,51 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact | ||||
|         ) | ||||
|  | ||||
|         return queryFactory | ||||
|             .selectFrom(creatorCommunity) | ||||
|             .select( | ||||
|                 QSelectCommunityPostResponse( | ||||
|                     creatorCommunity.id, | ||||
|                     creatorCommunity.member.id, | ||||
|                     creatorCommunity.member.nickname, | ||||
|                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), | ||||
|                     creatorCommunity.imagePath, | ||||
|                     creatorCommunity.content, | ||||
|                     creatorCommunity.createdAt, | ||||
|                     creatorCommunity.isCommentAvailable, | ||||
|                     creatorCommunity.price | ||||
|                 ) | ||||
|             ) | ||||
|             .from(creatorCommunity) | ||||
|             .innerJoin(creatorCommunity.member, member) | ||||
|             .where(where) | ||||
|             .orderBy(creatorCommunity.createdAt.desc()) | ||||
|             .limit(10) | ||||
|             .fetch() | ||||
|     } | ||||
|  | ||||
|     override fun getCommunityPost(postId: Long, isAdult: Boolean): SelectCommunityPostResponse? { | ||||
|         var where = creatorCommunity.id.eq(postId) | ||||
|             .and(creatorCommunity.isActive.isTrue) | ||||
|  | ||||
|         if (!isAdult) { | ||||
|             where = where.and(creatorCommunity.isAdult.isFalse) | ||||
|         } | ||||
|  | ||||
|         return queryFactory | ||||
|             .select( | ||||
|                 QSelectCommunityPostResponse( | ||||
|                     creatorCommunity.id, | ||||
|                     creatorCommunity.member.id, | ||||
|                     creatorCommunity.member.nickname, | ||||
|                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), | ||||
|                     creatorCommunity.imagePath, | ||||
|                     creatorCommunity.content, | ||||
|                     creatorCommunity.createdAt, | ||||
|                     creatorCommunity.isCommentAvailable, | ||||
|                     creatorCommunity.price | ||||
|                 ) | ||||
|             ) | ||||
|             .from(creatorCommunity) | ||||
|             .where(where) | ||||
|             .fetchFirst() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -3,6 +3,9 @@ package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity | ||||
| import com.amazonaws.services.s3.model.ObjectMetadata | ||||
| import com.fasterxml.jackson.databind.ObjectMapper | ||||
| import kr.co.vividnext.sodalive.aws.s3.S3Uploader | ||||
| import kr.co.vividnext.sodalive.can.payment.CanPaymentService | ||||
| import kr.co.vividnext.sodalive.can.use.CanUsage | ||||
| import kr.co.vividnext.sodalive.can.use.UseCanRepository | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityComment | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityCommentRepository | ||||
| @@ -28,10 +31,13 @@ import java.time.LocalDateTime | ||||
|  | ||||
| @Service | ||||
| class CreatorCommunityService( | ||||
|     private val canPaymentService: CanPaymentService, | ||||
|  | ||||
|     private val repository: CreatorCommunityRepository, | ||||
|     private val blockMemberRepository: BlockMemberRepository, | ||||
|     private val likeRepository: CreatorCommunityLikeRepository, | ||||
|     private val commentRepository: CreatorCommunityCommentRepository, | ||||
|     private val useCanRepository: UseCanRepository, | ||||
|  | ||||
|     private val s3Uploader: S3Uploader, | ||||
|     private val objectMapper: ObjectMapper, | ||||
| @@ -47,8 +53,13 @@ class CreatorCommunityService( | ||||
|     fun createCommunityPost(postImage: MultipartFile?, requestString: String, member: Member) { | ||||
|         val request = objectMapper.readValue(requestString, CreateCommunityPostRequest::class.java) | ||||
|  | ||||
|         if (request.price > 0 && postImage == null) { | ||||
|             throw SodaException("유료 게시글 등록을 위해서는 이미지가 필요합니다.") | ||||
|         } | ||||
|  | ||||
|         val post = CreatorCommunity( | ||||
|             content = request.content, | ||||
|             price = request.price, | ||||
|             isCommentAvailable = request.isCommentAvailable, | ||||
|             isAdult = request.isAdult | ||||
|         ) | ||||
| @@ -133,6 +144,10 @@ class CreatorCommunityService( | ||||
|         limit: Long, | ||||
|         isAdult: Boolean | ||||
|     ): List<GetCommunityPostListResponse> { | ||||
|         if (blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = creatorId)) { | ||||
|             return listOf() | ||||
|         } | ||||
|  | ||||
|         val postList = repository.getCommunityPostList( | ||||
|             creatorId = creatorId, | ||||
|             offset = offset, | ||||
| @@ -141,19 +156,12 @@ class CreatorCommunityService( | ||||
|         ) | ||||
|  | ||||
|         return postList | ||||
|             .asSequence() | ||||
|             .filter { | ||||
|                 !blockMemberRepository.isBlocked( | ||||
|                     blockedMemberId = memberId, | ||||
|                     memberId = creatorId | ||||
|                 ) | ||||
|             } | ||||
|             .map { | ||||
|                 val isLike = | ||||
|                     likeRepository.findByPostIdAndMemberId(postId = it.id!!, memberId = memberId)?.isActive ?: false | ||||
|                 val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(it.id!!) | ||||
|                 val isLike = likeRepository.findByPostIdAndMemberId(postId = it.id, memberId = memberId)?.isActive | ||||
|                     ?: false | ||||
|                 val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(it.id) | ||||
|                 val commentCount = if (it.isCommentAvailable) { | ||||
|                     commentRepository.totalCountCommentByPostId(postId = it.id!!) | ||||
|                     commentRepository.totalCountCommentByPostId(postId = it.id) | ||||
|                 } else { | ||||
|                     0 | ||||
|                 } | ||||
| @@ -161,7 +169,7 @@ class CreatorCommunityService( | ||||
|                     commentRepository.findByPostId( | ||||
|                         cloudFrontHost = imageHost, | ||||
|                         timezone = timezone, | ||||
|                         id = it.id!!, | ||||
|                         id = it.id, | ||||
|                         offset = 0, | ||||
|                         limit = 1 | ||||
|                     ) | ||||
| @@ -175,31 +183,33 @@ class CreatorCommunityService( | ||||
|                     null | ||||
|                 } | ||||
|  | ||||
|                 GetCommunityPostListResponse( | ||||
|                     postId = it.id!!, | ||||
|                     creatorId = it.member!!.id!!, | ||||
|                     creatorNickname = it.member!!.nickname, | ||||
|                     creatorProfileUrl = if (it.member!!.profileImage != null) { | ||||
|                         "$imageHost/${it.member!!.profileImage}" | ||||
|                 val existOrdered = useCanRepository.isExistOrdered(postId = it.id, memberId = memberId) | ||||
|  | ||||
|                 val content = if (it.price > 0 && memberId != it.creatorId) { | ||||
|                     if (existOrdered) { | ||||
|                         it.content | ||||
|                     } else { | ||||
|                         "$imageHost/profile/default-profile.png" | ||||
|                     }, | ||||
|                     imageUrl = if (it.imagePath != null) { | ||||
|                         "$imageHost/${it.imagePath!!}" | ||||
|                     } else { | ||||
|                         null | ||||
|                     }, | ||||
|                     content = it.content, | ||||
|                     date = getTimeAgoString(it.createdAt!!), | ||||
|                     isCommentAvailable = it.isCommentAvailable, | ||||
|                     isAdult = it.isAdult, | ||||
|                         it.content.substring(0, 5).plus("...") | ||||
|                     } | ||||
|                 } else { | ||||
|                     it.content | ||||
|                 } | ||||
|  | ||||
|                 it.toCommunityPostListResponse( | ||||
|                     imageHost = imageHost, | ||||
|                     content = content, | ||||
|                     date = getTimeAgoString(it.date), | ||||
|                     isLike = isLike, | ||||
|                     existOrdered = if (memberId == it.creatorId) { | ||||
|                         true | ||||
|                     } else { | ||||
|                         existOrdered | ||||
|                     }, | ||||
|                     likeCount = likeCount, | ||||
|                     commentCount = commentCount, | ||||
|                     firstComment = firstComment | ||||
|                 ) | ||||
|             } | ||||
|             .toList() | ||||
|     } | ||||
|  | ||||
|     fun getCommunityPostDetail( | ||||
| @@ -208,16 +218,16 @@ class CreatorCommunityService( | ||||
|         timezone: String, | ||||
|         isAdult: Boolean | ||||
|     ): GetCommunityPostListResponse { | ||||
|         val post = repository.findByIdAndActive(postId, isAdult = isAdult) | ||||
|         val post = repository.getCommunityPost(postId, isAdult = isAdult) | ||||
|             ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.") | ||||
|  | ||||
|         val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = post.member!!.id!!) | ||||
|         if (isBlocked) throw SodaException("${post.member!!.nickname}님의 요청으로 접근이 제한됩니다.") | ||||
|         val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = post.creatorId) | ||||
|         if (isBlocked) throw SodaException("${post.creatorNickname}님의 요청으로 접근이 제한됩니다.") | ||||
|  | ||||
|         val isLike = likeRepository.findByPostIdAndMemberId(postId = post.id!!, memberId = memberId)?.isActive ?: false | ||||
|         val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(post.id!!) | ||||
|         val isLike = likeRepository.findByPostIdAndMemberId(postId = post.id, memberId = memberId)?.isActive ?: false | ||||
|         val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(post.id) | ||||
|         val commentCount = if (post.isCommentAvailable) { | ||||
|             commentRepository.totalCountCommentByPostId(postId = post.id!!) | ||||
|             commentRepository.totalCountCommentByPostId(postId = post.id) | ||||
|         } else { | ||||
|             0 | ||||
|         } | ||||
| @@ -225,7 +235,7 @@ class CreatorCommunityService( | ||||
|             commentRepository.findByPostId( | ||||
|                 cloudFrontHost = imageHost, | ||||
|                 timezone = timezone, | ||||
|                 id = post.id!!, | ||||
|                 id = post.id, | ||||
|                 offset = 0, | ||||
|                 limit = 1 | ||||
|             ) | ||||
| @@ -239,25 +249,28 @@ class CreatorCommunityService( | ||||
|             null | ||||
|         } | ||||
|  | ||||
|         return GetCommunityPostListResponse( | ||||
|             postId = post.id!!, | ||||
|             creatorId = post.member!!.id!!, | ||||
|             creatorNickname = post.member!!.nickname, | ||||
|             creatorProfileUrl = if (post.member!!.profileImage != null) { | ||||
|                 "$imageHost/${post.member!!.profileImage}" | ||||
|         val existOrdered = useCanRepository.isExistOrdered(postId = post.id, memberId = memberId) | ||||
|  | ||||
|         val content = if (post.price > 0 && memberId != post.creatorId) { | ||||
|             if (existOrdered) { | ||||
|                 post.content | ||||
|             } else { | ||||
|                 "$imageHost/profile/default-profile.png" | ||||
|             }, | ||||
|             imageUrl = if (post.imagePath != null) { | ||||
|                 "$imageHost/${post.imagePath!!}" | ||||
|             } else { | ||||
|                 null | ||||
|             }, | ||||
|             content = post.content, | ||||
|             date = getTimeAgoString(post.createdAt!!), | ||||
|             isCommentAvailable = post.isCommentAvailable, | ||||
|             isAdult = post.isAdult, | ||||
|                 post.content.substring(0, 5).plus("...") | ||||
|             } | ||||
|         } else { | ||||
|             post.content | ||||
|         } | ||||
|  | ||||
|         return post.toCommunityPostListResponse( | ||||
|             imageHost = imageHost, | ||||
|             content = content, | ||||
|             date = getTimeAgoString(post.date), | ||||
|             isLike = isLike, | ||||
|             existOrdered = if (memberId == post.creatorId) { | ||||
|                 true | ||||
|             } else { | ||||
|                 existOrdered | ||||
|             }, | ||||
|             likeCount = likeCount, | ||||
|             commentCount = commentCount, | ||||
|             firstComment = firstComment | ||||
| @@ -383,11 +396,10 @@ class CreatorCommunityService( | ||||
|         val postList = repository.getLatestPostListFromCreatorsYouFollow(memberId = memberId, isAdult = isAdult) | ||||
|  | ||||
|         return postList | ||||
|             .asSequence() | ||||
|             .filter { | ||||
|                 !blockMemberRepository.isBlocked( | ||||
|                     blockedMemberId = memberId, | ||||
|                     memberId = it.member!!.id!! | ||||
|                     memberId = it.creatorId | ||||
|                 ) | ||||
|             } | ||||
|             .map { | ||||
| @@ -403,7 +415,7 @@ class CreatorCommunityService( | ||||
|                     commentRepository.findByPostId( | ||||
|                         cloudFrontHost = imageHost, | ||||
|                         timezone = timezone, | ||||
|                         id = it.id!!, | ||||
|                         id = it.id, | ||||
|                         offset = 0, | ||||
|                         limit = 1 | ||||
|                     ) | ||||
| @@ -417,30 +429,95 @@ class CreatorCommunityService( | ||||
|                     null | ||||
|                 } | ||||
|  | ||||
|                 GetCommunityPostListResponse( | ||||
|                     postId = it.id!!, | ||||
|                     creatorId = it.member!!.id!!, | ||||
|                     creatorNickname = it.member!!.nickname, | ||||
|                     creatorProfileUrl = if (it.member!!.profileImage != null) { | ||||
|                         "$imageHost/${it.member!!.profileImage}" | ||||
|                 val existOrdered = useCanRepository.isExistOrdered(postId = it.id, memberId = memberId) | ||||
|  | ||||
|                 val content = if (it.price > 0 && memberId != it.creatorId) { | ||||
|                     if (existOrdered) { | ||||
|                         it.content | ||||
|                     } else { | ||||
|                         "$imageHost/profile/default-profile.png" | ||||
|                     }, | ||||
|                     imageUrl = if (it.imagePath != null) { | ||||
|                         "$imageHost/${it.imagePath!!}" | ||||
|                     } else { | ||||
|                         null | ||||
|                     }, | ||||
|                     content = it.content, | ||||
|                     date = getTimeAgoString(it.createdAt!!), | ||||
|                     isCommentAvailable = it.isCommentAvailable, | ||||
|                     isAdult = it.isAdult, | ||||
|                         it.content.substring(0, 5).plus("...") | ||||
|                     } | ||||
|                 } else { | ||||
|                     it.content | ||||
|                 } | ||||
|  | ||||
|                 it.toCommunityPostListResponse( | ||||
|                     imageHost = imageHost, | ||||
|                     content = content, | ||||
|                     date = getTimeAgoString(it.date), | ||||
|                     isLike = isLike, | ||||
|                     existOrdered = if (memberId == it.creatorId) { | ||||
|                         true | ||||
|                     } else { | ||||
|                         existOrdered | ||||
|                     }, | ||||
|                     likeCount = likeCount, | ||||
|                     commentCount = commentCount, | ||||
|                     firstComment = firstComment | ||||
|                 ) | ||||
|             } | ||||
|             .toList() | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun purchasePost( | ||||
|         postId: Long, | ||||
|         memberId: Long, | ||||
|         timezone: String, | ||||
|         isAdult: Boolean, | ||||
|         container: String | ||||
|     ): GetCommunityPostListResponse { | ||||
|         val post = repository.findByIdAndActive(postId, isAdult) | ||||
|             ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.") | ||||
|  | ||||
|         val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = post.member!!.id!!) | ||||
|         if (isBlocked) throw SodaException("${post.member!!.nickname}님의 요청으로 접근이 제한됩니다.") | ||||
|  | ||||
|         val existOrdered = useCanRepository.isExistOrdered(postId = postId, memberId = memberId) | ||||
|  | ||||
|         if (!existOrdered) { | ||||
|             canPaymentService.spendCan( | ||||
|                 memberId = memberId, | ||||
|                 needCan = post.price, | ||||
|                 canUsage = CanUsage.PAID_COMMUNITY_POST, | ||||
|                 communityPost = post, | ||||
|                 container = container | ||||
|             ) | ||||
|         } | ||||
|  | ||||
|         val isLike = likeRepository.findByPostIdAndMemberId(postId = post.id!!, memberId = memberId)?.isActive ?: false | ||||
|         val likeCount = likeRepository.totalCountCommunityPostLikeByPostId(post.id!!) | ||||
|         val commentCount = if (post.isCommentAvailable) { | ||||
|             commentRepository.totalCountCommentByPostId(postId = post.id!!) | ||||
|         } else { | ||||
|             0 | ||||
|         } | ||||
|         val commentList = if (post.isCommentAvailable) { | ||||
|             commentRepository.findByPostId( | ||||
|                 cloudFrontHost = imageHost, | ||||
|                 timezone = timezone, | ||||
|                 id = post.id!!, | ||||
|                 offset = 0, | ||||
|                 limit = 1 | ||||
|             ) | ||||
|         } else { | ||||
|             listOf() | ||||
|         } | ||||
|  | ||||
|         val firstComment = if (post.isCommentAvailable && commentList.isNotEmpty()) { | ||||
|             commentList[0] | ||||
|         } else { | ||||
|             null | ||||
|         } | ||||
|  | ||||
|         return post.toCommunityPostListResponse( | ||||
|             imageHost = imageHost, | ||||
|             content = post.content, | ||||
|             date = getTimeAgoString(post.createdAt!!), | ||||
|             isLike = isLike, | ||||
|             existOrdered = true, | ||||
|             likeCount = likeCount, | ||||
|             commentCount = commentCount, | ||||
|             firstComment = firstComment | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -10,10 +10,12 @@ data class GetCommunityPostListResponse @QueryProjection constructor( | ||||
|     val creatorProfileUrl: String, | ||||
|     val imageUrl: String?, | ||||
|     val content: String, | ||||
|     val price: Int, | ||||
|     val date: String, | ||||
|     val isCommentAvailable: Boolean, | ||||
|     val isAdult: Boolean, | ||||
|     val isLike: Boolean, | ||||
|     val existOrdered: Boolean, | ||||
|     val likeCount: Int, | ||||
|     val commentCount: Int, | ||||
|     val firstComment: GetCommunityPostCommentListItem? | ||||
|   | ||||
| @@ -0,0 +1,3 @@ | ||||
| package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity | ||||
|  | ||||
| data class PurchasePostRequest(val postId: Long, val timezone: String, val container: String) | ||||
| @@ -0,0 +1,50 @@ | ||||
| package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity | ||||
|  | ||||
| import com.querydsl.core.annotations.QueryProjection | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListItem | ||||
| import java.time.LocalDateTime | ||||
|  | ||||
| data class SelectCommunityPostResponse @QueryProjection constructor( | ||||
|     val id: Long, | ||||
|     val creatorId: Long, | ||||
|     val creatorNickname: String, | ||||
|     val creatorProfileUrl: String, | ||||
|     val imagePath: String?, | ||||
|     val content: String, | ||||
|     val date: LocalDateTime, | ||||
|     val isCommentAvailable: Boolean, | ||||
|     val price: Int | ||||
| ) { | ||||
|     fun toCommunityPostListResponse( | ||||
|         imageHost: String, | ||||
|         content: String, | ||||
|         date: String, | ||||
|         isLike: Boolean, | ||||
|         existOrdered: Boolean, | ||||
|         likeCount: Int, | ||||
|         commentCount: Int, | ||||
|         firstComment: GetCommunityPostCommentListItem? | ||||
|     ): GetCommunityPostListResponse { | ||||
|         return GetCommunityPostListResponse( | ||||
|             postId = id, | ||||
|             creatorId = creatorId, | ||||
|             creatorNickname = creatorNickname, | ||||
|             creatorProfileUrl = "$imageHost/$creatorProfileUrl", | ||||
|             imageUrl = if (imagePath != null) { | ||||
|                 "$imageHost/$imagePath" | ||||
|             } else { | ||||
|                 null | ||||
|             }, | ||||
|             content = content, | ||||
|             price = price, | ||||
|             date = date, | ||||
|             isCommentAvailable = isCommentAvailable, | ||||
|             isAdult = false, | ||||
|             isLike = isLike, | ||||
|             existOrdered = existOrdered, | ||||
|             likeCount = likeCount, | ||||
|             commentCount = commentCount, | ||||
|             firstComment = firstComment | ||||
|         ) | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user