diff --git a/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/api/QnaSetController.java b/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/api/QnaSetController.java index 35b4de5e2..b9ee2fece 100644 --- a/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/api/QnaSetController.java +++ b/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/api/QnaSetController.java @@ -86,8 +86,8 @@ public ResponseEntity> updateQnaSet( @DeleteMapping("/{qnaSetId}") public ResponseEntity> deleteQnaSet(@PathVariable Long qnaSetId) { qnaSetService.deleteQnaSet(qnaSetId); - var resposne = ApiResponse.success(COMMON204); - return ResponseEntity.ok(resposne); + var response = ApiResponse.success(COMMON204); + return ResponseEntity.ok(response); } @Operation( diff --git a/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/service/QnaSetService.java b/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/service/QnaSetService.java index 2c3ca2916..d7d95e37c 100644 --- a/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/service/QnaSetService.java +++ b/backend/src/main/java/com/shyashyashya/refit/domain/qnaset/service/QnaSetService.java @@ -137,6 +137,7 @@ public Page getMyScrapFoldersWithQnaSetContainingInfo return qnaSetScrapFolderRepository.findAllScrapFoldersWithQnaSetContainingInfo(requestUser, qnaSet, pageable); } + // TODO: ID->Entity 변환기 별도로 분리 고려 private QnaSet getValidatedQnaSet(Long qnaSetId) { QnaSet qnaSet = qnaSetRepository.findById(qnaSetId).orElseThrow(() -> new CustomException(QNA_SET_NOT_FOUND)); User requestUser = requestUserContext.getRequestUser(); diff --git a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/api/ScrapFolderController.java b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/api/ScrapFolderController.java index 44b715a84..7bb203890 100644 --- a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/api/ScrapFolderController.java +++ b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/api/ScrapFolderController.java @@ -23,6 +23,7 @@ import org.springframework.web.bind.annotation.PatchMapping; 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.RestController; @@ -83,4 +84,24 @@ public ResponseEntity> updateScrapFolderName( var response = ApiResponse.success(COMMON200); return ResponseEntity.ok(response); } + + // TODO: Integration Test 작성 필요 + @Operation(summary = "주어진 스크랩 폴더에 지정한 질문 답변 세트를 추가합니다.", description = "이미 추가된 상태인 경우 아무 일도 발생하지 않습니다.") + @PutMapping("{scrapFolderId}/qna-set/{qnaSetId}") + public ResponseEntity> addQnaSetToScrapFolder( + @PathVariable Long qnaSetId, @PathVariable Long scrapFolderId) { + scrapFolderService.addQnaSetToScrapFolder(qnaSetId, scrapFolderId); + var response = ApiResponse.success(COMMON200); + return ResponseEntity.ok(response); + } + + // TODO: Integration Test 작성 필요 + @Operation(summary = "주어진 스크랩 폴더에서 지정한 질문 답변 세트를 제거합니다.", description = "이미 제거된 상태인 경우 아무 일도 발생하지 않습니다.") + @DeleteMapping("{scrapFolderId}/qna-set/{qnaSetId}") + public ResponseEntity> removeQnaSetFromScrapFolder( + @PathVariable Long qnaSetId, @PathVariable Long scrapFolderId) { + scrapFolderService.removeQnaSetFromScrapFolder(qnaSetId, scrapFolderId); + var response = ApiResponse.success(COMMON204); + return ResponseEntity.ok(response); + } } diff --git a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/model/QnaSetScrapFolder.java b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/model/QnaSetScrapFolder.java index 911e8ad0c..e2f51574f 100644 --- a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/model/QnaSetScrapFolder.java +++ b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/model/QnaSetScrapFolder.java @@ -11,13 +11,19 @@ import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; import jakarta.persistence.Table; +import jakarta.persistence.UniqueConstraint; import lombok.AccessLevel; import lombok.Builder; import lombok.Getter; import lombok.NoArgsConstructor; @Entity -@Table(name = "qna_sets_scrap_folders") +@Table( + name = "qna_sets_scrap_folders", + uniqueConstraints = + @UniqueConstraint( + name = "uk_qna_set_scrap_folder", + columnNames = {"qna_set_id", "scrap_folder_id"})) @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) public class QnaSetScrapFolder extends BaseEntity { diff --git a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/repository/QnaSetScrapFolderRepository.java b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/repository/QnaSetScrapFolderRepository.java index ffc3f87ae..50da81db2 100644 --- a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/repository/QnaSetScrapFolderRepository.java +++ b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/repository/QnaSetScrapFolderRepository.java @@ -41,4 +41,8 @@ Page findAllScrapFoldersWithQnaSetContainingInfo( User user, QnaSet qnaSet, Pageable pageable); void deleteAllByScrapFolder(ScrapFolder scrapFolder); + + boolean existsByQnaSetAndScrapFolder(QnaSet qnaSet, ScrapFolder scrapFolder); + + void deleteByQnaSetAndScrapFolder(QnaSet qnaSet, ScrapFolder scrapFolder); } diff --git a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/service/ScrapFolderService.java b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/service/ScrapFolderService.java index 02df62703..abbedc541 100644 --- a/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/service/ScrapFolderService.java +++ b/backend/src/main/java/com/shyashyashya/refit/domain/scrapfolder/service/ScrapFolderService.java @@ -1,9 +1,14 @@ package com.shyashyashya.refit.domain.scrapfolder.service; +import static com.shyashyashya.refit.global.exception.ErrorCode.QNA_SET_NOT_FOUND; import static com.shyashyashya.refit.global.exception.ErrorCode.SCRAP_FOLDER_NOT_FOUND; +import com.shyashyashya.refit.domain.interview.service.validator.InterviewValidator; +import com.shyashyashya.refit.domain.qnaset.model.QnaSet; +import com.shyashyashya.refit.domain.qnaset.repository.QnaSetRepository; import com.shyashyashya.refit.domain.scrapfolder.dto.response.ScrapFolderQnaSetResponse; import com.shyashyashya.refit.domain.scrapfolder.dto.response.ScrapFolderResponse; +import com.shyashyashya.refit.domain.scrapfolder.model.QnaSetScrapFolder; import com.shyashyashya.refit.domain.scrapfolder.model.ScrapFolder; import com.shyashyashya.refit.domain.scrapfolder.repository.QnaSetScrapFolderRepository; import com.shyashyashya.refit.domain.scrapfolder.repository.ScrapFolderRepository; @@ -24,8 +29,10 @@ public class ScrapFolderService { private final ScrapFolderRepository scrapFolderRepository; private final QnaSetScrapFolderRepository qnaSetScrapFolderRepository; + private final QnaSetRepository qnaSetRepository; private final RequestUserContext requestUserContext; private final ScrapFolderValidator scrapFolderValidator; + private final InterviewValidator interviewValidator; @Transactional(readOnly = true) public Page getMyScrapFolders(Pageable pageable) { @@ -83,4 +90,38 @@ public void updateScrapFolderName(Long scrapFolderId, String scrapFolderName) { scrapFolderValidator.validateScrapFolderOwner(scrapFolder, user); scrapFolder.updateName(scrapFolderName); } + + @Transactional + public void addQnaSetToScrapFolder(Long qnaSetId, Long scrapFolderId) { + ScrapFolder scrapFolder = scrapFolderRepository + .findById(scrapFolderId) + .orElseThrow(() -> new CustomException(SCRAP_FOLDER_NOT_FOUND)); + QnaSet qnaSet = getValidatedQnaSet(qnaSetId); + scrapFolderValidator.validateScrapFolderOwner( + scrapFolder, qnaSet.getInterview().getUser()); + + if (!qnaSetScrapFolderRepository.existsByQnaSetAndScrapFolder(qnaSet, scrapFolder)) { + qnaSetScrapFolderRepository.save(QnaSetScrapFolder.create(qnaSet, scrapFolder)); + } + } + + @Transactional + public void removeQnaSetFromScrapFolder(Long qnaSetId, Long scrapFolderId) { + ScrapFolder scrapFolder = scrapFolderRepository + .findById(scrapFolderId) + .orElseThrow(() -> new CustomException(SCRAP_FOLDER_NOT_FOUND)); + QnaSet qnaSet = getValidatedQnaSet(qnaSetId); + scrapFolderValidator.validateScrapFolderOwner( + scrapFolder, qnaSet.getInterview().getUser()); + + qnaSetScrapFolderRepository.deleteByQnaSetAndScrapFolder(qnaSet, scrapFolder); + } + + // TODO: ID->Entity 변환기 별도로 분리 고려 + private QnaSet getValidatedQnaSet(Long qnaSetId) { + QnaSet qnaSet = qnaSetRepository.findById(qnaSetId).orElseThrow(() -> new CustomException(QNA_SET_NOT_FOUND)); + User requestUser = requestUserContext.getRequestUser(); + interviewValidator.validateInterviewOwner(qnaSet.getInterview(), requestUser); + return qnaSet; + } }