From 198ecddc89b72d557f6d59d66eee17a8277eea78 Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 1 Apr 2025 16:21:32 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20-=20=EC=9D=B4=EC=A0=84=ED=99=94/=EB=8B=A4=EC=9D=8C?= =?UTF-8?q?=ED=99=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../content/AudioContentRepository.kt | 37 +++++++++++++++++++ .../sodalive/content/AudioContentService.kt | 7 +++- .../content/GetAudioContentDetailResponse.kt | 4 +- 3 files changed, 46 insertions(+), 2 deletions(-) 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 47a96d4..f904232 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt @@ -22,6 +22,7 @@ import kr.co.vividnext.sodalive.content.pin.QPinContent.pinContent import kr.co.vividnext.sodalive.content.playlist.AudioContentPlaylistContent import kr.co.vividnext.sodalive.content.playlist.QAudioContentPlaylistContent import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme +import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent import kr.co.vividnext.sodalive.event.QEvent.event import kr.co.vividnext.sodalive.member.MemberRole import kr.co.vividnext.sodalive.member.QMember.member @@ -163,6 +164,8 @@ interface AudioContentQueryRepository { fun fetchContentForPlaylist(contentIdList: List): List fun getCoverImageById(id: Long): String? + fun findPreviousContent(title: String): OtherContentResponse? + fun findNextContent(title: String): OtherContentResponse? } @Repository @@ -1152,4 +1155,38 @@ class AudioContentQueryRepositoryImpl( .where(audioContent.id.eq(id)) .fetchFirst() } + + override fun findPreviousContent(title: String): OtherContentResponse? { + return queryFactory + .select( + QOtherContentResponse( + audioContent.id, + audioContent.title, + audioContent.coverImage.prepend("$imageHost/") + ) + ) + .from(seriesContent) + .innerJoin(seriesContent.content, audioContent) + .where(audioContent.title.lt(title)) + .orderBy(audioContent.title.asc()) + .limit(1) + .fetchFirst() + } + + override fun findNextContent(title: String): OtherContentResponse? { + return queryFactory + .select( + QOtherContentResponse( + audioContent.id, + audioContent.title, + audioContent.coverImage.prepend("$imageHost/") + ) + ) + .from(seriesContent) + .innerJoin(seriesContent.content, audioContent) + .where(audioContent.title.gt(title)) + .orderBy(audioContent.title.asc()) + .limit(1) + .fetchFirst() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index 53e86d9..6aaabb8 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -473,6 +473,9 @@ class AudioContentService( null } + val previousContent = repository.findPreviousContent(title = audioContent.title) + val nextContent = repository.findNextContent(title = audioContent.title) + if ( !isExistsAudioContent && !audioContent.isActive && @@ -666,7 +669,9 @@ class AudioContentService( isFollowing = creatorFollowing?.isFollow ?: false, isFollow = creatorFollowing?.isFollow ?: false, isNotify = creatorFollowing?.isNotify ?: false - ) + ), + previousContent = previousContent, + nextContent = nextContent ) } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/GetAudioContentDetailResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/GetAudioContentDetailResponse.kt index d7346ef..67dd32b 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/GetAudioContentDetailResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/GetAudioContentDetailResponse.kt @@ -35,7 +35,9 @@ data class GetAudioContentDetailResponse( val commentCount: Int, val isPin: Boolean, val isAvailablePin: Boolean, - val creator: AudioContentCreator + val creator: AudioContentCreator, + val previousContent: OtherContentResponse?, + val nextContent: OtherContentResponse? ) data class OtherContentResponse @QueryProjection constructor( -- 2.40.1 From ce8cc3eb290456ee4fc7032162fd409d88dfa048 Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 1 Apr 2025 17:36:32 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20-=20=EC=9D=B4=EC=A0=84=ED=99=94/=EB=8B=A4=EC=9D=8C?= =?UTF-8?q?=ED=99=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../content/AudioContentController.kt | 10 +++- .../content/AudioContentRepository.kt | 59 +++++++++++++++++-- .../sodalive/content/AudioContentService.kt | 31 +++++++++- 3 files changed, 90 insertions(+), 10 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt index 4b4549a..f5a529a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt @@ -131,11 +131,19 @@ class AudioContentController(private val service: AudioContentService) { fun getDetail( @PathVariable id: Long, @RequestParam timezone: String, + @RequestParam("isAdultContentVisible", required = false) isAdultContentVisible: Boolean? = null, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? ) = run { if (member == null) throw SodaException("로그인 정보를 확인해주세요.") - ApiResponse.ok(service.getDetail(id = id, member = member, timezone = timezone)) + ApiResponse.ok( + service.getDetail( + id = id, + member = member, + isAdultContentVisible = isAdultContentVisible ?: true, + timezone = timezone + ) + ) } @GetMapping("/{id}/generate-url") 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 f904232..c46527f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt @@ -22,6 +22,7 @@ import kr.co.vividnext.sodalive.content.pin.QPinContent.pinContent import kr.co.vividnext.sodalive.content.playlist.AudioContentPlaylistContent import kr.co.vividnext.sodalive.content.playlist.QAudioContentPlaylistContent import kr.co.vividnext.sodalive.content.theme.QAudioContentTheme.audioContentTheme +import kr.co.vividnext.sodalive.creator.admin.content.series.QSeries.series import kr.co.vividnext.sodalive.creator.admin.content.series.QSeriesContent.seriesContent import kr.co.vividnext.sodalive.event.QEvent.event import kr.co.vividnext.sodalive.member.MemberRole @@ -164,8 +165,10 @@ interface AudioContentQueryRepository { fun fetchContentForPlaylist(contentIdList: List): List fun getCoverImageById(id: Long): String? - fun findPreviousContent(title: String): OtherContentResponse? - fun findNextContent(title: String): OtherContentResponse? + fun findPreviousContent(seriesId: Long, title: String, isAdult: Boolean): OtherContentResponse? + fun findNextContent(seriesId: Long, title: String, isAdult: Boolean): OtherContentResponse? + + fun findSeriesIdByContentId(contentId: Long, isAdult: Boolean): Long? } @Repository @@ -1156,7 +1159,18 @@ class AudioContentQueryRepositoryImpl( .fetchFirst() } - override fun findPreviousContent(title: String): OtherContentResponse? { + override fun findPreviousContent(seriesId: Long, title: String, isAdult: Boolean): OtherContentResponse? { + var where = series.isActive.isTrue + .and(series.id.eq(seriesId)) + .and(audioContent.isActive.isTrue) + .and(audioContent.title.lt(title)) + .and(audioContent.limited.isNull) + .and(audioContent.releaseDate.goe(LocalDateTime.now())) + + if (!isAdult) { + where = where.and(audioContent.isAdult.isFalse) + } + return queryFactory .select( QOtherContentResponse( @@ -1166,14 +1180,26 @@ class AudioContentQueryRepositoryImpl( ) ) .from(seriesContent) + .innerJoin(seriesContent.series, series) .innerJoin(seriesContent.content, audioContent) - .where(audioContent.title.lt(title)) + .where(where) .orderBy(audioContent.title.asc()) .limit(1) .fetchFirst() } - override fun findNextContent(title: String): OtherContentResponse? { + override fun findNextContent(seriesId: Long, title: String, isAdult: Boolean): OtherContentResponse? { + var where = series.isActive.isTrue + .and(series.id.eq(seriesId)) + .and(audioContent.isActive.isTrue) + .and(audioContent.title.gt(title)) + .and(audioContent.limited.isNull) + .and(audioContent.releaseDate.goe(LocalDateTime.now())) + + if (!isAdult) { + where = where.and(audioContent.isAdult.isFalse) + } + return queryFactory .select( QOtherContentResponse( @@ -1183,10 +1209,31 @@ class AudioContentQueryRepositoryImpl( ) ) .from(seriesContent) + .innerJoin(seriesContent.series, series) .innerJoin(seriesContent.content, audioContent) - .where(audioContent.title.gt(title)) + .where(where) .orderBy(audioContent.title.asc()) .limit(1) .fetchFirst() } + + override fun findSeriesIdByContentId(contentId: Long, isAdult: Boolean): Long? { + var where = series.isActive.isTrue + .and(audioContent.isActive.isTrue) + .and(audioContent.id.eq(contentId)) + + if (!isAdult) { + where = where.and(series.isAdult.isFalse) + } + + return queryFactory + .select(series.id) + .from(seriesContent) + .innerJoin(seriesContent.series, series) + .innerJoin(seriesContent.content, audioContent) + .where(where) + .orderBy(seriesContent.id.asc()) + .limit(1) + .fetchFirst() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index 6aaabb8..2082361 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -440,7 +440,14 @@ class AudioContentService( } } - fun getDetail(id: Long, member: Member, timezone: String): GetAudioContentDetailResponse { + fun getDetail( + id: Long, + member: Member, + isAdultContentVisible: Boolean, + timezone: String + ): GetAudioContentDetailResponse { + val isAdult = member.auth != null && isAdultContentVisible + // 오디오 콘텐츠 조회 (content_id, 제목, 내용, 테마, 태그, 19여부, 이미지, 콘텐츠 PATH) val audioContent = repository.findByIdOrNull(id) ?: throw SodaException("잘못된 콘텐츠 입니다.\n다시 시도해 주세요.") @@ -473,8 +480,26 @@ class AudioContentService( null } - val previousContent = repository.findPreviousContent(title = audioContent.title) - val nextContent = repository.findNextContent(title = audioContent.title) + val seriesId = repository.findSeriesIdByContentId(audioContent.id!!, isAdult) + val previousContent = if (seriesId != null) { + repository.findPreviousContent( + seriesId = seriesId, + title = audioContent.title, + isAdult = isAdult + ) + } else { + null + } + + val nextContent = if (seriesId != null) { + repository.findNextContent( + seriesId = seriesId, + title = audioContent.title, + isAdult = isAdult + ) + } else { + null + } if ( !isExistsAudioContent && -- 2.40.1 From 6e229af790d7c5a6aa9ae6d9070a51c6dba0b13a Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 1 Apr 2025 18:27:59 +0900 Subject: [PATCH 3/3] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=83=81?= =?UTF-8?q?=EC=84=B8=20-=20=EC=9D=B4=EC=A0=84=ED=99=94/=EB=8B=A4=EC=9D=8C?= =?UTF-8?q?=ED=99=94=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vividnext/sodalive/content/AudioContentRepository.kt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) 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 c46527f..fcffe5f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt @@ -1165,7 +1165,7 @@ class AudioContentQueryRepositoryImpl( .and(audioContent.isActive.isTrue) .and(audioContent.title.lt(title)) .and(audioContent.limited.isNull) - .and(audioContent.releaseDate.goe(LocalDateTime.now())) + .and(audioContent.releaseDate.loe(LocalDateTime.now())) if (!isAdult) { where = where.and(audioContent.isAdult.isFalse) @@ -1183,7 +1183,7 @@ class AudioContentQueryRepositoryImpl( .innerJoin(seriesContent.series, series) .innerJoin(seriesContent.content, audioContent) .where(where) - .orderBy(audioContent.title.asc()) + .orderBy(audioContent.title.desc()) .limit(1) .fetchFirst() } @@ -1194,7 +1194,7 @@ class AudioContentQueryRepositoryImpl( .and(audioContent.isActive.isTrue) .and(audioContent.title.gt(title)) .and(audioContent.limited.isNull) - .and(audioContent.releaseDate.goe(LocalDateTime.now())) + .and(audioContent.releaseDate.loe(LocalDateTime.now())) if (!isAdult) { where = where.and(audioContent.isAdult.isFalse) @@ -1211,6 +1211,7 @@ class AudioContentQueryRepositoryImpl( .from(seriesContent) .innerJoin(seriesContent.series, series) .innerJoin(seriesContent.content, audioContent) + .innerJoin(series.member, member) .where(where) .orderBy(audioContent.title.asc()) .limit(1) @@ -1221,6 +1222,7 @@ class AudioContentQueryRepositoryImpl( var where = series.isActive.isTrue .and(audioContent.isActive.isTrue) .and(audioContent.id.eq(contentId)) + .and(member.role.eq(MemberRole.CREATOR)) if (!isAdult) { where = where.and(series.isAdult.isFalse) @@ -1231,6 +1233,7 @@ class AudioContentQueryRepositoryImpl( .from(seriesContent) .innerJoin(seriesContent.series, series) .innerJoin(seriesContent.content, audioContent) + .innerJoin(series.member, member) .where(where) .orderBy(seriesContent.id.asc()) .limit(1) -- 2.40.1