From 945fd5d5a380184cc798afc25aa4edf8a4f75c88 Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 5 Mar 2024 15:40:24 +0900 Subject: [PATCH 01/14] =?UTF-8?q?=EB=A9=94=EB=89=B4=ED=8C=90=20=ED=94=84?= =?UTF-8?q?=EB=A6=AC=EC=85=8B=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../live/room/menu/CreateLiveMenuRequest.kt | 3 + .../live/room/menu/GetMenuResponse.kt | 6 ++ .../sodalive/live/room/menu/LiveRoomMenu.kt | 15 +++ .../live/room/menu/LiveRoomMenuController.kt | 66 ++++++++++++ .../live/room/menu/LiveRoomMenuRepository.kt | 7 ++ .../live/room/menu/LiveRoomMenuService.kt | 102 ++++++++++++++++++ .../live/room/menu/UpdateLiveMenuRequest.kt | 3 + 7 files changed, 202 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/CreateLiveMenuRequest.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenu.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/UpdateLiveMenuRequest.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/CreateLiveMenuRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/CreateLiveMenuRequest.kt new file mode 100644 index 0000000..8ec8188 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/CreateLiveMenuRequest.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.live.room.menu + +data class CreateLiveMenuRequest(val menu: String, val isActive: Boolean) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt new file mode 100644 index 0000000..c1187e9 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt @@ -0,0 +1,6 @@ +package kr.co.vividnext.sodalive.live.room.menu + +data class GetMenuResponse( + val id: Long, + val menu: String +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenu.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenu.kt new file mode 100644 index 0000000..947ccf4 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenu.kt @@ -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 +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt new file mode 100644 index 0000000..0531e8f --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt @@ -0,0 +1,66 @@ +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 kr.co.vividnext.sodalive.member.MemberRole +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.PostMapping +import org.springframework.web.bind.annotation.PutMapping +import org.springframework.web.bind.annotation.RequestBody +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("/creator") + @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!!)) + } + + @PostMapping + @PreAuthorize("hasRole('CREATOR')") + fun createLiveMenu( + @RequestBody request: CreateLiveMenuRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null || member.role != MemberRole.CREATOR) { + throw SodaException("로그인 정보를 확인해주세요.") + } + + ApiResponse.ok(service.createLiveMenu(memberId = member.id!!, request = request)) + } + + @PutMapping + @PreAuthorize("hasRole('CREATOR')") + fun updateLiveMenu( + @RequestBody request: UpdateLiveMenuRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null || member.role != MemberRole.CREATOR) { + throw SodaException("로그인 정보를 확인해주세요.") + } + + ApiResponse.ok(service.updateLiveMenu(memberId = member.id!!, request = request)) + } + + @GetMapping + fun getMenu( + @RequestParam creatorId: Long, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.getLiveMenu(creatorId = creatorId)) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuRepository.kt new file mode 100644 index 0000000..62c553f --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuRepository.kt @@ -0,0 +1,7 @@ +package kr.co.vividnext.sodalive.live.room.menu + +import org.springframework.data.repository.CrudRepository + +interface LiveRoomMenuRepository : CrudRepository { + fun findByCreatorId(creatorId: Long): List +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt new file mode 100644 index 0000000..4673943 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt @@ -0,0 +1,102 @@ +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 { + if (creatorId != memberId) throw SodaException("잘못된 요청입니다.") + + return repository.findByCreatorId(creatorId) + .sortedBy { it.id } + .asSequence() + .map { GetMenuResponse(id = it.id, menu = it.menu) } + .toList() + } + + fun createLiveMenu(memberId: Long, request: CreateLiveMenuRequest): Boolean { + liveMenuValidate(menu = request.menu) + + if (request.isActive) { + val menuList = repository.findByCreatorId(creatorId = memberId) + 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): Boolean { + liveMenuValidate(menu = request.menu) + + val menuList = repository.findByCreatorId(creatorId = memberId) + if (menuList.isEmpty()) { + throw SodaException("잘못된 요청입니다.") + } + + var isActive = false + menuList.forEach { + if (request.isActive || it.isActive) { + isActive = true + } + + 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) + } + } + + return isActive + } + + fun getLiveMenu(creatorId: Long): GetMenuResponse { + val menuList = repository.findByCreatorId(creatorId = creatorId) + + if (menuList.isEmpty()) { + throw SodaException("설정된 메뉴판이 없습니다.") + } + + var activeMenu: LiveRoomMenu? = null + for (menu in menuList) { + if (menu.isActive) { + activeMenu = menu + break + } + } + + if (activeMenu == null || activeMenu.menu.isEmpty()) { + throw SodaException("설정된 메뉴판이 없습니다.") + } + + return GetMenuResponse(id = activeMenu.id, menu = activeMenu.menu) + } + + private fun liveMenuValidate(menu: String) { + if (menu.isBlank()) { + throw SodaException("메뉴판은 빈칸일 수 없습니다.") + } + } + + companion object { + const val SEQUENCE_NAME = "LiveRoomMenu:sequence" + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/UpdateLiveMenuRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/UpdateLiveMenuRequest.kt new file mode 100644 index 0000000..2b91b8a --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/UpdateLiveMenuRequest.kt @@ -0,0 +1,3 @@ +package kr.co.vividnext.sodalive.live.room.menu + +data class UpdateLiveMenuRequest(val id: Long, val menu: String, val isActive: Boolean) From 59a035e5c20b809f959d9168079b611591265db9 Mon Sep 17 00:00:00 2001 From: Klaus Date: Tue, 5 Mar 2024 22:20:40 +0900 Subject: [PATCH 02/14] =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=EC=A0=95?= =?UTF-8?q?=EB=B3=B4=20=EC=A1=B0=ED=9A=8C=20API=20-=20=EC=9D=91=EB=8B=B5?= =?UTF-8?q?=EC=97=90=20=EB=A9=94=EB=89=B4=ED=8C=90=20=EC=A0=95=EB=B3=B4=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/co/vividnext/sodalive/live/room/LiveRoomService.kt | 6 ++++++ .../sodalive/live/room/info/GetRoomInfoResponse.kt | 1 + 2 files changed, 7 insertions(+) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index 7fb751c..c8937bc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -38,6 +38,7 @@ 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.LiveRoomMenuService import kr.co.vividnext.sodalive.live.room.visit.LiveRoomVisitService import kr.co.vividnext.sodalive.live.roulette.NewRouletteRepository import kr.co.vividnext.sodalive.live.tag.LiveTagRepository @@ -65,6 +66,8 @@ 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, @@ -703,6 +706,8 @@ class LiveRoomService( listOf() } + val menuPan = menuService.getLiveMenu(creatorId = room.member!!.id!!) + return GetRoomInfoResponse( roomId = roomId, title = room.title, @@ -738,6 +743,7 @@ class LiveRoomService( listenerList = roomInfo.listenerList, managerList = roomInfo.managerList, donationRankingTop3UserIds = donationRankingTop3UserIds, + menuPan = menuPan.menu, isPrivateRoom = room.type == LiveRoomType.PRIVATE, password = room.password, isActiveRoulette = isActiveRoulette diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/info/GetRoomInfoResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/info/GetRoomInfoResponse.kt index fd0de33..d4d536e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/info/GetRoomInfoResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/info/GetRoomInfoResponse.kt @@ -19,6 +19,7 @@ data class GetRoomInfoResponse( val listenerList: List, val managerList: List, val donationRankingTop3UserIds: List, + val menuPan: String, val isPrivateRoom: Boolean = false, val password: String? = null, val isActiveRoulette: Boolean = false From 31e33d49df1ab7974f125fa30f78a5fe8ea1a9c3 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 6 Mar 2024 00:55:37 +0900 Subject: [PATCH 03/14] =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=EB=A9=94?= =?UTF-8?q?=EB=89=B4=ED=8C=90=20-=20=EB=B6=88=ED=95=84=EC=9A=94=ED=95=9C?= =?UTF-8?q?=20API=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../live/room/menu/LiveRoomMenuController.kt | 42 +------------------ 1 file changed, 1 insertion(+), 41 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt index 0531e8f..11e3aa8 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuController.kt @@ -3,13 +3,9 @@ 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 kr.co.vividnext.sodalive.member.MemberRole 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.PostMapping -import org.springframework.web.bind.annotation.PutMapping -import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RequestParam import org.springframework.web.bind.annotation.RestController @@ -17,7 +13,7 @@ import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/live/room/menu") class LiveRoomMenuController(private val service: LiveRoomMenuService) { - @GetMapping("/creator") + @GetMapping("/all") @PreAuthorize("hasRole('CREATOR')") fun getAllLiveMenu( @RequestParam creatorId: Long, @@ -27,40 +23,4 @@ class LiveRoomMenuController(private val service: LiveRoomMenuService) { ApiResponse.ok(service.getAllLiveMenu(creatorId = creatorId, memberId = member.id!!)) } - - @PostMapping - @PreAuthorize("hasRole('CREATOR')") - fun createLiveMenu( - @RequestBody request: CreateLiveMenuRequest, - @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? - ) = run { - if (member == null || member.role != MemberRole.CREATOR) { - throw SodaException("로그인 정보를 확인해주세요.") - } - - ApiResponse.ok(service.createLiveMenu(memberId = member.id!!, request = request)) - } - - @PutMapping - @PreAuthorize("hasRole('CREATOR')") - fun updateLiveMenu( - @RequestBody request: UpdateLiveMenuRequest, - @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? - ) = run { - if (member == null || member.role != MemberRole.CREATOR) { - throw SodaException("로그인 정보를 확인해주세요.") - } - - ApiResponse.ok(service.updateLiveMenu(memberId = member.id!!, request = request)) - } - - @GetMapping - fun getMenu( - @RequestParam creatorId: Long, - @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? - ) = run { - if (member == null) throw SodaException("로그인 정보를 확인해주세요.") - - ApiResponse.ok(service.getLiveMenu(creatorId = creatorId)) - } } From ae04b22b2ac3e1ac398db92af6f8fbe25f07f107 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 6 Mar 2024 01:40:25 +0900 Subject: [PATCH 04/14] =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=EB=A7=8C?= =?UTF-8?q?=EB=93=A4=EA=B8=B0,=20=EC=88=98=EC=A0=95=20-=20=EB=A9=94?= =?UTF-8?q?=EB=89=B4=ED=8C=90=20=EB=A7=8C=EB=93=A4=EA=B8=B0,=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EA=B8=B0=EB=8A=A5=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../live/room/CreateLiveRoomRequest.kt | 5 +- .../live/room/EditLiveRoomInfoRequest.kt | 5 +- .../sodalive/live/room/LiveRoomService.kt | 88 ++++++++++++++----- .../live/room/menu/LiveRoomMenuService.kt | 29 +++--- 4 files changed, 93 insertions(+), 34 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/CreateLiveRoomRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/CreateLiveRoomRequest.kt index 22b5468..9a50a39 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/CreateLiveRoomRequest.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/CreateLiveRoomRequest.kt @@ -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 ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt index 437e8f9..9d24bfd 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt @@ -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 ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index c8937bc..74b2d48 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -38,7 +38,9 @@ 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.tag.LiveTagRepository @@ -272,6 +274,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, @@ -607,6 +630,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) @@ -628,27 +673,28 @@ 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) { + 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!!) } } } @@ -743,7 +789,7 @@ class LiveRoomService( listenerList = roomInfo.listenerList, managerList = roomInfo.managerList, donationRankingTop3UserIds = donationRankingTop3UserIds, - menuPan = menuPan.menu, + menuPan = menuPan?.menu ?: "", isPrivateRoom = room.type == LiveRoomType.PRIVATE, password = room.password, isActiveRoulette = isActiveRoulette diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt index 4673943..f6ab126 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt @@ -22,8 +22,13 @@ class LiveRoomMenuService( 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) { - val menuList = repository.findByCreatorId(creatorId = memberId) menuList.forEach { it.isActive = false repository.save(it) @@ -41,7 +46,7 @@ class LiveRoomMenuService( return request.isActive } - fun updateLiveMenu(memberId: Long, request: UpdateLiveMenuRequest): Boolean { + fun updateLiveMenu(memberId: Long, request: UpdateLiveMenuRequest) { liveMenuValidate(menu = request.menu) val menuList = repository.findByCreatorId(creatorId = memberId) @@ -49,12 +54,7 @@ class LiveRoomMenuService( throw SodaException("잘못된 요청입니다.") } - var isActive = false menuList.forEach { - if (request.isActive || it.isActive) { - isActive = true - } - if (it.id == request.id) { it.menu = request.menu it.isActive = request.isActive @@ -64,11 +64,9 @@ class LiveRoomMenuService( repository.save(it) } } - - return isActive } - fun getLiveMenu(creatorId: Long): GetMenuResponse { + fun getLiveMenu(creatorId: Long): GetMenuResponse? { val menuList = repository.findByCreatorId(creatorId = creatorId) if (menuList.isEmpty()) { @@ -84,12 +82,21 @@ class LiveRoomMenuService( } if (activeMenu == null || activeMenu.menu.isEmpty()) { - throw SodaException("설정된 메뉴판이 없습니다.") + return null } return GetMenuResponse(id = activeMenu.id, menu = activeMenu.menu) } + 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("메뉴판은 빈칸일 수 없습니다.") From 97d44104e10449c0b23e78faefb765147609d248 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 6 Mar 2024 13:43:03 +0900 Subject: [PATCH 05/14] =?UTF-8?q?=EB=A9=94=EB=89=B4=ED=8C=90=20=EA=B0=80?= =?UTF-8?q?=EC=A0=B8=EC=98=A4=EA=B8=B0=20-=20=EB=A9=94=EB=89=B4=ED=8C=90?= =?UTF-8?q?=EC=9D=B4=20=EC=97=86=EC=9D=84=20=EB=95=8C=20=EC=98=88=EC=99=B8?= =?UTF-8?q?=EC=B2=98=EB=A6=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt index f6ab126..e27c78a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt @@ -69,10 +69,6 @@ class LiveRoomMenuService( fun getLiveMenu(creatorId: Long): GetMenuResponse? { val menuList = repository.findByCreatorId(creatorId = creatorId) - if (menuList.isEmpty()) { - throw SodaException("설정된 메뉴판이 없습니다.") - } - var activeMenu: LiveRoomMenu? = null for (menu in menuList) { if (menu.isActive) { From bbfcf5fd4fd5dee0727ccdd511102c63b5d7f0a3 Mon Sep 17 00:00:00 2001 From: Klaus Date: Wed, 6 Mar 2024 13:45:32 +0900 Subject: [PATCH 06/14] =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=EC=A2=85?= =?UTF-8?q?=EB=A3=8C=20-=20=EB=A9=94=EB=89=B4=ED=8C=90=20=EB=B9=84?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/co/vividnext/sodalive/live/room/LiveRoomService.kt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index 74b2d48..5b0fffc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -1071,6 +1071,8 @@ class LiveRoomService( rouletteRepository.save(it) } } + + menuService.deactivateAll(memberId = member.id!!) } else { roomInfo.removeSpeaker(member) roomInfo.removeListener(member) From 5609bdb6f4a506b9e3b35ebb005ac55d91e1cfbc Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 04:34:41 +0900 Subject: [PATCH 07/14] =?UTF-8?q?=EB=A9=94=EB=89=B4=ED=8C=90=20-=20?= =?UTF-8?q?=ED=99=9C=EC=84=B1=ED=99=94=20=EC=97=AC=EB=B6=80=EB=A5=BC=20?= =?UTF-8?q?=ED=91=9C=EC=8B=9C=ED=95=98=EB=8A=94=20isActive=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/live/room/menu/GetMenuPresetResponse.kt | 7 +++++++ .../vividnext/sodalive/live/room/menu/GetMenuResponse.kt | 6 ------ .../sodalive/live/room/menu/LiveRoomMenuService.kt | 8 ++++---- 3 files changed, 11 insertions(+), 10 deletions(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt delete mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt new file mode 100644 index 0000000..b1d6aec --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuPresetResponse.kt @@ -0,0 +1,7 @@ +package kr.co.vividnext.sodalive.live.room.menu + +data class GetMenuPresetResponse( + val id: Long, + val menu: String, + val isActive: Boolean +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt deleted file mode 100644 index c1187e9..0000000 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/GetMenuResponse.kt +++ /dev/null @@ -1,6 +0,0 @@ -package kr.co.vividnext.sodalive.live.room.menu - -data class GetMenuResponse( - val id: Long, - val menu: String -) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt index e27c78a..e9fc6ab 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/menu/LiveRoomMenuService.kt @@ -9,13 +9,13 @@ class LiveRoomMenuService( private val idGenerator: RedisIdGenerator, private val repository: LiveRoomMenuRepository ) { - fun getAllLiveMenu(creatorId: Long, memberId: Long): List { + fun getAllLiveMenu(creatorId: Long, memberId: Long): List { if (creatorId != memberId) throw SodaException("잘못된 요청입니다.") return repository.findByCreatorId(creatorId) .sortedBy { it.id } .asSequence() - .map { GetMenuResponse(id = it.id, menu = it.menu) } + .map { GetMenuPresetResponse(id = it.id, menu = it.menu, isActive = it.isActive) } .toList() } @@ -66,7 +66,7 @@ class LiveRoomMenuService( } } - fun getLiveMenu(creatorId: Long): GetMenuResponse? { + fun getLiveMenu(creatorId: Long): GetMenuPresetResponse? { val menuList = repository.findByCreatorId(creatorId = creatorId) var activeMenu: LiveRoomMenu? = null @@ -81,7 +81,7 @@ class LiveRoomMenuService( return null } - return GetMenuResponse(id = activeMenu.id, menu = activeMenu.menu) + return GetMenuPresetResponse(id = activeMenu.id, menu = activeMenu.menu, isActive = activeMenu.isActive) } fun deactivateAll(memberId: Long) { From c66421b45d96bef8610ec8aeb2972f701912b815 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 05:39:16 +0900 Subject: [PATCH 08/14] =?UTF-8?q?=EB=9D=BC=EC=9D=B4=EB=B8=8C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20-=20=EB=A9=94=EB=89=B4=ED=8C=90=20=ED=99=9C?= =?UTF-8?q?=EC=84=B1=ED=99=94/=EB=B9=84=ED=99=9C=EC=84=B1=ED=99=94=20?= =?UTF-8?q?=EB=A1=9C=EC=A7=81=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../live/room/EditLiveRoomInfoRequest.kt | 2 +- .../sodalive/live/room/LiveRoomService.kt | 38 ++++++++++--------- 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt index 9d24bfd..bfa5f37 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/EditLiveRoomInfoRequest.kt @@ -8,5 +8,5 @@ data class EditLiveRoomInfoRequest( val timezone: String?, val menuPanId: Long = 0, val menuPan: String = "", - val isActiveMenuPan: Boolean + val isActiveMenuPan: Boolean? = null ) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index 5b0fffc..2320726 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -674,27 +674,29 @@ class LiveRoomService( .toLocalDateTime() } - if (request.isActiveMenuPan) { - if (request.menuPanId > 0) { - menuService.updateLiveMenu( - memberId = member.id!!, - request = UpdateLiveMenuRequest( - id = request.menuPanId, - menu = request.menuPan, - isActive = true + 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.createLiveMenu( - memberId = member.id!!, - request = CreateLiveMenuRequest( - menu = request.menuPan, - isActive = true - ) - ) + menuService.deactivateAll(memberId = member.id!!) } - } else { - menuService.deactivateAll(memberId = member.id!!) } } } From 0d402b608ca2b6c9c35a0ffcf0cca0bde13d5715 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 17:44:38 +0900 Subject: [PATCH 09/14] =?UTF-8?q?=EA=B4=80=EB=A6=AC=EC=9E=90=20-=20?= =?UTF-8?q?=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20=EC=BA=94=20=EB=93=B1?= =?UTF-8?q?=EB=A1=9D/=EC=88=98=EC=A0=95=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../signature/GetSignatureCanListResponse.kt | 10 +++ .../live/signature/SignatureCanController.kt | 47 +++++++++++ .../live/signature/SignatureCanRepository.kt | 33 ++++++++ .../live/signature/SignatureCanService.kt | 80 +++++++++++++++++++ .../sodalive/live/signature/SignatureCan.kt | 20 +++++ 5 files changed, 190 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt new file mode 100644 index 0000000..851a1f3 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt @@ -0,0 +1,10 @@ +package kr.co.vividnext.sodalive.admin.live.signature + +import com.querydsl.core.annotations.QueryProjection + +data class GetSignatureCanListResponse @QueryProjection constructor( + val id: Long, + val can: Int, + val image: String, + val nickname: String +) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanController.kt new file mode 100644 index 0000000..9272b50 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanController.kt @@ -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 SignatureCanController(private val service: SignatureCanService) { + @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") image: MultipartFile?, + @RequestParam("isActive") isActive: Boolean? + ) = run { + if (image == null && isActive == null) { + throw SodaException("변경사항이 없습니다.") + } + + ApiResponse.ok( + service.modifySignatureCan(id = id, image = image, isActive = isActive), + "수정되었습니다." + ) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanRepository.kt new file mode 100644 index 0000000..90aa2c0 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanRepository.kt @@ -0,0 +1,33 @@ +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 SignatureCanRepository : JpaRepository, SignatureCanQueryRepository + +interface SignatureCanQueryRepository { + fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List +} + +class SignatureCanQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : SignatureCanQueryRepository { + override fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List { + return queryFactory.select( + QGetSignatureCanListResponse( + 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() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanService.kt new file mode 100644 index 0000000..afc044a --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanService.kt @@ -0,0 +1,80 @@ +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 SignatureCanService( + private val repository: SignatureCanRepository, + 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): List { + return repository.getSignatureCanList( + imageHost = imageHost, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ) + } + + @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 + + 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 + } + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt new file mode 100644 index 0000000..4d98e9f --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt @@ -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 = false +) : BaseEntity() { + var image: String? = null + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "creator_id", nullable = false) + var creator: Member? = null +} From 71937ce89cfb40fc2233074c11bca1d29847185a Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 19:38:25 +0900 Subject: [PATCH 10/14] =?UTF-8?q?=ED=9B=84=EC=9B=90=20-=20=EA=B2=B0?= =?UTF-8?q?=EA=B3=BC=EA=B0=92=EC=97=90=20=EC=8B=9C=EA=B7=B8=EB=8B=88?= =?UTF-8?q?=EC=B2=98=20=EC=9D=B4=EB=AF=B8=EC=A7=80=20URL=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...kt => AdminAdminSignatureCanRepository.kt} | 8 +++--- ...ller.kt => AdminSignatureCanController.kt} | 2 +- ...Service.kt => AdminSignatureCanService.kt} | 4 +-- .../sodalive/live/room/LiveRoomService.kt | 10 +++++++- .../live/signature/SignatureCanRepository.kt | 25 +++++++++++++++++++ 5 files changed, 42 insertions(+), 7 deletions(-) rename src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/{SignatureCanRepository.kt => AdminAdminSignatureCanRepository.kt} (79%) rename src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/{SignatureCanController.kt => AdminSignatureCanController.kt} (95%) rename src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/{SignatureCanService.kt => AdminSignatureCanService.kt} (96%) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminAdminSignatureCanRepository.kt similarity index 79% rename from src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanRepository.kt rename to src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminAdminSignatureCanRepository.kt index 90aa2c0..ce71442 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminAdminSignatureCanRepository.kt @@ -6,13 +6,15 @@ import kr.co.vividnext.sodalive.live.signature.SignatureCan import kr.co.vividnext.sodalive.member.QMember.member import org.springframework.data.jpa.repository.JpaRepository -interface SignatureCanRepository : JpaRepository, SignatureCanQueryRepository +interface AdminAdminSignatureCanRepository : JpaRepository, AdminSignatureCanQueryRepository -interface SignatureCanQueryRepository { +interface AdminSignatureCanQueryRepository { fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List } -class SignatureCanQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : SignatureCanQueryRepository { +class AdminSignatureCanQueryRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : AdminSignatureCanQueryRepository { override fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List { return queryFactory.select( QGetSignatureCanListResponse( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanController.kt similarity index 95% rename from src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanController.kt rename to src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanController.kt index 9272b50..6023343 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanController.kt @@ -15,7 +15,7 @@ import org.springframework.web.multipart.MultipartFile @RestController @PreAuthorize("hasRole('ADMIN')") @RequestMapping("/admin/live/signature-can") -class SignatureCanController(private val service: SignatureCanService) { +class AdminSignatureCanController(private val service: AdminSignatureCanService) { @GetMapping fun getSignatureCanList(pageable: Pageable) = ApiResponse.ok(data = service.getSignatureCanList(pageable)) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt similarity index 96% rename from src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanService.kt rename to src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt index afc044a..3da5cba 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/SignatureCanService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt @@ -14,8 +14,8 @@ import org.springframework.transaction.annotation.Transactional import org.springframework.web.multipart.MultipartFile @Service -class SignatureCanService( - private val repository: SignatureCanRepository, +class AdminSignatureCanService( + private val repository: AdminAdminSignatureCanRepository, private val memberRepository: MemberRepository, private val s3Uploader: S3Uploader, diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt index 2320726..85dfd1a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/room/LiveRoomService.kt @@ -43,6 +43,7 @@ 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 @@ -76,6 +77,7 @@ class LiveRoomService( private val roomCancelRepository: LiveRoomCancelRepository, private val kickOutService: LiveRoomKickOutService, private val blockMemberRepository: BlockMemberRepository, + private val signatureCanRepository: SignatureCanRepository, private val applicationEventPublisher: ApplicationEventPublisher, private val useCanCalculateRepository: UseCanCalculateRepository, @@ -970,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("해당하는 라이브가 없습니다.") @@ -1003,6 +1005,12 @@ class LiveRoomService( roomInfoRepository.save(roomInfo) } } + + return signatureCanRepository.findImageByCreatorIdAndCan( + creatorId = host.id!!, + can = request.can, + imageHost = cloudFrontHost + ) } @Transactional diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt new file mode 100644 index 0000000..51d67e9 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCanRepository.kt @@ -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, 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() + } +} From 6d40ef6f4d5d18b8954400e1357a060dc283ba75 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 21:34:07 +0900 Subject: [PATCH 11/14] =?UTF-8?q?=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20?= =?UTF-8?q?=EC=BA=94=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20-=20=EC=B4=9D=20?= =?UTF-8?q?=EA=B0=9C=EC=88=98=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../AdminAdminSignatureCanRepository.kt | 16 +++++++++++++--- .../live/signature/AdminSignatureCanService.kt | 7 +++++-- .../signature/GetSignatureCanListResponse.kt | 7 ++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminAdminSignatureCanRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminAdminSignatureCanRepository.kt index ce71442..215e006 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminAdminSignatureCanRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminAdminSignatureCanRepository.kt @@ -9,15 +9,25 @@ import org.springframework.data.jpa.repository.JpaRepository interface AdminAdminSignatureCanRepository : JpaRepository, AdminSignatureCanQueryRepository interface AdminSignatureCanQueryRepository { - fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List + fun getSignatureCanListTotalCount(): Int + + fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List } class AdminSignatureCanQueryRepositoryImpl( private val queryFactory: JPAQueryFactory ) : AdminSignatureCanQueryRepository { - override fun getSignatureCanList(imageHost: String, offset: Long, limit: Long): List { + 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 { return queryFactory.select( - QGetSignatureCanListResponse( + QGetSignatureCanListItem( signatureCan.id, signatureCan.can, signatureCan.image.prepend("/").prepend(imageHost), diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt index 3da5cba..f26e10d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt @@ -25,12 +25,15 @@ class AdminSignatureCanService( @Value("\${cloud.aws.cloud-front.host}") private val imageHost: String ) { - fun getSignatureCanList(pageable: Pageable): List { - return repository.getSignatureCanList( + 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 diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt index 851a1f3..d197058 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/GetSignatureCanListResponse.kt @@ -2,7 +2,12 @@ package kr.co.vividnext.sodalive.admin.live.signature import com.querydsl.core.annotations.QueryProjection -data class GetSignatureCanListResponse @QueryProjection constructor( +data class GetSignatureCanListResponse( + val totalCount: Int, + val items: List +) + +data class GetSignatureCanListItem @QueryProjection constructor( val id: Long, val can: Int, val image: String, From 64c6cc05de2c83af29a1da6b9220ae7e629ee068 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 23:32:42 +0900 Subject: [PATCH 12/14] =?UTF-8?q?=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20?= =?UTF-8?q?=EC=BA=94=20=EC=88=98=EC=A0=95=20-=20=EC=9D=B4=EB=AF=B8?= =?UTF-8?q?=EC=A7=80,=20=ED=99=9C=EC=84=B1=ED=99=94=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=ED=95=84=EC=88=98=EC=97=90=EC=84=9C=20=EC=A0=9C?= =?UTF-8?q?=EC=99=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../admin/live/signature/AdminSignatureCanController.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanController.kt index 6023343..17b4c3d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanController.kt @@ -32,8 +32,8 @@ class AdminSignatureCanController(private val service: AdminSignatureCanService) @PutMapping fun modifySignatureCan( @RequestParam("id") id: Long, - @RequestParam("image") image: MultipartFile?, - @RequestParam("isActive") isActive: Boolean? + @RequestParam("image", required = false) image: MultipartFile?, + @RequestParam("isActive", required = false) isActive: Boolean? ) = run { if (image == null && isActive == null) { throw SodaException("변경사항이 없습니다.") From 400d281cf671bfa539ee52a6cfaed10b54436b65 Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 23:49:03 +0900 Subject: [PATCH 13/14] =?UTF-8?q?=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20?= =?UTF-8?q?=EC=BA=94=20=EB=93=B1=EB=A1=9D=20-=20DB=EC=97=90=20=EC=A0=80?= =?UTF-8?q?=EC=9E=A5=ED=95=98=EC=A7=80=20=EC=95=8A=EB=8D=98=20=EB=B2=84?= =?UTF-8?q?=EA=B7=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/admin/live/signature/AdminSignatureCanService.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt index f26e10d..cae253a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/live/signature/AdminSignatureCanService.kt @@ -45,6 +45,7 @@ class AdminSignatureCanService( val signatureCan = SignatureCan(can = can) signatureCan.creator = creator + repository.save(signatureCan) val metadata = ObjectMetadata() metadata.contentLength = image.size From 3d581b16778360bf7533e9f76413103e3bae88fd Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 7 Mar 2024 23:57:05 +0900 Subject: [PATCH 14/14] =?UTF-8?q?=EC=8B=9C=EA=B7=B8=EB=8B=88=EC=B2=98=20?= =?UTF-8?q?=EC=BA=94=20-=20isActive=20default=20true?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kr/co/vividnext/sodalive/live/signature/SignatureCan.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt index 4d98e9f..66c666a 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/live/signature/SignatureCan.kt @@ -10,7 +10,7 @@ import javax.persistence.ManyToOne @Entity data class SignatureCan( val can: Int, - var isActive: Boolean = false + var isActive: Boolean = true ) : BaseEntity() { var image: String? = null