diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt index af0b47d..3cf3390 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt @@ -11,6 +11,7 @@ import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository import kr.co.vividnext.sodalive.explorer.profile.PostWriteCheersRequest import kr.co.vividnext.sodalive.explorer.profile.PutWriteCheersRequest +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityService import kr.co.vividnext.sodalive.fcm.FcmEvent import kr.co.vividnext.sodalive.fcm.FcmEventType import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailUser @@ -36,6 +37,8 @@ class ExplorerService( private val queryRepository: ExplorerQueryRepository, private val cheersRepository: CreatorCheersRepository, private val noticeRepository: ChannelNoticeRepository, + private val communityService: CreatorCommunityService, + private val applicationEventPublisher: ApplicationEventPublisher, @Value("\${cloud.aws.cloud-front.host}") @@ -227,6 +230,16 @@ class ExplorerService( // 공지사항 val notice = queryRepository.getNoticeString(creatorId) + // 커뮤니티 + val communityPostList = communityService.getCommunityPostList( + creatorId = creatorId, + memberId = member.id!!, + timezone = timezone, + offset = 0, + limit = 3, + isAdult = member.auth != null + ) + // 응원 val cheers = queryRepository.getCheersList(creatorId, timezone = timezone, offset = 0, limit = 4) @@ -262,6 +275,7 @@ class ExplorerService( liveRoomList = liveRoomList, contentList = contentList, notice = notice, + communityPostList = communityPostList, cheers = cheers, activitySummary = GetCreatorActivitySummary( liveCount = liveCount, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt index d7f9a83..da86441 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/GetCreatorProfileResponse.kt @@ -1,6 +1,7 @@ package kr.co.vividnext.sodalive.explorer import kr.co.vividnext.sodalive.content.GetAudioContentListItem +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.GetCommunityPostListResponse data class GetCreatorProfileResponse( val creator: CreatorResponse, @@ -9,6 +10,7 @@ data class GetCreatorProfileResponse( val liveRoomList: List, val contentList: List, val notice: String, + val communityPostList: List, val cheers: GetCheersResponse, val activitySummary: GetCreatorActivitySummary, val isBlock: Boolean 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 new file mode 100644 index 0000000..d6320e4 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreateCommunityPostRequest.kt @@ -0,0 +1,7 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity + +data class CreateCommunityPostRequest( + val content: String, + val isCommentAvailable: Boolean, + val isAdult: Boolean +) 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 new file mode 100644 index 0000000..7dea288 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunity.kt @@ -0,0 +1,24 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity + +import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.member.Member +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne + +@Entity +data class CreatorCommunity( + @Column(columnDefinition = "TEXT", nullable = false) + var content: String, + var isCommentAvailable: Boolean, + var isAdult: Boolean, + @Column(nullable = true) + var imagePath: String? = null, + var isActive: Boolean = true +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + var member: Member? = null +} 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 new file mode 100644 index 0000000..9c18a29 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityController.kt @@ -0,0 +1,198 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity + +import kr.co.vividnext.sodalive.common.ApiResponse +import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreateCommunityPostCommentRequest +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.ModifyCommunityPostCommentRequest +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeRequest +import kr.co.vividnext.sodalive.member.Member +import org.springframework.data.domain.Pageable +import org.springframework.lang.Nullable +import org.springframework.security.access.prepost.PreAuthorize +import org.springframework.security.core.annotation.AuthenticationPrincipal +import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PathVariable +import org.springframework.web.bind.annotation.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RequestPart +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.multipart.MultipartFile + +@RestController +@RequestMapping("/creator-community") +class CreatorCommunityController(private val service: CreatorCommunityService) { + @PostMapping + @PreAuthorize("hasRole('CREATOR')") + fun createCommunityPost( + @Nullable + @RequestPart("postImage") + postImage: MultipartFile?, + @RequestPart("request") requestString: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.createCommunityPost( + postImage = postImage, + requestString = requestString, + member = member + ) + ) + } + + @PutMapping + @PreAuthorize("hasRole('CREATOR')") + fun modifyCommunityPost( + @Nullable + @RequestPart("postImage") + postImage: MultipartFile?, + @RequestPart("request") requestString: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.modifyCommunityPost( + postImage = postImage, + requestString = requestString, + member = member + ) + ) + } + + @GetMapping + fun getCommunityPostList( + @RequestParam creatorId: Long, + @RequestParam timezone: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, + pageable: Pageable + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.getCommunityPostList( + creatorId = creatorId, + memberId = member.id!!, + timezone = timezone, + offset = pageable.offset, + limit = pageable.pageSize.toLong(), + isAdult = member.auth != null + ) + ) + } + + @GetMapping("/{id}") + fun getCommunityPostDetail( + @PathVariable("id") postId: Long, + @RequestParam timezone: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.getCommunityPostDetail( + postId = postId, + memberId = member.id!!, + timezone = timezone, + isAdult = member.auth != null + ) + ) + } + + @PostMapping("/like") + fun communityPostLike( + @RequestBody request: PostCommunityPostLikeRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.communityPostLike(request, member)) + } + + @PostMapping("/comment") + fun createCommunityPostComment( + @RequestBody request: CreateCommunityPostCommentRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.createCommunityPostComment( + comment = request.comment, + postId = request.postId, + parentId = request.parentId, + member = member + ) + ) + } + + @PutMapping("/comment") + fun modifyCommunityPostComment( + @RequestBody request: ModifyCommunityPostCommentRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.modifyCommunityPostComment(request = request, member = member) + ) + } + + @GetMapping("/{id}/comment") + fun getCommunityPostCommentList( + @PathVariable("id") postId: Long, + @RequestParam timezone: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, + pageable: Pageable + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.getCommunityPostCommentList( + postId = postId, + timezone = timezone, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ) + ) + } + + @GetMapping("/comment/{id}") + fun getCommentReplyList( + @PathVariable("id") commentId: Long, + @RequestParam timezone: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, + pageable: Pageable + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.getCommentReplyList( + commentId = commentId, + timezone = timezone, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ) + ) + } + + @GetMapping("/latest") + fun getLatestPostListFromCreatorsYouFollow( + @RequestParam timezone: String, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.getLatestPostListFromCreatorsYouFollow( + timezone = timezone, + memberId = member.id!!, + isAdult = member.auth != null + ) + ) + } +} 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 new file mode 100644 index 0000000..cd426d6 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityRepository.kt @@ -0,0 +1,115 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity + +import com.querydsl.core.types.dsl.Expressions +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommunity.creatorCommunity +import kr.co.vividnext.sodalive.member.QMember.member +import kr.co.vividnext.sodalive.member.following.QCreatorFollowing.creatorFollowing +import org.springframework.data.jpa.repository.JpaRepository +import java.time.LocalDate +import java.time.LocalDateTime +import java.time.LocalTime + +interface CreatorCommunityRepository : JpaRepository, CreatorCommunityQueryRepository + +interface CreatorCommunityQueryRepository { + fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunity? + + fun getCommunityPostList( + creatorId: Long, + offset: Long, + limit: Long, + isAdult: Boolean + ): List + + fun findByIdAndActive(postId: Long, isAdult: Boolean): CreatorCommunity? + fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List +} + +class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CreatorCommunityQueryRepository { + override fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunity? { + return queryFactory + .selectFrom(creatorCommunity) + .where( + creatorCommunity.id.eq(id) + .and(creatorCommunity.member.id.eq(memberId)) + ) + .fetchFirst() + } + + override fun getCommunityPostList( + creatorId: Long, + offset: Long, + limit: Long, + isAdult: Boolean + ): List { + var where = creatorCommunity.member.id.eq(creatorId) + .and(creatorCommunity.isActive.isTrue) + + if (!isAdult) { + where = where.and(creatorCommunity.isAdult.isFalse) + } + + return queryFactory + .selectFrom(creatorCommunity) + .innerJoin(creatorCommunity.member, member) + .where(where) + .offset(offset) + .limit(limit) + .orderBy(creatorCommunity.createdAt.desc()) + .fetch() + } + + override fun findByIdAndActive(postId: Long, isAdult: Boolean): CreatorCommunity? { + var where = creatorCommunity.id.eq(postId) + .and(creatorCommunity.isActive.isTrue) + + if (!isAdult) { + where = where.and(creatorCommunity.isAdult.isFalse) + } + + return queryFactory + .selectFrom(creatorCommunity) + .where(where) + .fetchFirst() + } + + override fun getLatestPostListFromCreatorsYouFollow(memberId: Long, isAdult: Boolean): List { + val creatorCommunity = QCreatorCommunity.creatorCommunity + val latest = QCreatorCommunity.creatorCommunity + + val localDate = LocalDate.now().minusDays(7) + val localTime = LocalTime.of(0, 0) + var where = creatorCommunity.isActive.isTrue + .and(creatorCommunity.createdAt.after(LocalDateTime.of(localDate, localTime))) + + if (!isAdult) { + where = where.and(creatorCommunity.isAdult.isFalse) + } + + val subQuery = queryFactory + .select(latest.member.id, latest.createdAt.max().`as`("maxCreatedAt")) + .from(latest) + .groupBy(latest.member.id) + + where = where.and( + Expressions.list(creatorCommunity.member.id, creatorCommunity.createdAt).`in`(subQuery) + ) + + val memberSubQuery = queryFactory + .select(creatorFollowing.creator.id) + .from(creatorFollowing) + .where(creatorFollowing.member.id.eq(memberId)) + + where = where.and( + creatorCommunity.member.id.`in`(memberSubQuery) + ) + + return queryFactory + .selectFrom(creatorCommunity) + .where(where) + .orderBy(creatorCommunity.createdAt.desc()) + .limit(10) + .fetch() + } +} 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 new file mode 100644 index 0000000..37e0dae --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/CreatorCommunityService.kt @@ -0,0 +1,429 @@ +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.common.SodaException +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityComment +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.CreatorCommunityCommentRepository +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListResponse +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.ModifyCommunityPostCommentRequest +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCommunityLike +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCommunityLikeRepository +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeRequest +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeResponse +import kr.co.vividnext.sodalive.fcm.FcmEvent +import kr.co.vividnext.sodalive.fcm.FcmEventType +import kr.co.vividnext.sodalive.member.Member +import kr.co.vividnext.sodalive.utils.generateFileName +import org.springframework.beans.factory.annotation.Value +import org.springframework.context.ApplicationEventPublisher +import org.springframework.data.repository.findByIdOrNull +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.multipart.MultipartFile +import java.time.Duration +import java.time.LocalDateTime + +@Service +class CreatorCommunityService( + private val repository: CreatorCommunityRepository, + private val likeRepository: CreatorCommunityLikeRepository, + private val commentRepository: CreatorCommunityCommentRepository, + + private val s3Uploader: S3Uploader, + private val objectMapper: ObjectMapper, + private val applicationEventPublisher: ApplicationEventPublisher, + + @Value("\${cloud.aws.s3.bucket}") + private val imageBucket: String, + + @Value("\${cloud.aws.cloud-front.host}") + private val imageHost: String +) { + @Transactional + fun createCommunityPost(postImage: MultipartFile?, requestString: String, member: Member) { + val request = objectMapper.readValue(requestString, CreateCommunityPostRequest::class.java) + + val post = CreatorCommunity( + content = request.content, + isCommentAvailable = request.isCommentAvailable, + isAdult = request.isAdult + ) + post.member = member + repository.save(post) + + if (postImage != null) { + val metadata = ObjectMetadata() + metadata.contentLength = postImage.size + + // 커버 이미지 파일명 생성 + val imageFileName = generateFileName(prefix = "${post.id}-image") + + // 커버 이미지 업로드 + val imagePath = s3Uploader.upload( + inputStream = postImage.inputStream, + bucket = imageBucket, + filePath = "creator_community/${post.id}/$imageFileName", + metadata = metadata + ) + + post.imagePath = imagePath + } + + applicationEventPublisher.publishEvent( + FcmEvent( + type = FcmEventType.CHANGE_NOTICE, + title = member.nickname, + message = "공지를 등록했습니다.", + creatorId = member.id!! + ) + ) + } + + @Transactional + fun modifyCommunityPost(postImage: MultipartFile?, requestString: String, member: Member) { + val request = objectMapper.readValue(requestString, ModifyCommunityPostRequest::class.java) + + val post = repository.findByIdAndMemberId(id = request.creatorCommunityId, memberId = member.id!!) + ?: throw SodaException("잘못된 요청입니다.") + + if (request.content != null) { + post.content = request.content + } + + if (request.isCommentAvailable != null) { + post.isCommentAvailable = request.isCommentAvailable + } + + if (request.isAdult != null) { + post.isAdult = request.isAdult + } + + if (request.isActive != null) { + post.isActive = request.isActive + } + + if (postImage != null) { + val metadata = ObjectMetadata() + metadata.contentLength = postImage.size + + // 커버 이미지 파일명 생성 + val imageFileName = generateFileName(prefix = "${post.id}-image") + + // 커버 이미지 업로드 + val imagePath = s3Uploader.upload( + inputStream = postImage.inputStream, + bucket = imageBucket, + filePath = "creator_community/${post.id}/$imageFileName", + metadata = metadata + ) + + post.imagePath = imagePath + } + } + + fun getCommunityPostList( + creatorId: Long, + memberId: Long, + timezone: String, + offset: Long, + limit: Long, + isAdult: Boolean + ): List { + val postList = repository.getCommunityPostList( + creatorId = creatorId, + offset = offset, + limit = limit, + isAdult = isAdult + ) + + return postList + .asSequence() + .map { + 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!!) + } else { + 0 + } + val commentList = if (it.isCommentAvailable) { + commentRepository.findByPostId( + cloudFrontHost = imageHost, + timezone = timezone, + id = it.id!!, + offset = 0, + limit = 1 + ) + } else { + listOf() + } + + val firstComment = if (it.isCommentAvailable && commentList.isNotEmpty()) { + commentList[0] + } else { + null + } + + GetCommunityPostListResponse( + postId = it.id!!, + creatorId = it.member!!.id!!, + creatorNickname = it.member!!.nickname, + creatorProfileUrl = if (it.member!!.profileImage != null) { + "$imageHost/${it.member!!.profileImage}" + } 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, + isLike = isLike, + likeCount = likeCount, + commentCount = commentCount, + firstComment = firstComment + ) + } + .toList() + } + + fun getCommunityPostDetail( + postId: Long, + memberId: Long, + timezone: String, + isAdult: Boolean + ): GetCommunityPostListResponse { + val post = repository.findByIdAndActive(postId, isAdult = isAdult) + ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.") + + 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 GetCommunityPostListResponse( + postId = post.id!!, + creatorId = post.member!!.id!!, + creatorNickname = post.member!!.nickname, + creatorProfileUrl = if (post.member!!.profileImage != null) { + "$imageHost/${post.member!!.profileImage}" + } 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, + isLike = isLike, + likeCount = likeCount, + commentCount = commentCount, + firstComment = firstComment + ) + } + + private fun getTimeAgoString(dateTime: LocalDateTime): String { + val now = LocalDateTime.now() + val duration = Duration.between(dateTime, now) + + return when { + duration.toMinutes() < 60 -> "${duration.toMinutes()}분전" + duration.toHours() < 24 -> "${duration.toHours()}시간전" + duration.toDays() < 30 -> "${duration.toDays()}일전" + duration.toDays() < 365 -> "${duration.toDays() / 30}분전" + else -> "${duration.toDays() / 365}년전" + } + } + + @Transactional + fun communityPostLike(request: PostCommunityPostLikeRequest, member: Member): PostCommunityPostLikeResponse { + var postLike = likeRepository.findByPostIdAndMemberId(postId = request.postId, memberId = member.id!!) + + if (postLike == null) { + postLike = CreatorCommunityLike() + postLike.member = member + + val post = repository.findByIdAndActive(request.postId, isAdult = member.auth != null) + ?: throw SodaException("잘못된 요청입니다.\n다시 시도해 주세요.") + + postLike.creatorCommunity = post + likeRepository.save(postLike) + } else { + postLike.isActive = !postLike.isActive + } + + return PostCommunityPostLikeResponse(like = postLike.isActive) + } + + @Transactional + fun createCommunityPostComment(comment: String, postId: Long, parentId: Long?, member: Member) { + val post = repository.findByIdOrNull(id = postId) + ?: throw SodaException("잘못된 게시물 입니다.\n다시 시도해 주세요.") + + val postComment = CreatorCommunityComment(comment = comment) + postComment.creatorCommunity = post + postComment.member = member + + val parent = if (parentId != null) { + commentRepository.findByIdOrNull(id = parentId) + } else { + null + } + + if (parent != null) { + postComment.parent = parent + } + + commentRepository.save(postComment) + } + + @Transactional + fun modifyCommunityPostComment(request: ModifyCommunityPostCommentRequest, member: Member) { + val postComment = commentRepository.findByIdOrNull(id = request.commentId) + ?: throw SodaException("잘못된 접근 입니다.\n확인 후 다시 시도해 주세요.") + + if (request.comment != null && postComment.member!!.id!! == member.id!!) { + postComment.comment = request.comment + } + + if ( + request.isActive != null && + ( + postComment.member!!.id!! == member.id!! || + postComment.creatorCommunity!!.member!!.id!! == member.id!! + ) + ) { + postComment.isActive = request.isActive + } + } + + fun getCommunityPostCommentList( + postId: Long, + timezone: String, + offset: Long, + limit: Long + ): GetCommunityPostCommentListResponse { + val commentList = commentRepository.findByPostId( + cloudFrontHost = imageHost, + timezone = timezone, + id = postId, + offset = offset, + limit = limit + ) + + val totalCount = commentRepository.totalCountCommentByPostId(postId = postId) + return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList) + } + + fun getCommentReplyList( + commentId: Long, + timezone: String, + offset: Long, + limit: Long + ): GetCommunityPostCommentListResponse { + val commentList = commentRepository.getCommunityCommentReplyList( + cloudFrontHost = imageHost, + commentId = commentId, + timezone = timezone, + offset = offset, + limit = limit + ) + + val totalCount = commentRepository.commentReplyCountByCommentId(commentId) + return GetCommunityPostCommentListResponse(totalCount = totalCount, items = commentList) + } + + fun getLatestPostListFromCreatorsYouFollow( + timezone: String, + memberId: Long, + isAdult: Boolean + ): List { + val postList = repository.getLatestPostListFromCreatorsYouFollow(memberId = memberId, isAdult = isAdult) + + return postList + .asSequence() + .map { + 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!!) + } else { + 0 + } + val commentList = if (it.isCommentAvailable) { + commentRepository.findByPostId( + cloudFrontHost = imageHost, + timezone = timezone, + id = it.id!!, + offset = 0, + limit = 1 + ) + } else { + listOf() + } + + val firstComment = if (it.isCommentAvailable && commentList.isNotEmpty()) { + commentList[0] + } else { + null + } + + GetCommunityPostListResponse( + postId = it.id!!, + creatorId = it.member!!.id!!, + creatorNickname = it.member!!.nickname, + creatorProfileUrl = if (it.member!!.profileImage != null) { + "$imageHost/${it.member!!.profileImage}" + } 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, + isLike = isLike, + likeCount = likeCount, + commentCount = commentCount, + firstComment = firstComment + ) + } + .toList() + } +} 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 new file mode 100644 index 0000000..4aed806 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/GetCommunityPostListResponse.kt @@ -0,0 +1,20 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity + +import com.querydsl.core.annotations.QueryProjection +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.GetCommunityPostCommentListItem + +data class GetCommunityPostListResponse @QueryProjection constructor( + val postId: Long, + val creatorId: Long, + val creatorNickname: String, + val creatorProfileUrl: String, + val imageUrl: String?, + val content: String, + val date: String, + val isCommentAvailable: Boolean, + val isAdult: Boolean, + val isLike: Boolean, + val likeCount: Int, + val commentCount: Int, + val firstComment: GetCommunityPostCommentListItem? +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt new file mode 100644 index 0000000..d887db4 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/ModifyCommunityPostRequest.kt @@ -0,0 +1,9 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity + +data class ModifyCommunityPostRequest( + val creatorCommunityId: Long, + val content: String?, + val isCommentAvailable: Boolean?, + val isAdult: Boolean?, + val isActive: Boolean? +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreateCommunityPostCommentRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreateCommunityPostCommentRequest.kt new file mode 100644 index 0000000..5e833d6 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreateCommunityPostCommentRequest.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment + +data class CreateCommunityPostCommentRequest(val comment: String, val postId: Long, val parentId: Long?) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityComment.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityComment.kt new file mode 100644 index 0000000..6e65c0a --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityComment.kt @@ -0,0 +1,37 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment + +import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity +import kr.co.vividnext.sodalive.member.Member +import javax.persistence.Column +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne +import javax.persistence.OneToMany + +@Entity +data class CreatorCommunityComment( + @Column(columnDefinition = "TEXT", nullable = false) + var comment: String, + var isActive: Boolean = true +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "parent_id", nullable = true) + var parent: CreatorCommunityComment? = null + set(value) { + value?.children?.add(this) + field = value + } + + @OneToMany(mappedBy = "parent") + var children: MutableList = mutableListOf() + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + var member: Member? = null + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "creator_community_id", nullable = false) + var creatorCommunity: CreatorCommunity? = null +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt new file mode 100644 index 0000000..2ee60bd --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/CreatorCommunityCommentRepository.kt @@ -0,0 +1,142 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment.QCreatorCommunityComment.creatorCommunityComment +import org.springframework.data.jpa.repository.JpaRepository +import java.time.ZoneId +import java.time.format.DateTimeFormatter + +interface CreatorCommunityCommentRepository : + JpaRepository, CreatorCommunityCommentQueryRepository + +interface CreatorCommunityCommentQueryRepository { + fun findByPostId( + cloudFrontHost: String, + timezone: String, + id: Long, + offset: Long, + limit: Long + ): List + + fun commentReplyCountByCommentId(commentId: Long): Int + + fun totalCountCommentByPostId(postId: Long): Int + + fun getCommunityCommentReplyList( + cloudFrontHost: String, + commentId: Long, + timezone: String, + offset: Long, + limit: Long + ): List +} + +class CreatorCommunityCommentQueryRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : CreatorCommunityCommentQueryRepository { + override fun findByPostId( + cloudFrontHost: String, + timezone: String, + id: Long, + offset: Long, + limit: Long + ): List { + return queryFactory + .selectFrom(creatorCommunityComment) + .where( + creatorCommunityComment.isActive.isTrue + .and(creatorCommunityComment.creatorCommunity.id.eq(id)) + .and(creatorCommunityComment.parent.isNull) + ) + .offset(offset) + .limit(limit) + .orderBy(creatorCommunityComment.createdAt.desc()) + .fetch() + .asSequence() + .map { + val date = it.createdAt!! + .atZone(ZoneId.of("UTC")) + .withZoneSameInstant(ZoneId.of(timezone)) + + GetCommunityPostCommentListItem( + id = it.id!!, + writerId = it.member!!.id!!, + nickname = it.member!!.nickname, + profileUrl = if (it.member!!.profileImage != null) { + "$cloudFrontHost/${it.member!!.profileImage}" + } else { + "$cloudFrontHost/profile/default-profile.png" + }, + comment = it.comment, + date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), + replyCount = commentReplyCountByCommentId(it.id!!) + ) + } + .toList() + } + + override fun commentReplyCountByCommentId(commentId: Long): Int { + return queryFactory.select(creatorCommunityComment.id) + .from(creatorCommunityComment) + .where( + creatorCommunityComment.isActive.isTrue + .and(creatorCommunityComment.parent.isNotNull) + .and(creatorCommunityComment.parent.id.eq(commentId)) + ) + .fetch() + .size + } + + override fun totalCountCommentByPostId(postId: Long): Int { + return queryFactory.select(creatorCommunityComment.id) + .from(creatorCommunityComment) + .where( + creatorCommunityComment.creatorCommunity.id.eq(postId) + .and(creatorCommunityComment.isActive.isTrue) + .and(creatorCommunityComment.parent.isNull) + ) + .fetch() + .size + } + + override fun getCommunityCommentReplyList( + cloudFrontHost: String, + commentId: Long, + timezone: String, + offset: Long, + limit: Long + ): List { + return queryFactory + .selectFrom(creatorCommunityComment) + .where( + creatorCommunityComment.isActive.isTrue + .and(creatorCommunityComment.parent.isNotNull) + .and(creatorCommunityComment.parent.id.eq(commentId)) + ) + .offset(offset) + .limit(limit) + .orderBy(creatorCommunityComment.createdAt.desc()) + .fetch() + .asSequence() + .map { + val date = it.createdAt!! + .atZone(ZoneId.of("UTC")) + .withZoneSameInstant(ZoneId.of(timezone)) + + GetCommunityPostCommentListItem( + id = it.id!!, + writerId = it.member!!.id!!, + nickname = it.member!!.nickname, + profileUrl = if (it.member!!.profileImage != null) { + "$cloudFrontHost/${it.member!!.profileImage}" + } else { + "$cloudFrontHost/profile/default-profile.png" + }, + comment = it.comment, + date = date.format(DateTimeFormatter.ofPattern("yyyy.MM.dd E hh:mm a")), + replyCount = commentReplyCountByCommentId(it.id!!) + ) + } + .toList() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/GetCommunityPostCommentListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/GetCommunityPostCommentListResponse.kt new file mode 100644 index 0000000..58c15a4 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/GetCommunityPostCommentListResponse.kt @@ -0,0 +1,16 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment + +data class GetCommunityPostCommentListResponse( + val totalCount: Int, + val items: List +) + +data class GetCommunityPostCommentListItem( + val id: Long, + val writerId: Long, + val nickname: String, + val profileUrl: String, + val comment: String, + val date: String, + val replyCount: Int +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/ModifyCommunityPostCommentRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/ModifyCommunityPostCommentRequest.kt new file mode 100644 index 0000000..0a363fd --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/comment/ModifyCommunityPostCommentRequest.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment + +data class ModifyCommunityPostCommentRequest(val commentId: Long, val comment: String?, val isActive: Boolean?) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLike.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLike.kt new file mode 100644 index 0000000..36ea0d0 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLike.kt @@ -0,0 +1,22 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like + +import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity +import kr.co.vividnext.sodalive.member.Member +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne + +@Entity +data class CreatorCommunityLike( + var isActive: Boolean = true +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + var member: Member? = null + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "creator_community_id", nullable = false) + var creatorCommunity: CreatorCommunity? = null +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt new file mode 100644 index 0000000..263548b --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/CreatorCommunityLikeRepository.kt @@ -0,0 +1,42 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.QCreatorCommunity.creatorCommunity +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.QCreatorCommunityLike.creatorCommunityLike +import org.springframework.data.jpa.repository.JpaRepository + +interface CreatorCommunityLikeRepository : + JpaRepository, CreatorCommunityLikeQueryRepository + +interface CreatorCommunityLikeQueryRepository { + fun findByPostIdAndMemberId(postId: Long, memberId: Long): CreatorCommunityLike? + + fun totalCountCommunityPostLikeByPostId(postId: Long): Int +} + +class CreatorCommunityLikeQueryRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : CreatorCommunityLikeQueryRepository { + override fun findByPostIdAndMemberId(postId: Long, memberId: Long): CreatorCommunityLike? { + return queryFactory + .selectFrom(creatorCommunityLike) + .innerJoin(creatorCommunityLike.creatorCommunity, creatorCommunity) + .where( + creatorCommunityLike.creatorCommunity.id.eq(postId) + .and(creatorCommunityLike.member.id.eq(memberId)) + ) + .fetchFirst() + } + + override fun totalCountCommunityPostLikeByPostId(postId: Long): Int { + return queryFactory + .select(creatorCommunityLike.id) + .from(creatorCommunityLike) + .where( + creatorCommunityLike.isActive.isTrue + .and(creatorCommunityLike.creatorCommunity.id.eq(postId)) + ) + .fetch() + .size + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeRequest.kt new file mode 100644 index 0000000..53a5c48 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeRequest.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like + +data class PostCommunityPostLikeRequest(val postId: Long) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeResponse.kt new file mode 100644 index 0000000..199e6b5 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/profile/creatorCommunity/like/PostCommunityPostLikeResponse.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like + +data class PostCommunityPostLikeResponse(val like: Boolean) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt b/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt index 3133dcc..25075e4 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/report/Report.kt @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.report import kr.co.vividnext.sodalive.common.BaseEntity import kr.co.vividnext.sodalive.explorer.profile.CreatorCheers +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunity import kr.co.vividnext.sodalive.member.Member import javax.persistence.Entity import javax.persistence.EnumType @@ -27,8 +28,12 @@ data class Report( @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "cheers_id", nullable = true) var cheers: CreatorCheers? = null + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "community_post_id", nullable = true) + var communityPost: CreatorCommunity? = null } enum class ReportType { - PROFILE, USER, CHEERS, AUDIO_CONTENT + PROFILE, USER, CHEERS, AUDIO_CONTENT, COMMUNITY_POST } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt index 0c52797..e94e345 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportRequest.kt @@ -5,5 +5,6 @@ data class ReportRequest( val reason: String, val reportedMemberId: Long? = null, val cheersId: Long? = null, - val audioContentId: Long? = null + val audioContentId: Long? = null, + val communityPostId: Long? = null ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt index 2926dda..5a8107b 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/report/ReportService.kt @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.report import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.explorer.profile.CreatorCheersRepository +import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.CreatorCommunityRepository import kr.co.vividnext.sodalive.member.Member import kr.co.vividnext.sodalive.member.MemberRepository import org.springframework.data.repository.findByIdOrNull @@ -13,7 +14,8 @@ import org.springframework.transaction.annotation.Transactional class ReportService( private val repository: ReportRepository, private val memberRepository: MemberRepository, - private val cheersRepository: CreatorCheersRepository + private val cheersRepository: CreatorCheersRepository, + private val creatorCommunityRepository: CreatorCommunityRepository ) { @Transactional fun save(member: Member, request: ReportRequest) { @@ -35,18 +37,32 @@ class ReportService( null } + val communityPost = if (request.communityPostId != null) { + creatorCommunityRepository.findByIdOrNull(request.communityPostId) + ?: throw SodaException("신고가 접수되었습니다.") + } else { + null + } + val report = Report(type = request.type, reason = request.reason) report.member = member report.reportedAccount = reportedAccount report.cheers = cheers + report.communityPost = communityPost repository.save(report) } private fun conditionAllIsNull(request: ReportRequest, isNull: Boolean): Boolean { return if (isNull) { - request.reportedMemberId == null && request.cheersId == null && request.audioContentId == null + request.reportedMemberId == null && + request.cheersId == null && + request.audioContentId == null && + request.communityPostId == null } else { - request.reportedMemberId != null && request.cheersId != null && request.audioContentId != null + request.reportedMemberId != null && + request.cheersId != null && + request.audioContentId != null && + request.communityPostId != null } } }