test #248
| @@ -9,7 +9,6 @@ import org.springframework.web.bind.annotation.GetMapping | |||||||
| import org.springframework.web.bind.annotation.PostMapping | import org.springframework.web.bind.annotation.PostMapping | ||||||
| import org.springframework.web.bind.annotation.RequestBody | import org.springframework.web.bind.annotation.RequestBody | ||||||
| import org.springframework.web.bind.annotation.RequestMapping | import org.springframework.web.bind.annotation.RequestMapping | ||||||
| import org.springframework.web.bind.annotation.RequestParam |  | ||||||
| import org.springframework.web.bind.annotation.RestController | import org.springframework.web.bind.annotation.RestController | ||||||
|  |  | ||||||
| @RestController | @RestController | ||||||
| @@ -34,7 +33,6 @@ class OrderController(private val service: OrderService) { | |||||||
|  |  | ||||||
|     @GetMapping("/audio-content") |     @GetMapping("/audio-content") | ||||||
|     fun getAudioContentOrderList( |     fun getAudioContentOrderList( | ||||||
|         @RequestParam(value = "orderType", required = false) orderType: OrderType? = null, |  | ||||||
|         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, |         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, | ||||||
|         pageable: Pageable |         pageable: Pageable | ||||||
|     ) = run { |     ) = run { | ||||||
| @@ -42,7 +40,6 @@ class OrderController(private val service: OrderService) { | |||||||
|  |  | ||||||
|         ApiResponse.ok( |         ApiResponse.ok( | ||||||
|             service.getAudioContentOrderList( |             service.getAudioContentOrderList( | ||||||
|                 orderType = orderType, |  | ||||||
|                 member = member, |                 member = member, | ||||||
|                 offset = pageable.offset, |                 offset = pageable.offset, | ||||||
|                 limit = pageable.pageSize.toLong() |                 limit = pageable.pageSize.toLong() | ||||||
|   | |||||||
| @@ -6,6 +6,8 @@ import kr.co.vividnext.sodalive.content.QAudioContent.audioContent | |||||||
| import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem | import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem | ||||||
| import kr.co.vividnext.sodalive.content.main.QGetAudioContentMainItem | import kr.co.vividnext.sodalive.content.main.QGetAudioContentMainItem | ||||||
| import kr.co.vividnext.sodalive.content.order.QOrder.order | import kr.co.vividnext.sodalive.content.order.QOrder.order | ||||||
|  | import kr.co.vividnext.sodalive.content.playlist.ContentIdAndEndDateData | ||||||
|  | import kr.co.vividnext.sodalive.content.playlist.QContentIdAndEndDateData | ||||||
| import kr.co.vividnext.sodalive.member.QMember.member | import kr.co.vividnext.sodalive.member.QMember.member | ||||||
| import org.springframework.data.jpa.repository.JpaRepository | import org.springframework.data.jpa.repository.JpaRepository | ||||||
| import org.springframework.stereotype.Repository | import org.springframework.stereotype.Repository | ||||||
| @@ -20,7 +22,6 @@ interface OrderQueryRepository { | |||||||
|     fun isExistOrderedAndOrderType(memberId: Long, contentId: Long): Pair<Boolean, OrderType?> |     fun isExistOrderedAndOrderType(memberId: Long, contentId: Long): Pair<Boolean, OrderType?> | ||||||
|     fun getAudioContentRemainingTime(memberId: Long, contentId: Long, timezone: String): String |     fun getAudioContentRemainingTime(memberId: Long, contentId: Long, timezone: String): String | ||||||
|     fun getAudioContentOrderList( |     fun getAudioContentOrderList( | ||||||
|         orderType: OrderType?, |  | ||||||
|         dateTime: LocalDateTime, |         dateTime: LocalDateTime, | ||||||
|         coverImageHost: String, |         coverImageHost: String, | ||||||
|         memberId: Long, |         memberId: Long, | ||||||
| @@ -28,7 +29,7 @@ interface OrderQueryRepository { | |||||||
|         limit: Long = 10 |         limit: Long = 10 | ||||||
|     ): List<GetAudioContentOrderListItem> |     ): List<GetAudioContentOrderListItem> | ||||||
|  |  | ||||||
|     fun totalAudioContentOrderListCount(orderType: OrderType?, memberId: Long, dateTime: LocalDateTime): Int |     fun totalAudioContentOrderListCount(memberId: Long, dateTime: LocalDateTime): Int | ||||||
|     fun getAudioContentMainOrderList( |     fun getAudioContentMainOrderList( | ||||||
|         dateTime: LocalDateTime, |         dateTime: LocalDateTime, | ||||||
|         coverImageHost: String, |         coverImageHost: String, | ||||||
| @@ -38,6 +39,7 @@ interface OrderQueryRepository { | |||||||
|     ): List<GetAudioContentMainItem> |     ): List<GetAudioContentMainItem> | ||||||
|  |  | ||||||
|     fun findOrderedContent(contentIdList: List<Long>, memberId: Long): List<Long> |     fun findOrderedContent(contentIdList: List<Long>, memberId: Long): List<Long> | ||||||
|  |     fun findEndDateByContentId(contentIdList: List<Long>, memberId: Long): List<ContentIdAndEndDateData> | ||||||
| } | } | ||||||
|  |  | ||||||
| @Repository | @Repository | ||||||
| @@ -118,40 +120,22 @@ class OrderQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Orde | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun getAudioContentOrderList( |     override fun getAudioContentOrderList( | ||||||
|         orderType: OrderType?, |  | ||||||
|         dateTime: LocalDateTime, |         dateTime: LocalDateTime, | ||||||
|         coverImageHost: String, |         coverImageHost: String, | ||||||
|         memberId: Long, |         memberId: Long, | ||||||
|         offset: Long, |         offset: Long, | ||||||
|         limit: Long |         limit: Long | ||||||
|     ): List<GetAudioContentOrderListItem> { |     ): List<GetAudioContentOrderListItem> { | ||||||
|         var where = order.member.id.eq(memberId) |         val where = order.member.id.eq(memberId) | ||||||
|             .and(order.isActive.isTrue) |             .and(order.isActive.isTrue) | ||||||
|  |             .and( | ||||||
|         when (orderType) { |                 order.type.eq(OrderType.KEEP) | ||||||
|             OrderType.RENTAL -> { |                     .or( | ||||||
|                 where = where.and( |                         order.type.eq(OrderType.RENTAL) | ||||||
|                     order.type.eq(OrderType.RENTAL) |                             .and(order.startDate.before(dateTime)) | ||||||
|                         .and(order.startDate.before(dateTime)) |                             .and(order.endDate.after(dateTime)) | ||||||
|                         .and(order.endDate.after(dateTime)) |                     ) | ||||||
|                 ) |             ) | ||||||
|             } |  | ||||||
|  |  | ||||||
|             OrderType.KEEP -> { |  | ||||||
|                 where = where.and(order.type.eq(OrderType.KEEP)) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             null -> { |  | ||||||
|                 where = where.and( |  | ||||||
|                     order.type.eq(OrderType.KEEP) |  | ||||||
|                         .or( |  | ||||||
|                             order.type.eq(OrderType.RENTAL) |  | ||||||
|                                 .and(order.startDate.before(dateTime)) |  | ||||||
|                                 .and(order.endDate.after(dateTime)) |  | ||||||
|                         ) |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return queryFactory |         return queryFactory | ||||||
|             .select( |             .select( | ||||||
| @@ -178,34 +162,17 @@ class OrderQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Orde | |||||||
|             .fetch() |             .fetch() | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     override fun totalAudioContentOrderListCount(orderType: OrderType?, memberId: Long, dateTime: LocalDateTime): Int { |     override fun totalAudioContentOrderListCount(memberId: Long, dateTime: LocalDateTime): Int { | ||||||
|         var where = order.member.id.eq(memberId) |         val where = order.member.id.eq(memberId) | ||||||
|             .and(order.isActive.isTrue) |             .and(order.isActive.isTrue) | ||||||
|  |             .and( | ||||||
|         when (orderType) { |                 order.type.eq(OrderType.KEEP) | ||||||
|             OrderType.RENTAL -> { |                     .or( | ||||||
|                 where = where.and( |                         order.type.eq(OrderType.RENTAL) | ||||||
|                     order.type.eq(OrderType.RENTAL) |                             .and(order.startDate.before(dateTime)) | ||||||
|                         .and(order.startDate.before(dateTime)) |                             .and(order.endDate.after(dateTime)) | ||||||
|                         .and(order.endDate.after(dateTime)) |                     ) | ||||||
|                 ) |             ) | ||||||
|             } |  | ||||||
|  |  | ||||||
|             OrderType.KEEP -> { |  | ||||||
|                 where = where.and(order.type.eq(OrderType.KEEP)) |  | ||||||
|             } |  | ||||||
|  |  | ||||||
|             null -> { |  | ||||||
|                 where = where.and( |  | ||||||
|                     order.type.eq(OrderType.KEEP) |  | ||||||
|                         .or( |  | ||||||
|                             order.type.eq(OrderType.RENTAL) |  | ||||||
|                                 .and(order.startDate.before(dateTime)) |  | ||||||
|                                 .and(order.endDate.after(dateTime)) |  | ||||||
|                         ) |  | ||||||
|                 ) |  | ||||||
|             } |  | ||||||
|         } |  | ||||||
|  |  | ||||||
|         return queryFactory.select(order.id) |         return queryFactory.select(order.id) | ||||||
|             .from(order) |             .from(order) | ||||||
| @@ -265,9 +232,24 @@ class OrderQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : Orde | |||||||
|             .innerJoin(order.audioContent, audioContent) |             .innerJoin(order.audioContent, audioContent) | ||||||
|             .where( |             .where( | ||||||
|                 order.isActive.isTrue, |                 order.isActive.isTrue, | ||||||
|                 order.endDate.isNull, |  | ||||||
|                 member.id.eq(memberId), |                 member.id.eq(memberId), | ||||||
|                 audioContent.id.`in`(contentIdList) |                 audioContent.id.`in`(contentIdList), | ||||||
|  |                 order.endDate.isNull.or(order.endDate.after(LocalDateTime.now())) | ||||||
|  |             ) | ||||||
|  |             .fetch() | ||||||
|  |     } | ||||||
|  |  | ||||||
|  |     override fun findEndDateByContentId(contentIdList: List<Long>, memberId: Long): List<ContentIdAndEndDateData> { | ||||||
|  |         return queryFactory | ||||||
|  |             .select(QContentIdAndEndDateData(audioContent.id, order.endDate)) | ||||||
|  |             .from(order) | ||||||
|  |             .innerJoin(order.member, member) | ||||||
|  |             .innerJoin(order.audioContent, audioContent) | ||||||
|  |             .where( | ||||||
|  |                 order.isActive.isTrue, | ||||||
|  |                 member.id.eq(memberId), | ||||||
|  |                 audioContent.id.`in`(contentIdList), | ||||||
|  |                 order.endDate.isNull.or(order.endDate.after(LocalDateTime.now())) | ||||||
|             ) |             ) | ||||||
|             .fetch() |             .fetch() | ||||||
|     } |     } | ||||||
|   | |||||||
| @@ -90,18 +90,15 @@ class OrderService( | |||||||
|     } |     } | ||||||
|  |  | ||||||
|     fun getAudioContentOrderList( |     fun getAudioContentOrderList( | ||||||
|         orderType: OrderType? = null, |  | ||||||
|         member: Member, |         member: Member, | ||||||
|         offset: Long, |         offset: Long, | ||||||
|         limit: Long |         limit: Long | ||||||
|     ): GetAudioContentOrderListResponse { |     ): GetAudioContentOrderListResponse { | ||||||
|         val totalCount = repository.totalAudioContentOrderListCount( |         val totalCount = repository.totalAudioContentOrderListCount( | ||||||
|             orderType = orderType, |  | ||||||
|             memberId = member.id!!, |             memberId = member.id!!, | ||||||
|             dateTime = LocalDateTime.now() |             dateTime = LocalDateTime.now() | ||||||
|         ) |         ) | ||||||
|         val orderItems = repository.getAudioContentOrderList( |         val orderItems = repository.getAudioContentOrderList( | ||||||
|             orderType = orderType, |  | ||||||
|             dateTime = LocalDateTime.now(), |             dateTime = LocalDateTime.now(), | ||||||
|             coverImageHost = audioContentCoverImageHost, |             coverImageHost = audioContentCoverImageHost, | ||||||
|             memberId = member.id!!, |             memberId = member.id!!, | ||||||
|   | |||||||
| @@ -7,6 +7,7 @@ import kr.co.vividnext.sodalive.live.roulette.RedisIdGenerator | |||||||
| import kr.co.vividnext.sodalive.member.Member | import kr.co.vividnext.sodalive.member.Member | ||||||
| import org.springframework.data.repository.findByIdOrNull | import org.springframework.data.repository.findByIdOrNull | ||||||
| import org.springframework.stereotype.Service | import org.springframework.stereotype.Service | ||||||
|  | import java.time.LocalDateTime | ||||||
| import java.time.ZoneId | import java.time.ZoneId | ||||||
| import java.time.format.DateTimeFormatter | import java.time.format.DateTimeFormatter | ||||||
|  |  | ||||||
| @@ -27,10 +28,9 @@ class AudioContentPlaylistService( | |||||||
|             throw SodaException("플레이 리스트는 최대 10개까지 생성할 수 있습니다.") |             throw SodaException("플레이 리스트는 최대 10개까지 생성할 수 있습니다.") | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         // 콘텐츠 유효성 검사 (소장으로 구매한 콘텐츠 인가?) |         val contentIdAndOrderList = validateAndGetContentIdAndOrderList( | ||||||
|         validateContent( |             contentIdAndOrderList = request.contentIdAndOrderList, | ||||||
|             contentIdList = request.contentIdAndOrderList.map { it.contentId }, |             member | ||||||
|             memberId = member.id!! |  | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         val playlist = AudioContentPlaylist( |         val playlist = AudioContentPlaylist( | ||||||
| @@ -38,12 +38,34 @@ class AudioContentPlaylistService( | |||||||
|             memberId = member.id!!, |             memberId = member.id!!, | ||||||
|             title = request.title, |             title = request.title, | ||||||
|             desc = request.desc, |             desc = request.desc, | ||||||
|             contentIdAndOrderList = request.contentIdAndOrderList |             contentIdAndOrderList = contentIdAndOrderList | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         redisRepository.save(playlist) |         redisRepository.save(playlist) | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     private fun validateAndGetContentIdAndOrderList( | ||||||
|  |         contentIdAndOrderList: List<PlaylistContentIdAndOrder>, | ||||||
|  |         member: Member | ||||||
|  |     ): List<PlaylistContentIdAndOrder> { | ||||||
|  |         validateContent( | ||||||
|  |             contentIdList = contentIdAndOrderList.map { it.contentId }, | ||||||
|  |             memberId = member.id!! | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         val contentIdAndEndDate = orderRepository.findEndDateByContentId( | ||||||
|  |             contentIdList = contentIdAndOrderList.map { it.contentId }, | ||||||
|  |             memberId = member.id!! | ||||||
|  |         ) | ||||||
|  |  | ||||||
|  |         val contentIdAndEndDateMap = contentIdAndEndDate.associate { it.contentId to it.endDate } | ||||||
|  |  | ||||||
|  |         return contentIdAndOrderList.map { | ||||||
|  |             it.endDate = contentIdAndEndDateMap[it.contentId] | ||||||
|  |             it | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  |  | ||||||
|     private fun validateContent(contentIdList: List<Long>, memberId: Long) { |     private fun validateContent(contentIdList: List<Long>, memberId: Long) { | ||||||
|         if (contentIdList.isEmpty()) { |         if (contentIdList.isEmpty()) { | ||||||
|             throw SodaException("콘텐츠를 1개 이상 추가하세요") |             throw SodaException("콘텐츠를 1개 이상 추가하세요") | ||||||
| @@ -61,7 +83,7 @@ class AudioContentPlaylistService( | |||||||
|         val notOrderedContentList = orderedContentMap.filterValues { !it }.keys |         val notOrderedContentList = orderedContentMap.filterValues { !it }.keys | ||||||
|  |  | ||||||
|         if (notOrderedContentList.isNotEmpty()) { |         if (notOrderedContentList.isNotEmpty()) { | ||||||
|             throw SodaException("소장하지 않은 콘텐츠는 재생목록에 추가할 수 없습니다.") |             throw SodaException("대여/소장하지 않은 콘텐츠는 재생목록에 추가할 수 없습니다.") | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
|  |  | ||||||
| @@ -77,15 +99,15 @@ class AudioContentPlaylistService( | |||||||
|             throw SodaException("잘못된 요청입니다.") |             throw SodaException("잘못된 요청입니다.") | ||||||
|         } |         } | ||||||
|  |  | ||||||
|         checkOrderedContent( |         val contentIdAndOrderList = validateAndGetContentIdAndOrderList( | ||||||
|             contentIdList = request.contentIdAndOrderList.map { it.contentId }, |             contentIdAndOrderList = request.contentIdAndOrderList, | ||||||
|             memberId = member.id!! |             member | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         val updatePlaylist = playlist.copy( |         val updatePlaylist = playlist.copy( | ||||||
|             title = request.title ?: playlist.title, |             title = request.title ?: playlist.title, | ||||||
|             desc = request.desc ?: playlist.desc, |             desc = request.desc ?: playlist.desc, | ||||||
|             contentIdAndOrderList = request.contentIdAndOrderList |             contentIdAndOrderList = contentIdAndOrderList | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         redisRepository.save(updatePlaylist) |         redisRepository.save(updatePlaylist) | ||||||
| @@ -98,18 +120,22 @@ class AudioContentPlaylistService( | |||||||
|  |  | ||||||
|         return GetPlaylistsResponse( |         return GetPlaylistsResponse( | ||||||
|             totalCount = playlists.size, |             totalCount = playlists.size, | ||||||
|             items = playlists.map { |             items = playlists.map { playlist -> | ||||||
|                 val contentCount = it.contentIdAndOrderList.size |                 val contentIdAndOrderList = playlist.contentIdAndOrderList.filter { | ||||||
|  |                     it.endDate == null || it.endDate!! > LocalDateTime.now() | ||||||
|  |                 } | ||||||
|  |  | ||||||
|  |                 val contentCount = contentIdAndOrderList.size | ||||||
|                 val coverImageUrl = if (contentCount > 0) { |                 val coverImageUrl = if (contentCount > 0) { | ||||||
|                     audioContentRepository.getCoverImageById(id = it.contentIdAndOrderList[0].contentId) |                     audioContentRepository.getCoverImageById(id = contentIdAndOrderList[0].contentId) | ||||||
|                         ?: "" |                         ?: "" | ||||||
|                 } else { |                 } else { | ||||||
|                     "" |                     "" | ||||||
|                 } |                 } | ||||||
|                 GetPlaylistsItem( |                 GetPlaylistsItem( | ||||||
|                     id = it.id, |                     id = playlist.id, | ||||||
|                     title = it.title, |                     title = playlist.title, | ||||||
|                     desc = it.desc ?: "", |                     desc = playlist.desc ?: "", | ||||||
|                     contentCount = contentCount, |                     contentCount = contentCount, | ||||||
|                     coverImageUrl = coverImageUrl |                     coverImageUrl = coverImageUrl | ||||||
|                 ) |                 ) | ||||||
| @@ -142,11 +168,15 @@ class AudioContentPlaylistService( | |||||||
|             .withZoneSameInstant(ZoneId.of("Asia/Seoul")) |             .withZoneSameInstant(ZoneId.of("Asia/Seoul")) | ||||||
|             .format(dateTimeFormatter) |             .format(dateTimeFormatter) | ||||||
|  |  | ||||||
|  |         val contentIdAndOrderList = playlist.contentIdAndOrderList.filter { | ||||||
|  |             it.endDate == null || it.endDate!! > LocalDateTime.now() | ||||||
|  |         } | ||||||
|  |  | ||||||
|         val contentList = audioContentRepository.fetchContentForPlaylist( |         val contentList = audioContentRepository.fetchContentForPlaylist( | ||||||
|             contentIdList = playlist.contentIdAndOrderList.map { it.contentId } |             contentIdList = contentIdAndOrderList.map { it.contentId } | ||||||
|         ) |         ) | ||||||
|  |  | ||||||
|         val orderMap = playlist.contentIdAndOrderList.sortedBy { it.order } |         val orderMap = contentIdAndOrderList.sortedBy { it.order } | ||||||
|             .mapIndexed { index, item -> item.contentId to index } |             .mapIndexed { index, item -> item.contentId to index } | ||||||
|             .toMap() |             .toMap() | ||||||
|  |  | ||||||
|   | |||||||
| @@ -0,0 +1,9 @@ | |||||||
|  | package kr.co.vividnext.sodalive.content.playlist | ||||||
|  |  | ||||||
|  | import com.querydsl.core.annotations.QueryProjection | ||||||
|  | import java.time.LocalDateTime | ||||||
|  |  | ||||||
|  | data class ContentIdAndEndDateData @QueryProjection constructor( | ||||||
|  |     val contentId: Long, | ||||||
|  |     val endDate: LocalDateTime? | ||||||
|  | ) | ||||||
| @@ -1,6 +1,9 @@ | |||||||
| package kr.co.vividnext.sodalive.content.playlist | package kr.co.vividnext.sodalive.content.playlist | ||||||
|  |  | ||||||
|  | import java.time.LocalDateTime | ||||||
|  |  | ||||||
| data class PlaylistContentIdAndOrder( | data class PlaylistContentIdAndOrder( | ||||||
|     val contentId: Long, |     val contentId: Long, | ||||||
|     val order: Int |     val order: Int, | ||||||
|  |     var endDate: LocalDateTime? = null | ||||||
| ) | ) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user