커뮤니티 API 추가
This commit is contained in:
parent
7e02acd22c
commit
8a3d11ae59
|
@ -0,0 +1,7 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
|
||||||
|
|
||||||
|
data class CreateCommunityPostRequest(
|
||||||
|
val content: String,
|
||||||
|
val isCommentAvailable: Boolean,
|
||||||
|
val isAdult: Boolean
|
||||||
|
)
|
|
@ -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,
|
||||||
|
val isActive: Boolean = true
|
||||||
|
) : BaseEntity() {
|
||||||
|
@ManyToOne(fetch = FetchType.LAZY)
|
||||||
|
@JoinColumn(name = "member_id", nullable = false)
|
||||||
|
var member: Member? = null
|
||||||
|
}
|
|
@ -0,0 +1,143 @@
|
||||||
|
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.RequestParam
|
||||||
|
import org.springframework.web.bind.annotation.RequestPart
|
||||||
|
import org.springframework.web.bind.annotation.RestController
|
||||||
|
import org.springframework.web.multipart.MultipartFile
|
||||||
|
|
||||||
|
@RestController("/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
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@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()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,64 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
|
||||||
|
|
||||||
|
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 org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
|
||||||
|
interface CreatorCommunityRepository : JpaRepository<CreatorCommunity, Long>, CreatorCommunityQueryRepository
|
||||||
|
|
||||||
|
interface CreatorCommunityQueryRepository {
|
||||||
|
fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunity?
|
||||||
|
|
||||||
|
fun getCommunityPostList(
|
||||||
|
creatorId: Long,
|
||||||
|
offset: Long,
|
||||||
|
limit: Long,
|
||||||
|
isAdult: Boolean
|
||||||
|
): List<CreatorCommunity>
|
||||||
|
|
||||||
|
fun findByIdAndActive(postId: Long): CreatorCommunity?
|
||||||
|
}
|
||||||
|
|
||||||
|
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<CreatorCommunity> {
|
||||||
|
var where = creatorCommunity.member.id.eq(creatorId)
|
||||||
|
|
||||||
|
if (!isAdult) {
|
||||||
|
where = where.and(creatorCommunity.isAdult.isFalse)
|
||||||
|
}
|
||||||
|
|
||||||
|
return queryFactory
|
||||||
|
.selectFrom(creatorCommunity)
|
||||||
|
.innerJoin(creatorCommunity.member, member)
|
||||||
|
.where(where)
|
||||||
|
.offset(offset)
|
||||||
|
.limit(limit)
|
||||||
|
.fetch()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun findByIdAndActive(postId: Long): CreatorCommunity? {
|
||||||
|
return queryFactory
|
||||||
|
.selectFrom(creatorCommunity)
|
||||||
|
.where(
|
||||||
|
creatorCommunity.id.eq(postId)
|
||||||
|
.and(creatorCommunity.isActive.isTrue)
|
||||||
|
)
|
||||||
|
.fetchFirst()
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,277 @@
|
||||||
|
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 (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<GetCommunityPostListResponse> {
|
||||||
|
val postList = repository.getCommunityPostList(
|
||||||
|
creatorId = creatorId,
|
||||||
|
offset = offset,
|
||||||
|
limit = limit,
|
||||||
|
isAdult = isAdult
|
||||||
|
)
|
||||||
|
|
||||||
|
return postList
|
||||||
|
.asSequence()
|
||||||
|
.map {
|
||||||
|
val isLike = likeRepository.findByIdAndMemberId(id = 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 = commentRepository.findByPostId(
|
||||||
|
cloudFrontHost = imageHost,
|
||||||
|
timezone = timezone,
|
||||||
|
id = it.id!!,
|
||||||
|
offset = 0,
|
||||||
|
limit = 1
|
||||||
|
)
|
||||||
|
|
||||||
|
val firstComment = if (commentList.isNotEmpty()) {
|
||||||
|
commentList[0]
|
||||||
|
} else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
|
||||||
|
GetCommunityPostListResponse(
|
||||||
|
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!!),
|
||||||
|
isLike = isLike,
|
||||||
|
likeCount = likeCount,
|
||||||
|
commentCount = commentCount,
|
||||||
|
firstComment = firstComment
|
||||||
|
)
|
||||||
|
}
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
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.findByIdAndMemberId(id = request.postId, memberId = member.id!!)
|
||||||
|
|
||||||
|
if (postLike == null) {
|
||||||
|
postLike = CreatorCommunityLike()
|
||||||
|
postLike.member = member
|
||||||
|
|
||||||
|
val post = repository.findByIdAndActive(request.postId)
|
||||||
|
?: 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)
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
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 creatorNickname: String,
|
||||||
|
val creatorProfileUrl: String,
|
||||||
|
val imageUrl: String?,
|
||||||
|
val content: String,
|
||||||
|
val date: String,
|
||||||
|
val isLike: Boolean,
|
||||||
|
val likeCount: Int,
|
||||||
|
val commentCount: Int,
|
||||||
|
val firstComment: GetCommunityPostCommentListItem?
|
||||||
|
)
|
|
@ -0,0 +1,8 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity
|
||||||
|
|
||||||
|
data class ModifyCommunityPostRequest(
|
||||||
|
val creatorCommunityId: Long,
|
||||||
|
val content: String?,
|
||||||
|
val isCommentAvailable: Boolean?,
|
||||||
|
val isAdult: Boolean?
|
||||||
|
)
|
|
@ -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?)
|
|
@ -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<CreatorCommunityComment> = 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
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
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<CreatorCommunityComment, Long>, CreatorCommunityCommentQueryRepository
|
||||||
|
|
||||||
|
interface CreatorCommunityCommentQueryRepository {
|
||||||
|
fun findByPostId(
|
||||||
|
cloudFrontHost: String,
|
||||||
|
timezone: String,
|
||||||
|
id: Long,
|
||||||
|
offset: Long,
|
||||||
|
limit: Long
|
||||||
|
): List<GetCommunityPostCommentListItem>
|
||||||
|
|
||||||
|
fun commentReplyCountByCommentId(commentId: Long): Int
|
||||||
|
|
||||||
|
fun totalCountCommentByPostId(postId: Long): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreatorCommunityCommentQueryRepositoryImpl(
|
||||||
|
private val queryFactory: JPAQueryFactory
|
||||||
|
) : CreatorCommunityCommentQueryRepository {
|
||||||
|
override fun findByPostId(
|
||||||
|
cloudFrontHost: String,
|
||||||
|
timezone: String,
|
||||||
|
id: Long,
|
||||||
|
offset: Long,
|
||||||
|
limit: Long
|
||||||
|
): List<GetCommunityPostCommentListItem> {
|
||||||
|
return queryFactory
|
||||||
|
.selectFrom(creatorCommunityComment)
|
||||||
|
.where(
|
||||||
|
creatorCommunityComment.isActive.isTrue
|
||||||
|
.and(creatorCommunityComment.creatorCommunity.id.eq(id))
|
||||||
|
)
|
||||||
|
.offset(offset)
|
||||||
|
.limit(limit)
|
||||||
|
.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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,16 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.comment
|
||||||
|
|
||||||
|
data class GetCommunityPostCommentListResponse(
|
||||||
|
val totalCount: Int,
|
||||||
|
val items: List<GetCommunityPostCommentListItem>
|
||||||
|
)
|
||||||
|
|
||||||
|
data class GetCommunityPostCommentListItem(
|
||||||
|
val id: Long,
|
||||||
|
val writerId: Long,
|
||||||
|
val nickname: String,
|
||||||
|
val profileUrl: String,
|
||||||
|
val comment: String,
|
||||||
|
val date: String,
|
||||||
|
val replyCount: Int
|
||||||
|
)
|
|
@ -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?)
|
|
@ -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
|
||||||
|
}
|
|
@ -0,0 +1,30 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
|
||||||
|
|
||||||
|
import com.querydsl.jpa.impl.JPAQueryFactory
|
||||||
|
import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.QCreatorCommunityLike.creatorCommunityLike
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository
|
||||||
|
|
||||||
|
interface CreatorCommunityLikeRepository :
|
||||||
|
JpaRepository<CreatorCommunityLike, Long>, CreatorCommunityLikeQueryRepository {
|
||||||
|
fun findByIdAndMemberId(id: Long, memberId: Long): CreatorCommunityLike?
|
||||||
|
}
|
||||||
|
|
||||||
|
interface CreatorCommunityLikeQueryRepository {
|
||||||
|
fun totalCountCommunityPostLikeByPostId(postId: Long): Int
|
||||||
|
}
|
||||||
|
|
||||||
|
class CreatorCommunityLikeQueryRepositoryImpl(
|
||||||
|
private val queryFactory: JPAQueryFactory
|
||||||
|
) : CreatorCommunityLikeQueryRepository {
|
||||||
|
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
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
|
||||||
|
|
||||||
|
data class PostCommunityPostLikeRequest(val postId: Long)
|
|
@ -0,0 +1,3 @@
|
||||||
|
package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like
|
||||||
|
|
||||||
|
data class PostCommunityPostLikeResponse(val like: Boolean)
|
Loading…
Reference in New Issue