diff --git a/data/src/main/kotlin/com/kw/data/domain/bundle/repository/BundleRepository.kt b/data/src/main/kotlin/com/kw/data/domain/bundle/repository/BundleRepository.kt index 8575248..1e24db4 100644 --- a/data/src/main/kotlin/com/kw/data/domain/bundle/repository/BundleRepository.kt +++ b/data/src/main/kotlin/com/kw/data/domain/bundle/repository/BundleRepository.kt @@ -8,6 +8,9 @@ import org.springframework.data.repository.query.Param interface BundleRepository : JpaRepository, BundleCustomRepository { + @Query("SELECT b FROM Bundle b WHERE b.member.id = :memberId AND b.id IN :ids") + fun findAllByMemberIdAndIdIn(@Param("memberId") memberId: Long, @Param("ids") ids: List): List + @Query("SELECT b FROM Bundle b LEFT JOIN FETCH b.bundleTags bt LEFT JOIN FETCH bt.tag WHERE b.id = :id") fun findWithTagsById(@Param("id") id: Long): Bundle? diff --git a/server/api/src/main/kotlin/com/kw/api/common/exception/ApiErrorCode.kt b/server/api/src/main/kotlin/com/kw/api/common/exception/ApiErrorCode.kt index 37d2d81..853cfac 100644 --- a/server/api/src/main/kotlin/com/kw/api/common/exception/ApiErrorCode.kt +++ b/server/api/src/main/kotlin/com/kw/api/common/exception/ApiErrorCode.kt @@ -11,6 +11,7 @@ enum class ApiErrorCode( // bundle FORBIDDEN_BUNDLE(HttpStatus.FORBIDDEN, "FORBIDDEN_BUNDLE", "비공개 꾸러미입니다."), NOT_FOUND_BUNDLE(HttpStatus.NOT_FOUND, "NOT_FOUND_BUNDLE", "존재하지 않는 꾸러미입니다."), + INCLUDE_INVALID_BUNDLE(HttpStatus.NOT_FOUND, "INCLUDE_INVALID_BUNDLE", "권한이 없거나 존재하지 않는 꾸러미가 포함되어 있습니다."), // question NOT_FOUND_QUESTION(HttpStatus.NOT_FOUND, "NOT_FOUND_QUESTION", "존재하지 않는 질문입니다."), diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/controller/BundleController.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/controller/BundleController.kt index 95ddfa0..71238ab 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/controller/BundleController.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/bundle/controller/BundleController.kt @@ -2,7 +2,10 @@ package com.kw.api.domain.bundle.controller import com.kw.api.common.dto.request.PageCondition import com.kw.api.common.dto.response.PageResponse -import com.kw.api.domain.bundle.dto.request.* +import com.kw.api.domain.bundle.dto.request.BundleCreateRequest +import com.kw.api.domain.bundle.dto.request.BundleQuestionAddRequest +import com.kw.api.domain.bundle.dto.request.BundleQuestionRemoveRequest +import com.kw.api.domain.bundle.dto.request.BundleUpdateRequest import com.kw.api.domain.bundle.dto.response.BundleDetailResponse import com.kw.api.domain.bundle.dto.response.BundleResponse import com.kw.api.domain.bundle.service.BundleService @@ -25,16 +28,6 @@ class BundleController( private val bundleService: BundleService ) { - @Operation(summary = "꾸러미 순서 변경") - @ResponseStatus(HttpStatus.NO_CONTENT) - @PatchMapping("/bundles/bundle-order") - fun updateBundleOrder( - @AuthToMember member: Member, - @RequestBody request: BundleOrderUpdateRequest - ) { - bundleService.updateBundleOrder(member, request) - } - @Operation(summary = "꾸러미 생성") @ResponseStatus(HttpStatus.CREATED) @PostMapping("/bundles") @@ -84,6 +77,16 @@ class BundleController( return bundleService.updateBundle(id, request, member) } + @Operation(summary = "꾸러미 순서 변경") + @ResponseStatus(HttpStatus.NO_CONTENT) + @PatchMapping("/bundles/bundle-order") + fun updateBundleOrder( + @AuthToMember member: Member, + @RequestBody request: BundleOrderUpdateRequest + ) { + bundleService.updateBundleOrder(member, request) + } + @Operation(summary = "꾸러미 삭제") @ResponseStatus(HttpStatus.NO_CONTENT) @DeleteMapping("/bundles/{id}") @@ -104,26 +107,14 @@ class BundleController( bundleService.scrapeBundle(id, member) } - @Operation(summary = "꾸러미 내 질문 순서 변경") + @Operation(summary = "선택한 질문 여러 꾸러미에 추가") @ResponseStatus(HttpStatus.NO_CONTENT) - @PatchMapping("/bundles/{id}/question-order") - fun updateQuestionOrder( - @PathVariable id: Long, - @RequestBody @Valid request: BundleQuestionOrderUpdateRequest, - @AuthToMember member: Member - ) { - bundleService.updateQuestionOrder(id, request, member) - } - - @Operation(summary = "선택한 질문 꾸러미에 추가") - @ResponseStatus(HttpStatus.NO_CONTENT) - @PostMapping("/bundles/{id}/questions") + @PostMapping("/bundles/questions") fun addQuestion( - @PathVariable id: Long, @RequestBody @Valid request: BundleQuestionAddRequest, @AuthToMember member: Member ) { - bundleService.addQuestion(id, request, member) + bundleService.addQuestion(request, member) } @Operation(summary = "선택한 질문 꾸러미에서 삭제") diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt index 250a3ab..78d481b 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/bundle/dto/request/BundleQuestionAddRequest.kt @@ -3,6 +3,9 @@ package com.kw.api.domain.bundle.dto.request import jakarta.validation.constraints.Size data class BundleQuestionAddRequest( + @field:Size(min = 1, message = "추가할 꾸러미를 선택해 주세요.") + val bundleIds: List, + @field:Size(min = 1, message = "추가할 질문을 선택해 주세요.") val questionIds: List ) diff --git a/server/api/src/main/kotlin/com/kw/api/domain/bundle/service/BundleService.kt b/server/api/src/main/kotlin/com/kw/api/domain/bundle/service/BundleService.kt index 0eaf3d3..a57a730 100644 --- a/server/api/src/main/kotlin/com/kw/api/domain/bundle/service/BundleService.kt +++ b/server/api/src/main/kotlin/com/kw/api/domain/bundle/service/BundleService.kt @@ -32,10 +32,6 @@ class BundleService( private val questionRepository: QuestionRepository, ) { - fun updateBundleOrder(member: Member, request: BundleOrderUpdateRequest) { - member.updateBundleOrder(request.bundleIds.joinToString(" ")) - } - fun createBundle(request: BundleCreateRequest, member: Member): BundleDetailResponse { val tags = request.tagIds?.let { getExistTags(it) } ?: emptyList() val bundle = request.toEntity(member) @@ -112,6 +108,10 @@ class BundleService( return BundleResponse.from(bundle) } + fun updateBundleOrder(member: Member, request: BundleOrderUpdateRequest) { + member.updateBundleOrder(request.bundleIds.joinToString(" ")) + } + fun deleteBundle(id: Long, member: Member) { val bundle = getExistBundle(id) if (bundle.member.id != member.id) { @@ -148,23 +148,25 @@ class BundleService( bundle.updateQuestionOrder(request.questionOrder.joinToString(" ")) } - fun addQuestion(id: Long, request: BundleQuestionAddRequest, member: Member) { - val bundle = getExistBundle(id) - if (bundle.member.id != member.id) { - throw ApiException(ApiErrorCode.FORBIDDEN) + fun addQuestion(request: BundleQuestionAddRequest, member: Member) { + val bundles = bundleRepository.findAllByMemberIdAndIdIn(member.id!!, request.bundleIds) + if (bundles.size != request.bundleIds.size) { + throw ApiException(ApiErrorCode.INCLUDE_INVALID_BUNDLE) } - val questionCount = questionRepository.countAllByBundleId(id) - if (questionCount + request.questionIds.size >= 100) { - throw ApiException(ApiErrorCode.OVER_QUESTION_LIMIT) - } + bundles.forEach { bundle -> + val questionCount = questionRepository.countAllByBundleId(bundle.id!!) + if (questionCount + request.questionIds.size >= 100) { + throw ApiException(ApiErrorCode.OVER_QUESTION_LIMIT) + } - val questions = questionRepository.findAllWithTagsByIdIn(request.questionIds) - questionRepository.increaseShareCountByIdIn(questions.map { it.id!! }) + val questions = questionRepository.findAllWithTagsByIdIn(request.questionIds) + questionRepository.increaseShareCountByIdIn(questions.map { it.id!! }) - val copiedAndSavedQuestions = questions - .map { questionRepository.save(it.copy(bundle, member)) } - bundle.updateQuestionOrder((bundle.questionOrder + " " + copiedAndSavedQuestions.joinToString(" ") { it.id.toString() }).trim()) + val copiedAndSavedQuestions = questions + .map { questionRepository.save(it.copy(bundle, member)) } + bundle.updateQuestionOrder((bundle.questionOrder + " " + copiedAndSavedQuestions.joinToString(" ") { it.id.toString() }).trim()) + } } fun removeQuestion(id: Long, request: BundleQuestionRemoveRequest, member: Member) {