| @@ -236,4 +236,24 @@ class AudioContentController(private val service: AudioContentService) { | ||||
|  | ||||
|         ApiResponse.ok(service.unpinAtTheTop(contentId = id, member = member)) | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/replay-live") | ||||
|     fun replayLive( | ||||
|         @RequestParam("isAdultContentVisible", required = false) isAdultContentVisible: Boolean? = null, | ||||
|         @RequestParam("contentType", required = false) contentType: ContentType? = null, | ||||
|         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||
|     ) = run { | ||||
|         ApiResponse.ok( | ||||
|             service.getLatestContentByTheme( | ||||
|                 theme = listOf("다시듣기"), | ||||
|                 contentType = contentType ?: ContentType.ALL, | ||||
|                 isFree = false, | ||||
|                 isAdult = if (member != null) { | ||||
|                     (isAdultContentVisible ?: true) && member.auth != null | ||||
|                 } else { | ||||
|                     false | ||||
|                 } | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -490,10 +490,8 @@ class AudioContentQueryRepositoryImpl( | ||||
|             where = where.and(audioContentTheme.theme.`in`(theme)) | ||||
|         } | ||||
|  | ||||
|         where = if (isFree) { | ||||
|             where.and(audioContent.price.loe(0)) | ||||
|         } else { | ||||
|             where.and(audioContent.price.gt(0)) | ||||
|         if (isFree) { | ||||
|             where = where.and(audioContent.price.loe(0)) | ||||
|         } | ||||
|  | ||||
|         return queryFactory | ||||
|   | ||||
| @@ -16,6 +16,7 @@ import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCo | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.CreatorCommunityLikeRepository | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeRequest | ||||
| import kr.co.vividnext.sodalive.explorer.profile.creatorCommunity.like.PostCommunityPostLikeResponse | ||||
| import kr.co.vividnext.sodalive.extensions.getTimeAgoString | ||||
| import kr.co.vividnext.sodalive.fcm.FcmEvent | ||||
| import kr.co.vividnext.sodalive.fcm.FcmEventType | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| @@ -28,8 +29,6 @@ import org.springframework.data.repository.findByIdOrNull | ||||
| import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | ||||
| import org.springframework.web.multipart.MultipartFile | ||||
| import java.time.Duration | ||||
| import java.time.LocalDateTime | ||||
|  | ||||
| @Service | ||||
| class CreatorCommunityService( | ||||
| @@ -243,7 +242,7 @@ class CreatorCommunityService( | ||||
|                 it.toCommunityPostListResponse( | ||||
|                     imageHost = imageHost, | ||||
|                     audioUrl = audioUrl, | ||||
|                     date = getTimeAgoString(it.date), | ||||
|                     date = it.date.getTimeAgoString(), | ||||
|                     isLike = isLike, | ||||
|                     memberId = memberId, | ||||
|                     existOrdered = if (memberId == it.creatorId) { | ||||
| @@ -314,7 +313,7 @@ class CreatorCommunityService( | ||||
|         return post.toCommunityPostListResponse( | ||||
|             imageHost = imageHost, | ||||
|             audioUrl = audioUrl, | ||||
|             date = getTimeAgoString(post.date), | ||||
|             date = post.date.getTimeAgoString(), | ||||
|             isLike = isLike, | ||||
|             memberId = memberId, | ||||
|             existOrdered = if (memberId == post.creatorId) { | ||||
| @@ -328,19 +327,6 @@ class CreatorCommunityService( | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     private fun getTimeAgoString(dateTime: LocalDateTime): String { | ||||
|         val now = LocalDateTime.now() | ||||
|         val duration = Duration.between(dateTime, now) | ||||
|  | ||||
|         return when { | ||||
|             duration.toMinutes() < 60 -> "${duration.toMinutes()}분전" | ||||
|             duration.toHours() < 24 -> "${duration.toHours()}시간전" | ||||
|             duration.toDays() < 30 -> "${duration.toDays()}일전" | ||||
|             duration.toDays() < 365 -> "${duration.toDays() / 30}개월전" | ||||
|             else -> "${duration.toDays() / 365}년전" | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun communityPostLike(request: PostCommunityPostLikeRequest, member: Member): PostCommunityPostLikeResponse { | ||||
|         var postLike = likeRepository.findByPostIdAndMemberId(postId = request.postId, memberId = member.id!!) | ||||
| @@ -506,7 +492,7 @@ class CreatorCommunityService( | ||||
|                 it.toCommunityPostListResponse( | ||||
|                     imageHost = imageHost, | ||||
|                     audioUrl = null, | ||||
|                     date = getTimeAgoString(it.date), | ||||
|                     date = it.date.getTimeAgoString(), | ||||
|                     isLike = isLike, | ||||
|                     memberId = memberId, | ||||
|                     existOrdered = if (memberId == it.creatorId) { | ||||
| @@ -590,7 +576,7 @@ class CreatorCommunityService( | ||||
|             imageHost = imageHost, | ||||
|             audioUrl = audioUrl, | ||||
|             content = post.content, | ||||
|             date = getTimeAgoString(post.createdAt!!), | ||||
|             date = post.createdAt!!.getTimeAgoString(), | ||||
|             isLike = isLike, | ||||
|             existOrdered = true, | ||||
|             likeCount = likeCount, | ||||
|   | ||||
| @@ -0,0 +1,18 @@ | ||||
| package kr.co.vividnext.sodalive.extensions | ||||
|  | ||||
| import java.time.Duration | ||||
| import java.time.LocalDateTime | ||||
|  | ||||
| fun LocalDateTime.getTimeAgoString(): String { | ||||
|     val now = LocalDateTime.now() | ||||
|     val duration = Duration.between(this, now) | ||||
|  | ||||
|     return when { | ||||
|         duration.toMinutes() < 1 -> "방금 전" | ||||
|         duration.toMinutes() < 60 -> "${duration.toMinutes()}분전" | ||||
|         duration.toHours() < 24 -> "${duration.toHours()}시간전" | ||||
|         duration.toDays() < 30 -> "${duration.toDays()}일전" | ||||
|         duration.toDays() < 365 -> "${duration.toDays() / 30}개월전" | ||||
|         else -> "${duration.toDays() / 365}년전" | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
| package kr.co.vividnext.sodalive.live.room | ||||
|  | ||||
| import com.querydsl.core.annotations.QueryProjection | ||||
| import kr.co.vividnext.sodalive.extensions.getTimeAgoString | ||||
| import java.time.LocalDateTime | ||||
|  | ||||
| data class GetLatestFinishedLiveQueryResponse @QueryProjection constructor( | ||||
|     val memberId: Long, | ||||
|     val nickname: String, | ||||
|     val profileImageUrl: String, | ||||
|     val title: String, | ||||
|     val updatedAt: LocalDateTime | ||||
| ) | ||||
|  | ||||
| data class GetLatestFinishedLiveResponse( | ||||
|     val memberId: Long, | ||||
|     val nickname: String, | ||||
|     val profileImageUrl: String, | ||||
|     val title: String, | ||||
|     val timeAgo: String | ||||
| ) { | ||||
|     constructor(response: GetLatestFinishedLiveQueryResponse) : this( | ||||
|         response.memberId, | ||||
|         response.nickname, | ||||
|         response.profileImageUrl, | ||||
|         response.title, | ||||
|         response.updatedAt.getTimeAgoString() | ||||
|     ) | ||||
| } | ||||
| @@ -5,6 +5,7 @@ data class GetRoomListResponse( | ||||
|     val title: String, | ||||
|     val content: String, | ||||
|     val beginDateTime: String, | ||||
|     val beginDateTimeUtc: String, | ||||
|     val numberOfParticipate: Int, | ||||
|     val numberOfPeople: Int, | ||||
|     val coverImageUrl: String, | ||||
|   | ||||
| @@ -171,7 +171,7 @@ class LiveRoomController( | ||||
|     ) = run { | ||||
|         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||
|  | ||||
|         ApiResponse.ok(service.getDonationTotal(roomId, memberId = member.id!!)) | ||||
|         ApiResponse.ok(service.getDonationTotal(roomId)) | ||||
|     } | ||||
|  | ||||
|     @PutMapping("/info/set/speaker") | ||||
| @@ -291,4 +291,11 @@ class LiveRoomController( | ||||
|  | ||||
|         ApiResponse.ok(service.getHeartList(roomId)) | ||||
|     } | ||||
|  | ||||
|     @GetMapping("/latest-finished-live") | ||||
|     fun getLatestFinishedLive( | ||||
|         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||
|     ) = run { | ||||
|         ApiResponse.ok(service.getLatestFinishedLive(member)) | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ import com.querydsl.core.types.Projections | ||||
| import com.querydsl.core.types.dsl.CaseBuilder | ||||
| import com.querydsl.core.types.dsl.Expressions | ||||
| import com.querydsl.core.types.dsl.NumberExpression | ||||
| import com.querydsl.jpa.JPAExpressions | ||||
| import com.querydsl.jpa.impl.JPAQueryFactory | ||||
| import kr.co.vividnext.sodalive.can.use.CanUsage | ||||
| import kr.co.vividnext.sodalive.can.use.QUseCan.useCan | ||||
| @@ -14,6 +15,7 @@ import kr.co.vividnext.sodalive.live.room.donation.GetLiveRoomDonationItem | ||||
| import kr.co.vividnext.sodalive.live.room.donation.QGetLiveRoomDonationItem | ||||
| import kr.co.vividnext.sodalive.live.room.like.GetLiveRoomHeartListItem | ||||
| import kr.co.vividnext.sodalive.live.room.like.QGetLiveRoomHeartListItem | ||||
| import kr.co.vividnext.sodalive.member.MemberRole | ||||
| import kr.co.vividnext.sodalive.member.QMember.member | ||||
| import org.springframework.beans.factory.annotation.Value | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
| @@ -60,6 +62,7 @@ interface LiveRoomQueryRepository { | ||||
|     fun getTotalHeartCount(roomId: Long): Int? | ||||
|     fun getLiveRoomCreatorId(roomId: Long): Long? | ||||
|     fun getHeartList(roomId: Long): List<GetLiveRoomHeartListItem> | ||||
|     fun getLatestFinishedLive(): List<GetLatestFinishedLiveQueryResponse> | ||||
| } | ||||
|  | ||||
| class LiveRoomQueryRepositoryImpl( | ||||
| @@ -380,4 +383,39 @@ class LiveRoomQueryRepositoryImpl( | ||||
|             .orderBy(useCan.can.add(useCan.rewardCan).sum().desc()) | ||||
|             .fetch() | ||||
|     } | ||||
|  | ||||
|     override fun getLatestFinishedLive(): List<GetLatestFinishedLiveQueryResponse> { | ||||
|         val liveRoom = liveRoom | ||||
|         val subLiveRoom = QLiveRoom.liveRoom | ||||
|  | ||||
|         val subQuery = JPAExpressions | ||||
|             .select(subLiveRoom.member.id, subLiveRoom.updatedAt.max()) | ||||
|             .from(subLiveRoom) | ||||
|             .where( | ||||
|                 subLiveRoom.isActive.isFalse | ||||
|                     .and(subLiveRoom.channelName.isNotNull) | ||||
|                     .and(subLiveRoom.member.role.eq(MemberRole.CREATOR)) | ||||
|             ) | ||||
|             .groupBy(subLiveRoom.member.id) | ||||
|  | ||||
|         return queryFactory | ||||
|             .select( | ||||
|                 QGetLatestFinishedLiveQueryResponse( | ||||
|                     member.id, | ||||
|                     member.nickname, | ||||
|                     member.profileImage.prepend("/").prepend(cloudFrontHost), | ||||
|                     liveRoom.title, | ||||
|                     liveRoom.updatedAt | ||||
|                 ) | ||||
|             ) | ||||
|             .from(liveRoom) | ||||
|             .innerJoin(liveRoom.member, member) | ||||
|             .where( | ||||
|                 Expressions.list(liveRoom.member.id, liveRoom.updatedAt) | ||||
|                     .`in`(subQuery) | ||||
|             ) | ||||
|             .orderBy(liveRoom.updatedAt.desc()) | ||||
|             .limit(20) | ||||
|             .fetch() | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -176,11 +176,15 @@ class LiveRoomService( | ||||
|                             .withLocale(Locale.KOREAN) | ||||
|                     ) | ||||
|  | ||||
|                 val beginDateTimeUtc = it.beginDateTime | ||||
|                     .format(DateTimeFormatter.ISO_LOCAL_DATE_TIME) | ||||
|  | ||||
|                 GetRoomListResponse( | ||||
|                     roomId = it.id!!, | ||||
|                     title = it.title, | ||||
|                     content = it.notice, | ||||
|                     beginDateTime = beginDateTime, | ||||
|                     beginDateTimeUtc = beginDateTimeUtc, | ||||
|                     numberOfParticipate = (roomInfo?.listenerCount ?: 0) + | ||||
|                         (roomInfo?.speakerCount ?: 0) + | ||||
|                         (roomInfo?.managerCount ?: 0), | ||||
| @@ -993,7 +997,7 @@ class LiveRoomService( | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fun getDonationTotal(roomId: Long, memberId: Long): GetLiveRoomDonationTotalResponse { | ||||
|     fun getDonationTotal(roomId: Long): GetLiveRoomDonationTotalResponse { | ||||
|         return GetLiveRoomDonationTotalResponse( | ||||
|             totalDonationCan = repository.getDonationTotal(roomId = roomId) ?: 0 | ||||
|         ) | ||||
| @@ -1292,4 +1296,18 @@ class LiveRoomService( | ||||
|             totalHeart = heartList.sumOf { it.heart } | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     fun getLatestFinishedLive(member: Member?): List<GetLatestFinishedLiveResponse> { | ||||
|         return repository.getLatestFinishedLive() | ||||
|             .filter { | ||||
|                 if (member?.id != null) { | ||||
|                     !blockMemberRepository.isBlocked(blockedMemberId = member.id!!, memberId = it.memberId) | ||||
|                 } else { | ||||
|                     true | ||||
|                 } | ||||
|             } | ||||
|             .map { | ||||
|                 GetLatestFinishedLiveResponse(response = it) | ||||
|             } | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user