diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt index c484bd9..f7a02fb 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt @@ -62,11 +62,18 @@ interface AudioContentQueryRepository { cloudfrontHost: String, memberId: Long, theme: String = "", + sortType: SortType = SortType.NEWEST, isAdult: Boolean = false, offset: Long = 0, limit: Long = 20 ): List + fun totalCountByTheme( + memberId: Long, + theme: String = "", + isAdult: Boolean = false + ): Int + fun findByThemeFor2Weeks( cloudfrontHost: String, memberId: Long, @@ -317,10 +324,17 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) cloudfrontHost: String, memberId: Long, theme: String, + sortType: SortType, isAdult: Boolean, offset: Long, limit: Long ): List { + val orderBy = when (sortType) { + SortType.NEWEST -> audioContent.releaseDate.desc() + SortType.PRICE_HIGH -> audioContent.price.desc() + SortType.PRICE_LOW -> audioContent.price.asc() + } + var where = audioContent.isActive.isTrue .and( audioContent.releaseDate.isNull @@ -344,7 +358,9 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) audioContent.title, member.id, member.profileImage.prepend("/").prepend(cloudfrontHost), - member.nickname + member.nickname, + audioContent.price, + audioContent.duration ) ) .from(audioContent) @@ -353,10 +369,36 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) .where(where) .offset(offset) .limit(limit) - .orderBy(audioContent.releaseDate.desc()) + .orderBy(orderBy) .fetch() } + override fun totalCountByTheme(memberId: Long, theme: String, isAdult: Boolean): Int { + var where = audioContent.isActive.isTrue + .and( + audioContent.releaseDate.isNull + .or(audioContent.releaseDate.loe(LocalDateTime.now())) + .or(audioContent.member.id.eq(memberId)) + ) + + 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 totalCountNewContentFor2Weeks(theme: String, memberId: Long, isAdult: Boolean): Int { var where = audioContent.isActive.isTrue .and(audioContent.releaseDate.goe(LocalDateTime.now().minusWeeks(2))) @@ -416,7 +458,9 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) audioContent.title, member.id, member.profileImage.prepend("/").prepend(cloudfrontHost), - member.nickname + member.nickname, + audioContent.price, + audioContent.duration ) ) .from(audioContent) @@ -519,7 +563,9 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) member.profileImage .prepend("/") .prepend(cloudfrontHost), - member.nickname + member.nickname, + audioContent.price, + audioContent.duration ) ) .from(audioContent) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainItem.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainItem.kt index 93e884d..a329cd4 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainItem.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainItem.kt @@ -9,5 +9,7 @@ data class GetAudioContentMainItem @QueryProjection constructor( @JsonProperty("title") val title: String, @JsonProperty("creatorId") val creatorId: Long, @JsonProperty("creatorProfileImageUrl") val creatorProfileImageUrl: String, - @JsonProperty("creatorNickname") val creatorNickname: String + @JsonProperty("creatorNickname") val creatorNickname: String, + @JsonProperty("price") val price: Int, + @JsonProperty("duration") val duration: String ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainResponse.kt deleted file mode 100644 index 656e54e..0000000 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/GetAudioContentMainResponse.kt +++ /dev/null @@ -1,16 +0,0 @@ -package kr.co.vividnext.sodalive.content.main - -import com.fasterxml.jackson.annotation.JsonProperty -import kr.co.vividnext.sodalive.content.main.banner.GetAudioContentBannerResponse -import kr.co.vividnext.sodalive.content.main.curation.GetAudioContentCurationResponse - -data class GetAudioContentMainResponse( - @JsonProperty("newContentUploadCreatorList") val newContentUploadCreatorList: List, - @JsonProperty("bannerList") val bannerList: List, - @JsonProperty("orderList") val orderList: List, - @JsonProperty("themeList") val themeList: List, - @JsonProperty("newContentList") val newContentList: List, - @JsonProperty("curationList") val curationList: List, - @JsonProperty("contentRankingSortTypeList") val contentRankingSortTypeList: List, - @JsonProperty("contentRanking") val contentRanking: GetAudioContentRanking -) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/curation/AudioContentCurationQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/curation/AudioContentCurationQueryRepository.kt index 878bf58..91994c6 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/main/curation/AudioContentCurationQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/main/curation/AudioContentCurationQueryRepository.kt @@ -59,7 +59,9 @@ class AudioContentCurationQueryRepository(private val queryFactory: JPAQueryFact audioContent.title, member.id, member.profileImage.prepend("/").prepend(cloudfrontHost), - member.nickname + member.nickname, + audioContent.price, + audioContent.duration ) ) .from(audioContent) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderRepository.kt index feb941d..bcdce03 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/order/OrderRepository.kt @@ -192,7 +192,9 @@ class OrderQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Orde member.profileImage .prepend("/") .prepend(coverImageHost), - member.nickname + member.nickname, + audioContent.price, + audioContent.duration ) ) .from(order) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeController.kt index 7b13530..9c85c48 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeController.kt @@ -2,11 +2,15 @@ package kr.co.vividnext.sodalive.content.theme 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.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.RequestMapping +import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @RestController @@ -21,4 +25,24 @@ class AudioContentThemeController(private val service: AudioContentThemeService) ApiResponse.ok(service.getThemes()) } + + @GetMapping("/{id}/content") + fun getContentByTheme( + @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.getContentByTheme( + themeId = id, + sortType = sortType, + member = member, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ) + ) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeService.kt index f8b2fb0..64f600b 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/AudioContentThemeService.kt @@ -1,10 +1,63 @@ package kr.co.vividnext.sodalive.content.theme +import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.content.AudioContentRepository +import kr.co.vividnext.sodalive.content.SortType +import kr.co.vividnext.sodalive.content.theme.content.GetContentByThemeResponse +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.stereotype.Service +import org.springframework.transaction.annotation.Transactional @Service -class AudioContentThemeService(private val queryRepository: AudioContentThemeQueryRepository) { +class AudioContentThemeService( + private val queryRepository: AudioContentThemeQueryRepository, + private val blockMemberRepository: BlockMemberRepository, + private val contentRepository: AudioContentRepository, + + @Value("\${cloud.aws.cloud-front.host}") + private val imageHost: String +) { + @Transactional(readOnly = true) fun getThemes(): List { return queryRepository.getActiveThemes() } + + @Transactional(readOnly = true) + fun getContentByTheme( + themeId: Long, + sortType: SortType, + member: Member, + offset: Long, + limit: Long + ): GetContentByThemeResponse { + val theme = queryRepository.findThemeByIdAndActive(themeId) + ?: throw SodaException("잘못된 요청입니다.") + + val totalCount = contentRepository.totalCountByTheme( + memberId = member.id!!, + theme = theme.theme, + isAdult = member.auth != null + ) + + val items = contentRepository.findByTheme( + cloudfrontHost = imageHost, + memberId = member.id!!, + theme = theme.theme, + sortType = sortType, + isAdult = member.auth != null, + offset = offset, + limit = limit + ) + .asSequence() + .filter { !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.creatorId) } + .toList() + + return GetContentByThemeResponse( + theme = theme.theme, + totalCount = totalCount, + items = items + ) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/content/GetContentByThemeResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/content/GetContentByThemeResponse.kt new file mode 100644 index 0000000..2776363 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/theme/content/GetContentByThemeResponse.kt @@ -0,0 +1,9 @@ +package kr.co.vividnext.sodalive.content.theme.content + +import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem + +data class GetContentByThemeResponse( + val theme: String, + val totalCount: Int, + val items: List +) 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 33ca0eb..6186c1b 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/explorer/ExplorerService.kt @@ -442,7 +442,7 @@ class ExplorerService( FcmEvent( type = FcmEventType.CHANGE_NOTICE, title = member.nickname, - message = "공지를 등록했습니다.", + message = "새 글이 등록되었습니다.", creatorId = member.id!! ) ) 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 6adb097..c2d3958 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 @@ -77,7 +77,7 @@ class CreatorCommunityService( FcmEvent( type = FcmEventType.CHANGE_NOTICE, title = member.nickname, - message = "공지를 등록했습니다.", + message = "새 글이 등록되었습니다.", creatorId = member.id!! ) )