diff --git a/src/main/java/notai/annotation/application/AnnotationQueryService.java b/src/main/java/notai/annotation/application/AnnotationQueryService.java index 54b7b79..62aa952 100644 --- a/src/main/java/notai/annotation/application/AnnotationQueryService.java +++ b/src/main/java/notai/annotation/application/AnnotationQueryService.java @@ -5,7 +5,9 @@ import notai.annotation.domain.AnnotationRepository; import notai.annotation.presentation.response.AnnotationResponse; import notai.common.exception.type.NotFoundException; +import notai.document.domain.Document; import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,8 +24,11 @@ public class AnnotationQueryService { private final DocumentRepository documentRepository; @Transactional(readOnly = true) - public List getAnnotationsByDocumentAndPageNumbers(Long documentId, List pageNumbers) { - documentRepository.getById(documentId); + public List getAnnotationsByDocumentAndPageNumbers( + Member member, Long documentId, List pageNumbers + ) { + Document document = documentRepository.getById(documentId); + document.validateOwner(member); List annotations = annotationRepository.findByDocumentIdAndPageNumberIn(documentId, pageNumbers); if (annotations.isEmpty()) { diff --git a/src/main/java/notai/annotation/application/AnnotationService.java b/src/main/java/notai/annotation/application/AnnotationService.java index 7aba5be..983c0c3 100644 --- a/src/main/java/notai/annotation/application/AnnotationService.java +++ b/src/main/java/notai/annotation/application/AnnotationService.java @@ -6,6 +6,7 @@ import notai.annotation.presentation.response.AnnotationResponse; import notai.document.domain.Document; import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -17,8 +18,11 @@ public class AnnotationService { private final DocumentRepository documentRepository; @Transactional - public AnnotationResponse createAnnotation(Long documentId, int pageNumber, int x, int y, int width, int height, String content) { + public AnnotationResponse createAnnotation( + Member member, Long documentId, int pageNumber, int x, int y, int width, int height, String content + ) { Document document = documentRepository.getById(documentId); + document.validateOwner(member); Annotation annotation = new Annotation(document, pageNumber, x, y, width, height, content); Annotation savedAnnotation = annotationRepository.save(annotation); @@ -26,16 +30,20 @@ public AnnotationResponse createAnnotation(Long documentId, int pageNumber, int } @Transactional - public AnnotationResponse updateAnnotation(Long documentId, Long annotationId, int x, int y, int width, int height, String content) { - documentRepository.getById(documentId); + public AnnotationResponse updateAnnotation( + Member member, Long documentId, Long annotationId, int x, int y, int width, int height, String content + ) { + Document document = documentRepository.getById(documentId); + document.validateOwner(member); Annotation annotation = annotationRepository.getById(annotationId); annotation.updateAnnotation(x, y, width, height, content); return AnnotationResponse.from(annotation); } @Transactional - public void deleteAnnotation(Long documentId, Long annotationId) { - documentRepository.getById(documentId); + public void deleteAnnotation(Member member, Long documentId, Long annotationId) { + Document document = documentRepository.getById(documentId); + document.validateOwner(member); Annotation annotation = annotationRepository.getById(annotationId); annotationRepository.delete(annotation); } diff --git a/src/main/java/notai/auth/AuthArgumentResolver.java b/src/main/java/notai/auth/AuthArgumentResolver.java index 4065082..0682f5c 100644 --- a/src/main/java/notai/auth/AuthArgumentResolver.java +++ b/src/main/java/notai/auth/AuthArgumentResolver.java @@ -3,6 +3,7 @@ import jakarta.servlet.http.HttpServletRequest; import lombok.RequiredArgsConstructor; +import notai.member.domain.Member; import notai.member.domain.MemberRepository; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; @@ -23,7 +24,7 @@ public boolean supportsParameter(MethodParameter parameter) { } @Override - public Long resolveArgument( + public Member resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -31,6 +32,6 @@ public Long resolveArgument( ) { HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); Long memberId = (Long) request.getAttribute("memberId"); - return memberRepository.getById(memberId).getId(); + return memberRepository.getById(memberId); } } diff --git a/src/main/java/notai/common/exception/ErrorMessages.java b/src/main/java/notai/common/exception/ErrorMessages.java index 0fd77c8..ca3e952 100644 --- a/src/main/java/notai/common/exception/ErrorMessages.java +++ b/src/main/java/notai/common/exception/ErrorMessages.java @@ -19,8 +19,7 @@ public enum ErrorMessages { // folder FOLDER_NOT_FOUND("폴더를 찾을 수 없습니다."), - - // llm task + FOLDER_AND_DOCUMENT_INVALID_RESPONSE("허용하지 않는 데이터 타입입니다."), // llm task LLM_TASK_LOG_NOT_FOUND("AI 작업 기록을 찾을 수 없습니다."), LLM_TASK_RESULT_ERROR("AI 요약 및 문제 생성 중에 문제가 발생했습니다."), @@ -37,15 +36,15 @@ public enum ErrorMessages { RECORDING_NOT_FOUND("녹음 파일을 찾을 수 없습니다."), // external api call - KAKAO_API_ERROR("카카오 API 호출에 예외가 발생했습니다."), + KAKAO_API_ERROR("카카오 API 호출에 예외가 발생했습니다."), AI_SERVER_ERROR("AI 서버 API 호출에 예외가 발생했습니다."), SLACK_API_ERROR("슬랙 API 호출에 예외가 발생했습니다."), // auth - INVALID_ACCESS_TOKEN("유효하지 않은 토큰입니다."), - INVALID_REFRESH_TOKEN("유요하지 않은 Refresh Token입니다."), - EXPIRED_REFRESH_TOKEN("만료된 Refresh Token입니다."), - INVALID_LOGIN_TYPE("지원하지 않는 소셜 로그인 타입입니다."), + INVALID_ACCESS_TOKEN("유효하지 않은 토큰입니다."), + INVALID_REFRESH_TOKEN("유요하지 않은 Refresh Token입니다."), + EXPIRED_REFRESH_TOKEN("만료된 Refresh Token입니다."), + INVALID_LOGIN_TYPE("지원하지 않는 소셜 로그인 타입입니다."), NOTFOUND_ACCESS_TOKEN("토큰 정보가 존재하지 않습니다."), // stt diff --git a/src/main/java/notai/document/application/DocumentQueryService.java b/src/main/java/notai/document/application/DocumentQueryService.java index 0e45f85..6cbb050 100644 --- a/src/main/java/notai/document/application/DocumentQueryService.java +++ b/src/main/java/notai/document/application/DocumentQueryService.java @@ -5,11 +5,13 @@ import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class DocumentQueryService { private final DocumentRepository documentRepository; diff --git a/src/main/java/notai/document/application/DocumentService.java b/src/main/java/notai/document/application/DocumentService.java index 6a04c5e..cb438a6 100644 --- a/src/main/java/notai/document/application/DocumentService.java +++ b/src/main/java/notai/document/application/DocumentService.java @@ -10,51 +10,50 @@ import notai.folder.domain.Folder; import notai.folder.domain.FolderRepository; import notai.member.domain.Member; -import notai.member.domain.MemberRepository; import notai.ocr.application.OCRService; import notai.pdf.PdfService; import notai.pdf.result.PdfSaveResult; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.util.List; @Service @RequiredArgsConstructor +@Transactional public class DocumentService { private final PdfService pdfService; private final OCRService ocrService; private final DocumentRepository documentRepository; private final FolderRepository folderRepository; - private final MemberRepository memberRepository; private static final Long ROOT_FOLDER_ID = -1L; public DocumentSaveResult saveDocument( - Long memberId, Long folderId, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest + Member member, Long folderId, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest ) { PdfSaveResult pdfSaveResult = pdfService.savePdf(pdfFile); - Document document = saveAndReturnDocument(memberId, folderId, documentSaveRequest, pdfSaveResult); + Document document = saveAndReturnDocument(member, folderId, documentSaveRequest, pdfSaveResult); ocrService.saveOCR(document, pdfSaveResult.pdf()); return DocumentSaveResult.of(document.getId(), document.getName(), document.getUrl()); } public DocumentSaveResult saveRootDocument( - Long memberId, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest + Member member, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest ) { PdfSaveResult pdfSaveResult = pdfService.savePdf(pdfFile); - Document document = saveAndReturnRootDocument(memberId, documentSaveRequest, pdfSaveResult); + Document document = saveAndReturnRootDocument(member, documentSaveRequest, pdfSaveResult); ocrService.saveOCR(document, pdfSaveResult.pdf()); return DocumentSaveResult.of(document.getId(), document.getName(), document.getUrl()); } public DocumentUpdateResult updateDocument( - Long memberId, Long folderId, Long documentId, DocumentUpdateRequest documentUpdateRequest + Member member, Long folderId, Long documentId, DocumentUpdateRequest documentUpdateRequest ) { Document document = documentRepository.getById(documentId); - Member member = memberRepository.getById(memberId); document.validateOwner(member); @@ -67,10 +66,9 @@ public DocumentUpdateResult updateDocument( } public void deleteDocument( - Long memberId, Long folderId, Long documentId + Member member, Long folderId, Long documentId ) { Document document = documentRepository.getById(documentId); - Member member = memberRepository.getById(memberId); document.validateOwner(member); @@ -82,18 +80,17 @@ public void deleteDocument( } public void deleteAllByFolder( - Long memberId, Folder folder + Member member, Folder folder ) { List documents = documentRepository.findAllByFolderId(folder.getId()); for (Document document : documents) { - deleteDocument(memberId, folder.getId(), document.getId()); + deleteDocument(member, folder.getId(), document.getId()); } } private Document saveAndReturnDocument( - Long memberId, Long folderId, DocumentSaveRequest documentSaveRequest, PdfSaveResult pdfSaveResult + Member member, Long folderId, DocumentSaveRequest documentSaveRequest, PdfSaveResult pdfSaveResult ) { - Member member = memberRepository.getById(memberId); Folder folder = folderRepository.getById(folderId); Document document = new Document(folder, member, @@ -105,9 +102,8 @@ private Document saveAndReturnDocument( } private Document saveAndReturnRootDocument( - Long memberId, DocumentSaveRequest documentSaveRequest, PdfSaveResult pdfSaveResult + Member member, DocumentSaveRequest documentSaveRequest, PdfSaveResult pdfSaveResult ) { - Member member = memberRepository.getById(memberId); Document document = new Document(member, documentSaveRequest.name(), pdfSaveResult.pdfUrl(), diff --git a/src/main/java/notai/document/presentation/DocumentController.java b/src/main/java/notai/document/presentation/DocumentController.java index 36b341d..548cfc2 100644 --- a/src/main/java/notai/document/presentation/DocumentController.java +++ b/src/main/java/notai/document/presentation/DocumentController.java @@ -14,6 +14,7 @@ import notai.document.presentation.response.DocumentFindResponse; import notai.document.presentation.response.DocumentSaveResponse; import notai.document.presentation.response.DocumentUpdateResponse; +import notai.member.domain.Member; import org.springframework.http.MediaType; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -35,18 +36,18 @@ public class DocumentController { @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity saveDocument( - @Auth Long memberId, + @Auth Member member, @PathVariable Long folderId, - @Parameter(content = @Content(mediaType = MediaType.APPLICATION_PDF_VALUE)) - @RequestPart MultipartFile pdfFile, + @Parameter(content = @Content(mediaType = MediaType.APPLICATION_PDF_VALUE)) @RequestPart + MultipartFile pdfFile, @RequestPart DocumentSaveRequest documentSaveRequest ) { DocumentSaveResult documentSaveResult; if (folderId.equals(ROOT_FOLDER_ID)) { - documentSaveResult = documentService.saveRootDocument(memberId, pdfFile, documentSaveRequest); + documentSaveResult = documentService.saveRootDocument(member, pdfFile, documentSaveRequest); } else { - documentSaveResult = documentService.saveDocument(memberId, folderId, pdfFile, documentSaveRequest); + documentSaveResult = documentService.saveDocument(member, folderId, pdfFile, documentSaveRequest); } DocumentSaveResponse response = DocumentSaveResponse.from(documentSaveResult); String url = String.format(FOLDER_URL_FORMAT, folderId, response.id()); @@ -55,13 +56,12 @@ public ResponseEntity saveDocument( @PutMapping(value = "/{id}") public ResponseEntity updateDocument( - @Auth Long memberId, + @Auth Member member, @PathVariable Long folderId, @PathVariable Long id, @RequestBody DocumentUpdateRequest documentUpdateRequest ) { - DocumentUpdateResult documentUpdateResult = documentService.updateDocument( - memberId, + DocumentUpdateResult documentUpdateResult = documentService.updateDocument(member, folderId, id, documentUpdateRequest @@ -72,11 +72,11 @@ public ResponseEntity updateDocument( @GetMapping public ResponseEntity> getDocuments( - @Auth Long memberId, @PathVariable Long folderId + @Auth Member member, @PathVariable Long folderId ) { List documentResults; if (folderId.equals(ROOT_FOLDER_ID)) { - documentResults = documentQueryService.findRootDocuments(memberId); + documentResults = documentQueryService.findRootDocuments(member.getId()); } else { documentResults = documentQueryService.findDocuments(folderId); } @@ -87,9 +87,9 @@ public ResponseEntity> getDocuments( @DeleteMapping("/{id}") public ResponseEntity deleteDocument( - @Auth Long memberId, @PathVariable Long folderId, @PathVariable Long id + @Auth Member member, @PathVariable Long folderId, @PathVariable Long id ) { - documentService.deleteDocument(memberId, folderId, id); + documentService.deleteDocument(member, folderId, id); return ResponseEntity.noContent().build(); } } diff --git a/src/main/java/notai/folder/application/FolderQueryService.java b/src/main/java/notai/folder/application/FolderQueryService.java index 1a3a830..0ee9c14 100644 --- a/src/main/java/notai/folder/application/FolderQueryService.java +++ b/src/main/java/notai/folder/application/FolderQueryService.java @@ -4,27 +4,31 @@ import notai.folder.application.result.FolderFindResult; import notai.folder.domain.Folder; import notai.folder.domain.FolderRepository; +import notai.member.domain.Member; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class FolderQueryService { private final FolderRepository folderRepository; + private static final Long ROOT_ID = -1L; - public List getFolders(Long memberId, Long parentFolderId) { - List folders = getFoldersWithMemberAndParent(memberId, parentFolderId); + public List getFolders(Member member, Long folderId) { + List folders = getFoldersWithMemberAndParent(member, folderId); // document read return folders.stream().map(this::getFolderResult).toList(); } - private List getFoldersWithMemberAndParent(Long memberId, Long parentFolderId) { - if (parentFolderId == null) { - return folderRepository.findAllByMemberIdAndParentFolderIsNull(memberId); + private List getFoldersWithMemberAndParent(Member member, Long folderId) { + if (folderId == null || folderId.equals(ROOT_ID)) { + return folderRepository.findAllByMemberIdAndParentFolderIsNull(member.getId()); } - return folderRepository.findAllByMemberIdAndParentFolderId(memberId, parentFolderId); + return folderRepository.findAllByMemberIdAndParentFolderId(member.getId(), folderId); } private FolderFindResult getFolderResult(Folder folder) { diff --git a/src/main/java/notai/folder/application/FolderService.java b/src/main/java/notai/folder/application/FolderService.java index 11abcae..7fd965a 100644 --- a/src/main/java/notai/folder/application/FolderService.java +++ b/src/main/java/notai/folder/application/FolderService.java @@ -11,67 +11,65 @@ import notai.folder.presentation.request.FolderSaveRequest; import notai.folder.presentation.request.FolderUpdateRequest; import notai.member.domain.Member; -import notai.member.domain.MemberRepository; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor +@Transactional public class FolderService { private final FolderRepository folderRepository; - private final MemberRepository memberRepository; private final DocumentService documentService; - public FolderSaveResult saveRootFolder(Long memberId, FolderSaveRequest folderSaveRequest) { - Member member = memberRepository.getById(memberId); + public FolderSaveResult saveRootFolder(Member member, FolderSaveRequest folderSaveRequest) { Folder folder = new Folder(member, folderSaveRequest.name()); Folder savedFolder = folderRepository.save(folder); return getFolderSaveResult(savedFolder); } - public FolderSaveResult saveSubFolder(Long memberId, FolderSaveRequest folderSaveRequest) { - Member member = memberRepository.getById(memberId); + public FolderSaveResult saveSubFolder(Member member, FolderSaveRequest folderSaveRequest) { Folder parentFolder = folderRepository.getById(folderSaveRequest.parentFolderId()); Folder folder = new Folder(member, folderSaveRequest.name(), parentFolder); Folder savedFolder = folderRepository.save(folder); return getFolderSaveResult(savedFolder); } - public FolderMoveResult moveRootFolder(Long memberId, Long id) { + public FolderMoveResult moveRootFolder(Member member, Long id) { Folder folder = folderRepository.getById(id); - folder.validateOwner(memberId); + folder.validateOwner(member); folder.moveRootFolder(); folderRepository.save(folder); return getFolderMoveResult(folder); } - public FolderMoveResult moveNewParentFolder(Long memberId, Long id, FolderMoveRequest folderMoveRequest) { + public FolderMoveResult moveNewParentFolder(Member member, Long id, FolderMoveRequest folderMoveRequest) { Folder folder = folderRepository.getById(id); Folder parentFolder = folderRepository.getById(folderMoveRequest.targetFolderId()); - folder.validateOwner(memberId); + folder.validateOwner(member); folder.moveNewParentFolder(parentFolder); folderRepository.save(folder); return getFolderMoveResult(folder); } - public FolderUpdateResult updateFolder(Long memberId, Long id, FolderUpdateRequest folderUpdateRequest) { + public FolderUpdateResult updateFolder(Member member, Long id, FolderUpdateRequest folderUpdateRequest) { Folder folder = folderRepository.getById(id); - folder.validateOwner(memberId); + folder.validateOwner(member); folder.updateName(folderUpdateRequest.name()); folderRepository.save(folder); return getFolderUpdateResult(folder); } - public void deleteFolder(Long memberId, Long id) { + public void deleteFolder(Member member, Long id) { Folder folder = folderRepository.getById(id); - folder.validateOwner(memberId); + folder.validateOwner(member); List subFolders = folderRepository.findAllByParentFolder(folder); for (Folder subFolder : subFolders) { - deleteFolder(memberId, subFolder.getId()); + deleteFolder(member, subFolder.getId()); } - documentService.deleteAllByFolder(memberId, folder); + documentService.deleteAllByFolder(member, folder); folderRepository.delete(folder); } diff --git a/src/main/java/notai/folder/domain/Folder.java b/src/main/java/notai/folder/domain/Folder.java index 8abfef3..7e62c38 100644 --- a/src/main/java/notai/folder/domain/Folder.java +++ b/src/main/java/notai/folder/domain/Folder.java @@ -59,8 +59,8 @@ public void moveNewParentFolder(Folder parentFolder) { this.parentFolder = parentFolder; } - public void validateOwner(Long memberId) { - if (!this.member.getId().equals(memberId)) { + public void validateOwner(Member member) { + if (!this.member.getId().equals(member.getId())) { log.info("폴더 소유자가 요청 사용자와 다릅니다."); throw new NotFoundException(FOLDER_NOT_FOUND); } diff --git a/src/main/java/notai/folder/presentation/FolderController.java b/src/main/java/notai/folder/presentation/FolderController.java index ab2c4af..748a807 100644 --- a/src/main/java/notai/folder/presentation/FolderController.java +++ b/src/main/java/notai/folder/presentation/FolderController.java @@ -3,6 +3,9 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import notai.auth.Auth; +import notai.document.application.DocumentQueryService; +import notai.document.application.result.DocumentFindResult; +import notai.document.presentation.response.DocumentFindResponse; import notai.folder.application.FolderQueryService; import notai.folder.application.FolderService; import notai.folder.application.result.FolderFindResult; @@ -12,14 +15,13 @@ import notai.folder.presentation.request.FolderMoveRequest; import notai.folder.presentation.request.FolderSaveRequest; import notai.folder.presentation.request.FolderUpdateRequest; -import notai.folder.presentation.response.FolderFindResponse; -import notai.folder.presentation.response.FolderMoveResponse; -import notai.folder.presentation.response.FolderSaveResponse; -import notai.folder.presentation.response.FolderUpdateResponse; +import notai.folder.presentation.response.*; +import notai.member.domain.Member; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.net.URI; +import java.util.ArrayList; import java.util.List; @RestController @@ -29,62 +31,92 @@ public class FolderController { private final FolderService folderService; private final FolderQueryService folderQueryService; + private final DocumentQueryService documentQueryService; + + private static final Long ROOT_ID = -1L; @PostMapping public ResponseEntity saveFolder( - @Auth Long memberId, @Valid @RequestBody FolderSaveRequest folderSaveRequest + @Auth Member member, @Valid @RequestBody FolderSaveRequest folderSaveRequest ) { - FolderSaveResult folderResult = saveFolderResult(memberId, folderSaveRequest); + FolderSaveResult folderResult = saveFolderResult(member, folderSaveRequest); FolderSaveResponse response = FolderSaveResponse.from(folderResult); return ResponseEntity.created(URI.create("/api/folders/" + response.id())).body(response); } @PostMapping("/{id}/move") public ResponseEntity moveFolder( - @Auth Long memberId, @PathVariable Long id, @Valid @RequestBody FolderMoveRequest folderMoveRequest + @Auth Member member, @PathVariable Long id, @Valid @RequestBody FolderMoveRequest folderMoveRequest ) { - FolderMoveResult folderResult = moveFolderWithRequest(memberId, id, folderMoveRequest); + FolderMoveResult folderResult = moveFolderWithRequest(member, id, folderMoveRequest); FolderMoveResponse response = FolderMoveResponse.from(folderResult); return ResponseEntity.ok(response); } @PutMapping("/{id}") public ResponseEntity updateFolder( - @Auth Long memberId, @PathVariable Long id, @Valid @RequestBody FolderUpdateRequest folderUpdateRequest + @Auth Member member, @PathVariable Long id, @Valid @RequestBody FolderUpdateRequest folderUpdateRequest ) { - FolderUpdateResult folderResult = folderService.updateFolder(memberId, id, folderUpdateRequest); + FolderUpdateResult folderResult = folderService.updateFolder(member, id, folderUpdateRequest); FolderUpdateResponse response = FolderUpdateResponse.from(folderResult); return ResponseEntity.ok(response); } - @GetMapping - public ResponseEntity> getFolders( - @Auth Long memberId, @RequestParam(required = false) Long parentFolderId + @GetMapping("/{id}") + public ResponseEntity> getFolders( + @Auth Member member, @PathVariable Long id ) { - List folderResults = folderQueryService.getFolders(memberId, parentFolderId); - List response = folderResults.stream().map(FolderFindResponse::from).toList(); - return ResponseEntity.ok(response); + List result = new ArrayList<>(); + + insertFolderFindResponse(result, member, id); + insertDocumentFindResponse(result, member, id); + + return ResponseEntity.ok(result); } @DeleteMapping("/{id}") public ResponseEntity deleteFolder( - @Auth Long memberId, @PathVariable Long id + @Auth Member member, @PathVariable Long id ) { - folderService.deleteFolder(memberId, id); + folderService.deleteFolder(member, id); return ResponseEntity.noContent().build(); } - private FolderSaveResult saveFolderResult(Long memberId, FolderSaveRequest folderSaveRequest) { + private FolderSaveResult saveFolderResult(Member member, FolderSaveRequest folderSaveRequest) { if (folderSaveRequest.parentFolderId() != null) { - return folderService.saveSubFolder(memberId, folderSaveRequest); + return folderService.saveSubFolder(member, folderSaveRequest); } - return folderService.saveRootFolder(memberId, folderSaveRequest); + return folderService.saveRootFolder(member, folderSaveRequest); } - private FolderMoveResult moveFolderWithRequest(Long memberId, Long id, FolderMoveRequest folderMoveRequest) { + private FolderMoveResult moveFolderWithRequest(Member member, Long id, FolderMoveRequest folderMoveRequest) { if (folderMoveRequest.targetFolderId() != null) { - return folderService.moveNewParentFolder(memberId, id, folderMoveRequest); + return folderService.moveNewParentFolder(member, id, folderMoveRequest); + } + return folderService.moveRootFolder(member, id); + } + + private void insertFolderFindResponse(List result, Member member, Long folderId) { + List folderResults = folderQueryService.getFolders(member, folderId); + List folderResponses = folderResults.stream().map(FolderFindResponse::from).toList(); + + for (FolderFindResponse response : folderResponses) { + result.add(FindResponseWrapper.fromFolderFindResponse(response)); + } + } + + private void insertDocumentFindResponse(List result, Member member, Long folderId) { + List documentResults; + if (folderId == null || folderId.equals(ROOT_ID)) { + documentResults = documentQueryService.findRootDocuments(member.getId()); + } else { + documentResults = documentQueryService.findDocuments(folderId); + } + List documentResponses = + documentResults.stream().map(DocumentFindResponse::from).toList(); + + for (DocumentFindResponse response : documentResponses) { + result.add(FindResponseWrapper.fromDocumentFindResponse(response)); } - return folderService.moveRootFolder(memberId, id); } } diff --git a/src/main/java/notai/folder/presentation/response/FindResponseWrapper.java b/src/main/java/notai/folder/presentation/response/FindResponseWrapper.java new file mode 100644 index 0000000..9b1dabb --- /dev/null +++ b/src/main/java/notai/folder/presentation/response/FindResponseWrapper.java @@ -0,0 +1,29 @@ +package notai.folder.presentation.response; + +import notai.common.exception.ErrorMessages; +import notai.common.exception.type.BadRequestException; +import notai.document.presentation.response.DocumentFindResponse; + +public record FindResponseWrapper( + Object response, + FolderAndDocumentResponseType folderAndDocumentResponseType + +) { + public static FindResponseWrapper fromFolderFindResponse( + Object response + ) { + if (response instanceof FolderFindResponse) { + return new FindResponseWrapper(response, FolderAndDocumentResponseType.FOLDER); + } + throw new BadRequestException(ErrorMessages.FOLDER_AND_DOCUMENT_INVALID_RESPONSE); + } + + public static FindResponseWrapper fromDocumentFindResponse( + Object response + ) { + if (response instanceof DocumentFindResponse) { + return new FindResponseWrapper(response, FolderAndDocumentResponseType.DOCUMENT); + } + throw new BadRequestException(ErrorMessages.FOLDER_AND_DOCUMENT_INVALID_RESPONSE); + } +} diff --git a/src/main/java/notai/folder/presentation/response/FolderAndDocumentResponseType.java b/src/main/java/notai/folder/presentation/response/FolderAndDocumentResponseType.java new file mode 100644 index 0000000..d561de3 --- /dev/null +++ b/src/main/java/notai/folder/presentation/response/FolderAndDocumentResponseType.java @@ -0,0 +1,5 @@ +package notai.folder.presentation.response; + +public enum FolderAndDocumentResponseType { + FOLDER, DOCUMENT +} diff --git a/src/main/java/notai/llm/application/LlmTaskQueryService.java b/src/main/java/notai/llm/application/LlmTaskQueryService.java index 39c642a..ec55477 100644 --- a/src/main/java/notai/llm/application/LlmTaskQueryService.java +++ b/src/main/java/notai/llm/application/LlmTaskQueryService.java @@ -2,10 +2,8 @@ import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; -import static notai.common.exception.ErrorMessages.DOCUMENT_NOT_FOUND; -import static notai.common.exception.ErrorMessages.LLM_TASK_RESULT_ERROR; import notai.common.exception.type.InternalServerErrorException; -import notai.common.exception.type.NotFoundException; +import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.llm.application.command.LlmTaskPageResultCommand; import notai.llm.application.command.LlmTaskPageStatusCommand; @@ -16,8 +14,8 @@ import notai.llm.application.result.LlmTaskPageResult; import notai.llm.application.result.LlmTaskPageStatusResult; import notai.llm.domain.TaskStatus; -import static notai.llm.domain.TaskStatus.*; import notai.llm.query.LlmTaskQueryRepository; +import notai.member.domain.Member; import notai.problem.domain.ProblemRepository; import notai.problem.query.result.ProblemPageContentResult; import notai.summary.domain.SummaryRepository; @@ -27,6 +25,9 @@ import java.util.Collections; import java.util.List; +import static notai.common.exception.ErrorMessages.LLM_TASK_RESULT_ERROR; +import static notai.llm.domain.TaskStatus.*; + @Slf4j @Service @RequiredArgsConstructor @@ -37,8 +38,10 @@ public class LlmTaskQueryService { private final SummaryRepository summaryRepository; private final ProblemRepository problemRepository; - public LlmTaskOverallStatusResult fetchOverallStatus(Long documentId) { - checkDocumentExists(documentId); + public LlmTaskOverallStatusResult fetchOverallStatus(Member member, Long documentId) { + Document foundDocument = documentRepository.getById(documentId); + foundDocument.validateOwner(member); + List summaryIds = summaryRepository.getSummaryIdsByDocumentId(documentId); if (summaryIds.isEmpty()) { @@ -56,8 +59,10 @@ public LlmTaskOverallStatusResult fetchOverallStatus(Long documentId) { return LlmTaskOverallStatusResult.of(documentId, IN_PROGRESS, totalPages, completedPages); } - public LlmTaskPageStatusResult fetchPageStatus(LlmTaskPageStatusCommand command) { // TODO: 페이지 번호 검증 추가 - checkDocumentExists(command.documentId()); + public LlmTaskPageStatusResult fetchPageStatus(Member member, LlmTaskPageStatusCommand command) { // TODO: 페이지 번호 검증 추가 + Document foundDocument = documentRepository.getById(command.documentId()); + foundDocument.validateOwner(member); + Long summaryId = summaryRepository.getSummaryIdByDocumentIdAndPageNumber(command.documentId(), command.pageNumber()); @@ -67,8 +72,9 @@ public LlmTaskPageStatusResult fetchPageStatus(LlmTaskPageStatusCommand command) return LlmTaskPageStatusResult.from(llmTaskQueryRepository.getTaskStatusBySummaryId(summaryId)); } - public LlmTaskAllPagesResult findAllPagesResult(Long documentId) { - checkDocumentExists(documentId); + public LlmTaskAllPagesResult findAllPagesResult(Member member, Long documentId) { + Document foundDocument = documentRepository.getById(documentId); + foundDocument.validateOwner(member); List summaryResults = summaryRepository.getPageNumbersAndContentByDocumentId(documentId); @@ -92,8 +98,9 @@ public LlmTaskAllPagesResult findAllPagesResult(Long documentId) { return LlmTaskAllPagesResult.of(documentId, results); } - public LlmTaskPageResult findPageResult(LlmTaskPageResultCommand command) { // TODO: 페이지 번호 검증 추가 - checkDocumentExists(command.documentId()); + public LlmTaskPageResult findPageResult(Member member, LlmTaskPageResultCommand command) { // TODO: 페이지 번호 검증 추가 + Document foundDocument = documentRepository.getById(command.documentId()); + foundDocument.validateOwner(member); String summaryResult = summaryRepository.getSummaryContentByDocumentIdAndPageNumber( command.documentId(), command.pageNumber()); @@ -105,9 +112,10 @@ public LlmTaskPageResult findPageResult(LlmTaskPageResultCommand command) { // T return LlmTaskPageResult.of(summaryResult, problemResult); } - private static void checkSummaryAndProblemConsistency( + private void checkSummaryAndProblemConsistency( LlmTaskPageResultCommand command, String summaryResult, - String problemResult) { + String problemResult + ) { if (summaryResult == null && problemResult != null) { log.error("요약과 문제 생성 결과가 매칭되지 않습니다. {} 페이지에 대한 요약 결과가 없습니다.", command.pageNumber()); throw new InternalServerErrorException(LLM_TASK_RESULT_ERROR); @@ -119,13 +127,7 @@ private static void checkSummaryAndProblemConsistency( } } - private void checkDocumentExists(Long documentId) { - if (!documentRepository.existsById(documentId)) { - throw new NotFoundException(DOCUMENT_NOT_FOUND); - } - } - - private static void checkSummaryAndProblemCountsEqual( + private void checkSummaryAndProblemCountsEqual( List summaryResults, List problemResults ) { if (summaryResults.size() != problemResults.size()) { diff --git a/src/main/java/notai/llm/presentation/LlmTaskController.java b/src/main/java/notai/llm/presentation/LlmTaskController.java index 352698b..e259d21 100644 --- a/src/main/java/notai/llm/presentation/LlmTaskController.java +++ b/src/main/java/notai/llm/presentation/LlmTaskController.java @@ -2,6 +2,7 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import notai.auth.Auth; import notai.llm.application.LlmTaskQueryService; import notai.llm.application.LlmTaskService; import notai.llm.application.command.LlmTaskPageResultCommand; @@ -12,6 +13,7 @@ import notai.llm.presentation.request.LlmTaskSubmitRequest; import notai.llm.presentation.request.SummaryAndProblemUpdateRequest; import notai.llm.presentation.response.*; +import notai.member.domain.Member; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -31,31 +33,40 @@ public ResponseEntity submitTask(@RequestBody @Valid LlmT } @GetMapping("/status/{documentId}") - public ResponseEntity fetchOverallStatus(@PathVariable("documentId") Long documentId) { - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(documentId); + public ResponseEntity fetchOverallStatus( + @Auth Member member, @PathVariable("documentId") Long documentId + ) { + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); return ResponseEntity.ok(LlmTaskOverallStatusResponse.from(result)); } @GetMapping("/status/{documentId}/{pageNumber}") public ResponseEntity fetchPageStatus( - @PathVariable("documentId") Long documentId, @PathVariable("pageNumber") Integer pageNumber + @Auth Member member, + @PathVariable("documentId") Long documentId, + @PathVariable("pageNumber") Integer pageNumber ) { LlmTaskPageStatusCommand command = LlmTaskPageStatusCommand.of(documentId, pageNumber); - LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(command); + LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member, command); return ResponseEntity.ok(LlmTaskPageStatusResponse.from(result)); } @GetMapping("/results/{documentId}") - public ResponseEntity findAllPagesResult(@PathVariable("documentId") Long documentId) { - LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(documentId); + public ResponseEntity findAllPagesResult( + @Auth Member member, @PathVariable("documentId") Long documentId + ) { + LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(member, documentId); return ResponseEntity.ok(LlmTaskAllPagesResultResponse.from(result)); } @GetMapping("/results/{documentId}/{pageNumber}") public ResponseEntity findPageResult( - @PathVariable("documentId") Long documentId, @PathVariable("pageNumber") Integer pageNumber) { + @Auth Member member, + @PathVariable("documentId") Long documentId, + @PathVariable("pageNumber") Integer pageNumber + ) { LlmTaskPageResultCommand command = LlmTaskPageResultCommand.of(documentId, pageNumber); - LlmTaskPageResult result = llmTaskQueryService.findPageResult(command); + LlmTaskPageResult result = llmTaskQueryService.findPageResult(member, command); return ResponseEntity.ok(LlmTaskPageResultResponse.from(result)); } diff --git a/src/main/java/notai/ocr/application/OCRQueryService.java b/src/main/java/notai/ocr/application/OCRQueryService.java index c0b4c87..688c7ce 100644 --- a/src/main/java/notai/ocr/application/OCRQueryService.java +++ b/src/main/java/notai/ocr/application/OCRQueryService.java @@ -3,21 +3,26 @@ import lombok.RequiredArgsConstructor; import static notai.common.exception.ErrorMessages.OCR_RESULT_NOT_FOUND; import notai.common.exception.type.NotFoundException; +import notai.member.domain.Member; import notai.ocr.application.result.OCRFindResult; import notai.ocr.domain.OCR; import notai.ocr.domain.OCRRepository; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class OCRQueryService { private final OCRRepository ocrRepository; - public OCRFindResult findOCR(Long documentId, Integer pageNumber) { - OCR ocr = ocrRepository.findOCRByDocumentIdAndPageNumber(documentId, + public OCRFindResult findOCR(Member member, Long documentId, Integer pageNumber) { + OCR ocr = ocrRepository.findOCRByDocumentIdAndPageNumber( + documentId, pageNumber ).orElseThrow(() -> new NotFoundException(OCR_RESULT_NOT_FOUND)); + ocr.getDocument().validateOwner(member); return OCRFindResult.of(documentId, pageNumber, ocr.getContent()); } diff --git a/src/main/java/notai/ocr/application/OCRService.java b/src/main/java/notai/ocr/application/OCRService.java index f5c9a21..971797a 100644 --- a/src/main/java/notai/ocr/application/OCRService.java +++ b/src/main/java/notai/ocr/application/OCRService.java @@ -13,12 +13,14 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.awt.image.BufferedImage; import java.io.File; @Service @RequiredArgsConstructor +@Transactional public class OCRService { private final OCRRepository ocrRepository; diff --git a/src/main/java/notai/ocr/presentation/OCRController.java b/src/main/java/notai/ocr/presentation/OCRController.java index e042773..06786b9 100644 --- a/src/main/java/notai/ocr/presentation/OCRController.java +++ b/src/main/java/notai/ocr/presentation/OCRController.java @@ -1,6 +1,8 @@ package notai.ocr.presentation; import lombok.RequiredArgsConstructor; +import notai.auth.Auth; +import notai.member.domain.Member; import notai.ocr.application.OCRQueryService; import notai.ocr.application.result.OCRFindResult; import notai.ocr.presentation.response.OCRFindResponse; @@ -16,9 +18,9 @@ public class OCRController { @GetMapping public ResponseEntity getDocuments( - @PathVariable Long documentId, @RequestParam Integer pageNumber + @Auth Member member, @PathVariable Long documentId, @RequestParam Integer pageNumber ) { - OCRFindResult result = ocrQueryService.findOCR(documentId, pageNumber); + OCRFindResult result = ocrQueryService.findOCR(member, documentId, pageNumber); OCRFindResponse response = OCRFindResponse.from(result); return ResponseEntity.ok(response); } diff --git a/src/main/java/notai/pageRecording/application/PageRecordingService.java b/src/main/java/notai/pageRecording/application/PageRecordingService.java index c8b4a44..a468a69 100644 --- a/src/main/java/notai/pageRecording/application/PageRecordingService.java +++ b/src/main/java/notai/pageRecording/application/PageRecordingService.java @@ -1,7 +1,9 @@ package notai.pageRecording.application; import lombok.RequiredArgsConstructor; -import notai.common.exception.type.NotFoundException; +import notai.document.domain.Document; +import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; import notai.pageRecording.application.command.PageRecordingSaveCommand; import notai.pageRecording.domain.PageRecording; import notai.pageRecording.domain.PageRecordingRepository; @@ -10,8 +12,6 @@ import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; -import static notai.common.exception.ErrorMessages.RECORDING_NOT_FOUND; - @Service @Transactional @RequiredArgsConstructor @@ -19,10 +19,13 @@ public class PageRecordingService { private final PageRecordingRepository pageRecordingRepository; private final RecordingRepository recordingRepository; + private final DocumentRepository documentRepository; - public void savePageRecording(PageRecordingSaveCommand command) { + public void savePageRecording(Member member, PageRecordingSaveCommand command) { Recording foundRecording = recordingRepository.getById(command.recordingId()); - checkDocumentOwnershipOfRecording(command, foundRecording); + Document foundDocument = documentRepository.getById(command.documentId()); + foundDocument.validateOwner(member); + foundRecording.validateDocumentOwnership(foundDocument); command.sessions().forEach(session -> { PageRecording pageRecording = new PageRecording( @@ -34,10 +37,4 @@ public void savePageRecording(PageRecordingSaveCommand command) { pageRecordingRepository.save(pageRecording); }); } - - private static void checkDocumentOwnershipOfRecording(PageRecordingSaveCommand command, Recording foundRecording) { - if (!foundRecording.isRecordingOwnedByDocument(command.documentId())) { - throw new NotFoundException(RECORDING_NOT_FOUND); - } - } } diff --git a/src/main/java/notai/pageRecording/presentation/PageRecordingController.java b/src/main/java/notai/pageRecording/presentation/PageRecordingController.java index 9506f7f..6bfeced 100644 --- a/src/main/java/notai/pageRecording/presentation/PageRecordingController.java +++ b/src/main/java/notai/pageRecording/presentation/PageRecordingController.java @@ -1,17 +1,15 @@ package notai.pageRecording.presentation; -import static org.springframework.http.HttpStatus.CREATED; - import lombok.RequiredArgsConstructor; +import notai.auth.Auth; +import notai.member.domain.Member; import notai.pageRecording.application.PageRecordingService; import notai.pageRecording.application.command.PageRecordingSaveCommand; import notai.pageRecording.presentation.request.PageRecordingSaveRequest; import org.springframework.http.ResponseEntity; -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.RestController; +import org.springframework.web.bind.annotation.*; + +import static org.springframework.http.HttpStatus.CREATED; @RestController @RequestMapping("/api/documents/{documentId}/recordings/page-turns") @@ -22,10 +20,12 @@ public class PageRecordingController { @PostMapping public ResponseEntity savePageRecording( - @PathVariable("documentId") Long documentId, @RequestBody PageRecordingSaveRequest request + @Auth Member member, + @PathVariable("documentId") Long documentId, + @RequestBody PageRecordingSaveRequest request ) { PageRecordingSaveCommand command = request.toCommand(documentId); - pageRecordingService.savePageRecording(command); + pageRecordingService.savePageRecording(member, command); return ResponseEntity.status(CREATED).build(); } } diff --git a/src/main/java/notai/recording/application/RecordingService.java b/src/main/java/notai/recording/application/RecordingService.java index 4140908..0d87b96 100644 --- a/src/main/java/notai/recording/application/RecordingService.java +++ b/src/main/java/notai/recording/application/RecordingService.java @@ -2,14 +2,13 @@ import lombok.RequiredArgsConstructor; import notai.common.domain.vo.FilePath; -import static notai.common.exception.ErrorMessages.FILE_SAVE_ERROR; -import static notai.common.exception.ErrorMessages.INVALID_AUDIO_ENCODING; import notai.common.exception.type.BadRequestException; import notai.common.exception.type.InternalServerErrorException; import notai.common.utils.AudioDecoder; import notai.common.utils.FileManager; import notai.document.domain.Document; import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; import notai.recording.application.command.RecordingSaveCommand; import notai.recording.application.result.RecordingSaveResult; import notai.recording.domain.Recording; @@ -24,6 +23,9 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static notai.common.exception.ErrorMessages.FILE_SAVE_ERROR; +import static notai.common.exception.ErrorMessages.INVALID_AUDIO_ENCODING; + @Service @Transactional @RequiredArgsConstructor @@ -38,8 +40,9 @@ public class RecordingService { @Value("${file.audio.basePath}") private String audioBasePath; - public RecordingSaveResult saveRecording(RecordingSaveCommand command) { + public RecordingSaveResult saveRecording(Member member, RecordingSaveCommand command) { Document foundDocument = documentRepository.getById(command.documentId()); + foundDocument.validateOwner(member); Recording recording = new Recording(foundDocument); Recording savedRecording = recordingRepository.save(recording); diff --git a/src/main/java/notai/recording/domain/Recording.java b/src/main/java/notai/recording/domain/Recording.java index 64a8c3b..20a995f 100644 --- a/src/main/java/notai/recording/domain/Recording.java +++ b/src/main/java/notai/recording/domain/Recording.java @@ -6,11 +6,13 @@ import lombok.NoArgsConstructor; import notai.common.domain.RootEntity; import notai.common.domain.vo.FilePath; +import notai.common.exception.type.NotFoundException; import notai.document.domain.Document; import static jakarta.persistence.FetchType.LAZY; import static jakarta.persistence.GenerationType.IDENTITY; import static lombok.AccessLevel.PROTECTED; +import static notai.common.exception.ErrorMessages.RECORDING_NOT_FOUND; @Getter @NoArgsConstructor(access = PROTECTED) @@ -37,7 +39,9 @@ public void updateFilePath(FilePath filePath) { this.filePath = filePath; } - public boolean isRecordingOwnedByDocument(Long documentId) { - return this.document.getId().equals(documentId); + public void validateDocumentOwnership(Document document) { + if (this.document.getId().equals(document.getId())) { + throw new NotFoundException(RECORDING_NOT_FOUND); + } } } diff --git a/src/main/java/notai/recording/presentation/RecordingController.java b/src/main/java/notai/recording/presentation/RecordingController.java index 9224cd4..4daf0dc 100644 --- a/src/main/java/notai/recording/presentation/RecordingController.java +++ b/src/main/java/notai/recording/presentation/RecordingController.java @@ -1,20 +1,18 @@ package notai.recording.presentation; -import static org.springframework.http.HttpStatus.CREATED; - import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; +import notai.auth.Auth; +import notai.member.domain.Member; import notai.recording.application.RecordingService; import notai.recording.application.command.RecordingSaveCommand; import notai.recording.application.result.RecordingSaveResult; import notai.recording.presentation.request.RecordingSaveRequest; import notai.recording.presentation.response.RecordingSaveResponse; import org.springframework.http.ResponseEntity; -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.RestController; +import org.springframework.web.bind.annotation.*; + +import static org.springframework.http.HttpStatus.CREATED; @RestController @RequestMapping("/api/documents/{documentId}/recordings") @@ -25,10 +23,12 @@ public class RecordingController { @PostMapping public ResponseEntity saveRecording( - @PathVariable("documentId") Long documentId, @RequestBody @Valid RecordingSaveRequest request + @Auth Member member, + @PathVariable("documentId") Long documentId, + @RequestBody @Valid RecordingSaveRequest request ) { RecordingSaveCommand command = request.toCommand(documentId); - RecordingSaveResult result = recordingService.saveRecording(command); + RecordingSaveResult result = recordingService.saveRecording(member, command); return ResponseEntity.status(CREATED).body(RecordingSaveResponse.from(result)); } } diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 277fd4f..de3678d 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -6,6 +6,11 @@ spring: h2: console: enabled: true + servlet: + multipart: + max-file-size: 10MB + max-request-size: 10MB + enabled: true datasource: driver-class-name: org.h2.Driver url: jdbc:h2:mem:test;MODE=MYSQL;DB_CLOSE_DELAY=-1 diff --git a/src/test/java/notai/annotation/AnnotationServiceTest.java b/src/test/java/notai/annotation/presentation/AnnotationControllerTest.java similarity index 75% rename from src/test/java/notai/annotation/AnnotationServiceTest.java rename to src/test/java/notai/annotation/presentation/AnnotationControllerTest.java index 36d21f0..fcdf64a 100644 --- a/src/test/java/notai/annotation/AnnotationServiceTest.java +++ b/src/test/java/notai/annotation/presentation/AnnotationControllerTest.java @@ -1,22 +1,29 @@ -package notai.annotation; +package notai.annotation.presentation; import notai.annotation.application.AnnotationQueryService; import notai.annotation.application.AnnotationService; -import notai.annotation.presentation.AnnotationController; import notai.annotation.presentation.request.CreateAnnotationRequest; import notai.annotation.presentation.response.AnnotationResponse; +import notai.auth.TokenService; +import notai.member.domain.Member; +import notai.member.domain.MemberRepository; +import notai.member.domain.OauthId; +import notai.member.domain.OauthProvider; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import java.time.LocalDateTime; import java.util.List; +import java.util.Optional; import static org.mockito.ArgumentMatchers.*; +import static org.mockito.BDDMockito.given; import static org.mockito.Mockito.*; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; @@ -31,15 +38,26 @@ class AnnotationControllerTest { @Mock private AnnotationQueryService annotationQueryService; + @Mock + private MemberRepository memberRepository; + @InjectMocks private AnnotationController annotationController; private MockMvc mockMvc; + private static final Member member = new Member( + new OauthId("oauthId", OauthProvider.KAKAO), "email.com", "nickname" + ); + @BeforeEach void setUp() { MockitoAnnotations.initMocks(this); mockMvc = MockMvcBuilders.standaloneSetup(annotationController).build(); + + given(memberRepository.findById(1L)).willReturn(Optional.of(member)); + TokenService tokenService = Mockito.mock(TokenService.class); + given(tokenService.extractMemberId(any())).willReturn(1L); } @Test @@ -48,12 +66,13 @@ void testCreateAnnotation_success() throws Exception { LocalDateTime now = LocalDateTime.now(); AnnotationResponse response = new AnnotationResponse(1L, 1L, 1, 100, 200, 300, 100, "굵은글씨", now.toString(), now.toString()); - when(annotationService.createAnnotation(anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) + when(annotationService.createAnnotation(any(Member.class), anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) .thenReturn(response); mockMvc.perform(post("/api/documents/1/annotations") .contentType("application/json") - .content("{\"pageNumber\": 1, \"x\": 100, \"y\": 200, \"width\": 300, \"height\": 100, \"content\": \"굵은글씨\"}")) + .content("{\"pageNumber\": 1, \"x\": 100, \"y\": 200, \"width\": 300, \"height\": 100, \"content\": \"굵은글씨\"}") + .header("Authorization", "Bearer token")) .andExpect(status().isCreated()) .andExpect(jsonPath("$.id").value(1L)) .andExpect(jsonPath("$.pageNumber").value(1)) @@ -74,11 +93,12 @@ void testGetAnnotations_success() throws Exception { new AnnotationResponse(2L, 1L, 2, 150, 250, 350, 120, "", now.toString(), now.toString()) ); - when(annotationQueryService.getAnnotationsByDocumentAndPageNumbers(anyLong(), anyList())).thenReturn(responses); + when(annotationQueryService.getAnnotationsByDocumentAndPageNumbers(any(Member.class), anyLong(), anyList())).thenReturn(responses); mockMvc.perform(get("/api/documents/1/annotations?pageNumbers=1,2") - .contentType("application/json")) - .andExpect(status().isOk()) + .contentType("application/json") + .header("Authorization", "Bearer token")) + .andExpect(status().isOk()) .andExpect(jsonPath("$[0].id").value(1L)) .andExpect(jsonPath("$[0].pageNumber").value(1)) .andExpect(jsonPath("$[0].x").value(100)) @@ -102,13 +122,14 @@ void testUpdateAnnotation_success() throws Exception { LocalDateTime now = LocalDateTime.now(); AnnotationResponse response = new AnnotationResponse(1L, 1L, 1, 150, 250, 350, 120, "수정된 주석", now.toString(), now.toString()); - when(annotationService.updateAnnotation(anyLong(), anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) + when(annotationService.updateAnnotation(any(Member.class), anyLong(), anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) .thenReturn(response); mockMvc.perform(put("/api/documents/1/annotations/1") .contentType("application/json") - .content("{\"pageNumber\": 1, \"x\": 150, \"y\": 250, \"width\": 350, \"height\": 120, \"content\": \"수정된 주석\"}")) - .andExpect(status().isOk()) + .content("{\"pageNumber\": 1, \"x\": 150, \"y\": 250, \"width\": 350, \"height\": 120, \"content\": \"수정된 주석\"}") + .header("Authorization", "Bearer token")) + .andExpect(status().isOk()) .andExpect(jsonPath("$.id").value(1L)) .andExpect(jsonPath("$.pageNumber").value(1)) .andExpect(jsonPath("$.content").value("수정된 주석")) @@ -121,12 +142,13 @@ void testUpdateAnnotation_success() throws Exception { @Test void testDeleteAnnotation_success() throws Exception { - doNothing().when(annotationService).deleteAnnotation(anyLong(), anyLong()); + doNothing().when(annotationService).deleteAnnotation(any(Member.class), anyLong(), anyLong()); mockMvc.perform(delete("/api/documents/1/annotations/1") - .contentType("application/json")) - .andExpect(status().isNoContent()); + .contentType("application/json") + .header("Authorization", "Bearer token")) + .andExpect(status().isOk()); - verify(annotationService, times(1)).deleteAnnotation(1L, 1L); + verify(annotationService, times(1)).deleteAnnotation(any(Member.class),anyLong(), anyLong()); } } diff --git a/src/test/java/notai/folder/application/FolderQueryServiceTest.java b/src/test/java/notai/folder/application/FolderQueryServiceTest.java index a567e1d..2071361 100644 --- a/src/test/java/notai/folder/application/FolderQueryServiceTest.java +++ b/src/test/java/notai/folder/application/FolderQueryServiceTest.java @@ -5,17 +5,20 @@ import notai.folder.domain.FolderRepository; import notai.member.domain.Member; import org.assertj.core.api.Assertions; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import static org.mockito.ArgumentMatchers.any; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import java.util.List; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.*; + @ExtendWith(MockitoExtension.class) class FolderQueryServiceTest { @@ -24,6 +27,14 @@ class FolderQueryServiceTest { @InjectMocks private FolderQueryService folderQueryService; + @Mock + private Member member; + + @BeforeEach + void setUp() { + given(member.getId()).willReturn(1L); + } + @Test @DisplayName("루트 폴더 조회") void getFolders_success_parentFolderIdIsNull() { @@ -33,7 +44,7 @@ void getFolders_success_parentFolderIdIsNull() { when(folderRepository.findAllByMemberIdAndParentFolderIsNull(any(Long.class))).thenReturn(expectedResults); //when - List folders = folderQueryService.getFolders(1L, null); + List folders = folderQueryService.getFolders(member, null); Assertions.assertThat(folders.size()).isEqualTo(1); } @@ -50,7 +61,7 @@ void getFolders_success_parentFolderId() { when(folderRepository.findAllByMemberIdAndParentFolderId(any(Long.class), any(Long.class))).thenReturn( expectedResults); //when - List folders = folderQueryService.getFolders(1L, 1L); + List folders = folderQueryService.getFolders(member, 1L); Assertions.assertThat(folders.size()).isEqualTo(2); } diff --git a/src/test/java/notai/llm/application/LlmTaskQueryServiceTest.java b/src/test/java/notai/llm/application/LlmTaskQueryServiceTest.java index 390b0bc..dd04d5b 100644 --- a/src/test/java/notai/llm/application/LlmTaskQueryServiceTest.java +++ b/src/test/java/notai/llm/application/LlmTaskQueryServiceTest.java @@ -2,6 +2,7 @@ import notai.common.exception.type.InternalServerErrorException; import notai.common.exception.type.NotFoundException; +import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.llm.application.command.LlmTaskPageResultCommand; import notai.llm.application.command.LlmTaskPageStatusCommand; @@ -9,26 +10,29 @@ import notai.llm.application.result.LlmTaskOverallStatusResult; import notai.llm.application.result.LlmTaskPageResult; import notai.llm.application.result.LlmTaskPageStatusResult; -import static notai.llm.domain.TaskStatus.*; import notai.llm.query.LlmTaskQueryRepository; +import notai.member.domain.Member; import notai.problem.domain.ProblemRepository; import notai.problem.query.result.ProblemPageContentResult; import notai.summary.domain.SummaryRepository; import notai.summary.query.result.SummaryPageContentResult; -import static org.assertj.core.api.Assertions.assertThat; -import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.BDDMockito.given; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.verify; import org.mockito.junit.jupiter.MockitoExtension; import java.util.Collections; import java.util.List; +import static notai.llm.domain.TaskStatus.*; +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willDoNothing; +import static org.mockito.Mockito.verify; + @ExtendWith(MockitoExtension.class) class LlmTaskQueryServiceTest { @@ -47,15 +51,22 @@ class LlmTaskQueryServiceTest { @Mock private ProblemRepository problemRepository; + @Mock + private Member member; + + @Mock + private Document document; + @Test void 작업_상태_확인시_존재하지_않는_문서ID로_요청한_경우_예외_발생() { // given - given(documentRepository.existsById(anyLong())).willReturn(false); + given(documentRepository.getById(eq(2L))).willThrow(NotFoundException.class); // when & then - assertAll(() -> assertThrows(NotFoundException.class, () -> llmTaskQueryService.fetchOverallStatus(1L)), - () -> verify(documentRepository).existsById(anyLong()) - ); + assertAll(() -> assertThrows( + NotFoundException.class, + () -> llmTaskQueryService.fetchOverallStatus(member, 2L) + )); } @Test @@ -64,20 +75,22 @@ class LlmTaskQueryServiceTest { Long documentId = 1L; List summaryIds = List.of(1L, 2L, 3L); - given(documentRepository.existsById(anyLong())).willReturn(true); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + given(summaryRepository.getSummaryIdsByDocumentId(documentId)).willReturn(summaryIds); given(llmTaskQueryRepository.getTaskStatusBySummaryId(1L)).willReturn(COMPLETED); given(llmTaskQueryRepository.getTaskStatusBySummaryId(2L)).willReturn(COMPLETED); given(llmTaskQueryRepository.getTaskStatusBySummaryId(3L)).willReturn(COMPLETED); // when - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(documentId); + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); // then - assertAll(() -> assertThat(result.overallStatus()).isEqualTo(COMPLETED), + assertAll( + () -> assertThat(result.overallStatus()).isEqualTo(COMPLETED), () -> assertThat(result.totalPages()).isEqualTo(3), () -> assertThat(result.completedPages()).isEqualTo(3), - () -> verify(documentRepository).existsById(documentId), () -> verify(summaryRepository).getSummaryIdsByDocumentId(documentId), () -> verify(llmTaskQueryRepository).getTaskStatusBySummaryId(documentId) ); @@ -89,20 +102,22 @@ class LlmTaskQueryServiceTest { Long documentId = 1L; List summaryIds = List.of(1L, 2L, 3L); - given(documentRepository.existsById(anyLong())).willReturn(true); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + given(summaryRepository.getSummaryIdsByDocumentId(documentId)).willReturn(summaryIds); given(llmTaskQueryRepository.getTaskStatusBySummaryId(1L)).willReturn(COMPLETED); given(llmTaskQueryRepository.getTaskStatusBySummaryId(2L)).willReturn(IN_PROGRESS); given(llmTaskQueryRepository.getTaskStatusBySummaryId(3L)).willReturn(PENDING); // when - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(documentId); + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); // then - assertAll(() -> assertThat(result.overallStatus()).isEqualTo(IN_PROGRESS), + assertAll( + () -> assertThat(result.overallStatus()).isEqualTo(IN_PROGRESS), () -> assertThat(result.totalPages()).isEqualTo(3), () -> assertThat(result.completedPages()).isEqualTo(1), - () -> verify(documentRepository).existsById(documentId), () -> verify(summaryRepository).getSummaryIdsByDocumentId(documentId), () -> verify(llmTaskQueryRepository).getTaskStatusBySummaryId(documentId) ); @@ -116,12 +131,14 @@ class LlmTaskQueryServiceTest { Integer pageNumber = 20; LlmTaskPageStatusCommand command = new LlmTaskPageStatusCommand(documentId, pageNumber); - given(documentRepository.existsById(anyLong())).willReturn(true); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + given(summaryRepository.getSummaryIdByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(summaryId); given(llmTaskQueryRepository.getTaskStatusBySummaryId(summaryId)).willReturn(IN_PROGRESS); // when - LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(command); + LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member, command); // then assertThat(result.status()).isEqualTo(IN_PROGRESS); @@ -134,11 +151,13 @@ class LlmTaskQueryServiceTest { Integer pageNumber = 20; LlmTaskPageStatusCommand command = new LlmTaskPageStatusCommand(documentId, pageNumber); - given(documentRepository.existsById(anyLong())).willReturn(true); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + given(summaryRepository.getSummaryIdByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); // when - LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(command); + LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member, command); // then assertThat(result.status()).isEqualTo(NOT_REQUESTED); @@ -147,12 +166,13 @@ class LlmTaskQueryServiceTest { @Test void 작업_결과_확인시_존재하지_않는_문서ID로_요청한_경우_예외_발생() { // given - given(documentRepository.existsById(anyLong())).willReturn(false); + given(documentRepository.getById(eq(2L))).willThrow(NotFoundException.class); // when & then - assertAll(() -> assertThrows(NotFoundException.class, () -> llmTaskQueryService.findAllPagesResult(1L)), - () -> verify(documentRepository).existsById(anyLong()) - ); + assertAll(() -> assertThrows( + NotFoundException.class, + () -> llmTaskQueryService.findAllPagesResult(member, 2L) + )); } @Test @@ -160,17 +180,23 @@ class LlmTaskQueryServiceTest { // given Long documentId = 1L; List summaryResults = List.of(new SummaryPageContentResult(1, "요약 내용")); - List problemResults = List.of(new ProblemPageContentResult(1, "문제 내용"), + List problemResults = List.of( + new ProblemPageContentResult(1, "문제 내용"), new ProblemPageContentResult(2, "문제 내용") ); - given(documentRepository.existsById(anyLong())).willReturn(true); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + given(summaryRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(summaryResults); given(problemRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(problemResults); // when & then - assertAll(() -> assertThrows(InternalServerErrorException.class, () -> llmTaskQueryService.findAllPagesResult(1L)), - () -> verify(documentRepository).existsById(documentId), + assertAll( + () -> assertThrows( + InternalServerErrorException.class, + () -> llmTaskQueryService.findAllPagesResult(member, 1L) + ), () -> verify(summaryRepository).getPageNumbersAndContentByDocumentId(documentId), () -> verify(problemRepository).getPageNumbersAndContentByDocumentId(documentId) ); @@ -180,24 +206,28 @@ class LlmTaskQueryServiceTest { void 작업_결과_확인() { // given Long documentId = 1L; - List summaryResults = List.of(new SummaryPageContentResult(1, "요약 내용"), + List summaryResults = List.of( + new SummaryPageContentResult(1, "요약 내용"), new SummaryPageContentResult(2, "요약 내용") ); - List problemResults = List.of(new ProblemPageContentResult(1, "문제 내용"), + List problemResults = List.of( + new ProblemPageContentResult(1, "문제 내용"), new ProblemPageContentResult(2, "문제 내용") ); - given(documentRepository.existsById(anyLong())).willReturn(true); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + given(summaryRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(summaryResults); given(problemRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(problemResults); // when - LlmTaskAllPagesResult response = llmTaskQueryService.findAllPagesResult(documentId); + LlmTaskAllPagesResult response = llmTaskQueryService.findAllPagesResult(member, documentId); // then - assertAll(() -> assertEquals(documentId, response.documentId()), + assertAll( + () -> assertEquals(documentId, response.documentId()), () -> assertEquals(2, response.results().size()), - () -> verify(documentRepository).existsById(documentId), () -> verify(summaryRepository).getPageNumbersAndContentByDocumentId(documentId), () -> verify(problemRepository).getPageNumbersAndContentByDocumentId(documentId) ); @@ -212,12 +242,16 @@ class LlmTaskQueryServiceTest { String problemResult = "문제 내용"; LlmTaskPageResultCommand command = new LlmTaskPageResultCommand(documentId, pageNumber); - given(documentRepository.existsById(anyLong())).willReturn(true); - given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(summaryResult); - given(problemRepository.getProblemContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(problemResult); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + + given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn( + summaryResult); + given(problemRepository.getProblemContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn( + problemResult); // when - LlmTaskPageResult result = llmTaskQueryService.findPageResult(command); + LlmTaskPageResult result = llmTaskQueryService.findPageResult(member, command); // then assertAll( @@ -233,12 +267,14 @@ class LlmTaskQueryServiceTest { Integer pageNumber = 20; LlmTaskPageResultCommand command = new LlmTaskPageResultCommand(documentId, pageNumber); - given(documentRepository.existsById(anyLong())).willReturn(true); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); given(problemRepository.getProblemContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); // when - LlmTaskPageResult result = llmTaskQueryService.findPageResult(command); + LlmTaskPageResult result = llmTaskQueryService.findPageResult(member, command); // then assertAll( @@ -255,12 +291,15 @@ class LlmTaskQueryServiceTest { String summaryResult = "요약 내용"; LlmTaskPageResultCommand command = new LlmTaskPageResultCommand(documentId, pageNumber); - given(documentRepository.existsById(anyLong())).willReturn(true); - given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(summaryResult); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + + given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn( + summaryResult); given(problemRepository.getProblemContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); // when & then - assertThrows(InternalServerErrorException.class, () -> llmTaskQueryService.findPageResult(command)); + assertThrows(InternalServerErrorException.class, () -> llmTaskQueryService.findPageResult(member, command)); } @Test @@ -268,11 +307,13 @@ class LlmTaskQueryServiceTest { // given Long documentId = 1L; - given(documentRepository.existsById(anyLong())).willReturn(true); given(summaryRepository.getSummaryIdsByDocumentId(documentId)).willReturn(Collections.emptyList()); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + // when - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(documentId); + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); // then assertAll( @@ -287,11 +328,13 @@ class LlmTaskQueryServiceTest { // given Long documentId = 1L; - given(documentRepository.existsById(anyLong())).willReturn(true); given(summaryRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(Collections.emptyList()); + given(documentRepository.getById(eq(1L))).willReturn(document); + willDoNothing().given(document).validateOwner(member); + // when - LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(documentId); + LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(member, documentId); // then assertAll( diff --git a/src/test/java/notai/llm/application/LlmTaskServiceTest.java b/src/test/java/notai/llm/application/LlmTaskServiceTest.java index 3f796ed..4082625 100644 --- a/src/test/java/notai/llm/application/LlmTaskServiceTest.java +++ b/src/test/java/notai/llm/application/LlmTaskServiceTest.java @@ -21,20 +21,21 @@ import notai.problem.domain.ProblemRepository; import notai.summary.domain.Summary; import notai.summary.domain.SummaryRepository; -import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyLong; -import static org.mockito.BDDMockito.given; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import java.util.List; import java.util.UUID; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.BDDMockito.given; +import static org.mockito.Mockito.*; + @ExtendWith(MockitoExtension.class) class LlmTaskServiceTest { @@ -69,7 +70,8 @@ class LlmTaskServiceTest { given(documentRepository.getById(anyLong())).willThrow(NotFoundException.class); // when & then - assertAll(() -> assertThrows(NotFoundException.class, () -> llmTaskService.submitTasks(command)), + assertAll( + () -> assertThrows(NotFoundException.class, () -> llmTaskService.submitTasks(command)), () -> verify(documentRepository, times(1)).getById(documentId), () -> verify(llmTaskRepository, never()).save(any(LlmTask.class)) ); @@ -86,7 +88,8 @@ class LlmTaskServiceTest { Folder folder = new Folder(member, "TestFolder"); Document document = new Document(folder, member, "TestDocument", "http://example.com/test.pdf", 43); - List annotations = List.of(new Annotation(document, 1, 10, 20, 100, 50, "Annotation 1"), + List annotations = List.of( + new Annotation(document, 1, 10, 20, 100, 50, "Annotation 1"), new Annotation(document, 1, 30, 40, 80, 60, "Annotation 2"), new Annotation(document, 2, 50, 60, 120, 70, "Annotation 3") ); @@ -103,7 +106,8 @@ class LlmTaskServiceTest { LlmTaskSubmitResult result = llmTaskService.submitTasks(command); // then - assertAll(() -> verify(documentRepository, times(1)).getById(documentId), + assertAll( + () -> verify(documentRepository, times(1)).getById(documentId), () -> verify(annotationRepository, times(1)).findByDocumentId(documentId), () -> verify(aiClient, times(2)).submitLlmTask(any(LlmTaskRequest.class)), () -> verify(llmTaskRepository, times(2)).save(any(LlmTask.class)) @@ -127,7 +131,8 @@ class LlmTaskServiceTest { Summary summary = mock(Summary.class); Problem problem = mock(Problem.class); - SummaryAndProblemUpdateCommand command = new SummaryAndProblemUpdateCommand(taskId, + SummaryAndProblemUpdateCommand command = new SummaryAndProblemUpdateCommand( + taskId, summaryContent, problemContent ); @@ -146,7 +151,8 @@ class LlmTaskServiceTest { Integer resultPageNumber = llmTaskService.updateSummaryAndProblem(command); // then - assertAll(() -> verify(taskRecord).completeTask(), + assertAll( + () -> verify(taskRecord).completeTask(), () -> verify(summary).updateContent(summaryContent), () -> verify(problem).updateContent(problemContent), () -> verify(llmTaskRepository, times(1)).save(taskRecord), diff --git a/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java b/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java index 085a4ca..a57ec5f 100644 --- a/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java +++ b/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java @@ -1,5 +1,8 @@ package notai.pageRecording.application; +import notai.document.domain.Document; +import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; import notai.pageRecording.application.command.PageRecordingSaveCommand; import notai.pageRecording.application.command.PageRecordingSaveCommand.PageRecordingSession; import notai.pageRecording.domain.PageRecording; @@ -8,14 +11,14 @@ import notai.recording.domain.RecordingRepository; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import static org.mockito.BDDMockito.given; import org.mockito.InjectMocks; import org.mockito.Mock; -import static org.mockito.Mockito.*; import org.mockito.junit.jupiter.MockitoExtension; import java.util.List; +import static org.mockito.BDDMockito.*; + @ExtendWith(MockitoExtension.class) class PageRecordingServiceTest { @@ -28,23 +31,36 @@ class PageRecordingServiceTest { @Mock private RecordingRepository recordingRepository; + @Mock + private DocumentRepository documentRepository; + + @Mock + private Member member; + + @Mock + private Document document; + @Test void 페이지_넘김_이벤트에_따라_페이지별_녹음_시간을_저장() { // given Long recordingId = 1L; Long documentId = 1L; - PageRecordingSaveCommand command = new PageRecordingSaveCommand(recordingId, + PageRecordingSaveCommand command = new PageRecordingSaveCommand( + recordingId, documentId, List.of(new PageRecordingSession(1, 100.0, 185.5), new PageRecordingSession(5, 185.5, 290.3)) ); Recording foundRecording = mock(Recording.class); given(recordingRepository.getById(recordingId)).willReturn(foundRecording); - given(foundRecording.isRecordingOwnedByDocument(documentId)).willReturn(true); + + given(documentRepository.getById(anyLong())).willReturn(document); + willDoNothing().given(document).validateOwner(member); + willDoNothing().given(foundRecording).validateDocumentOwnership(any(Document.class)); // when - pageRecordingService.savePageRecording(command); + pageRecordingService.savePageRecording(member, command); // then verify(pageRecordingRepository, times(2)).save(any(PageRecording.class)); diff --git a/src/test/java/notai/recording/application/RecordingServiceTest.java b/src/test/java/notai/recording/application/RecordingServiceTest.java index c97dde0..d0545ad 100644 --- a/src/test/java/notai/recording/application/RecordingServiceTest.java +++ b/src/test/java/notai/recording/application/RecordingServiceTest.java @@ -6,10 +6,12 @@ import notai.common.utils.FileManager; import notai.document.domain.Document; import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; import notai.recording.application.command.RecordingSaveCommand; import notai.recording.application.result.RecordingSaveResult; import notai.recording.domain.Recording; import notai.recording.domain.RecordingRepository; +import notai.stt.application.SttTaskService; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; @@ -27,6 +29,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.willDoNothing; import static org.mockito.Mockito.mock; @ExtendWith(MockitoExtension.class) @@ -41,12 +44,18 @@ class RecordingServiceTest { @Mock private DocumentRepository documentRepository; + @Mock + private SttTaskService sttTaskService; + @Spy private final AudioDecoder audioDecoder = new AudioDecoder(); @Spy private final FileManager fileManager = new FileManager(); + @Mock + private Member member; + @BeforeEach void setUp() { ReflectionTestUtils.setField(recordingService, "audioBasePath", "src/main/resources/audio/"); @@ -70,7 +79,7 @@ void setUp() { // when & then assertThrows(BadRequestException.class, () -> { - recordingService.saveRecording(command); + recordingService.saveRecording(member, command); }); } @@ -91,8 +100,10 @@ void setUp() { given(recordingRepository.save(any(Recording.class))).willReturn(savedRecording); given(document.getName()).willReturn("안녕하세요백종원입니다"); + willDoNothing().given(sttTaskService).submitSttTask(any()); + // when - RecordingSaveResult result = recordingService.saveRecording(command); + RecordingSaveResult result = recordingService.saveRecording(member, command); // then FilePath filePath = FilePath.from("안녕하세요백종원입니다_1.mp3");