Merge pull request '크리에이터 커뮤니티' (#201) from test into main
Reviewed-on: #201
This commit is contained in:
		| @@ -17,6 +17,8 @@ data class CreatorCommunity( | |||||||
|     var isCommentAvailable: Boolean, |     var isCommentAvailable: Boolean, | ||||||
|     var isAdult: Boolean, |     var isAdult: Boolean, | ||||||
|     @Column(nullable = true) |     @Column(nullable = true) | ||||||
|  |     var audioPath: String? = null, | ||||||
|  |     @Column(nullable = true) | ||||||
|     var imagePath: String? = null, |     var imagePath: String? = null, | ||||||
|     var isActive: Boolean = true |     var isActive: Boolean = true | ||||||
| ) : BaseEntity() { | ) : BaseEntity() { | ||||||
| @@ -26,6 +28,7 @@ data class CreatorCommunity( | |||||||
|  |  | ||||||
|     fun toCommunityPostListResponse( |     fun toCommunityPostListResponse( | ||||||
|         imageHost: String, |         imageHost: String, | ||||||
|  |         audioUrl: String?, | ||||||
|         content: String, |         content: String, | ||||||
|         date: String, |         date: String, | ||||||
|         isLike: Boolean, |         isLike: Boolean, | ||||||
| @@ -44,6 +47,7 @@ data class CreatorCommunity( | |||||||
|             } else { |             } else { | ||||||
|                 null |                 null | ||||||
|             }, |             }, | ||||||
|  |             audioUrl = audioUrl, | ||||||
|             content = content, |             content = content, | ||||||
|             price = price, |             price = price, | ||||||
|             date = date, |             date = date, | ||||||
|   | |||||||
| @@ -27,6 +27,9 @@ class CreatorCommunityController(private val service: CreatorCommunityService) { | |||||||
|     @PostMapping |     @PostMapping | ||||||
|     @PreAuthorize("hasRole('CREATOR')") |     @PreAuthorize("hasRole('CREATOR')") | ||||||
|     fun createCommunityPost( |     fun createCommunityPost( | ||||||
|  |         @Nullable | ||||||
|  |         @RequestPart("audioFile") | ||||||
|  |         audioFile: MultipartFile?, | ||||||
|         @Nullable |         @Nullable | ||||||
|         @RequestPart("postImage") |         @RequestPart("postImage") | ||||||
|         postImage: MultipartFile?, |         postImage: MultipartFile?, | ||||||
| @@ -37,6 +40,7 @@ class CreatorCommunityController(private val service: CreatorCommunityService) { | |||||||
|  |  | ||||||
|         ApiResponse.ok( |         ApiResponse.ok( | ||||||
|             service.createCommunityPost( |             service.createCommunityPost( | ||||||
|  |                 audioFile = audioFile, | ||||||
|                 postImage = postImage, |                 postImage = postImage, | ||||||
|                 requestString = requestString, |                 requestString = requestString, | ||||||
|                 member = member |                 member = member | ||||||
|   | |||||||
| @@ -64,6 +64,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact | |||||||
|                     creatorCommunity.member.nickname, |                     creatorCommunity.member.nickname, | ||||||
|                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), |                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), | ||||||
|                     creatorCommunity.imagePath, |                     creatorCommunity.imagePath, | ||||||
|  |                     creatorCommunity.audioPath, | ||||||
|                     creatorCommunity.content, |                     creatorCommunity.content, | ||||||
|                     creatorCommunity.createdAt, |                     creatorCommunity.createdAt, | ||||||
|                     creatorCommunity.isCommentAvailable, |                     creatorCommunity.isCommentAvailable, | ||||||
| @@ -149,6 +150,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact | |||||||
|                     creatorCommunity.member.nickname, |                     creatorCommunity.member.nickname, | ||||||
|                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), |                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), | ||||||
|                     creatorCommunity.imagePath, |                     creatorCommunity.imagePath, | ||||||
|  |                     creatorCommunity.audioPath, | ||||||
|                     creatorCommunity.content, |                     creatorCommunity.content, | ||||||
|                     creatorCommunity.createdAt, |                     creatorCommunity.createdAt, | ||||||
|                     creatorCommunity.isCommentAvailable, |                     creatorCommunity.isCommentAvailable, | ||||||
| @@ -179,6 +181,7 @@ class CreatorCommunityQueryRepositoryImpl(private val queryFactory: JPAQueryFact | |||||||
|                     creatorCommunity.member.nickname, |                     creatorCommunity.member.nickname, | ||||||
|                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), |                     creatorCommunity.member.profileImage.coalesce("profile/default_profile.png"), | ||||||
|                     creatorCommunity.imagePath, |                     creatorCommunity.imagePath, | ||||||
|  |                     creatorCommunity.audioPath, | ||||||
|                     creatorCommunity.content, |                     creatorCommunity.content, | ||||||
|                     creatorCommunity.createdAt, |                     creatorCommunity.createdAt, | ||||||
|                     creatorCommunity.isCommentAvailable, |                     creatorCommunity.isCommentAvailable, | ||||||
|   | |||||||
| @@ -2,6 +2,7 @@ package kr.co.vividnext.sodalive.explorer.profile.creatorCommunity | |||||||
|  |  | ||||||
| import com.amazonaws.services.s3.model.ObjectMetadata | import com.amazonaws.services.s3.model.ObjectMetadata | ||||||
| import com.fasterxml.jackson.databind.ObjectMapper | 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.aws.s3.S3Uploader | ||||||
| import kr.co.vividnext.sodalive.can.payment.CanPaymentService | import kr.co.vividnext.sodalive.can.payment.CanPaymentService | ||||||
| import kr.co.vividnext.sodalive.can.use.CanUsage | import kr.co.vividnext.sodalive.can.use.CanUsage | ||||||
| @@ -41,22 +42,35 @@ class CreatorCommunityService( | |||||||
|  |  | ||||||
|     private val s3Uploader: S3Uploader, |     private val s3Uploader: S3Uploader, | ||||||
|     private val objectMapper: ObjectMapper, |     private val objectMapper: ObjectMapper, | ||||||
|  |     private val audioContentCloudFront: AudioContentCloudFront, | ||||||
|     private val applicationEventPublisher: ApplicationEventPublisher, |     private val applicationEventPublisher: ApplicationEventPublisher, | ||||||
|  |  | ||||||
|     @Value("\${cloud.aws.s3.bucket}") |     @Value("\${cloud.aws.s3.bucket}") | ||||||
|     private val imageBucket: String, |     private val imageBucket: String, | ||||||
|  |  | ||||||
|  |     @Value("\${cloud.aws.s3.content-bucket}") | ||||||
|  |     private val contentBucket: String, | ||||||
|  |  | ||||||
|     @Value("\${cloud.aws.cloud-front.host}") |     @Value("\${cloud.aws.cloud-front.host}") | ||||||
|     private val imageHost: String |     private val imageHost: String | ||||||
| ) { | ) { | ||||||
|     @Transactional |     @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) |         val request = objectMapper.readValue(requestString, CreateCommunityPostRequest::class.java) | ||||||
|  |  | ||||||
|         if (request.price > 0 && postImage == null) { |         if (request.price > 0 && postImage == null) { | ||||||
|             throw SodaException("유료 게시글 등록을 위해서는 이미지가 필요합니다.") |             throw SodaException("유료 게시글 등록을 위해서는 이미지가 필요합니다.") | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         if (audioFile != null && postImage == null) { | ||||||
|  |             throw SodaException("오디오 등록을 위해서는 이미지가 필요합니다.") | ||||||
|  |         } | ||||||
|  |  | ||||||
|         val post = CreatorCommunity( |         val post = CreatorCommunity( | ||||||
|             content = request.content, |             content = request.content, | ||||||
|             price = request.price, |             price = request.price, | ||||||
| @@ -84,6 +98,20 @@ class CreatorCommunityService( | |||||||
|             post.imagePath = imagePath |             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( |         applicationEventPublisher.publishEvent( | ||||||
|             FcmEvent( |             FcmEvent( | ||||||
|                 type = FcmEventType.CHANGE_NOTICE, |                 type = FcmEventType.CHANGE_NOTICE, | ||||||
| @@ -186,8 +214,18 @@ class CreatorCommunityService( | |||||||
|  |  | ||||||
|                 val existOrdered = useCanRepository.isExistOrdered(postId = it.id, memberId = memberId) |                 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( |                 it.toCommunityPostListResponse( | ||||||
|                     imageHost = imageHost, |                     imageHost = imageHost, | ||||||
|  |                     audioUrl = audioUrl, | ||||||
|                     date = getTimeAgoString(it.date), |                     date = getTimeAgoString(it.date), | ||||||
|                     isLike = isLike, |                     isLike = isLike, | ||||||
|                     memberId = memberId, |                     memberId = memberId, | ||||||
| @@ -242,8 +280,18 @@ class CreatorCommunityService( | |||||||
|  |  | ||||||
|         val existOrdered = useCanRepository.isExistOrdered(postId = post.id, memberId = memberId) |         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( |         return post.toCommunityPostListResponse( | ||||||
|             imageHost = imageHost, |             imageHost = imageHost, | ||||||
|  |             audioUrl = audioUrl, | ||||||
|             date = getTimeAgoString(post.date), |             date = getTimeAgoString(post.date), | ||||||
|             isLike = isLike, |             isLike = isLike, | ||||||
|             memberId = memberId, |             memberId = memberId, | ||||||
| @@ -414,6 +462,7 @@ class CreatorCommunityService( | |||||||
|  |  | ||||||
|                 it.toCommunityPostListResponse( |                 it.toCommunityPostListResponse( | ||||||
|                     imageHost = imageHost, |                     imageHost = imageHost, | ||||||
|  |                     audioUrl = null, | ||||||
|                     date = getTimeAgoString(it.date), |                     date = getTimeAgoString(it.date), | ||||||
|                     isLike = isLike, |                     isLike = isLike, | ||||||
|                     memberId = memberId, |                     memberId = memberId, | ||||||
| @@ -480,8 +529,18 @@ class CreatorCommunityService( | |||||||
|             null |             null | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  |         val audioUrl = if (post.audioPath != null) { | ||||||
|  |             audioContentCloudFront.generateSignedURL( | ||||||
|  |                 resourcePath = post.audioPath!!, | ||||||
|  |                 expirationTime = 1000 * 60 * 30 | ||||||
|  |             ) | ||||||
|  |         } else { | ||||||
|  |             null | ||||||
|  |         } | ||||||
|  |  | ||||||
|         return post.toCommunityPostListResponse( |         return post.toCommunityPostListResponse( | ||||||
|             imageHost = imageHost, |             imageHost = imageHost, | ||||||
|  |             audioUrl = audioUrl, | ||||||
|             content = post.content, |             content = post.content, | ||||||
|             date = getTimeAgoString(post.createdAt!!), |             date = getTimeAgoString(post.createdAt!!), | ||||||
|             isLike = isLike, |             isLike = isLike, | ||||||
|   | |||||||
| @@ -9,6 +9,7 @@ data class GetCommunityPostListResponse @QueryProjection constructor( | |||||||
|     val creatorNickname: String, |     val creatorNickname: String, | ||||||
|     val creatorProfileUrl: String, |     val creatorProfileUrl: String, | ||||||
|     val imageUrl: String?, |     val imageUrl: String?, | ||||||
|  |     val audioUrl: String?, | ||||||
|     val content: String, |     val content: String, | ||||||
|     val price: Int, |     val price: Int, | ||||||
|     val date: String, |     val date: String, | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ data class SelectCommunityPostResponse @QueryProjection constructor( | |||||||
|     val creatorNickname: String, |     val creatorNickname: String, | ||||||
|     val creatorProfileUrl: String, |     val creatorProfileUrl: String, | ||||||
|     val imagePath: String?, |     val imagePath: String?, | ||||||
|  |     val audioPath: String?, | ||||||
|     val content: String, |     val content: String, | ||||||
|     val date: LocalDateTime, |     val date: LocalDateTime, | ||||||
|     val isCommentAvailable: Boolean, |     val isCommentAvailable: Boolean, | ||||||
| @@ -17,6 +18,7 @@ data class SelectCommunityPostResponse @QueryProjection constructor( | |||||||
| ) { | ) { | ||||||
|     fun toCommunityPostListResponse( |     fun toCommunityPostListResponse( | ||||||
|         imageHost: String, |         imageHost: String, | ||||||
|  |         audioUrl: String?, | ||||||
|         date: String, |         date: String, | ||||||
|         isLike: Boolean, |         isLike: Boolean, | ||||||
|         memberId: Long, |         memberId: Long, | ||||||
| @@ -35,6 +37,7 @@ data class SelectCommunityPostResponse @QueryProjection constructor( | |||||||
|             } else { |             } else { | ||||||
|                 null |                 null | ||||||
|             }, |             }, | ||||||
|  |             audioUrl = audioUrl, | ||||||
|             content = if (price > 0 && memberId != creatorId) { |             content = if (price > 0 && memberId != creatorId) { | ||||||
|                 if (existOrdered) { |                 if (existOrdered) { | ||||||
|                     content |                     content | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user