diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/AdminContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/AdminContentService.kt index 5b3e8a7..0edf5ab 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/AdminContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/content/AdminContentService.kt @@ -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) { diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt index 182ca9d..b6ed016 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/CanService.kt @@ -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!! diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt index 73e04dc..e36e8c1 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/payment/CanPaymentService.kt @@ -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("잘못된 요청입니다.") } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt index 58bbde9..9d4f218 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/CanUsage.kt @@ -5,5 +5,6 @@ enum class CanUsage { DONATION, CHANGE_NICKNAME, ORDER_CONTENT, - SPIN_ROULETTE + SPIN_ROULETTE, + PAID_COMMUNITY_POST } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCan.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCan.kt index 683492a..916d4b0 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCan.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCan.kt @@ -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 = mutableListOf() } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCanRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCanRepository.kt index f30429a..eeac478 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCanRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/can/use/UseCanRepository.kt @@ -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 +interface UseCanRepository : JpaRepository, 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 + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt index d6320e4..4a085de 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt @@ -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 ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt index 7dea288..68143c7 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt @@ -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 + ) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt index 9c18a29..0307940 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt @@ -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 + ) + ) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt index d4cd6b5..16247ae 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt @@ -20,10 +20,12 @@ interface CreatorCommunityQueryRepository { offset: Long, limit: Long, isAdult: Boolean - ): List + ): List fun findByIdAndActive(postId: Long, isAdult: Boolean): CreatorCommunity? - fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List + fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List + + 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 { + ): List { 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 { + override fun getLatestPostListFromCreatorsYouFollow( + memberId: Long, + isAdult: Boolean + ): List { 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() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt index c2d3958..24d0073 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt @@ -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 { + 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 + ) } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt index 4aed806..b4b9b94 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt @@ -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? diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/PurchasePostRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/PurchasePostRequest.kt new file mode 100644 index 0000000..a32e4f4 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/PurchasePostRequest.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity + +data class PurchasePostRequest(val postId: Long, val timezone: String, val container: String) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/SelectCommunityPostResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/SelectCommunityPostResponse.kt new file mode 100644 index 0000000..90aa413 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/SelectCommunityPostResponse.kt @@ -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 + ) + } +}