| @@ -52,9 +52,20 @@ interface AudioContentQueryRepository { | |||||||
|         cloudfrontHost: String, |         cloudfrontHost: String, | ||||||
|         theme: String = "", |         theme: String = "", | ||||||
|         isAdult: Boolean = false, |         isAdult: Boolean = false, | ||||||
|  |         offset: Long = 0, | ||||||
|         limit: Long = 20 |         limit: Long = 20 | ||||||
|     ): List<GetAudioContentMainItem> |     ): List<GetAudioContentMainItem> | ||||||
|  |  | ||||||
|  |     fun findByThemeFor2Weeks( | ||||||
|  |         cloudfrontHost: String, | ||||||
|  |         theme: String = "", | ||||||
|  |         isAdult: Boolean = false, | ||||||
|  |         offset: Long = 0, | ||||||
|  |         limit: Long = 20 | ||||||
|  |     ): List<GetAudioContentMainItem> | ||||||
|  |  | ||||||
|  |     fun totalCountNewContentFor2Weeks(theme: String, isAdult: Boolean): Int | ||||||
|  |  | ||||||
|     fun getNewContentUploadCreatorList( |     fun getNewContentUploadCreatorList( | ||||||
|         cloudfrontHost: String, |         cloudfrontHost: String, | ||||||
|         isAdult: Boolean = false |         isAdult: Boolean = false | ||||||
| @@ -215,6 +226,7 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) | |||||||
|         cloudfrontHost: String, |         cloudfrontHost: String, | ||||||
|         theme: String, |         theme: String, | ||||||
|         isAdult: Boolean, |         isAdult: Boolean, | ||||||
|  |         offset: Long, | ||||||
|         limit: Long |         limit: Long | ||||||
|     ): List<GetAudioContentMainItem> { |     ): List<GetAudioContentMainItem> { | ||||||
|         var where = audioContent.isActive.isTrue |         var where = audioContent.isActive.isTrue | ||||||
| @@ -243,6 +255,69 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) | |||||||
|             .innerJoin(audioContent.member, member) |             .innerJoin(audioContent.member, member) | ||||||
|             .innerJoin(audioContent.theme, audioContentTheme) |             .innerJoin(audioContent.theme, audioContentTheme) | ||||||
|             .where(where) |             .where(where) | ||||||
|  |             .offset(offset) | ||||||
|  |             .limit(limit) | ||||||
|  |             .orderBy(audioContent.createdAt.desc()) | ||||||
|  |             .fetch() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun totalCountNewContentFor2Weeks(theme: String, isAdult: Boolean): Int { | ||||||
|  |         var where = audioContent.isActive.isTrue | ||||||
|  |             .and(audioContent.createdAt.loe(LocalDateTime.now())) | ||||||
|  |  | ||||||
|  |         if (!isAdult) { | ||||||
|  |             where = where.and(audioContent.isAdult.isFalse) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (theme.isNotBlank()) { | ||||||
|  |             where = where.and(audioContentTheme.theme.eq(theme)) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return queryFactory | ||||||
|  |             .select(audioContent.id) | ||||||
|  |             .from(audioContent) | ||||||
|  |             .innerJoin(audioContent.member, member) | ||||||
|  |             .innerJoin(audioContent.theme, audioContentTheme) | ||||||
|  |             .where(where) | ||||||
|  |             .fetch() | ||||||
|  |             .size | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun findByThemeFor2Weeks( | ||||||
|  |         cloudfrontHost: String, | ||||||
|  |         theme: String, | ||||||
|  |         isAdult: Boolean, | ||||||
|  |         offset: Long, | ||||||
|  |         limit: Long | ||||||
|  |     ): List<GetAudioContentMainItem> { | ||||||
|  |         var where = audioContent.isActive.isTrue | ||||||
|  |             .and(audioContent.createdAt.loe(LocalDateTime.now())) | ||||||
|  |  | ||||||
|  |         if (!isAdult) { | ||||||
|  |             where = where.and(audioContent.isAdult.isFalse) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         if (theme.isNotBlank()) { | ||||||
|  |             where = where.and(audioContentTheme.theme.eq(theme)) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return queryFactory | ||||||
|  |             .select( | ||||||
|  |                 QGetAudioContentMainItem( | ||||||
|  |                     audioContent.id, | ||||||
|  |                     audioContent.coverImage.prepend("/").prepend(cloudfrontHost), | ||||||
|  |                     audioContent.title, | ||||||
|  |                     audioContent.isAdult, | ||||||
|  |                     member.id, | ||||||
|  |                     member.profileImage.prepend("/").prepend(cloudfrontHost), | ||||||
|  |                     member.nickname | ||||||
|  |                 ) | ||||||
|  |             ) | ||||||
|  |             .from(audioContent) | ||||||
|  |             .innerJoin(audioContent.member, member) | ||||||
|  |             .innerJoin(audioContent.theme, audioContentTheme) | ||||||
|  |             .where(where) | ||||||
|  |             .offset(offset) | ||||||
|             .limit(limit) |             .limit(limit) | ||||||
|             .orderBy(audioContent.createdAt.desc()) |             .orderBy(audioContent.createdAt.desc()) | ||||||
|             .fetch() |             .fetch() | ||||||
|   | |||||||
| @@ -28,9 +28,11 @@ import org.springframework.data.repository.findByIdOrNull | |||||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||||
| import org.springframework.transaction.annotation.Transactional | import org.springframework.transaction.annotation.Transactional | ||||||
| import org.springframework.web.multipart.MultipartFile | import org.springframework.web.multipart.MultipartFile | ||||||
|  | import java.text.SimpleDateFormat | ||||||
| import java.time.LocalDateTime | import java.time.LocalDateTime | ||||||
| import java.time.ZoneId | import java.time.ZoneId | ||||||
| import java.time.format.DateTimeFormatter | import java.time.format.DateTimeFormatter | ||||||
|  | import java.util.Locale | ||||||
|  |  | ||||||
| @Service | @Service | ||||||
| @Transactional(readOnly = true) | @Transactional(readOnly = true) | ||||||
| @@ -137,6 +139,9 @@ class AudioContentService( | |||||||
|         // request 내용 파싱 |         // request 내용 파싱 | ||||||
|         val request = objectMapper.readValue(requestString, CreateAudioContentRequest::class.java) |         val request = objectMapper.readValue(requestString, CreateAudioContentRequest::class.java) | ||||||
|  |  | ||||||
|  |         // 미리듣기 시간 체크 | ||||||
|  |         validatePreviewTime(request.previewStartTime, request.previewEndTime) | ||||||
|  |  | ||||||
|         // contentFile 체크 |         // contentFile 체크 | ||||||
|         if (contentFile == null && request.type == AudioContentType.INDIVIDUAL) { |         if (contentFile == null && request.type == AudioContentType.INDIVIDUAL) { | ||||||
|             throw SodaException("콘텐츠를 선택해 주세요.") |             throw SodaException("콘텐츠를 선택해 주세요.") | ||||||
| @@ -228,6 +233,11 @@ class AudioContentService( | |||||||
|             metadata.contentLength = contentFile.size |             metadata.contentLength = contentFile.size | ||||||
|             metadata.addUserMetadata("generate_preview", "true") |             metadata.addUserMetadata("generate_preview", "true") | ||||||
|  |  | ||||||
|  |             if (request.previewStartTime != null && request.previewEndTime != null) { | ||||||
|  |                 metadata.addUserMetadata("preview_start_time", request.previewStartTime) | ||||||
|  |                 metadata.addUserMetadata("preview_end_time", request.previewEndTime) | ||||||
|  |             } | ||||||
|  |  | ||||||
|             val contentPath = s3Uploader.upload( |             val contentPath = s3Uploader.upload( | ||||||
|                 inputStream = contentFile.inputStream, |                 inputStream = contentFile.inputStream, | ||||||
|                 bucket = audioContentBucket, |                 bucket = audioContentBucket, | ||||||
| @@ -253,6 +263,64 @@ class AudioContentService( | |||||||
|         return CreateAudioContentResponse(contentId = audioContent.id!!) |         return CreateAudioContentResponse(contentId = audioContent.id!!) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private fun validatePreviewTime(previewStartTime: String?, previewEndTime: String?) { | ||||||
|  |         if (previewStartTime != null && previewEndTime != null) { | ||||||
|  |             val startTimeArray = previewStartTime.split(":") | ||||||
|  |             if (startTimeArray.size != 3) { | ||||||
|  |                 throw SodaException("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다") | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             for (time in startTimeArray) { | ||||||
|  |                 if (time.length != 2) { | ||||||
|  |                     throw SodaException("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다") | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             val endTimeArray = previewEndTime.split(":") | ||||||
|  |             if (endTimeArray.size != 3) { | ||||||
|  |                 throw SodaException("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다") | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             for (time in endTimeArray) { | ||||||
|  |                 if (time.length != 2) { | ||||||
|  |                     throw SodaException("미리 듣기 시간 형식은 00:30:00 과 같아야 합니다") | ||||||
|  |                 } | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             val timeDifference = timeDifference(previewStartTime, previewEndTime) | ||||||
|  |  | ||||||
|  |             if (timeDifference < 30000) { | ||||||
|  |                 throw SodaException("미리 듣기의 최소 시간은 30초 입니다.") | ||||||
|  |             } | ||||||
|  |         } else { | ||||||
|  |             if (previewStartTime != null || previewEndTime != null) { | ||||||
|  |                 throw SodaException("미리 듣기 시작 시간과 종료 시간 둘 다 입력을 하거나 둘 다 입력 하지 않아야 합니다.") | ||||||
|  |             } | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     private fun timeDifference(startTime: String, endTime: String): Long { | ||||||
|  |         try { | ||||||
|  |             // Define a date format for parsing the times | ||||||
|  |             val dateFormat = SimpleDateFormat("HH:mm:ss", Locale.KOREAN) | ||||||
|  |  | ||||||
|  |             // Parse the input times into Date objects | ||||||
|  |             val date1 = dateFormat.parse(startTime) | ||||||
|  |             val date2 = dateFormat.parse(endTime) | ||||||
|  |  | ||||||
|  |             // Check if either date is null | ||||||
|  |             if (date1 == null || date2 == null) { | ||||||
|  |                 return 0 | ||||||
|  |             } | ||||||
|  |  | ||||||
|  |             // Check if the time difference is greater than 30 seconds (30000 milliseconds) | ||||||
|  |             return date2.time - date1.time | ||||||
|  |         } catch (e: Exception) { | ||||||
|  |             // Handle invalid time formats or parsing errors | ||||||
|  |             return 0 | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     @Transactional |     @Transactional | ||||||
|     fun uploadComplete(contentId: Long, content: String, duration: String) { |     fun uploadComplete(contentId: Long, content: String, duration: String) { | ||||||
|         val keyFileName = content.split("/").last() |         val keyFileName = content.split("/").last() | ||||||
|   | |||||||
| @@ -10,5 +10,7 @@ data class CreateAudioContentRequest( | |||||||
|     val isGeneratePreview: Boolean = true, |     val isGeneratePreview: Boolean = true, | ||||||
|     val isCommentAvailable: Boolean = false, |     val isCommentAvailable: Boolean = false, | ||||||
|     val type: AudioContentType = AudioContentType.INDIVIDUAL, |     val type: AudioContentType = AudioContentType.INDIVIDUAL, | ||||||
|     val childIds: List<Long>? = null |     val childIds: List<Long>? = null, | ||||||
|  |     val previewStartTime: String? = null, | ||||||
|  |     val previewEndTime: String? = null | ||||||
| ) | ) | ||||||
|   | |||||||
| @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.content.main | |||||||
| import kr.co.vividnext.sodalive.common.ApiResponse | import kr.co.vividnext.sodalive.common.ApiResponse | ||||||
| import kr.co.vividnext.sodalive.common.SodaException | import kr.co.vividnext.sodalive.common.SodaException | ||||||
| import kr.co.vividnext.sodalive.member.Member | import kr.co.vividnext.sodalive.member.Member | ||||||
|  | import org.springframework.data.domain.Pageable | ||||||
| import org.springframework.security.core.annotation.AuthenticationPrincipal | import org.springframework.security.core.annotation.AuthenticationPrincipal | ||||||
| import org.springframework.web.bind.annotation.GetMapping | import org.springframework.web.bind.annotation.GetMapping | ||||||
| import org.springframework.web.bind.annotation.RequestMapping | import org.springframework.web.bind.annotation.RequestMapping | ||||||
| @@ -25,10 +26,31 @@ class AudioContentMainController(private val service: AudioContentMainService) { | |||||||
|     @GetMapping("/new") |     @GetMapping("/new") | ||||||
|     fun getNewContentByTheme( |     fun getNewContentByTheme( | ||||||
|         @RequestParam("theme") theme: String, |         @RequestParam("theme") theme: String, | ||||||
|  |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, | ||||||
|  |         pageable: Pageable | ||||||
|  |     ) = run { | ||||||
|  |         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||||
|  |  | ||||||
|  |         ApiResponse.ok(service.getNewContentByTheme(theme, member, pageable)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @GetMapping("/theme") | ||||||
|  |     fun getThemeList( | ||||||
|         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||||
|     ) = run { |     ) = run { | ||||||
|         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") |         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||||
|  |  | ||||||
|         ApiResponse.ok(service.getNewContentByTheme(theme, member)) |         ApiResponse.ok(service.getThemeList(member)) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     @GetMapping("/new/all") | ||||||
|  |     fun getNewContentAllByTheme( | ||||||
|  |         @RequestParam("theme") theme: String, | ||||||
|  |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, | ||||||
|  |         pageable: Pageable | ||||||
|  |     ) = run { | ||||||
|  |         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||||
|  |  | ||||||
|  |         ApiResponse.ok(service.getNewContentFor2WeeksByTheme(theme, member, pageable)) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -10,6 +10,7 @@ import kr.co.vividnext.sodalive.event.EventItem | |||||||
| import kr.co.vividnext.sodalive.member.Member | import kr.co.vividnext.sodalive.member.Member | ||||||
| import kr.co.vividnext.sodalive.member.block.BlockMemberRepository | import kr.co.vividnext.sodalive.member.block.BlockMemberRepository | ||||||
| import org.springframework.beans.factory.annotation.Value | import org.springframework.beans.factory.annotation.Value | ||||||
|  | import org.springframework.data.domain.Pageable | ||||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||||
|  |  | ||||||
| @Service | @Service | ||||||
| @@ -104,6 +105,7 @@ class AudioContentMainService( | |||||||
|             .asSequence() |             .asSequence() | ||||||
|             .map { |             .map { | ||||||
|                 GetAudioContentCurationResponse( |                 GetAudioContentCurationResponse( | ||||||
|  |                     curationId = it.id!!, | ||||||
|                     title = it.title, |                     title = it.title, | ||||||
|                     description = it.description, |                     description = it.description, | ||||||
|                     contents = repository.findAudioContentByCurationId( |                     contents = repository.findAudioContentByCurationId( | ||||||
| @@ -134,14 +136,33 @@ class AudioContentMainService( | |||||||
|         ) |         ) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun getNewContentByTheme(theme: String, member: Member): List<GetAudioContentMainItem> { |     fun getThemeList(member: Member): List<String> { | ||||||
|  |         return audioContentThemeRepository.getActiveThemeOfContent(isAdult = member.auth != null) | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun getNewContentByTheme(theme: String, member: Member, pageable: Pageable): List<GetAudioContentMainItem> { | ||||||
|         return repository.findByTheme( |         return repository.findByTheme( | ||||||
|             cloudfrontHost = imageHost, |             cloudfrontHost = imageHost, | ||||||
|             theme = theme, |             theme = theme, | ||||||
|             isAdult = member.auth != null |             isAdult = member.auth != null, | ||||||
|  |             offset = pageable.offset, | ||||||
|  |             limit = pageable.pageSize.toLong() | ||||||
|         ) |         ) | ||||||
|             .asSequence() |             .asSequence() | ||||||
|             .filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) } |             .filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) } | ||||||
|             .toList() |             .toList() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     fun getNewContentFor2WeeksByTheme(theme: String, member: Member, pageable: Pageable): GetNewContentAllResponse { | ||||||
|  |         val totalCount = repository.totalCountNewContentFor2Weeks(theme, isAdult = member.auth != null) | ||||||
|  |         val items = repository.findByThemeFor2Weeks( | ||||||
|  |             cloudfrontHost = imageHost, | ||||||
|  |             theme = theme, | ||||||
|  |             isAdult = member.auth != null, | ||||||
|  |             offset = pageable.offset, | ||||||
|  |             limit = pageable.pageSize.toLong() | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         return GetNewContentAllResponse(totalCount, items) | ||||||
|  |     } | ||||||
| } | } | ||||||
|   | |||||||
| @@ -0,0 +1,6 @@ | |||||||
|  | package kr.co.vividnext.sodalive.content.main | ||||||
|  |  | ||||||
|  | data class GetNewContentAllResponse( | ||||||
|  |     val totalCount: Int, | ||||||
|  |     val items: List<GetAudioContentMainItem> | ||||||
|  | ) | ||||||
| @@ -0,0 +1,29 @@ | |||||||
|  | package kr.co.vividnext.sodalive.content.main.curation | ||||||
|  |  | ||||||
|  | import kr.co.vividnext.sodalive.common.ApiResponse | ||||||
|  | import kr.co.vividnext.sodalive.common.SodaException | ||||||
|  | import kr.co.vividnext.sodalive.content.SortType | ||||||
|  | import kr.co.vividnext.sodalive.member.Member | ||||||
|  | import org.springframework.data.domain.Pageable | ||||||
|  | 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.RequestMapping | ||||||
|  | import org.springframework.web.bind.annotation.RequestParam | ||||||
|  | import org.springframework.web.bind.annotation.RestController | ||||||
|  |  | ||||||
|  | @RestController | ||||||
|  | @RequestMapping("/audio-content/curation") | ||||||
|  | class AudioContentCurationController(private val service: AudioContentCurationService) { | ||||||
|  |     @GetMapping("/{id}") | ||||||
|  |     fun getCurationContent( | ||||||
|  |         @PathVariable id: Long, | ||||||
|  |         @RequestParam("sort-type", required = false) sortType: SortType = SortType.NEWEST, | ||||||
|  |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, | ||||||
|  |         pageable: Pageable | ||||||
|  |     ) = run { | ||||||
|  |         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||||
|  |  | ||||||
|  |         ApiResponse.ok(service.getCurationContent(id, sortType, member, pageable)) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,58 @@ | |||||||
|  | package kr.co.vividnext.sodalive.content.main.curation | ||||||
|  |  | ||||||
|  | import com.querydsl.jpa.impl.JPAQueryFactory | ||||||
|  | import kr.co.vividnext.sodalive.content.AudioContent | ||||||
|  | import kr.co.vividnext.sodalive.content.QAudioContent.audioContent | ||||||
|  | import kr.co.vividnext.sodalive.content.SortType | ||||||
|  | import org.springframework.stereotype.Repository | ||||||
|  |  | ||||||
|  | @Repository | ||||||
|  | class AudioContentCurationQueryRepository(private val queryFactory: JPAQueryFactory) { | ||||||
|  |     fun findTotalCountByCurationId(curationId: Long, isAdult: Boolean = false): Int { | ||||||
|  |         var where = audioContent.isActive.isTrue | ||||||
|  |             .and(audioContent.curation.id.eq(curationId)) | ||||||
|  |  | ||||||
|  |         if (!isAdult) { | ||||||
|  |             where = where.and(audioContent.isAdult.isFalse) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return queryFactory | ||||||
|  |             .select(audioContent.id) | ||||||
|  |             .from(audioContent) | ||||||
|  |             .where(where) | ||||||
|  |             .fetch() | ||||||
|  |             .size | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     fun findByCurationId( | ||||||
|  |         curationId: Long, | ||||||
|  |         isAdult: Boolean = false, | ||||||
|  |         sortType: SortType = SortType.NEWEST, | ||||||
|  |         offset: Long = 0, | ||||||
|  |         limit: Long = 10 | ||||||
|  |     ): List<AudioContent> { | ||||||
|  |         val orderBy = when (sortType) { | ||||||
|  |             SortType.NEWEST -> audioContent.createdAt.desc() | ||||||
|  |             SortType.PRICE_HIGH -> audioContent.price.desc() | ||||||
|  |             SortType.PRICE_LOW -> audioContent.price.asc() | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         var where = audioContent.isActive.isTrue | ||||||
|  |             .and(audioContent.member.isNotNull) | ||||||
|  |             .and(audioContent.duration.isNotNull) | ||||||
|  |             .and(audioContent.member.isActive.isTrue) | ||||||
|  |             .and(audioContent.curation.id.eq(curationId)) | ||||||
|  |  | ||||||
|  |         if (!isAdult) { | ||||||
|  |             where = where.and(audioContent.isAdult.isFalse) | ||||||
|  |         } | ||||||
|  |  | ||||||
|  |         return queryFactory | ||||||
|  |             .selectFrom(audioContent) | ||||||
|  |             .where(where) | ||||||
|  |             .offset(offset) | ||||||
|  |             .limit(limit) | ||||||
|  |             .orderBy(orderBy) | ||||||
|  |             .fetch() | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -0,0 +1,73 @@ | |||||||
|  | package kr.co.vividnext.sodalive.content.main.curation | ||||||
|  |  | ||||||
|  | import kr.co.vividnext.sodalive.content.GetAudioContentListItem | ||||||
|  | import kr.co.vividnext.sodalive.content.SortType | ||||||
|  | import kr.co.vividnext.sodalive.content.comment.AudioContentCommentRepository | ||||||
|  | import kr.co.vividnext.sodalive.content.like.AudioContentLikeRepository | ||||||
|  | import kr.co.vividnext.sodalive.member.Member | ||||||
|  | import kr.co.vividnext.sodalive.member.block.BlockMemberRepository | ||||||
|  | import org.springframework.beans.factory.annotation.Value | ||||||
|  | import org.springframework.data.domain.Pageable | ||||||
|  | import org.springframework.stereotype.Service | ||||||
|  |  | ||||||
|  | @Service | ||||||
|  | class AudioContentCurationService( | ||||||
|  |     private val repository: AudioContentCurationQueryRepository, | ||||||
|  |     private val blockMemberRepository: BlockMemberRepository, | ||||||
|  |     private val commentRepository: AudioContentCommentRepository, | ||||||
|  |     private val audioContentLikeRepository: AudioContentLikeRepository, | ||||||
|  |  | ||||||
|  |     @Value("\${cloud.aws.cloud-front.host}") | ||||||
|  |     private val cloudFrontHost: String | ||||||
|  | ) { | ||||||
|  |     fun getCurationContent( | ||||||
|  |         curationId: Long, | ||||||
|  |         sortType: SortType, | ||||||
|  |         member: Member, | ||||||
|  |         pageable: Pageable | ||||||
|  |     ): GetCurationContentResponse { | ||||||
|  |         val totalCount = repository.findTotalCountByCurationId(curationId, member.auth != null) | ||||||
|  |  | ||||||
|  |         val audioContentList = repository.findByCurationId( | ||||||
|  |             curationId = curationId, | ||||||
|  |             isAdult = member.auth != null, | ||||||
|  |             sortType = sortType, | ||||||
|  |             offset = pageable.offset, | ||||||
|  |             limit = pageable.pageSize.toLong() | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         val items = audioContentList | ||||||
|  |             .asSequence() | ||||||
|  |             .filter { content -> | ||||||
|  |                 !blockMemberRepository.isBlocked( | ||||||
|  |                     blockedMemberId = member.id!!, | ||||||
|  |                     memberId = content.member!!.id!! | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             .map { | ||||||
|  |                 val commentCount = commentRepository | ||||||
|  |                     .totalCountCommentByContentId(it.id!!) | ||||||
|  |  | ||||||
|  |                 val likeCount = audioContentLikeRepository | ||||||
|  |                     .totalCountAudioContentLike(it.id!!) | ||||||
|  |  | ||||||
|  |                 GetAudioContentListItem( | ||||||
|  |                     contentId = it.id!!, | ||||||
|  |                     coverImageUrl = "$cloudFrontHost/${it.coverImage!!}", | ||||||
|  |                     title = it.title, | ||||||
|  |                     price = it.price, | ||||||
|  |                     themeStr = it.theme!!.theme, | ||||||
|  |                     duration = it.duration, | ||||||
|  |                     likeCount = likeCount, | ||||||
|  |                     commentCount = commentCount, | ||||||
|  |                     isAdult = it.isAdult | ||||||
|  |                 ) | ||||||
|  |             } | ||||||
|  |             .toList() | ||||||
|  |  | ||||||
|  |         return GetCurationContentResponse( | ||||||
|  |             totalCount = totalCount, | ||||||
|  |             items = items | ||||||
|  |         ) | ||||||
|  |     } | ||||||
|  | } | ||||||
| @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.content.main.curation | |||||||
| import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem | import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem | ||||||
|  |  | ||||||
| data class GetAudioContentCurationResponse( | data class GetAudioContentCurationResponse( | ||||||
|  |     val curationId: Long, | ||||||
|     val title: String, |     val title: String, | ||||||
|     val description: String, |     val description: String, | ||||||
|     val contents: List<GetAudioContentMainItem> |     val contents: List<GetAudioContentMainItem> | ||||||
|   | |||||||
| @@ -0,0 +1,8 @@ | |||||||
|  | package kr.co.vividnext.sodalive.content.main.curation | ||||||
|  |  | ||||||
|  | import kr.co.vividnext.sodalive.content.GetAudioContentListItem | ||||||
|  |  | ||||||
|  | data class GetCurationContentResponse( | ||||||
|  |     val totalCount: Int, | ||||||
|  |     val items: List<GetAudioContentListItem> | ||||||
|  | ) | ||||||
		Reference in New Issue
	
	Block a user