From 34c08d434552a7d3133479eda6e88925fba5e3bb Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 1 Feb 2024 19:37:15 +0900 Subject: [PATCH 1/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20-=20=EB=93=B1=EB=A1=9D=20API=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 --- .../sodalive/content/category/Category.kt | 18 +++++++++ .../content/category/CategoryContent.kt | 21 ++++++++++ .../category/CategoryContentRepository.kt | 23 +++++++++++ .../content/category/CategoryController.kt | 28 +++++++++++++ .../content/category/CategoryRepository.kt | 23 +++++++++++ .../content/category/CategoryService.kt | 40 +++++++++++++++++++ .../content/category/CreateCategoryRequest.kt | 6 +++ 7 files changed, 159 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/CreateCategoryRequest.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt new file mode 100644 index 0000000..4d576ae --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt @@ -0,0 +1,18 @@ +package kr.co.vividnext.sodalive.content.category + +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 Category( + val title: String, + var isActive: Boolean = true +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "member_id", nullable = false) + var member: Member? = null +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt new file mode 100644 index 0000000..e48986d --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt @@ -0,0 +1,21 @@ +package kr.co.vividnext.sodalive.content.category + +import kr.co.vividnext.sodalive.common.BaseEntity +import kr.co.vividnext.sodalive.content.AudioContent +import javax.persistence.Entity +import javax.persistence.FetchType +import javax.persistence.JoinColumn +import javax.persistence.ManyToOne + +@Entity +data class CategoryContent( + var isActive: Boolean = true +) : BaseEntity() { + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "content_id", nullable = false) + var content: AudioContent? = null + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "category_id", nullable = false) + var category: Category? = null +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt new file mode 100644 index 0000000..af49a35 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt @@ -0,0 +1,23 @@ +package kr.co.vividnext.sodalive.content.category + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.content.category.QCategoryContent.categoryContent +import org.springframework.data.jpa.repository.JpaRepository + +interface CategoryContentRepository : JpaRepository, CategoryContentQueryRepository + +interface CategoryContentQueryRepository { + fun findByContentIdAndCategoryId(contentId: Long, categoryId: Long): CategoryContent? +} + +class CategoryContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CategoryContentQueryRepository { + override fun findByContentIdAndCategoryId(contentId: Long, categoryId: Long): CategoryContent? { + return queryFactory + .selectFrom(categoryContent) + .where( + categoryContent.content.id.eq(contentId) + .and(categoryContent.category.id.eq(categoryId)) + ) + .fetchFirst() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt new file mode 100644 index 0000000..331944d --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt @@ -0,0 +1,28 @@ +package kr.co.vividnext.sodalive.content.category + +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.PostMapping +import org.springframework.web.bind.annotation.RequestBody +import org.springframework.web.bind.annotation.RequestMapping +import org.springframework.web.bind.annotation.RestController + +@RestController +@RequestMapping("/category") +class CategoryController(private val service: CategoryService) { + @PostMapping + @PreAuthorize("hasRole('CREATOR')") + fun createCategory( + @RequestBody request: CreateCategoryRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok( + service.createCategory(request = request, member = member) + ) + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt new file mode 100644 index 0000000..24bab28 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt @@ -0,0 +1,23 @@ +package kr.co.vividnext.sodalive.content.category + +import com.querydsl.jpa.impl.JPAQueryFactory +import kr.co.vividnext.sodalive.content.category.QCategory.category +import org.springframework.data.jpa.repository.JpaRepository + +interface CategoryRepository : JpaRepository, CategoryQueryRepository + +interface CategoryQueryRepository { + fun findByTitleAndMemberId(title: String, memberId: Long): Category? +} + +class CategoryQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CategoryQueryRepository { + override fun findByTitleAndMemberId(title: String, memberId: Long): Category? { + return queryFactory + .selectFrom(category) + .where( + category.title.eq(title) + .and(category.member.id.eq(memberId)) + ) + .fetchFirst() + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt new file mode 100644 index 0000000..414e6b3 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt @@ -0,0 +1,40 @@ +package kr.co.vividnext.sodalive.content.category + +import kr.co.vividnext.sodalive.content.AudioContentRepository +import kr.co.vividnext.sodalive.member.Member +import org.springframework.stereotype.Service +import org.springframework.transaction.annotation.Transactional + +@Service +class CategoryService( + private val repository: CategoryRepository, + private val contentRepository: AudioContentRepository, + private val categoryContentRepository: CategoryContentRepository +) { + @Transactional + fun createCategory(request: CreateCategoryRequest, member: Member) { + val category = repository.findByTitleAndMemberId(title = request.title, memberId = member.id!!) + ?: repository.save( + Category(title = request.title).apply { + this.member = member + } + ) + category.isActive = true + + for (contentId in request.contentIdList) { + val content = contentRepository.findByIdAndActive(contentId = contentId) + ?: continue + + val categoryContent = categoryContentRepository.findByContentIdAndCategoryId( + contentId = contentId, + categoryId = category.id!! + ) ?: categoryContentRepository.save( + CategoryContent().apply { + this.content = content + this.category = category + } + ) + categoryContent.isActive = true + } + } +} diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CreateCategoryRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CreateCategoryRequest.kt new file mode 100644 index 0000000..7484b3c --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CreateCategoryRequest.kt @@ -0,0 +1,6 @@ +package kr.co.vividnext.sodalive.content.category + +data class CreateCategoryRequest( + val title: String, + val contentIdList: List +) From 8be2ec9319b1873355b6652fa726dca1bf8cb90c Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 1 Feb 2024 19:48:59 +0900 Subject: [PATCH 2/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20-=20=EC=82=AD=EC=A0=9C=20API=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 --- .../category/CategoryContentRepository.kt | 9 +++++++++ .../content/category/CategoryController.kt | 17 ++++++++++++++--- .../content/category/CategoryRepository.kt | 12 ++++++++++++ .../content/category/CategoryService.kt | 10 ++++++++++ 4 files changed, 45 insertions(+), 3 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt index af49a35..e560d60 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContentRepository.kt @@ -8,6 +8,7 @@ interface CategoryContentRepository : JpaRepository, Cate interface CategoryContentQueryRepository { fun findByContentIdAndCategoryId(contentId: Long, categoryId: Long): CategoryContent? + fun deleteByCategoryId(categoryId: Long) } class CategoryContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CategoryContentQueryRepository { @@ -20,4 +21,12 @@ class CategoryContentQueryRepositoryImpl(private val queryFactory: JPAQueryFacto ) .fetchFirst() } + + override fun deleteByCategoryId(categoryId: Long) { + queryFactory + .update(categoryContent) + .set(categoryContent.isActive, false) + .where(categoryContent.category.id.eq(categoryId)) + .execute() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt index 331944d..724408e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt @@ -5,6 +5,8 @@ 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.DeleteMapping +import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping @@ -21,8 +23,17 @@ class CategoryController(private val service: CategoryService) { ) = run { if (member == null) throw SodaException("로그인 정보를 확인해주세요.") - ApiResponse.ok( - service.createCategory(request = request, member = member) - ) + ApiResponse.ok(service.createCategory(request = request, member = member)) + } + + @DeleteMapping("/{id}") + @PreAuthorize("hasRole('CREATOR')") + fun deleteCategory( + @PathVariable("id") categoryId: Long, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.deleteCategory(categoryId = categoryId, member = member)) } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt index 24bab28..c3b3c2f 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt @@ -8,6 +8,8 @@ interface CategoryRepository : JpaRepository, CategoryQueryRepos interface CategoryQueryRepository { fun findByTitleAndMemberId(title: String, memberId: Long): Category? + + fun findByIdAndMemberId(categoryId: Long, memberId: Long): Category? } class CategoryQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CategoryQueryRepository { @@ -20,4 +22,14 @@ class CategoryQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : C ) .fetchFirst() } + + override fun findByIdAndMemberId(categoryId: Long, memberId: Long): Category? { + return queryFactory + .selectFrom(category) + .where( + category.id.eq(categoryId) + .and(category.member.id.eq(memberId)) + ) + .fetchFirst() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt index 414e6b3..7b44133 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt @@ -1,5 +1,6 @@ package kr.co.vividnext.sodalive.content.category +import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.content.AudioContentRepository import kr.co.vividnext.sodalive.member.Member import org.springframework.stereotype.Service @@ -37,4 +38,13 @@ class CategoryService( categoryContent.isActive = true } } + + @Transactional + fun deleteCategory(categoryId: Long, member: Member) { + val category = repository.findByIdAndMemberId(categoryId = categoryId, memberId = member.id!!) + ?: throw SodaException("잘못된 요청입니다.") + category.isActive = false + + categoryContentRepository.deleteByCategoryId(categoryId = categoryId) + } } From a2e6d09ee8f43ab2f94dc80209e7796cdfdf844b Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 1 Feb 2024 20:00:48 +0900 Subject: [PATCH 3/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20-=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=A1=B0=ED=9A=8C=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/content/category/CategoryController.kt | 12 ++++++++++++ .../sodalive/content/category/CategoryRepository.kt | 10 ++++++++++ .../sodalive/content/category/CategoryService.kt | 9 +++++++++ .../content/category/GetCategoryListResponse.kt | 8 ++++++++ 4 files changed, 39 insertions(+) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/GetCategoryListResponse.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt index 724408e..ac308bc 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt @@ -6,10 +6,12 @@ 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.DeleteMapping +import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.PostMapping 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 @@ -36,4 +38,14 @@ class CategoryController(private val service: CategoryService) { ApiResponse.ok(service.deleteCategory(categoryId = categoryId, member = member)) } + + @GetMapping + fun getCategoryList( + @RequestParam creatorId: Long, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.getCategoryList(creatorId = creatorId, memberId = member.id!!)) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt index c3b3c2f..eacc9bd 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryRepository.kt @@ -10,6 +10,8 @@ interface CategoryQueryRepository { fun findByTitleAndMemberId(title: String, memberId: Long): Category? fun findByIdAndMemberId(categoryId: Long, memberId: Long): Category? + + fun findByCreatorId(creatorId: Long): List } class CategoryQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : CategoryQueryRepository { @@ -32,4 +34,12 @@ class CategoryQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) : C ) .fetchFirst() } + + override fun findByCreatorId(creatorId: Long): List { + return queryFactory + .select(QGetCategoryListResponse(category.id, category.title)) + .from(category) + .where(category.member.id.eq(creatorId)) + .fetch() + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt index 7b44133..3265f70 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt @@ -3,6 +3,7 @@ package kr.co.vividnext.sodalive.content.category import kr.co.vividnext.sodalive.common.SodaException import kr.co.vividnext.sodalive.content.AudioContentRepository import kr.co.vividnext.sodalive.member.Member +import kr.co.vividnext.sodalive.member.block.BlockMemberRepository import org.springframework.stereotype.Service import org.springframework.transaction.annotation.Transactional @@ -10,6 +11,7 @@ import org.springframework.transaction.annotation.Transactional class CategoryService( private val repository: CategoryRepository, private val contentRepository: AudioContentRepository, + private val blockMemberRepository: BlockMemberRepository, private val categoryContentRepository: CategoryContentRepository ) { @Transactional @@ -47,4 +49,11 @@ class CategoryService( categoryContentRepository.deleteByCategoryId(categoryId = categoryId) } + + fun getCategoryList(creatorId: Long, memberId: Long): List { + val isBlocked = blockMemberRepository.isBlocked(blockedMemberId = memberId, memberId = creatorId) + if (isBlocked) throw SodaException("잘못된 접근입니다.") + + return repository.findByCreatorId(creatorId = creatorId) + } } diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/GetCategoryListResponse.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/GetCategoryListResponse.kt new file mode 100644 index 0000000..3e575c8 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/GetCategoryListResponse.kt @@ -0,0 +1,8 @@ +package kr.co.vividnext.sodalive.content.category + +import com.querydsl.core.annotations.QueryProjection + +data class GetCategoryListResponse @QueryProjection constructor( + val categoryId: Long, + val category: String +) From b8b387c33dd1b971709c44cab5f9caec498ec03b Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 1 Feb 2024 22:49:40 +0900 Subject: [PATCH 4/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20-=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=20=EC=88=98=EC=A0=95=20API=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sodalive/content/category/Category.kt | 2 +- .../content/category/CategoryController.kt | 12 +++++++ .../content/category/CategoryService.kt | 34 +++++++++++++++++++ .../content/category/ModifyCategoryRequest.kt | 8 +++++ 4 files changed, 55 insertions(+), 1 deletion(-) create mode 100644 src/main/kotlin/kr/co/vividnext/sodalive/content/category/ModifyCategoryRequest.kt diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt index 4d576ae..0b6c50d 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt @@ -9,7 +9,7 @@ import javax.persistence.ManyToOne @Entity data class Category( - val title: String, + var title: String, var isActive: Boolean = true ) : BaseEntity() { @ManyToOne(fetch = FetchType.LAZY) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt index ac308bc..b3db249 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryController.kt @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable 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 @@ -28,6 +29,17 @@ class CategoryController(private val service: CategoryService) { ApiResponse.ok(service.createCategory(request = request, member = member)) } + @PutMapping + @PreAuthorize("hasRole('CREATOR')") + fun modifyCategory( + @RequestBody request: ModifyCategoryRequest, + @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member? + ) = run { + if (member == null) throw SodaException("로그인 정보를 확인해주세요.") + + ApiResponse.ok(service.modifyCategory(request = request, member = member)) + } + @DeleteMapping("/{id}") @PreAuthorize("hasRole('CREATOR')") fun deleteCategory( diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt index 3265f70..01e168e 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt @@ -41,6 +41,40 @@ class CategoryService( } } + @Transactional + fun modifyCategory(request: ModifyCategoryRequest, member: Member) { + val category = repository.findByIdAndMemberId(categoryId = request.categoryId, memberId = member.id!!) + ?: throw SodaException("잘못된 요청입니다.") + + if (!request.title.isNullOrBlank()) { + category.title = request.title + } + + for (contentId in request.addContentIdList) { + val content = contentRepository.findByIdAndActive(contentId = contentId) + ?: continue + + val categoryContent = categoryContentRepository.findByContentIdAndCategoryId( + contentId = contentId, + categoryId = category.id!! + ) ?: categoryContentRepository.save( + CategoryContent().apply { + this.content = content + this.category = category + } + ) + categoryContent.isActive = true + } + + for (contentId in request.removeContentIdList) { + val categoryContent = categoryContentRepository.findByContentIdAndCategoryId( + contentId = contentId, + categoryId = category.id!! + ) ?: continue + categoryContent.isActive = false + } + } + @Transactional fun deleteCategory(categoryId: Long, member: Member) { val category = repository.findByIdAndMemberId(categoryId = categoryId, memberId = member.id!!) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/ModifyCategoryRequest.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/ModifyCategoryRequest.kt new file mode 100644 index 0000000..5bd5b37 --- /dev/null +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/ModifyCategoryRequest.kt @@ -0,0 +1,8 @@ +package kr.co.vividnext.sodalive.content.category + +data class ModifyCategoryRequest( + val categoryId: Long, + val title: String?, + val addContentIdList: List, + val removeContentIdList: List +) From c50f24b7559c7653d51e21e9b95aec4a2716ce8f Mon Sep 17 00:00:00 2001 From: Klaus Date: Thu, 1 Feb 2024 22:56:54 +0900 Subject: [PATCH 5/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20=EB=A7=8C=EB=93=A4=EA=B8=B0,=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20API=20-=20=EC=B9=B4=ED=85=8C=EA=B3=A0?= =?UTF-8?q?=EB=A6=AC=EB=AA=85=20=EA=B2=80=EC=A6=9D=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../vividnext/sodalive/content/category/CategoryService.kt | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt index 01e168e..3afe603 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryService.kt @@ -16,6 +16,7 @@ class CategoryService( ) { @Transactional fun createCategory(request: CreateCategoryRequest, member: Member) { + validateTitle(title = request.title) val category = repository.findByTitleAndMemberId(title = request.title, memberId = member.id!!) ?: repository.save( Category(title = request.title).apply { @@ -47,6 +48,7 @@ class CategoryService( ?: throw SodaException("잘못된 요청입니다.") if (!request.title.isNullOrBlank()) { + validateTitle(title = request.title) category.title = request.title } @@ -90,4 +92,8 @@ class CategoryService( return repository.findByCreatorId(creatorId = creatorId) } + + private fun validateTitle(title: String) { + if (title.length < 2) throw SodaException("카테고리명은 2글자 이상 입력하세요") + } } From 22f274fd321729835ad2bf7edb5062b7d57ddc5c Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 2 Feb 2024 20:03:23 +0900 Subject: [PATCH 6/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20-=20=EC=A1=B0=ED=9A=8C=20=EC=A1=B0=EA=B1=B4?= =?UTF-8?q?=EC=97=90=20=EC=B9=B4=ED=85=8C=EA=B3=A0=EB=A6=AC=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 --- .../vividnext/sodalive/content/AudioContentController.kt | 2 ++ .../vividnext/sodalive/content/AudioContentRepository.kt | 9 +++++++++ .../co/vividnext/sodalive/content/AudioContentService.kt | 2 ++ 3 files changed, 13 insertions(+) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt index d86afd3..409adb8 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt @@ -105,6 +105,7 @@ class AudioContentController(private val service: AudioContentService) { fun getAudioContentList( @RequestParam("creator-id") creatorId: Long, @RequestParam("sort-type", required = false) sortType: SortType = SortType.NEWEST, + @RequestParam("category-id", required = false) categoryId: Long = 0, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, pageable: Pageable ) = run { @@ -114,6 +115,7 @@ class AudioContentController(private val service: AudioContentService) { service.getAudioContentList( creatorId = creatorId, sortType = sortType, + categoryId = categoryId, member = member, offset = pageable.offset, limit = pageable.pageSize.toLong() diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt index 4e90a0e..ff06f60 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentRepository.kt @@ -4,6 +4,7 @@ import com.querydsl.core.types.dsl.Expressions import com.querydsl.jpa.impl.JPAQueryFactory import kr.co.vividnext.sodalive.content.QAudioContent.audioContent import kr.co.vividnext.sodalive.content.QBundleAudioContent.bundleAudioContent +import kr.co.vividnext.sodalive.content.category.QCategoryContent.categoryContent import kr.co.vividnext.sodalive.content.comment.QAudioContentComment.audioContentComment import kr.co.vividnext.sodalive.content.like.QAudioContentLike.audioContentLike import kr.co.vividnext.sodalive.content.main.GetAudioContentMainItem @@ -37,6 +38,7 @@ interface AudioContentQueryRepository { coverImageHost: String, isAdult: Boolean = false, sortType: SortType = SortType.NEWEST, + categoryId: Long = 0, offset: Long = 0, limit: Long = 10 ): List @@ -144,6 +146,7 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) coverImageHost: String, isAdult: Boolean, sortType: SortType, + categoryId: Long, offset: Long, limit: Long ): List { @@ -163,6 +166,10 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) where = where.and(audioContent.isAdult.isFalse) } + if (categoryId > 0) { + where = where.and(categoryContent.category.id.eq(categoryId)) + } + return queryFactory .select( QGetAudioContentListItem( @@ -180,6 +187,8 @@ class AudioContentQueryRepositoryImpl(private val queryFactory: JPAQueryFactory) ) ) .from(audioContent) + .leftJoin(categoryContent) + .on(audioContent.id.eq(categoryContent.content.id).and(categoryContent.isActive.ne(false))) .leftJoin(pinContent) .on(audioContent.id.eq(pinContent.content.id).and(pinContent.isActive.ne(false))) .where(where) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt index 9c52cb4..832a9f9 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentService.kt @@ -624,6 +624,7 @@ class AudioContentService( creatorId: Long, sortType: SortType, member: Member, + categoryId: Long = 0, offset: Long, limit: Long ): GetAudioContentListResponse { @@ -637,6 +638,7 @@ class AudioContentService( coverImageHost = coverImageHost, isAdult = member.auth != null, sortType = sortType, + categoryId = categoryId, offset = offset, limit = limit ) From 6efab40a85821db764fa27f3090ce91b321dd49a Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 2 Feb 2024 20:55:28 +0900 Subject: [PATCH 7/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=20-=20=EC=A0=95=EB=A0=AC=EC=88=9C?= =?UTF-8?q?=EC=84=9C=EB=A5=BC=20=ED=91=9C=EC=8B=9C=ED=95=98=EB=8A=94=20ord?= =?UTF-8?q?ers=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../kotlin/kr/co/vividnext/sodalive/content/category/Category.kt | 1 + .../kr/co/vividnext/sodalive/content/category/CategoryContent.kt | 1 + 2 files changed, 2 insertions(+) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt index 0b6c50d..6125131 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/Category.kt @@ -10,6 +10,7 @@ import javax.persistence.ManyToOne @Entity data class Category( var title: String, + var orders: Int = 1, var isActive: Boolean = true ) : BaseEntity() { @ManyToOne(fetch = FetchType.LAZY) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt index e48986d..2363226 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/category/CategoryContent.kt @@ -9,6 +9,7 @@ import javax.persistence.ManyToOne @Entity data class CategoryContent( + var orders: Int = 1, var isActive: Boolean = true ) : BaseEntity() { @ManyToOne(fetch = FetchType.LAZY) From e1ea1f14a5f69a40fc13d7d475a9d0fb598c4daf Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 2 Feb 2024 21:48:11 +0900 Subject: [PATCH 8/9] =?UTF-8?q?=EC=BD=98=ED=85=90=EC=B8=A0=20=EC=A0=95?= =?UTF-8?q?=EC=82=B0=20-=20=ED=95=98=EB=82=98=EC=9D=98=20=EC=BD=98?= =?UTF-8?q?=ED=85=90=EC=B8=A0=EB=A5=BC=20=EA=B5=AC=EB=A7=A4=ED=95=A0=20?= =?UTF-8?q?=EB=95=8C=20PG,=20APPLE=5FIAP=20=EC=99=80=20=EA=B0=99=EC=9D=B4?= =?UTF-8?q?=202=EA=B0=9C=20=EC=9D=B4=EC=83=81=EC=9D=98=20=EB=8B=A4?= =?UTF-8?q?=EB=A5=B8=20=EC=BA=94=EC=9C=BC=EB=A1=9C=20=EA=B2=B0=EC=A0=9C=20?= =?UTF-8?q?=ED=96=88=EC=9D=84=20=EB=95=8C=202=EA=B0=9C=20=EC=9D=B4?= =?UTF-8?q?=EC=83=81=20=EA=B5=AC=EB=A7=A4=EB=90=9C=20=EA=B2=83=EC=9C=BC?= =?UTF-8?q?=EB=A1=9C=20=ED=91=9C=EC=8B=9C=EB=90=98=EB=8A=94=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 --- .../admin/calculate/AdminCalculateQueryRepository.kt | 1 + .../calculate/CreatorAdminCalculateQueryRepository.kt | 10 ++++------ 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt index f94b641..2f61759 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/admin/calculate/AdminCalculateQueryRepository.kt @@ -65,6 +65,7 @@ class AdminCalculateQueryRepository(private val queryFactory: JPAQueryFactory) { .where( order.createdAt.goe(startDate) .and(order.createdAt.loe(endDate)) + .and(order.isActive.isTrue) ) .groupBy(audioContent.id, order.type, orderFormattedDate, order.can) .orderBy(member.id.desc(), orderFormattedDate.desc(), audioContent.id.asc()) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt index fb1fc98..2a7dc02 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/creator/admin/calculate/CreatorAdminCalculateQueryRepository.kt @@ -116,16 +116,14 @@ class CreatorAdminCalculateQueryRepository(private val queryFactory: JPAQueryFac order.can.sum() ) ) - .from(useCanCalculate) - .innerJoin(useCanCalculate.useCan, useCan) - .innerJoin(useCan.order, order) + .from(order) .innerJoin(order.audioContent, audioContent) .innerJoin(audioContent.member, member) .where( - useCanCalculate.status.eq(UseCanCalculateStatus.RECEIVED) - .and(useCanCalculate.recipientCreatorId.eq(memberId)) - .and(order.createdAt.goe(startDate)) + order.createdAt.goe(startDate) .and(order.createdAt.loe(endDate)) + .and(order.isActive.isTrue) + .and(order.creator.id.eq(memberId)) ) .groupBy(audioContent.id, order.type, orderFormattedDate, order.can) .offset(offset) From 720ee63505ccb31bbb7daa3211a71ec824fda4ab Mon Sep 17 00:00:00 2001 From: Klaus Date: Fri, 2 Feb 2024 21:52:10 +0900 Subject: [PATCH 9/9] =?UTF-8?q?=EC=A0=84=EC=B2=B4=20=EC=BD=98=ED=85=90?= =?UTF-8?q?=EC=B8=A0=20=EB=A6=AC=EC=8A=A4=ED=8A=B8=20-=20=EC=B9=B4?= =?UTF-8?q?=ED=85=8C=EA=B3=A0=EB=A6=AC=EB=A5=BC=20=EC=A7=80=EC=A0=95?= =?UTF-8?q?=ED=95=98=EC=A7=80=20=EC=95=8A=EC=9D=84=20=EB=95=8C=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=EB=90=98=EC=A7=80=20=EC=95=8A=EB=8A=94=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 --- .../co/vividnext/sodalive/content/AudioContentController.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt index 409adb8..f631261 100644 --- a/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt +++ b/src/main/kotlin/kr/co/vividnext/sodalive/content/AudioContentController.kt @@ -105,7 +105,7 @@ class AudioContentController(private val service: AudioContentService) { fun getAudioContentList( @RequestParam("creator-id") creatorId: Long, @RequestParam("sort-type", required = false) sortType: SortType = SortType.NEWEST, - @RequestParam("category-id", required = false) categoryId: Long = 0, + @RequestParam("category-id", required = false) categoryId: Long? = 0, @AuthenticationPrincipal(expression = "#this == 'anonymousUser' ? null : member") member: Member?, pageable: Pageable ) = run { @@ -115,7 +115,7 @@ class AudioContentController(private val service: AudioContentService) { service.getAudioContentList( creatorId = creatorId, sortType = sortType, - categoryId = categoryId, + categoryId = categoryId ?: 0, member = member, offset = pageable.offset, limit = pageable.pageSize.toLong()