| @@ -0,0 +1,45 @@ | ||||
| package kr.co.vividnext.sodalive.admin.live.signature | ||||
|  | ||||
| import com.querydsl.jpa.impl.JPAQueryFactory | ||||
| import kr.co.vividnext.sodalive.live.signature.QSignatureCan.signatureCan | ||||
| import kr.co.vividnext.sodalive.live.signature.SignatureCan | ||||
| import kr.co.vividnext.sodalive.member.QMember.member | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
|  | ||||
| interface AdminAdminSignatureCanRepository : JpaRepository<SignatureCan, Long>, AdminSignatureCanQueryRepository | ||||
|  | ||||
| interface AdminSignatureCanQueryRepository { | ||||
|     fun getSignatureCanListTotalCount(): Int | ||||
|  | ||||
|     fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List<GetSignatureCanListItem> | ||||
| } | ||||
|  | ||||
| class AdminSignatureCanQueryRepositoryImpl( | ||||
|     private val queryFactory: JPAQueryFactory | ||||
| ) : AdminSignatureCanQueryRepository { | ||||
|     override fun getSignatureCanListTotalCount(): Int { | ||||
|         return queryFactory.select(signatureCan.id) | ||||
|             .from(signatureCan) | ||||
|             .where(signatureCan.isActive.isTrue) | ||||
|             .fetch() | ||||
|             .size | ||||
|     } | ||||
|  | ||||
|     override fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List<GetSignatureCanListItem> { | ||||
|         return queryFactory.select( | ||||
|             QGetSignatureCanListItem( | ||||
|                 signatureCan.id, | ||||
|                 signatureCan.can, | ||||
|                 signatureCan.image.prepend("/").prepend(imageHost), | ||||
|                 member.nickname | ||||
|             ) | ||||
|         ) | ||||
|             .from(signatureCan) | ||||
|             .innerJoin(signatureCan.creator, member) | ||||
|             .where(signatureCan.isActive.isTrue) | ||||
|             .offset(offset) | ||||
|             .limit(limit) | ||||
|             .orderBy(signatureCan.id.desc()) | ||||
|             .fetch() | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| package kr.co.vividnext.sodalive.admin.live.signature | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.ApiResponse | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import org.springframework.data.domain.Pageable | ||||
| import org.springframework.security.access.prepost.PreAuthorize | ||||
| import org.springframework.web.bind.annotation.GetMapping | ||||
| import org.springframework.web.bind.annotation.PostMapping | ||||
| import org.springframework.web.bind.annotation.PutMapping | ||||
| 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.multipart.MultipartFile | ||||
|  | ||||
| @RestController | ||||
| @PreAuthorize("hasRole('ADMIN')") | ||||
| @RequestMapping("/admin/live/signature-can") | ||||
| class AdminSignatureCanController(private val service: AdminSignatureCanService) { | ||||
|     @GetMapping | ||||
|     fun getSignatureCanList(pageable: Pageable) = ApiResponse.ok(data = service.getSignatureCanList(pageable)) | ||||
|  | ||||
|     @PostMapping | ||||
|     fun createSignatureCan( | ||||
|         @RequestParam("can") can: Int, | ||||
|         @RequestParam("image") image: MultipartFile, | ||||
|         @RequestParam("creator_id") creatorId: Long | ||||
|     ) = ApiResponse.ok( | ||||
|         service.createSignatureCan(can = can, creatorId = creatorId, image = image), | ||||
|         "등록되었습니다." | ||||
|     ) | ||||
|  | ||||
|     @PutMapping | ||||
|     fun modifySignatureCan( | ||||
|         @RequestParam("id") id: Long, | ||||
|         @RequestParam("image", required = false) image: MultipartFile?, | ||||
|         @RequestParam("isActive", required = false) isActive: Boolean? | ||||
|     ) = run { | ||||
|         if (image == null && isActive == null) { | ||||
|             throw SodaException("변경사항이 없습니다.") | ||||
|         } | ||||
|  | ||||
|         ApiResponse.ok( | ||||
|             service.modifySignatureCan(id = id, image = image, isActive = isActive), | ||||
|             "수정되었습니다." | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,84 @@ | ||||
| package kr.co.vividnext.sodalive.admin.live.signature | ||||
|  | ||||
| import com.amazonaws.services.s3.model.ObjectMetadata | ||||
| import kr.co.vividnext.sodalive.aws.s3.S3Uploader | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.live.signature.SignatureCan | ||||
| import kr.co.vividnext.sodalive.member.MemberRepository | ||||
| import kr.co.vividnext.sodalive.utils.generateFileName | ||||
| import org.springframework.beans.factory.annotation.Value | ||||
| import org.springframework.data.domain.Pageable | ||||
| import org.springframework.data.repository.findByIdOrNull | ||||
| import org.springframework.stereotype.Service | ||||
| import org.springframework.transaction.annotation.Transactional | ||||
| import org.springframework.web.multipart.MultipartFile | ||||
|  | ||||
| @Service | ||||
| class AdminSignatureCanService( | ||||
|     private val repository: AdminAdminSignatureCanRepository, | ||||
|     private val memberRepository: MemberRepository, | ||||
|  | ||||
|     private val s3Uploader: S3Uploader, | ||||
|  | ||||
|     @Value("\${cloud.aws.s3.bucket}") | ||||
|     private val bucket: String, | ||||
|     @Value("\${cloud.aws.cloud-front.host}") | ||||
|     private val imageHost: String | ||||
| ) { | ||||
|     fun getSignatureCanList(pageable: Pageable): GetSignatureCanListResponse { | ||||
|         val totalCount = repository.getSignatureCanListTotalCount() | ||||
|         val items = repository.getSignatureCanList( | ||||
|             imageHost = imageHost, | ||||
|             offset = pageable.offset, | ||||
|             limit = pageable.pageSize.toLong() | ||||
|         ) | ||||
|  | ||||
|         return GetSignatureCanListResponse(totalCount, items) | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun createSignatureCan(can: Int, creatorId: Long, image: MultipartFile) { | ||||
|         if (creatorId < 1) throw SodaException("올바른 크리에이터를 선택해 주세요.") | ||||
|  | ||||
|         val creator = memberRepository.findCreatorByIdOrNull(memberId = creatorId) | ||||
|             ?: throw SodaException("올바른 크리에이터를 선택해 주세요.") | ||||
|  | ||||
|         val signatureCan = SignatureCan(can = can) | ||||
|         signatureCan.creator = creator | ||||
|         repository.save(signatureCan) | ||||
|  | ||||
|         val metadata = ObjectMetadata() | ||||
|         metadata.contentLength = image.size | ||||
|         val imagePath = s3Uploader.upload( | ||||
|             inputStream = image.inputStream, | ||||
|             bucket = bucket, | ||||
|             filePath = "signature_can/${signatureCan.id}/${generateFileName()}", | ||||
|             metadata = metadata | ||||
|         ) | ||||
|  | ||||
|         signatureCan.image = imagePath | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun modifySignatureCan(id: Long, image: MultipartFile?, isActive: Boolean?) { | ||||
|         val signatureCan = repository.findByIdOrNull(id = id) | ||||
|             ?: throw SodaException("잘못된 요청입니다.") | ||||
|  | ||||
|         if (isActive != null) { | ||||
|             signatureCan.isActive = isActive | ||||
|         } | ||||
|  | ||||
|         if (image != null) { | ||||
|             val metadata = ObjectMetadata() | ||||
|             metadata.contentLength = image.size | ||||
|             val imagePath = s3Uploader.upload( | ||||
|                 inputStream = image.inputStream, | ||||
|                 bucket = bucket, | ||||
|                 filePath = "signature_can/${signatureCan.id}/${generateFileName()}", | ||||
|                 metadata = metadata | ||||
|             ) | ||||
|  | ||||
|             signatureCan.image = imagePath | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,15 @@ | ||||
| package kr.co.vividnext.sodalive.admin.live.signature | ||||
|  | ||||
| import com.querydsl.core.annotations.QueryProjection | ||||
|  | ||||
| data class GetSignatureCanListResponse( | ||||
|     val totalCount: Int, | ||||
|     val items: List<GetSignatureCanListItem> | ||||
| ) | ||||
|  | ||||
| data class GetSignatureCanListItem @QueryProjection constructor( | ||||
|     val id: Long, | ||||
|     val can: Int, | ||||
|     val image: String, | ||||
|     val nickname: String | ||||
| ) | ||||
| @@ -11,5 +11,8 @@ data class CreateLiveRoomRequest( | ||||
|     val price: Int = 0, | ||||
|     val timezone: String, | ||||
|     val type: LiveRoomType = LiveRoomType.OPEN, | ||||
|     val password: String? = null | ||||
|     val password: String? = null, | ||||
|     val menuPanId: Long = 0, | ||||
|     val menuPan: String = "", | ||||
|     val isActiveMenuPan: Boolean = false | ||||
| ) | ||||
|   | ||||
| @@ -5,5 +5,8 @@ data class EditLiveRoomInfoRequest( | ||||
|     val notice: String?, | ||||
|     val numberOfPeople: Int?, | ||||
|     val beginDateTimeString: String?, | ||||
|     val timezone: String? | ||||
|     val timezone: String?, | ||||
|     val menuPanId: Long = 0, | ||||
|     val menuPan: String = "", | ||||
|     val isActiveMenuPan: Boolean? = null | ||||
| ) | ||||
|   | ||||
| @@ -38,8 +38,12 @@ import kr.co.vividnext.sodalive.live.room.info.LiveRoomInfo | ||||
| import kr.co.vividnext.sodalive.live.room.info.LiveRoomInfoRedisRepository | ||||
| import kr.co.vividnext.sodalive.live.room.info.LiveRoomMember | ||||
| import kr.co.vividnext.sodalive.live.room.kickout.LiveRoomKickOutService | ||||
| import kr.co.vividnext.sodalive.live.room.menu.CreateLiveMenuRequest | ||||
| import kr.co.vividnext.sodalive.live.room.menu.LiveRoomMenuService | ||||
| import kr.co.vividnext.sodalive.live.room.menu.UpdateLiveMenuRequest | ||||
| import kr.co.vividnext.sodalive.live.room.visit.LiveRoomVisitService | ||||
| import kr.co.vividnext.sodalive.live.roulette.NewRouletteRepository | ||||
| import kr.co.vividnext.sodalive.live.signature.SignatureCanRepository | ||||
| import kr.co.vividnext.sodalive.live.tag.LiveTagRepository | ||||
| import kr.co.vividnext.sodalive.member.Gender | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| @@ -65,12 +69,15 @@ import kotlin.concurrent.write | ||||
| @Service | ||||
| @Transactional(readOnly = true) | ||||
| class LiveRoomService( | ||||
|     private val menuService: LiveRoomMenuService, | ||||
|  | ||||
|     private val repository: LiveRoomRepository, | ||||
|     private val rouletteRepository: NewRouletteRepository, | ||||
|     private val roomInfoRepository: LiveRoomInfoRedisRepository, | ||||
|     private val roomCancelRepository: LiveRoomCancelRepository, | ||||
|     private val kickOutService: LiveRoomKickOutService, | ||||
|     private val blockMemberRepository: BlockMemberRepository, | ||||
|     private val signatureCanRepository: SignatureCanRepository, | ||||
|  | ||||
|     private val applicationEventPublisher: ApplicationEventPublisher, | ||||
|     private val useCanCalculateRepository: UseCanCalculateRepository, | ||||
| @@ -269,6 +276,27 @@ class LiveRoomService( | ||||
|             room.bgImage = request.coverImageUrl | ||||
|         } | ||||
|  | ||||
|         if (request.isActiveMenuPan) { | ||||
|             if (request.menuPanId > 0) { | ||||
|                 menuService.updateLiveMenu( | ||||
|                     memberId = member.id!!, | ||||
|                     request = UpdateLiveMenuRequest( | ||||
|                         id = request.menuPanId, | ||||
|                         menu = request.menuPan, | ||||
|                         isActive = true | ||||
|                     ) | ||||
|                 ) | ||||
|             } else { | ||||
|                 menuService.createLiveMenu( | ||||
|                     memberId = member.id!!, | ||||
|                     request = CreateLiveMenuRequest( | ||||
|                         menu = request.menuPan, | ||||
|                         isActive = true | ||||
|                     ) | ||||
|                 ) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         applicationEventPublisher.publishEvent( | ||||
|             FcmEvent( | ||||
|                 type = FcmEventType.CREATE_LIVE, | ||||
| @@ -604,6 +632,28 @@ class LiveRoomService( | ||||
|             throw SodaException("변경사항이 없습니다.") | ||||
|         } | ||||
|  | ||||
|         if (coverImage != null) { | ||||
|             val metadata = ObjectMetadata() | ||||
|             metadata.contentLength = coverImage.size | ||||
|  | ||||
|             // 커버 이미지 파일명 생성 | ||||
|             val coverImageFileName = generateFileName(prefix = "${room.id}-cover") | ||||
|  | ||||
|             // 커버 이미지 업로드 | ||||
|             val coverImagePath = s3Uploader.upload( | ||||
|                 inputStream = coverImage.inputStream, | ||||
|                 bucket = coverImageBucket, | ||||
|                 filePath = "live_room_cover/${room.id}/$coverImageFileName", | ||||
|                 metadata = metadata | ||||
|             ) | ||||
|  | ||||
|             room.bgImage = coverImagePath | ||||
|  | ||||
|             if (room.channelName == null) { | ||||
|                 room.coverImage = coverImagePath | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (requestString != null) { | ||||
|             val request = objectMapper.readValue(requestString, EditLiveRoomInfoRequest::class.java) | ||||
|  | ||||
| @@ -625,27 +675,30 @@ class LiveRoomService( | ||||
|                     .withZoneSameInstant(ZoneId.of("UTC")) | ||||
|                     .toLocalDateTime() | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (coverImage != null) { | ||||
|             val metadata = ObjectMetadata() | ||||
|             metadata.contentLength = coverImage.size | ||||
|  | ||||
|             // 커버 이미지 파일명 생성 | ||||
|             val coverImageFileName = generateFileName(prefix = "${room.id}-cover") | ||||
|  | ||||
|             // 커버 이미지 업로드 | ||||
|             val coverImagePath = s3Uploader.upload( | ||||
|                 inputStream = coverImage.inputStream, | ||||
|                 bucket = coverImageBucket, | ||||
|                 filePath = "live_room_cover/${room.id}/$coverImageFileName", | ||||
|                 metadata = metadata | ||||
|             ) | ||||
|  | ||||
|             room.bgImage = coverImagePath | ||||
|  | ||||
|             if (room.channelName == null) { | ||||
|                 room.coverImage = coverImagePath | ||||
|             if (request.isActiveMenuPan != null) { | ||||
|                 if (request.isActiveMenuPan) { | ||||
|                     if (request.menuPanId > 0) { | ||||
|                         menuService.updateLiveMenu( | ||||
|                             memberId = member.id!!, | ||||
|                             request = UpdateLiveMenuRequest( | ||||
|                                 id = request.menuPanId, | ||||
|                                 menu = request.menuPan, | ||||
|                                 isActive = true | ||||
|                             ) | ||||
|                         ) | ||||
|                     } else { | ||||
|                         menuService.createLiveMenu( | ||||
|                             memberId = member.id!!, | ||||
|                             request = CreateLiveMenuRequest( | ||||
|                                 menu = request.menuPan, | ||||
|                                 isActive = true | ||||
|                             ) | ||||
|                         ) | ||||
|                     } | ||||
|                 } else { | ||||
|                     menuService.deactivateAll(memberId = member.id!!) | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| @@ -703,6 +756,8 @@ class LiveRoomService( | ||||
|             listOf() | ||||
|         } | ||||
|  | ||||
|         val menuPan = menuService.getLiveMenu(creatorId = room.member!!.id!!) | ||||
|  | ||||
|         return GetRoomInfoResponse( | ||||
|             roomId = roomId, | ||||
|             title = room.title, | ||||
| @@ -738,6 +793,7 @@ class LiveRoomService( | ||||
|             listenerList = roomInfo.listenerList, | ||||
|             managerList = roomInfo.managerList, | ||||
|             donationRankingTop3UserIds = donationRankingTop3UserIds, | ||||
|             menuPan = menuPan?.menu ?: "", | ||||
|             isPrivateRoom = room.type == LiveRoomType.PRIVATE, | ||||
|             password = room.password, | ||||
|             isActiveRoulette = isActiveRoulette | ||||
| @@ -916,7 +972,7 @@ class LiveRoomService( | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
|     fun donation(request: LiveRoomDonationRequest, member: Member) { | ||||
|     fun donation(request: LiveRoomDonationRequest, member: Member): String? { | ||||
|         val room = repository.findByIdOrNull(request.roomId) | ||||
|             ?: throw SodaException("해당하는 라이브가 없습니다.") | ||||
|  | ||||
| @@ -949,6 +1005,12 @@ class LiveRoomService( | ||||
|                 roomInfoRepository.save(roomInfo) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return signatureCanRepository.findImageByCreatorIdAndCan( | ||||
|             creatorId = host.id!!, | ||||
|             can = request.can, | ||||
|             imageHost = cloudFrontHost | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     @Transactional | ||||
| @@ -1019,6 +1081,8 @@ class LiveRoomService( | ||||
|                             rouletteRepository.save(it) | ||||
|                         } | ||||
|                     } | ||||
|  | ||||
|                     menuService.deactivateAll(memberId = member.id!!) | ||||
|                 } else { | ||||
|                     roomInfo.removeSpeaker(member) | ||||
|                     roomInfo.removeListener(member) | ||||
|   | ||||
| @@ -19,6 +19,7 @@ data class GetRoomInfoResponse( | ||||
|     val listenerList: List<LiveRoomMember>, | ||||
|     val managerList: List<LiveRoomMember>, | ||||
|     val donationRankingTop3UserIds: List<Long>, | ||||
|     val menuPan: String, | ||||
|     val isPrivateRoom: Boolean = false, | ||||
|     val password: String? = null, | ||||
|     val isActiveRoulette: Boolean = false | ||||
|   | ||||
| @@ -0,0 +1,3 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.menu | ||||
|  | ||||
| data class CreateLiveMenuRequest(val menu: String, val isActive: Boolean) | ||||
| @@ -0,0 +1,7 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.menu | ||||
|  | ||||
| data class GetMenuPresetResponse( | ||||
|     val id: Long, | ||||
|     val menu: String, | ||||
|     val isActive: Boolean | ||||
| ) | ||||
| @@ -0,0 +1,15 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.menu | ||||
|  | ||||
| import org.springframework.data.redis.core.RedisHash | ||||
| import org.springframework.data.redis.core.index.Indexed | ||||
| import javax.persistence.Id | ||||
|  | ||||
| @RedisHash("LiveRoomMenu") | ||||
| data class LiveRoomMenu( | ||||
|     @Id | ||||
|     val id: Long, | ||||
|     @Indexed | ||||
|     val creatorId: Long, | ||||
|     var isActive: Boolean, | ||||
|     var menu: String | ||||
| ) | ||||
| @@ -0,0 +1,26 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.menu | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.ApiResponse | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| 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.RequestMapping | ||||
| import org.springframework.web.bind.annotation.RequestParam | ||||
| import org.springframework.web.bind.annotation.RestController | ||||
|  | ||||
| @RestController | ||||
| @RequestMapping("/live/room/menu") | ||||
| class LiveRoomMenuController(private val service: LiveRoomMenuService) { | ||||
|     @GetMapping("/all") | ||||
|     @PreAuthorize("hasRole('CREATOR')") | ||||
|     fun getAllLiveMenu( | ||||
|         @RequestParam creatorId: Long, | ||||
|         @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? | ||||
|     ) = run { | ||||
|         if (member == null) throw SodaException("로그인 정보를 확인해주세요.") | ||||
|  | ||||
|         ApiResponse.ok(service.getAllLiveMenu(creatorId = creatorId, memberId = member.id!!)) | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,7 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.menu | ||||
|  | ||||
| import org.springframework.data.repository.CrudRepository | ||||
|  | ||||
| interface LiveRoomMenuRepository : CrudRepository<LiveRoomMenu, Long> { | ||||
|     fun findByCreatorId(creatorId: Long): List<LiveRoomMenu> | ||||
| } | ||||
| @@ -0,0 +1,105 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.menu | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.SodaException | ||||
| import kr.co.vividnext.sodalive.live.roulette.RedisIdGenerator | ||||
| import org.springframework.stereotype.Service | ||||
|  | ||||
| @Service | ||||
| class LiveRoomMenuService( | ||||
|     private val idGenerator: RedisIdGenerator, | ||||
|     private val repository: LiveRoomMenuRepository | ||||
| ) { | ||||
|     fun getAllLiveMenu(creatorId: Long, memberId: Long): List<GetMenuPresetResponse> { | ||||
|         if (creatorId != memberId) throw SodaException("잘못된 요청입니다.") | ||||
|  | ||||
|         return repository.findByCreatorId(creatorId) | ||||
|             .sortedBy { it.id } | ||||
|             .asSequence() | ||||
|             .map { GetMenuPresetResponse(id = it.id, menu = it.menu, isActive = it.isActive) } | ||||
|             .toList() | ||||
|     } | ||||
|  | ||||
|     fun createLiveMenu(memberId: Long, request: CreateLiveMenuRequest): Boolean { | ||||
|         liveMenuValidate(menu = request.menu) | ||||
|  | ||||
|         val menuList = repository.findByCreatorId(creatorId = memberId) | ||||
|  | ||||
|         if (menuList.size >= 3) { | ||||
|             throw SodaException("메뉴판의 최대개수는 3개입니다.") | ||||
|         } | ||||
|  | ||||
|         if (request.isActive) { | ||||
|             menuList.forEach { | ||||
|                 it.isActive = false | ||||
|                 repository.save(it) | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         val menu = LiveRoomMenu( | ||||
|             id = idGenerator.generateId(SEQUENCE_NAME), | ||||
|             creatorId = memberId, | ||||
|             isActive = request.isActive, | ||||
|             menu = request.menu | ||||
|         ) | ||||
|  | ||||
|         repository.save(menu) | ||||
|         return request.isActive | ||||
|     } | ||||
|  | ||||
|     fun updateLiveMenu(memberId: Long, request: UpdateLiveMenuRequest) { | ||||
|         liveMenuValidate(menu = request.menu) | ||||
|  | ||||
|         val menuList = repository.findByCreatorId(creatorId = memberId) | ||||
|         if (menuList.isEmpty()) { | ||||
|             throw SodaException("잘못된 요청입니다.") | ||||
|         } | ||||
|  | ||||
|         menuList.forEach { | ||||
|             if (it.id == request.id) { | ||||
|                 it.menu = request.menu | ||||
|                 it.isActive = request.isActive | ||||
|                 repository.save(it) | ||||
|             } else if (request.isActive) { | ||||
|                 it.isActive = false | ||||
|                 repository.save(it) | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fun getLiveMenu(creatorId: Long): GetMenuPresetResponse? { | ||||
|         val menuList = repository.findByCreatorId(creatorId = creatorId) | ||||
|  | ||||
|         var activeMenu: LiveRoomMenu? = null | ||||
|         for (menu in menuList) { | ||||
|             if (menu.isActive) { | ||||
|                 activeMenu = menu | ||||
|                 break | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         if (activeMenu == null || activeMenu.menu.isEmpty()) { | ||||
|             return null | ||||
|         } | ||||
|  | ||||
|         return GetMenuPresetResponse(id = activeMenu.id, menu = activeMenu.menu, isActive = activeMenu.isActive) | ||||
|     } | ||||
|  | ||||
|     fun deactivateAll(memberId: Long) { | ||||
|         val menuList = repository.findByCreatorId(creatorId = memberId) | ||||
|  | ||||
|         menuList.forEach { | ||||
|             it.isActive = false | ||||
|             repository.save(it) | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private fun liveMenuValidate(menu: String) { | ||||
|         if (menu.isBlank()) { | ||||
|             throw SodaException("메뉴판은 빈칸일 수 없습니다.") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     companion object { | ||||
|         const val SEQUENCE_NAME = "LiveRoomMenu:sequence" | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,3 @@ | ||||
| package kr.co.vividnext.sodalive.live.room.menu | ||||
|  | ||||
| data class UpdateLiveMenuRequest(val id: Long, val menu: String, val isActive: Boolean) | ||||
| @@ -0,0 +1,20 @@ | ||||
| package kr.co.vividnext.sodalive.live.signature | ||||
|  | ||||
| import kr.co.vividnext.sodalive.common.BaseEntity | ||||
| import kr.co.vividnext.sodalive.member.Member | ||||
| import javax.persistence.Entity | ||||
| import javax.persistence.FetchType | ||||
| import javax.persistence.JoinColumn | ||||
| import javax.persistence.ManyToOne | ||||
|  | ||||
| @Entity | ||||
| data class SignatureCan( | ||||
|     val can: Int, | ||||
|     var isActive: Boolean = true | ||||
| ) : BaseEntity() { | ||||
|     var image: String? = null | ||||
|  | ||||
|     @ManyToOne(fetch = FetchType.LAZY) | ||||
|     @JoinColumn(name = "creator_id", nullable = false) | ||||
|     var creator: Member? = null | ||||
| } | ||||
| @@ -0,0 +1,25 @@ | ||||
| package kr.co.vividnext.sodalive.live.signature | ||||
|  | ||||
| import com.querydsl.jpa.impl.JPAQueryFactory | ||||
| import kr.co.vividnext.sodalive.live.signature.QSignatureCan.signatureCan | ||||
| import org.springframework.data.jpa.repository.JpaRepository | ||||
|  | ||||
| interface SignatureCanRepository : JpaRepository<SignatureCan, Long>, SignatureCanQueryRepository | ||||
|  | ||||
| interface SignatureCanQueryRepository { | ||||
|     fun findImageByCreatorIdAndCan(creatorId: Long, can: Int, imageHost: String): String? | ||||
| } | ||||
|  | ||||
| class SignatureCanQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : SignatureCanQueryRepository { | ||||
|     override fun findImageByCreatorIdAndCan(creatorId: Long, can: Int, imageHost: String): String? { | ||||
|         return queryFactory | ||||
|             .select(signatureCan.image.prepend("/").prepend(imageHost)) | ||||
|             .from(signatureCan) | ||||
|             .where( | ||||
|                 signatureCan.creator.id.eq(creatorId) | ||||
|                     .and(signatureCan.can.eq(can)) | ||||
|                     .and(signatureCan.isActive.isTrue) | ||||
|             ) | ||||
|             .fetchFirst() | ||||
|     } | ||||
| } | ||||
		Reference in New Issue
	
	Block a user