diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberController.kt index 3f14263..0acc861 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/member/CreatorAdminMemberController.kt @@ -13,13 +13,13 @@ import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController +@PreAuthorize("hasRole('CREATOR')") @RequestMapping("/creator-admin/member") class CreatorAdminMemberController(private val service: CreatorAdminMemberService) { @PostMapping("/login") fun login(@RequestBody loginRequest: LoginRequest) = service.login(loginRequest) @PostMapping("/logout") - @PreAuthorize("hasRole('CREATOR')") fun logout( @RequestHeader("Authorization") token: String, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureController.kt new file mode 100644 index 0000000..40e93df --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureController.kt @@ -0,0 +1,53 @@ +package kr.co.vividnext.sodalive.creator.admin.signature + +import kr.co.vividnext.sodalive.common.ApiResponse +import kr.co.vividnext.sodalive.common.SodaException +import kr.co.vividnext.sodalive.member.Member +import org.springframework.data.domain.Pageable +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.RequestMapping +import org.springframework.web.bind.annotation.RequestParam +import org.springframework.web.bind.annotation.RestController +import org.springframework.web.multipart.MultipartFile + +@RestController +@PreAuthorize("hasRole('CREATOR')") +@RequestMapping("/creator-admin/signature") +class CreatorAdminSignatureController(private val service: CreatorAdminSignatureService) { + @GetMapping + fun getSignatureCanList(pageable: Pageable) = ApiResponse.ok(data = service.getSignatureList(pageable)) + + @PostMapping + fun createSignature( + @RequestParam("can") can: Int, + @RequestParam("image") image: MultipartFile, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.createSignature(can = can, image = image, memberId = member.id!!), + "등록되었습니다." + ) + } + + @PutMapping + fun modifySignature( + @RequestParam("id") id: Long, + @RequestParam("image", required = false) image: MultipartFile?, + @RequestParam("isActive", required = false) isActive: Boolean?, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + if (image == null && isActive == null) throw SodaException("변경사항이 없습니다.") + + ApiResponse.ok( + service.modifySignature(id = id, image = image, isActive = isActive, memberId = member.id!!), + if (isActive == false) "삭제되었습니다." else "수정되었습니다." + ) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureRepository.kt new file mode 100644 index 0000000..14c76ad --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureRepository.kt @@ -0,0 +1,57 @@ +package kr.co.vividnext.sodalive.creator.admin.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 CreatorAdminSignatureRepository : JpaRepository, CreatorAdminSignatureQueryRepository + +interface CreatorAdminSignatureQueryRepository { + fun getSignatureListTotalCount(): Int + + fun getSignatureList(imageHost: String, offset: Long, limit: Long): List + + fun findSignatureByIdOrNull(id: Long, memberId: Long): SignatureCan? +} + +class CreatorAdminSignatureQueryRepositoryImpl( + private val queryFactory: JPAQueryFactory +) : CreatorAdminSignatureQueryRepository { + override fun getSignatureListTotalCount(): Int { + return queryFactory.select(signatureCan.id) + .from(signatureCan) + .where(signatureCan.isActive.isTrue) + .fetch() + .size + } + + override fun getSignatureList(imageHost: String, offset: Long, limit: Long): List { + return queryFactory.select( + QGetSignatureListItem( + 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() + } + + override fun findSignatureByIdOrNull(id: Long, memberId: Long): SignatureCan? { + return queryFactory + .selectFrom(signatureCan) + .where( + signatureCan.id.eq(id) + .and(signatureCan.creator.id.eq(memberId)) + ) + .fetchFirst() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureService.kt new file mode 100644 index 0000000..551eecf --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/CreatorAdminSignatureService.kt @@ -0,0 +1,80 @@ +package kr.co.vividnext.sodalive.creator.admin.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.stereotype.Service +import org.springframework.transaction.annotation.Transactional +import org.springframework.web.multipart.MultipartFile + +@Service +class CreatorAdminSignatureService( + private val repository: CreatorAdminSignatureRepository, + 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 getSignatureList(pageable: Pageable): GetSignatureListResponse { + val totalCount = repository.getSignatureListTotalCount() + val items = repository.getSignatureList( + imageHost = imageHost, + offset = pageable.offset, + limit = pageable.pageSize.toLong() + ) + + return GetSignatureListResponse(totalCount, items) + } + + fun createSignature(can: Int, image: MultipartFile, memberId: Long) { + val member = memberRepository.findCreatorByIdOrNull(memberId = memberId) + ?: throw SodaException("잘못된 접근입니다.") + + val signatureCan = SignatureCan(can = can) + signatureCan.creator = member + 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 modifySignature(id: Long, image: MultipartFile?, isActive: Boolean?, memberId: Long) { + val signatureCan = repository.findSignatureByIdOrNull(id = id, memberId = memberId) + ?: 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/creator/admin/signature/GetSignatureListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/GetSignatureListResponse.kt new file mode 100644 index 0000000..95093d8 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/signature/GetSignatureListResponse.kt @@ -0,0 +1,15 @@ +package kr.co.vividnext.sodalive.creator.admin.signature + +import com.querydsl.core.annotations.QueryProjection + +data class GetSignatureListResponse( + val totalCount: Int, + val items: List +) + +data class GetSignatureListItem @QueryProjection constructor( + val id: Long, + val can: Int, + val image: String, + val nickname: String +)