diff --git a/.gitmodules b/.gitmodules index fc0f695..b0abf98 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,4 +1,4 @@ [submodule "Team29_BE_Submodule"] path = Team29_BE_Submodule url = git@github.com:29ana-notai/Team29_BE_Submodule.git - branch = release/0.0.2 + branch = release/0.0.3 diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 6442c2e..0000000 --- a/Dockerfile +++ /dev/null @@ -1,5 +0,0 @@ -FROM gradle:jdk21-jammy - -WORKDIR /app - -CMD ["gradle", "bootRun"] \ No newline at end of file diff --git a/Team29_BE_Submodule b/Team29_BE_Submodule index 9786d71..2908ffc 160000 --- a/Team29_BE_Submodule +++ b/Team29_BE_Submodule @@ -1 +1 @@ -Subproject commit 9786d71108d3333313244c73fb01e56b6993916f +Subproject commit 2908ffc46ec197ceffb930fd23349ebc48f75b8f diff --git a/build.gradle b/build.gradle index 60edd53..a0d1a96 100644 --- a/build.gradle +++ b/build.gradle @@ -5,7 +5,7 @@ plugins { } group = 'notai' -version = '0.0.2' +version = '0.0.3' java { toolchain { 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/annotation/presentation/AnnotationController.java b/src/main/java/notai/annotation/presentation/AnnotationController.java index a57414c..f6eaabd 100644 --- a/src/main/java/notai/annotation/presentation/AnnotationController.java +++ b/src/main/java/notai/annotation/presentation/AnnotationController.java @@ -6,6 +6,8 @@ import notai.annotation.application.AnnotationService; import notai.annotation.presentation.request.CreateAnnotationRequest; import notai.annotation.presentation.response.AnnotationResponse; +import notai.auth.Auth; +import notai.member.domain.Member; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -22,10 +24,12 @@ public class AnnotationController { @PostMapping public ResponseEntity createAnnotation( - @PathVariable Long documentId, @RequestBody @Valid CreateAnnotationRequest request + @Auth Member member, @PathVariable Long documentId, @RequestBody @Valid CreateAnnotationRequest request ) { - AnnotationResponse response = annotationService.createAnnotation(documentId, + AnnotationResponse response = annotationService.createAnnotation( + member, + documentId, request.pageNumber(), request.x(), request.y(), @@ -40,10 +44,11 @@ public ResponseEntity createAnnotation( @GetMapping public ResponseEntity> getAnnotations( - @PathVariable Long documentId, @RequestParam List pageNumbers + @Auth Member member, @PathVariable Long documentId, @RequestParam List pageNumbers ) { List response = annotationQueryService.getAnnotationsByDocumentAndPageNumbers( + member, documentId, pageNumbers ); @@ -53,12 +58,15 @@ public ResponseEntity> getAnnotations( @PutMapping("/{annotationId}") public ResponseEntity updateAnnotation( + @Auth Member member, @PathVariable Long documentId, @PathVariable Long annotationId, @RequestBody @Valid CreateAnnotationRequest request ) { - AnnotationResponse response = annotationService.updateAnnotation(documentId, + AnnotationResponse response = annotationService.updateAnnotation( + member, + documentId, annotationId, request.x(), request.y(), @@ -72,10 +80,10 @@ public ResponseEntity updateAnnotation( @DeleteMapping("/{annotationId}") public ResponseEntity deleteAnnotation( - @PathVariable Long documentId, @PathVariable Long annotationId + @Auth Member member, @PathVariable Long documentId, @PathVariable Long annotationId ) { - annotationService.deleteAnnotation(documentId, annotationId); - return new ResponseEntity<>(HttpStatus.NO_CONTENT); + annotationService.deleteAnnotation(member, documentId, annotationId); + return new ResponseEntity<>(HttpStatus.OK); } } diff --git a/src/main/java/notai/annotation/presentation/request/CreateAnnotationRequest.java b/src/main/java/notai/annotation/presentation/request/CreateAnnotationRequest.java index 8e05acc..e2dc072 100644 --- a/src/main/java/notai/annotation/presentation/request/CreateAnnotationRequest.java +++ b/src/main/java/notai/annotation/presentation/request/CreateAnnotationRequest.java @@ -1,29 +1,29 @@ package notai.annotation.presentation.request; -import jakarta.validation.constraints.Max; import jakarta.validation.constraints.Positive; import jakarta.validation.constraints.PositiveOrZero; public record CreateAnnotationRequest( - @Positive(message = "페이지 번호는 양수여야 합니다.") + @PositiveOrZero(message = "페이지 번호는 0 이상이어야 합니다.") int pageNumber, -// @Max(value = ?, message = "x 좌표는 최대 ? 이하여야 합니다.") + // @Max(value = ?, message = "x 좌표는 최대 ? 이하여야 합니다.") @PositiveOrZero(message = "x 좌표는 0 이상이어야 합니다.") int x, -// @Max(value = ?, message = "x 좌표는 최대 ? 이하여야 합니다.") + // @Max(value = ?, message = "x 좌표는 최대 ? 이하여야 합니다.") @PositiveOrZero(message = "y 좌표는 0 이상이어야 합니다.") int y, -// @Max(value = ?, message = "width는 최대 ? 이하여야 합니다.") + // @Max(value = ?, message = "width는 최대 ? 이하여야 합니다.") @Positive(message = "width는 양수여야 합니다.") int width, -// @Max(value = ?, message = "height는 최대 ? 이하여야 합니다.") + // @Max(value = ?, message = "height는 최대 ? 이하여야 합니다.") @Positive(message = "height는 양수여야 합니다.") int height, String content -) {} +) { +} 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/client/ai/AiClient.java b/src/main/java/notai/client/ai/AiClient.java index c03507b..83f505e 100644 --- a/src/main/java/notai/client/ai/AiClient.java +++ b/src/main/java/notai/client/ai/AiClient.java @@ -2,17 +2,17 @@ import notai.client.ai.request.LlmTaskRequest; import notai.client.ai.response.TaskResponse; +import org.springframework.core.io.ByteArrayResource; import org.springframework.http.MediaType; import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestPart; import org.springframework.web.service.annotation.PostExchange; -import java.io.InputStream; - public interface AiClient { @PostExchange(url = "/api/ai/llm") TaskResponse submitLlmTask(@RequestBody LlmTaskRequest request); @PostExchange(url = "/api/ai/stt", contentType = MediaType.MULTIPART_FORM_DATA_VALUE) - TaskResponse submitSttTask(@RequestBody InputStream audioFileStream); + TaskResponse submitSttTask(@RequestPart("audio") ByteArrayResource audioFile); } diff --git a/src/main/java/notai/client/ai/AiClientConfig.java b/src/main/java/notai/client/ai/AiClientConfig.java index 5ab3db6..4bd3e5b 100644 --- a/src/main/java/notai/client/ai/AiClientConfig.java +++ b/src/main/java/notai/client/ai/AiClientConfig.java @@ -6,7 +6,10 @@ import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpStatusCode; +import org.springframework.http.converter.FormHttpMessageConverter; +import org.springframework.http.converter.ResourceHttpMessageConverter; import org.springframework.web.client.RestClient; +import org.springframework.web.client.RestTemplate; import static notai.client.HttpInterfaceUtil.createHttpInterface; import static notai.common.exception.ErrorMessages.AI_SERVER_ERROR; @@ -20,15 +23,26 @@ public class AiClientConfig { @Bean public AiClient aiClient() { - RestClient restClient = - RestClient.builder().baseUrl(aiServerUrl).requestInterceptor((request, body, execution) -> { - request.getHeaders().setContentLength(body.length); // Content-Length 설정 안하면 411 에러 발생 - return execution.execute(request, body); - }).defaultStatusHandler(HttpStatusCode::isError, (request, response) -> { - String responseBody = new String(response.getBody().readAllBytes()); - log.error("Response Status: {}", response.getStatusCode()); - throw new ExternalApiException(AI_SERVER_ERROR, response.getStatusCode().value()); - }).build(); + RestClient restClient = RestClient.builder() + .baseUrl(aiServerUrl) + .messageConverters(converters -> { + converters.addAll(new RestTemplate().getMessageConverters()); + converters.add(new FormHttpMessageConverter()); + }) + .requestInterceptor((request, body, execution) -> { + request.getHeaders().setContentLength(body.length); // Content-Length 설정 안하면 411 에러 발생 + return execution.execute(request, body); + }) + .defaultStatusHandler(HttpStatusCode::isError, (request, response) -> { + String responseBody = new String(response.getBody().readAllBytes()); + log.error("AI 서버에서 오류가 발생했습니다. - Status: {}, Body: {}", + response.getStatusCode(), + responseBody + ); + throw new ExternalApiException(AI_SERVER_ERROR, response.getStatusCode().value()); + }) + .build(); + return createHttpInterface(restClient, AiClient.class); } } diff --git a/src/main/java/notai/common/config/AuthConfig.java b/src/main/java/notai/common/config/AuthConfig.java index c0e8bc9..7cca462 100644 --- a/src/main/java/notai/common/config/AuthConfig.java +++ b/src/main/java/notai/common/config/AuthConfig.java @@ -17,8 +17,12 @@ public class AuthConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { - registry.addInterceptor(authInterceptor).addPathPatterns("/api/**").excludePathPatterns( - "/api/members/oauth/login/**").excludePathPatterns("/api/members/token/refresh"); + registry.addInterceptor(authInterceptor) + .addPathPatterns("/api/**") + .excludePathPatterns("/api/members/oauth/login/**") + .excludePathPatterns("/api/members/token/refresh") + .excludePathPatterns("/api/ai/stt/callback") + .excludePathPatterns("/api/ai/llm/callback"); } @Override diff --git a/src/main/java/notai/common/config/SwaggerConfig.java b/src/main/java/notai/common/config/SwaggerConfig.java index bcf6279..40959e5 100644 --- a/src/main/java/notai/common/config/SwaggerConfig.java +++ b/src/main/java/notai/common/config/SwaggerConfig.java @@ -38,6 +38,6 @@ public OpenAPI openAPI() { } private Info apiInfo() { - return new Info().title("notai API").description("notai API 문서입니다.").version("0.0.2"); + return new Info().title("notai API").description("notai API 문서입니다.").version("0.0.3"); } } diff --git a/src/main/java/notai/common/domain/vo/FilePath.java b/src/main/java/notai/common/domain/vo/FilePath.java index 78c7abd..eca6fc5 100644 --- a/src/main/java/notai/common/domain/vo/FilePath.java +++ b/src/main/java/notai/common/domain/vo/FilePath.java @@ -14,7 +14,7 @@ @NoArgsConstructor(access = PROTECTED) public class FilePath { - @Column(length = 50) + @Column(length = 255) private String filePath; private FilePath(String filePath) { @@ -22,11 +22,6 @@ private FilePath(String filePath) { } public static FilePath from(String filePath) { - // 추후 확장자 추가 - if (!filePath.matches( - "[a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣()\\[\\]+\\-&/_\\s]+(/[a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣()\\[\\]+\\-&/_\\s]+)*/?[a-zA-Z0-9ㄱ-ㅎㅏ-ㅣ가-힣()\\[\\]+\\-&/_\\s]+\\.mp3")) { - throw new BadRequestException(INVALID_FILE_TYPE); - } return new FilePath(filePath); } } diff --git a/src/main/java/notai/common/exception/type/BadRequestException.java b/src/main/java/notai/common/exception/type/BadRequestException.java index 55e0cbc..fc07ea0 100644 --- a/src/main/java/notai/common/exception/type/BadRequestException.java +++ b/src/main/java/notai/common/exception/type/BadRequestException.java @@ -9,4 +9,7 @@ public class BadRequestException extends ApplicationException { public BadRequestException(ErrorMessages message) { super(message, 400); } + public BadRequestException(String message) { + super(message, 400); + } } diff --git a/src/main/java/notai/document/application/DocumentQueryService.java b/src/main/java/notai/document/application/DocumentQueryService.java index 0e45f85..02d6e03 100644 --- a/src/main/java/notai/document/application/DocumentQueryService.java +++ b/src/main/java/notai/document/application/DocumentQueryService.java @@ -4,6 +4,7 @@ import notai.document.application.result.DocumentFindResult; import notai.document.domain.Document; import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; import org.springframework.stereotype.Service; import java.util.List; @@ -19,8 +20,8 @@ public List findDocuments(Long folderId) { return documents.stream().map(this::getDocumentFindResult).toList(); } - public List findRootDocuments(Long memberId) { - List documents = documentRepository.findAllByMemberIdAndFolderIdIsNull(memberId); + public List findRootDocuments(Member member) { + List documents = documentRepository.findAllByMemberIdAndFolderIdIsNull(member.getId()); return documents.stream().map(this::getDocumentFindResult).toList(); } diff --git a/src/main/java/notai/document/application/DocumentService.java b/src/main/java/notai/document/application/DocumentService.java index 6a04c5e..3084dbb 100644 --- a/src/main/java/notai/document/application/DocumentService.java +++ b/src/main/java/notai/document/application/DocumentService.java @@ -10,7 +10,6 @@ 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; @@ -27,34 +26,32 @@ public class DocumentService { 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 +64,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 +78,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 +100,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 12423c5..5539c9d 100644 --- a/src/main/java/notai/document/presentation/DocumentController.java +++ b/src/main/java/notai/document/presentation/DocumentController.java @@ -1,5 +1,7 @@ package notai.document.presentation; +import io.swagger.v3.oas.annotations.Parameter; +import io.swagger.v3.oas.annotations.media.Content; import lombok.RequiredArgsConstructor; import notai.auth.Auth; import notai.document.application.DocumentQueryService; @@ -12,6 +14,8 @@ 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.*; import org.springframework.web.multipart.MultipartFile; @@ -30,19 +34,20 @@ public class DocumentController { private static final Long ROOT_FOLDER_ID = -1L; private static final String FOLDER_URL_FORMAT = "/api/folders/%s/documents/%s"; - @PostMapping + @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, @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()); @@ -51,13 +56,13 @@ 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, + member, folderId, id, documentUpdateRequest @@ -68,11 +73,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); } else { documentResults = documentQueryService.findDocuments(folderId); } @@ -83,9 +88,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..b172767 100644 --- a/src/main/java/notai/folder/application/FolderQueryService.java +++ b/src/main/java/notai/folder/application/FolderQueryService.java @@ -4,6 +4,7 @@ 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 java.util.List; @@ -14,17 +15,17 @@ public class FolderQueryService { private final FolderRepository folderRepository; - public List getFolders(Long memberId, Long parentFolderId) { - List folders = getFoldersWithMemberAndParent(memberId, parentFolderId); + public List getFolders(Member member, Long parentFolderId) { + List folders = getFoldersWithMemberAndParent(member, parentFolderId); // document read return folders.stream().map(this::getFolderResult).toList(); } - private List getFoldersWithMemberAndParent(Long memberId, Long parentFolderId) { + private List getFoldersWithMemberAndParent(Member member, Long parentFolderId) { if (parentFolderId == null) { - return folderRepository.findAllByMemberIdAndParentFolderIsNull(memberId); + return folderRepository.findAllByMemberIdAndParentFolderIsNull(member.getId()); } - return folderRepository.findAllByMemberIdAndParentFolderId(memberId, parentFolderId); + return folderRepository.findAllByMemberIdAndParentFolderId(member.getId(), parentFolderId); } 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..96a7091 100644 --- a/src/main/java/notai/folder/application/FolderService.java +++ b/src/main/java/notai/folder/application/FolderService.java @@ -11,7 +11,6 @@ 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 java.util.List; @@ -21,57 +20,54 @@ 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..91daf29 100644 --- a/src/main/java/notai/folder/presentation/FolderController.java +++ b/src/main/java/notai/folder/presentation/FolderController.java @@ -16,6 +16,7 @@ import notai.folder.presentation.response.FolderMoveResponse; import notai.folder.presentation.response.FolderSaveResponse; import notai.folder.presentation.response.FolderUpdateResponse; +import notai.member.domain.Member; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @@ -32,59 +33,59 @@ public class FolderController { @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 + @Auth Member member, @RequestParam(required = false) Long parentFolderId ) { - List folderResults = folderQueryService.getFolders(memberId, parentFolderId); + List folderResults = folderQueryService.getFolders(member, parentFolderId); List response = folderResults.stream().map(FolderFindResponse::from).toList(); return ResponseEntity.ok(response); } @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(memberId, id); + return folderService.moveRootFolder(member, id); } } 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/application/LlmTaskService.java b/src/main/java/notai/llm/application/LlmTaskService.java index b6f41f3..d5f56fb 100644 --- a/src/main/java/notai/llm/application/LlmTaskService.java +++ b/src/main/java/notai/llm/application/LlmTaskService.java @@ -73,6 +73,8 @@ private void submitPageTask(Integer pageNumber, Map> a if (foundSummary.isEmpty() && foundProblem.isEmpty()) { Summary summary = new Summary(foundDocument, pageNumber); Problem problem = new Problem(foundDocument, pageNumber); + summaryRepository.save(summary); + problemRepository.save(problem); LlmTask taskRecord = new LlmTask(taskId, summary, problem); llmTaskRepository.save(taskRecord); @@ -80,6 +82,7 @@ private void submitPageTask(Integer pageNumber, Map> a if (foundSummary.isPresent() && foundProblem.isPresent()) { LlmTask foundTaskRecord = llmTaskRepository.getBySummaryAndProblem(foundSummary.get(), foundProblem.get()); llmTaskRepository.delete(foundTaskRecord); + llmTaskRepository.flush(); LlmTask taskRecord = new LlmTask(taskId, foundSummary.get(), foundProblem.get()); llmTaskRepository.save(taskRecord); diff --git a/src/main/java/notai/llm/domain/LlmTask.java b/src/main/java/notai/llm/domain/LlmTask.java index 24233d8..9ba0dec 100644 --- a/src/main/java/notai/llm/domain/LlmTask.java +++ b/src/main/java/notai/llm/domain/LlmTask.java @@ -25,12 +25,12 @@ public class LlmTask extends RootEntity { private UUID id; @NotNull - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "summary_id") private Summary summary; @NotNull - @OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.PERSIST) + @OneToOne(fetch = FetchType.LAZY) @JoinColumn(name = "problem_id") private Problem problem; 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/llm/presentation/request/LlmTaskSubmitRequest.java b/src/main/java/notai/llm/presentation/request/LlmTaskSubmitRequest.java index 7c03443..e46e10d 100644 --- a/src/main/java/notai/llm/presentation/request/LlmTaskSubmitRequest.java +++ b/src/main/java/notai/llm/presentation/request/LlmTaskSubmitRequest.java @@ -1,7 +1,7 @@ package notai.llm.presentation.request; import jakarta.validation.constraints.NotNull; -import jakarta.validation.constraints.Positive; +import jakarta.validation.constraints.PositiveOrZero; import notai.llm.application.command.LlmTaskSubmitCommand; import java.util.List; @@ -10,7 +10,7 @@ public record LlmTaskSubmitRequest( @NotNull(message = "문서 ID는 필수 입력 값입니다.") Long documentId, - List<@Positive(message = "페이지 번호는 양수여야 합니다.") Integer> pages + List<@PositiveOrZero(message = "페이지 번호는 음수일 수 없습니다.") Integer> pages ) { public LlmTaskSubmitCommand toCommand() { return new LlmTaskSubmitCommand(documentId, pages); diff --git a/src/main/java/notai/ocr/application/OCRQueryService.java b/src/main/java/notai/ocr/application/OCRQueryService.java index c0b4c87..102b5ca 100644 --- a/src/main/java/notai/ocr/application/OCRQueryService.java +++ b/src/main/java/notai/ocr/application/OCRQueryService.java @@ -1,23 +1,25 @@ package notai.ocr.application; 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 static notai.common.exception.ErrorMessages.OCR_RESULT_NOT_FOUND; + @Service @RequiredArgsConstructor public class OCRQueryService { private final OCRRepository ocrRepository; - public OCRFindResult findOCR(Long documentId, Integer pageNumber) { - OCR ocr = ocrRepository.findOCRByDocumentIdAndPageNumber(documentId, - pageNumber + 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/domain/OCR.java b/src/main/java/notai/ocr/domain/OCR.java index 061bcd7..00f4273 100644 --- a/src/main/java/notai/ocr/domain/OCR.java +++ b/src/main/java/notai/ocr/domain/OCR.java @@ -28,7 +28,7 @@ public class OCR extends RootEntity { private Integer pageNumber; @NotNull - @Column(name = "content", columnDefinition = "TEXT") + @Column(name = "content", columnDefinition = "LONGTEXT") private String content; public OCR(Document document, Integer pageNumber, String content) { 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/domain/PageRecording.java b/src/main/java/notai/pageRecording/domain/PageRecording.java index 288ae1f..a0cc39b 100644 --- a/src/main/java/notai/pageRecording/domain/PageRecording.java +++ b/src/main/java/notai/pageRecording/domain/PageRecording.java @@ -31,7 +31,6 @@ public class PageRecording { @NotNull private Double startTime; - @NotNull private Double endTime; public PageRecording(Recording recording, Integer pageNumber, Double startTime, Double endTime) { 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 d09e819..55602bf 100644 --- a/src/main/java/notai/recording/application/RecordingService.java +++ b/src/main/java/notai/recording/application/RecordingService.java @@ -10,6 +10,7 @@ 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; @@ -38,8 +39,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); @@ -60,7 +62,7 @@ public RecordingSaveResult saveRecording(RecordingSaveCommand command) { return RecordingSaveResult.of(savedRecording.getId(), foundDocument.getId(), savedRecording.getCreatedAt()); } catch (IllegalArgumentException e) { - throw new BadRequestException(INVALID_AUDIO_ENCODING); + throw new BadRequestException(INVALID_AUDIO_ENCODING + " : " + e.getMessage()); } catch (IOException e) { throw new InternalServerErrorException(FILE_SAVE_ERROR); // TODO: 재시도 로직 추가? } 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/java/notai/stt/application/SttService.java b/src/main/java/notai/stt/application/SttService.java index f48545d..105f617 100644 --- a/src/main/java/notai/stt/application/SttService.java +++ b/src/main/java/notai/stt/application/SttService.java @@ -33,6 +33,7 @@ public void updateSttResult(UpdateSttResultCommand command) { SttTask sttTask = sttTaskRepository.getById(command.taskId()); Stt stt = sttTask.getStt(); Recording recording = stt.getRecording(); + List pageRecordings = pageRecordingRepository.findAllByRecordingIdOrderByStartTime(recording.getId()); SttPageMatchedDto matchedResult = stt.matchWordsWithPages(command.words(), pageRecordings); diff --git a/src/main/java/notai/stt/application/SttTaskService.java b/src/main/java/notai/stt/application/SttTaskService.java index af2cfe9..7fedcc6 100644 --- a/src/main/java/notai/stt/application/SttTaskService.java +++ b/src/main/java/notai/stt/application/SttTaskService.java @@ -15,12 +15,13 @@ import notai.stt.domain.SttRepository; import notai.sttTask.domain.SttTask; import notai.sttTask.domain.SttTaskRepository; +import org.springframework.core.io.ByteArrayResource; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; +import java.nio.file.Files; @Service @Transactional @@ -35,8 +36,17 @@ public void submitSttTask(SttRequestCommand command) { Recording recording = recordingRepository.getById(command.recordingId()); File audioFile = validateAudioFile(command.audioFilePath()); - try (FileInputStream fileInputStream = new FileInputStream(audioFile)) { - TaskResponse response = aiClient.submitSttTask(fileInputStream); + try { + byte[] audioBytes = Files.readAllBytes(audioFile.toPath()); + + ByteArrayResource resource = new ByteArrayResource(audioBytes) { + @Override + public String getFilename() { + return audioFile.getName(); + } + }; + + TaskResponse response = aiClient.submitSttTask(resource); createAndSaveSttTask(recording, response); } catch (IOException e) { throw new FileProcessException(FILE_READ_ERROR); diff --git a/src/main/java/notai/stt/domain/Stt.java b/src/main/java/notai/stt/domain/Stt.java index 46794d6..b09ed97 100644 --- a/src/main/java/notai/stt/domain/Stt.java +++ b/src/main/java/notai/stt/domain/Stt.java @@ -92,7 +92,7 @@ public SttPageMatchedDto matchWordsWithPages( for (PageRecording page : pageRecordings) { List pageWords = new ArrayList<>(); double pageStart = page.getStartTime(); - double pageEnd = page.getEndTime(); + Double pageEnd = page.getEndTime(); // 현재 페이지의 시간 범위에 속하는 단어들을 찾아 매칭 while (wordIndex < words.size()) { @@ -104,18 +104,17 @@ public SttPageMatchedDto matchWordsWithPages( continue; } - // 마지막 페이지가 아닐 경우, 페이지 종료 시간을 벗어난 단어가 나오면 다음 페이지로 - if (page != lastPage && word.start() - TIME_THRESHOLD >= pageEnd) { + // 마지막 페이지이거나 endTime이 null이면 시작 시간만 체크 + if ((page == lastPage || pageEnd == null) || word.start() - TIME_THRESHOLD < pageEnd) { + pageWords.add(new SttPageMatchedDto.PageMatchedWord( + word.word(), + (int) word.start(), + (int) word.end() + )); + wordIndex++; + } else { break; } - - // 현재 페이지에 단어 매칭하여 추가 - pageWords.add(new SttPageMatchedDto.PageMatchedWord( - word.word(), - (int) word.start(), - (int) word.end() - )); - wordIndex++; } // 매칭된 단어가 있는 경우만 맵에 추가 diff --git a/src/main/java/notai/stt/presentation/request/SttCallbackRequest.java b/src/main/java/notai/stt/presentation/request/SttCallbackRequest.java index 1e58bc7..0633ee3 100644 --- a/src/main/java/notai/stt/presentation/request/SttCallbackRequest.java +++ b/src/main/java/notai/stt/presentation/request/SttCallbackRequest.java @@ -1,38 +1,29 @@ package notai.stt.presentation.request; import notai.stt.application.command.UpdateSttResultCommand; -import notai.stt.application.command.UpdateSttResultCommand.Word; import java.util.List; import java.util.UUID; public record SttCallbackRequest( String taskId, - String state, - SttResult result + String text, + List words ) { public UpdateSttResultCommand toCommand() { - List words = result.words().stream() - .map(word -> new Word( + List commandWords = words().stream() + .map(word -> new UpdateSttResultCommand.Word( word.word(), word.start(), - word.end() - )) + word.end())) .toList(); - return new UpdateSttResultCommand(UUID.fromString(taskId), words); + return new UpdateSttResultCommand(UUID.fromString(taskId), commandWords); } - - public record SttResult( - double audioLength, - String language, - double languageProbability, - String text, - List words + + public record Word( + String word, + double start, + double end ) { - public record Word( - double start, - double end, - String word - ) {} } } 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/client/ai/AiClientIntegrationTest.java b/src/test/java/notai/client/ai/AiClientIntegrationTest.java index 782f4b8..c71dbe1 100644 --- a/src/test/java/notai/client/ai/AiClientIntegrationTest.java +++ b/src/test/java/notai/client/ai/AiClientIntegrationTest.java @@ -8,6 +8,8 @@ import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.core.io.ByteArrayResource; + import java.io.ByteArrayInputStream; import java.io.InputStream; @@ -36,10 +38,10 @@ class AiClientIntegrationTest { void STT_태스크_제출_통합_테스트() { // Given byte[] audioBytes = "test audio content".getBytes(); - InputStream audioInputStream = new ByteArrayInputStream(audioBytes); + ByteArrayResource byteArrayResource = new ByteArrayResource(audioBytes); // When - TaskResponse response = aiClient.submitSttTask(audioInputStream); + TaskResponse response = aiClient.submitSttTask(byteArrayResource); // Then assertNotNull(response); diff --git a/src/test/java/notai/client/ai/AiClientTest.java b/src/test/java/notai/client/ai/AiClientTest.java index b447e0a..c1004f0 100644 --- a/src/test/java/notai/client/ai/AiClientTest.java +++ b/src/test/java/notai/client/ai/AiClientTest.java @@ -8,6 +8,7 @@ import org.mockito.Mock; import static org.mockito.Mockito.*; import org.mockito.MockitoAnnotations; +import org.springframework.core.io.ByteArrayResource; import java.io.InputStream; import java.util.UUID; @@ -41,16 +42,16 @@ void setUp() { @Test void STT_테스크_전달_테스트() { // Given - InputStream inputStream = mock(InputStream.class); + ByteArrayResource byteArrayResource = mock(ByteArrayResource.class); UUID expectedTaskId = UUID.randomUUID(); TaskResponse expectedResponse = new TaskResponse(expectedTaskId, "stt"); - when(aiClient.submitSttTask(inputStream)).thenReturn(expectedResponse); + when(aiClient.submitSttTask(byteArrayResource)).thenReturn(expectedResponse); // When - TaskResponse response = aiClient.submitSttTask(inputStream); + TaskResponse response = aiClient.submitSttTask(byteArrayResource); // Then assertEquals(expectedResponse, response); - verify(aiClient, times(1)).submitSttTask(inputStream); + verify(aiClient, times(1)).submitSttTask(byteArrayResource); } } 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 1f2f1b7..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)) ); @@ -84,9 +86,10 @@ class LlmTaskServiceTest { Member member = new Member(new OauthId("12345", OauthProvider.KAKAO), "test@example.com", "TestUser"); Folder folder = new Folder(member, "TestFolder"); - Document document = new Document(folder, "TestDocument", "http://example.com/test.pdf", 43); + 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");