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 +}