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 68143c7..e22cee7 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 @@ -17,6 +17,8 @@ data class CreatorCommunity( var isCommentAvailable: Boolean, var isAdult: Boolean, @Column(nullable = true) + var audioPath: String? = null, + @Column(nullable = true) var imagePath: String? = null, var isActive: Boolean = true ) : BaseEntity() { @@ -26,6 +28,7 @@ data class CreatorCommunity( fun toCommunityPostListResponse( imageHost: String, + audioUrl: String?, content: String, date: String, isLike: Boolean, @@ -44,6 +47,7 @@ data class CreatorCommunity( } else { null }, + audioUrl = audioUrl, content = content, price = price, date = date, 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 0307940..85c61b8 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 @@ -27,6 +27,9 @@ class CreatorCommunityController(private val service: CreatorCommunityService) { @PostMapping @PreAuthorize("hasRole('CREATOR')") fun createCommunityPost( + @Nullable + @RequestPart("audioFile") + audioFile: MultipartFile?, @Nullable @RequestPart("postImage") postImage: MultipartFile?, @@ -37,6 +40,7 @@ class CreatorCommunityController(private val service: CreatorCommunityService) { ApiResponse.ok( service.createCommunityPost( + audioFile = audioFile, postImage = postImage, requestString = requestString, member = member 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 49e22a7..6f3ffcf 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 @@ -64,6 +64,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact creatorCommunity.member.nickname, creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), creatorCommunity.imagePath, + creatorCommunity.audioPath, creatorCommunity.content, creatorCommunity.createdAt, creatorCommunity.isCommentAvailable, @@ -149,6 +150,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact creatorCommunity.member.nickname, creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), creatorCommunity.imagePath, + creatorCommunity.audioPath, creatorCommunity.content, creatorCommunity.createdAt, creatorCommunity.isCommentAvailable, @@ -179,6 +181,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact creatorCommunity.member.nickname, creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), creatorCommunity.imagePath, + creatorCommunity.audioPath, creatorCommunity.content, creatorCommunity.createdAt, creatorCommunity.isCommentAvailable, 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 cf429c1..11e3c72 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 @@ -2,6 +2,7 @@ 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.cloudfront.AudioContentCloudFront import kr.co.vividnext.sodalive.aws.s3.S3Uploader import kr.co.vividnext.sodalive.can.payment.CanPaymentService import kr.co.vividnext.sodalive.can.use.CanUsage @@ -41,22 +42,35 @@ class CreatorCommunityService( private val s3Uploader: S3Uploader, private val objectMapper: ObjectMapper, + private val audioContentCloudFront: AudioContentCloudFront, private val applicationEventPublisher: ApplicationEventPublisher, @Value("\${cloud.aws.s3.bucket}") private val imageBucket: String, + @Value("\${cloud.aws.s3.content-bucket}") + private val contentBucket: String, + @Value("\${cloud.aws.cloud-front.host}") private val imageHost: String ) { @Transactional - fun createCommunityPost(postImage: MultipartFile?, requestString: String, member: Member) { + fun createCommunityPost( + audioFile: MultipartFile?, + postImage: MultipartFile?, + requestString: String, + member: Member + ) { val request = objectMapper.readValue(requestString, CreateCommunityPostRequest::class.java) if (request.price > 0 && postImage == null) { throw SodaException("유료 게시글 등록을 위해서는 이미지가 필요합니다.") } + if (audioFile != null && postImage == null) { + throw SodaException("오디오 등록을 위해서는 이미지가 필요합니다.") + } + val post = CreatorCommunity( content = request.content, price = request.price, @@ -84,6 +98,20 @@ class CreatorCommunityService( post.imagePath = imagePath } + if (audioFile != null) { + val metadata = ObjectMetadata() + metadata.contentLength = audioFile.size + + val audioPath = s3Uploader.upload( + inputStream = audioFile.inputStream, + bucket = contentBucket, + filePath = "creator_community/${post.id}/${generateFileName(prefix = "${post.id}-audio")}.m4a", + metadata = metadata + ) + + post.audioPath = audioPath + } + applicationEventPublisher.publishEvent( FcmEvent( type = FcmEventType.CHANGE_NOTICE, @@ -186,8 +214,18 @@ class CreatorCommunityService( val existOrdered = useCanRepository.isExistOrdered(postId = it.id, memberId = memberId) + val audioUrl = if ((it.price <= 0 || existOrdered) && it.audioPath != null) { + audioContentCloudFront.generateSignedURL( + resourcePath = it.audioPath, + expirationTime = 1000 * 60 * 30 + ) + } else { + null + } + it.toCommunityPostListResponse( imageHost = imageHost, + audioUrl = audioUrl, date = getTimeAgoString(it.date), isLike = isLike, memberId = memberId, @@ -242,8 +280,18 @@ class CreatorCommunityService( val existOrdered = useCanRepository.isExistOrdered(postId = post.id, memberId = memberId) + val audioUrl = if ((post.price <= 0 || existOrdered) && post.audioPath != null) { + audioContentCloudFront.generateSignedURL( + resourcePath = post.audioPath, + expirationTime = 1000 * 60 * 30 + ) + } else { + null + } + return post.toCommunityPostListResponse( imageHost = imageHost, + audioUrl = audioUrl, date = getTimeAgoString(post.date), isLike = isLike, memberId = memberId, @@ -414,6 +462,7 @@ class CreatorCommunityService( it.toCommunityPostListResponse( imageHost = imageHost, + audioUrl = null, date = getTimeAgoString(it.date), isLike = isLike, memberId = memberId, @@ -480,8 +529,18 @@ class CreatorCommunityService( null } + val audioUrl = if (post.audioPath != null) { + audioContentCloudFront.generateSignedURL( + resourcePath = post.audioPath!!, + expirationTime = 1000 * 60 * 30 + ) + } else { + null + } + return post.toCommunityPostListResponse( imageHost = imageHost, + audioUrl = audioUrl, content = post.content, date = getTimeAgoString(post.createdAt!!), isLike = isLike, 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 b4b9b94..81a5f22 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 @@ -9,6 +9,7 @@ data class GetCommunityPostListResponse @QueryProjection constructor( val creatorNickname: String, val creatorProfileUrl: String, val imageUrl: String?, + val audioUrl: String?, val content: String, val price: Int, val date: 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 index ec0cb2d..8f69f6f 100644 --- 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 @@ -10,6 +10,7 @@ data class SelectCommunityPostResponse @QueryProjection constructor( val creatorNickname: String, val creatorProfileUrl: String, val imagePath: String?, + val audioPath: String?, val content: String, val date: LocalDateTime, val isCommentAvailable: Boolean, @@ -17,6 +18,7 @@ data class SelectCommunityPostResponse @QueryProjection constructor( ) { fun toCommunityPostListResponse( imageHost: String, + audioUrl: String?, date: String, isLike: Boolean, memberId: Long, @@ -35,6 +37,7 @@ data class SelectCommunityPostResponse @QueryProjection constructor( } else { null }, + audioUrl = audioUrl, content = if (price > 0 && memberId != creatorId) { if (existOrdered) { content