diff --git a/src/main/java/notai/annotation/application/AnnotationQueryService.java b/src/main/java/notai/annotation/application/AnnotationQueryService.java index 62aa952..580c274 100644 --- a/src/main/java/notai/annotation/application/AnnotationQueryService.java +++ b/src/main/java/notai/annotation/application/AnnotationQueryService.java @@ -8,6 +8,7 @@ import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -22,12 +23,14 @@ public class AnnotationQueryService { private final AnnotationRepository annotationRepository; private final DocumentRepository documentRepository; + private final MemberRepository memberRepository; @Transactional(readOnly = true) public List getAnnotationsByDocumentAndPageNumbers( - Member member, Long documentId, List pageNumbers + Long memberId, Long documentId, List pageNumbers ) { Document document = documentRepository.getById(documentId); + Member member = memberRepository.getById(memberId); document.validateOwner(member); List annotations = annotationRepository.findByDocumentIdAndPageNumberIn(documentId, pageNumbers); diff --git a/src/main/java/notai/annotation/application/AnnotationService.java b/src/main/java/notai/annotation/application/AnnotationService.java index 983c0c3..0be72dd 100644 --- a/src/main/java/notai/annotation/application/AnnotationService.java +++ b/src/main/java/notai/annotation/application/AnnotationService.java @@ -7,6 +7,7 @@ import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; @@ -16,12 +17,14 @@ public class AnnotationService { private final AnnotationRepository annotationRepository; private final DocumentRepository documentRepository; + private final MemberRepository memberRepository; @Transactional public AnnotationResponse createAnnotation( - Member member, Long documentId, int pageNumber, int x, int y, int width, int height, String content + Long memberId, Long documentId, int pageNumber, int x, int y, int width, int height, String content ) { Document document = documentRepository.getById(documentId); + Member member = memberRepository.getById(memberId); document.validateOwner(member); Annotation annotation = new Annotation(document, pageNumber, x, y, width, height, content); @@ -31,9 +34,10 @@ public AnnotationResponse createAnnotation( @Transactional public AnnotationResponse updateAnnotation( - Member member, Long documentId, Long annotationId, int x, int y, int width, int height, String content + Long memberId, Long documentId, Long annotationId, int x, int y, int width, int height, String content ) { Document document = documentRepository.getById(documentId); + Member member = memberRepository.getById(memberId); document.validateOwner(member); Annotation annotation = annotationRepository.getById(annotationId); annotation.updateAnnotation(x, y, width, height, content); @@ -41,8 +45,9 @@ public AnnotationResponse updateAnnotation( } @Transactional - public void deleteAnnotation(Member member, Long documentId, Long annotationId) { + public void deleteAnnotation(Long memberId, Long documentId, Long annotationId) { Document document = documentRepository.getById(documentId); + Member member = memberRepository.getById(memberId); 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 f6eaabd..583ef95 100644 --- a/src/main/java/notai/annotation/presentation/AnnotationController.java +++ b/src/main/java/notai/annotation/presentation/AnnotationController.java @@ -7,7 +7,6 @@ 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.*; @@ -24,11 +23,11 @@ public class AnnotationController { @PostMapping public ResponseEntity createAnnotation( - @Auth Member member, @PathVariable Long documentId, @RequestBody @Valid CreateAnnotationRequest request + @Auth Long memberId, @PathVariable Long documentId, @RequestBody @Valid CreateAnnotationRequest request ) { AnnotationResponse response = annotationService.createAnnotation( - member, + memberId, documentId, request.pageNumber(), request.x(), @@ -44,11 +43,10 @@ public ResponseEntity createAnnotation( @GetMapping public ResponseEntity> getAnnotations( - @Auth Member member, @PathVariable Long documentId, @RequestParam List pageNumbers + @Auth Long memberId, @PathVariable Long documentId, @RequestParam List pageNumbers ) { - List response = annotationQueryService.getAnnotationsByDocumentAndPageNumbers( - member, + memberId, documentId, pageNumbers ); @@ -58,14 +56,14 @@ public ResponseEntity> getAnnotations( @PutMapping("/{annotationId}") public ResponseEntity updateAnnotation( - @Auth Member member, + @Auth Long memberId, @PathVariable Long documentId, @PathVariable Long annotationId, @RequestBody @Valid CreateAnnotationRequest request ) { AnnotationResponse response = annotationService.updateAnnotation( - member, + memberId, documentId, annotationId, request.x(), @@ -80,10 +78,10 @@ public ResponseEntity updateAnnotation( @DeleteMapping("/{annotationId}") public ResponseEntity deleteAnnotation( - @Auth Member member, @PathVariable Long documentId, @PathVariable Long annotationId + @Auth Long memberId, @PathVariable Long documentId, @PathVariable Long annotationId ) { - annotationService.deleteAnnotation(member, documentId, annotationId); + annotationService.deleteAnnotation(memberId, documentId, annotationId); return new ResponseEntity<>(HttpStatus.OK); } } diff --git a/src/main/java/notai/auth/AuthArgumentResolver.java b/src/main/java/notai/auth/AuthArgumentResolver.java index 0682f5c..d832eba 100644 --- a/src/main/java/notai/auth/AuthArgumentResolver.java +++ b/src/main/java/notai/auth/AuthArgumentResolver.java @@ -7,6 +7,7 @@ import notai.member.domain.MemberRepository; import org.springframework.core.MethodParameter; import org.springframework.stereotype.Component; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.bind.support.WebDataBinderFactory; import org.springframework.web.context.request.NativeWebRequest; import org.springframework.web.method.support.HandlerMethodArgumentResolver; @@ -24,7 +25,7 @@ public boolean supportsParameter(MethodParameter parameter) { } @Override - public Member resolveArgument( + public Long resolveArgument( MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @@ -32,6 +33,6 @@ public Member resolveArgument( ) { HttpServletRequest request = (HttpServletRequest) webRequest.getNativeRequest(); Long memberId = (Long) request.getAttribute("memberId"); - return memberRepository.getById(memberId); + return memberRepository.getById(memberId).getId(); } } diff --git a/src/main/java/notai/common/config/AuthInterceptor.java b/src/main/java/notai/common/config/AuthInterceptor.java index 77d3a64..bb03adb 100644 --- a/src/main/java/notai/common/config/AuthInterceptor.java +++ b/src/main/java/notai/common/config/AuthInterceptor.java @@ -31,6 +31,10 @@ public boolean preHandle(HttpServletRequest request, HttpServletResponse respons String token = header.substring(BEARER_PREFIX_LENGTH); try { Long memberId = tokenService.extractMemberId(token); + if (memberId == null) { + throw new UnAuthorizedException(INVALID_ACCESS_TOKEN); + } + request.setAttribute("memberId", memberId); } catch (Exception e) { throw new UnAuthorizedException(INVALID_ACCESS_TOKEN); diff --git a/src/main/java/notai/common/exception/ErrorMessages.java b/src/main/java/notai/common/exception/ErrorMessages.java index 0fd77c8..ca3e952 100644 --- a/src/main/java/notai/common/exception/ErrorMessages.java +++ b/src/main/java/notai/common/exception/ErrorMessages.java @@ -19,8 +19,7 @@ public enum ErrorMessages { // folder FOLDER_NOT_FOUND("폴더를 찾을 수 없습니다."), - - // llm task + FOLDER_AND_DOCUMENT_INVALID_RESPONSE("허용하지 않는 데이터 타입입니다."), // llm task LLM_TASK_LOG_NOT_FOUND("AI 작업 기록을 찾을 수 없습니다."), LLM_TASK_RESULT_ERROR("AI 요약 및 문제 생성 중에 문제가 발생했습니다."), @@ -37,15 +36,15 @@ public enum ErrorMessages { RECORDING_NOT_FOUND("녹음 파일을 찾을 수 없습니다."), // external api call - KAKAO_API_ERROR("카카오 API 호출에 예외가 발생했습니다."), + KAKAO_API_ERROR("카카오 API 호출에 예외가 발생했습니다."), AI_SERVER_ERROR("AI 서버 API 호출에 예외가 발생했습니다."), SLACK_API_ERROR("슬랙 API 호출에 예외가 발생했습니다."), // auth - INVALID_ACCESS_TOKEN("유효하지 않은 토큰입니다."), - INVALID_REFRESH_TOKEN("유요하지 않은 Refresh Token입니다."), - EXPIRED_REFRESH_TOKEN("만료된 Refresh Token입니다."), - INVALID_LOGIN_TYPE("지원하지 않는 소셜 로그인 타입입니다."), + INVALID_ACCESS_TOKEN("유효하지 않은 토큰입니다."), + INVALID_REFRESH_TOKEN("유요하지 않은 Refresh Token입니다."), + EXPIRED_REFRESH_TOKEN("만료된 Refresh Token입니다."), + INVALID_LOGIN_TYPE("지원하지 않는 소셜 로그인 타입입니다."), NOTFOUND_ACCESS_TOKEN("토큰 정보가 존재하지 않습니다."), // stt diff --git a/src/main/java/notai/document/application/DocumentQueryService.java b/src/main/java/notai/document/application/DocumentQueryService.java index 02d6e03..9ed69e5 100644 --- a/src/main/java/notai/document/application/DocumentQueryService.java +++ b/src/main/java/notai/document/application/DocumentQueryService.java @@ -6,11 +6,13 @@ import notai.document.domain.DocumentRepository; import notai.member.domain.Member; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class DocumentQueryService { private final DocumentRepository documentRepository; @@ -20,8 +22,8 @@ public List findDocuments(Long folderId) { return documents.stream().map(this::getDocumentFindResult).toList(); } - public List findRootDocuments(Member member) { - List documents = documentRepository.findAllByMemberIdAndFolderIdIsNull(member.getId()); + public List findRootDocuments(Long memberId) { + List documents = documentRepository.findAllByMemberIdAndFolderIdIsNull(memberId); 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 3084dbb..7caae8d 100644 --- a/src/main/java/notai/document/application/DocumentService.java +++ b/src/main/java/notai/document/application/DocumentService.java @@ -10,49 +10,52 @@ import notai.folder.domain.Folder; import notai.folder.domain.FolderRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import notai.ocr.application.OCRService; import notai.pdf.PdfService; import notai.pdf.result.PdfSaveResult; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import java.util.List; @Service @RequiredArgsConstructor +@Transactional public class DocumentService { private final PdfService pdfService; private final OCRService ocrService; private final DocumentRepository documentRepository; private final FolderRepository folderRepository; + private final MemberRepository memberRepository; private static final Long ROOT_FOLDER_ID = -1L; - public DocumentSaveResult saveDocument( - Member member, Long folderId, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest + Long memberId, Long folderId, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest ) { PdfSaveResult pdfSaveResult = pdfService.savePdf(pdfFile); - Document document = saveAndReturnDocument(member, folderId, documentSaveRequest, pdfSaveResult); + Document document = saveAndReturnDocument(memberId, folderId, documentSaveRequest, pdfSaveResult); ocrService.saveOCR(document, pdfSaveResult.pdf()); return DocumentSaveResult.of(document.getId(), document.getName(), document.getUrl()); } public DocumentSaveResult saveRootDocument( - Member member, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest + Long memberId, MultipartFile pdfFile, DocumentSaveRequest documentSaveRequest ) { PdfSaveResult pdfSaveResult = pdfService.savePdf(pdfFile); - Document document = saveAndReturnRootDocument(member, documentSaveRequest, pdfSaveResult); + Document document = saveAndReturnRootDocument(memberId, documentSaveRequest, pdfSaveResult); ocrService.saveOCR(document, pdfSaveResult.pdf()); return DocumentSaveResult.of(document.getId(), document.getName(), document.getUrl()); } public DocumentUpdateResult updateDocument( - Member member, Long folderId, Long documentId, DocumentUpdateRequest documentUpdateRequest + Long memberId, Long folderId, Long documentId, DocumentUpdateRequest documentUpdateRequest ) { Document document = documentRepository.getById(documentId); - + Member member = memberRepository.getById(memberId); document.validateOwner(member); if (!folderId.equals(ROOT_FOLDER_ID)) { @@ -64,10 +67,10 @@ public DocumentUpdateResult updateDocument( } public void deleteDocument( - Member member, Long folderId, Long documentId + Long memberId, Long folderId, Long documentId ) { Document document = documentRepository.getById(documentId); - + Member member = memberRepository.getById(memberId); document.validateOwner(member); if (!folderId.equals(ROOT_FOLDER_ID)) { @@ -78,18 +81,19 @@ public void deleteDocument( } public void deleteAllByFolder( - Member member, Folder folder + Long memberId, Folder folder ) { List documents = documentRepository.findAllByFolderId(folder.getId()); for (Document document : documents) { - deleteDocument(member, folder.getId(), document.getId()); + deleteDocument(memberId, folder.getId(), document.getId()); } } private Document saveAndReturnDocument( - Member member, Long folderId, DocumentSaveRequest documentSaveRequest, PdfSaveResult pdfSaveResult + Long memberId, Long folderId, DocumentSaveRequest documentSaveRequest, PdfSaveResult pdfSaveResult ) { Folder folder = folderRepository.getById(folderId); + Member member = memberRepository.getById(memberId); Document document = new Document(folder, member, documentSaveRequest.name(), @@ -100,8 +104,9 @@ private Document saveAndReturnDocument( } private Document saveAndReturnRootDocument( - Member member, DocumentSaveRequest documentSaveRequest, PdfSaveResult pdfSaveResult + Long memberId, 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 5539c9d..b32bd52 100644 --- a/src/main/java/notai/document/presentation/DocumentController.java +++ b/src/main/java/notai/document/presentation/DocumentController.java @@ -36,18 +36,18 @@ public class DocumentController { @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity saveDocument( - @Auth Member member, + @Auth Long memberId, @PathVariable Long folderId, - @Parameter(content = @Content(mediaType = MediaType.APPLICATION_PDF_VALUE)) - @RequestPart MultipartFile pdfFile, + @Parameter(content = @Content(mediaType = MediaType.APPLICATION_PDF_VALUE)) @RequestPart + MultipartFile pdfFile, @RequestPart DocumentSaveRequest documentSaveRequest ) { DocumentSaveResult documentSaveResult; if (folderId.equals(ROOT_FOLDER_ID)) { - documentSaveResult = documentService.saveRootDocument(member, pdfFile, documentSaveRequest); + documentSaveResult = documentService.saveRootDocument(memberId, pdfFile, documentSaveRequest); } else { - documentSaveResult = documentService.saveDocument(member, folderId, pdfFile, documentSaveRequest); + documentSaveResult = documentService.saveDocument(memberId, folderId, pdfFile, documentSaveRequest); } DocumentSaveResponse response = DocumentSaveResponse.from(documentSaveResult); String url = String.format(FOLDER_URL_FORMAT, folderId, response.id()); @@ -56,13 +56,12 @@ public ResponseEntity saveDocument( @PutMapping(value = "/{id}") public ResponseEntity updateDocument( - @Auth Member member, + @Auth Long memberId, @PathVariable Long folderId, @PathVariable Long id, @RequestBody DocumentUpdateRequest documentUpdateRequest ) { - DocumentUpdateResult documentUpdateResult = documentService.updateDocument( - member, + DocumentUpdateResult documentUpdateResult = documentService.updateDocument(memberId, folderId, id, documentUpdateRequest @@ -73,11 +72,11 @@ public ResponseEntity updateDocument( @GetMapping public ResponseEntity> getDocuments( - @Auth Member member, @PathVariable Long folderId + @Auth Long memberId, @PathVariable Long folderId ) { List documentResults; if (folderId.equals(ROOT_FOLDER_ID)) { - documentResults = documentQueryService.findRootDocuments(member); + documentResults = documentQueryService.findRootDocuments(memberId); } else { documentResults = documentQueryService.findDocuments(folderId); } @@ -88,9 +87,9 @@ public ResponseEntity> getDocuments( @DeleteMapping("/{id}") public ResponseEntity deleteDocument( - @Auth Member member, @PathVariable Long folderId, @PathVariable Long id + @Auth Long memberId, @PathVariable Long folderId, @PathVariable Long id ) { - documentService.deleteDocument(member, folderId, id); + documentService.deleteDocument(memberId, 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 b172767..46acc4a 100644 --- a/src/main/java/notai/folder/application/FolderQueryService.java +++ b/src/main/java/notai/folder/application/FolderQueryService.java @@ -6,26 +6,29 @@ import notai.folder.domain.FolderRepository; import notai.member.domain.Member; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class FolderQueryService { private final FolderRepository folderRepository; + private static final Long ROOT_ID = -1L; - public List getFolders(Member member, Long parentFolderId) { - List folders = getFoldersWithMemberAndParent(member, parentFolderId); + public List getFolders(Long memberId, Long folderId) { + List folders = getFoldersWithMemberAndParent(memberId, folderId); // document read return folders.stream().map(this::getFolderResult).toList(); } - private List getFoldersWithMemberAndParent(Member member, Long parentFolderId) { - if (parentFolderId == null) { - return folderRepository.findAllByMemberIdAndParentFolderIsNull(member.getId()); + private List getFoldersWithMemberAndParent(Long memberId, Long folderId) { + if (folderId == null || folderId.equals(ROOT_ID)) { + return folderRepository.findAllByMemberIdAndParentFolderIsNull(memberId); } - return folderRepository.findAllByMemberIdAndParentFolderId(member.getId(), parentFolderId); + return folderRepository.findAllByMemberIdAndParentFolderId(memberId, folderId); } private FolderFindResult getFolderResult(Folder folder) { diff --git a/src/main/java/notai/folder/application/FolderService.java b/src/main/java/notai/folder/application/FolderService.java index 96a7091..c7c9087 100644 --- a/src/main/java/notai/folder/application/FolderService.java +++ b/src/main/java/notai/folder/application/FolderService.java @@ -11,63 +11,73 @@ import notai.folder.presentation.request.FolderSaveRequest; import notai.folder.presentation.request.FolderUpdateRequest; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.util.List; @Service @RequiredArgsConstructor +@Transactional public class FolderService { private final FolderRepository folderRepository; private final DocumentService documentService; + private final MemberRepository memberRepository; - public FolderSaveResult saveRootFolder(Member member, FolderSaveRequest folderSaveRequest) { + public FolderSaveResult saveRootFolder(Long memberId, FolderSaveRequest folderSaveRequest) { + Member member = memberRepository.getById(memberId); Folder folder = new Folder(member, folderSaveRequest.name()); Folder savedFolder = folderRepository.save(folder); return getFolderSaveResult(savedFolder); } - public FolderSaveResult saveSubFolder(Member member, FolderSaveRequest folderSaveRequest) { + public FolderSaveResult saveSubFolder(Long memberId, FolderSaveRequest folderSaveRequest) { Folder parentFolder = folderRepository.getById(folderSaveRequest.parentFolderId()); + Member member = memberRepository.getById(memberId); Folder folder = new Folder(member, folderSaveRequest.name(), parentFolder); Folder savedFolder = folderRepository.save(folder); return getFolderSaveResult(savedFolder); } - public FolderMoveResult moveRootFolder(Member member, Long id) { + public FolderMoveResult moveRootFolder(Long memberId, Long id) { Folder folder = folderRepository.getById(id); + Member member = memberRepository.getById(memberId); folder.validateOwner(member); folder.moveRootFolder(); folderRepository.save(folder); return getFolderMoveResult(folder); } - public FolderMoveResult moveNewParentFolder(Member member, Long id, FolderMoveRequest folderMoveRequest) { + public FolderMoveResult moveNewParentFolder(Long memberId, Long id, FolderMoveRequest folderMoveRequest) { Folder folder = folderRepository.getById(id); Folder parentFolder = folderRepository.getById(folderMoveRequest.targetFolderId()); + Member member = memberRepository.getById(memberId); folder.validateOwner(member); folder.moveNewParentFolder(parentFolder); folderRepository.save(folder); return getFolderMoveResult(folder); } - public FolderUpdateResult updateFolder(Member member, Long id, FolderUpdateRequest folderUpdateRequest) { + public FolderUpdateResult updateFolder(Long memberId, Long id, FolderUpdateRequest folderUpdateRequest) { Folder folder = folderRepository.getById(id); + Member member = memberRepository.getById(memberId); folder.validateOwner(member); folder.updateName(folderUpdateRequest.name()); folderRepository.save(folder); return getFolderUpdateResult(folder); } - public void deleteFolder(Member member, Long id) { + public void deleteFolder(Long memberId, Long id) { Folder folder = folderRepository.getById(id); + Member member = memberRepository.getById(memberId); folder.validateOwner(member); List subFolders = folderRepository.findAllByParentFolder(folder); for (Folder subFolder : subFolders) { - deleteFolder(member, subFolder.getId()); + deleteFolder(memberId, subFolder.getId()); } - documentService.deleteAllByFolder(member, folder); + documentService.deleteAllByFolder(memberId, folder); folderRepository.delete(folder); } diff --git a/src/main/java/notai/folder/presentation/FolderController.java b/src/main/java/notai/folder/presentation/FolderController.java index 91daf29..1a8d540 100644 --- a/src/main/java/notai/folder/presentation/FolderController.java +++ b/src/main/java/notai/folder/presentation/FolderController.java @@ -3,6 +3,9 @@ import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import notai.auth.Auth; +import notai.document.application.DocumentQueryService; +import notai.document.application.result.DocumentFindResult; +import notai.document.presentation.response.DocumentFindResponse; import notai.folder.application.FolderQueryService; import notai.folder.application.FolderService; import notai.folder.application.result.FolderFindResult; @@ -12,15 +15,12 @@ import notai.folder.presentation.request.FolderMoveRequest; import notai.folder.presentation.request.FolderSaveRequest; import notai.folder.presentation.request.FolderUpdateRequest; -import notai.folder.presentation.response.FolderFindResponse; -import notai.folder.presentation.response.FolderMoveResponse; -import notai.folder.presentation.response.FolderSaveResponse; -import notai.folder.presentation.response.FolderUpdateResponse; -import notai.member.domain.Member; +import notai.folder.presentation.response.*; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; import java.net.URI; +import java.util.ArrayList; import java.util.List; @RestController @@ -30,62 +30,92 @@ public class FolderController { private final FolderService folderService; private final FolderQueryService folderQueryService; + private final DocumentQueryService documentQueryService; + + private static final Long ROOT_ID = -1L; @PostMapping public ResponseEntity saveFolder( - @Auth Member member, @Valid @RequestBody FolderSaveRequest folderSaveRequest + @Auth Long memberId, @Valid @RequestBody FolderSaveRequest folderSaveRequest ) { - FolderSaveResult folderResult = saveFolderResult(member, folderSaveRequest); + FolderSaveResult folderResult = saveFolderResult(memberId, folderSaveRequest); FolderSaveResponse response = FolderSaveResponse.from(folderResult); return ResponseEntity.created(URI.create("/api/folders/" + response.id())).body(response); } @PostMapping("/{id}/move") public ResponseEntity moveFolder( - @Auth Member member, @PathVariable Long id, @Valid @RequestBody FolderMoveRequest folderMoveRequest + @Auth Long memberId, @PathVariable Long id, @Valid @RequestBody FolderMoveRequest folderMoveRequest ) { - FolderMoveResult folderResult = moveFolderWithRequest(member, id, folderMoveRequest); + FolderMoveResult folderResult = moveFolderWithRequest(memberId, id, folderMoveRequest); FolderMoveResponse response = FolderMoveResponse.from(folderResult); return ResponseEntity.ok(response); } @PutMapping("/{id}") public ResponseEntity updateFolder( - @Auth Member member, @PathVariable Long id, @Valid @RequestBody FolderUpdateRequest folderUpdateRequest + @Auth Long memberId, @PathVariable Long id, @Valid @RequestBody FolderUpdateRequest folderUpdateRequest ) { - FolderUpdateResult folderResult = folderService.updateFolder(member, id, folderUpdateRequest); + FolderUpdateResult folderResult = folderService.updateFolder(memberId, id, folderUpdateRequest); FolderUpdateResponse response = FolderUpdateResponse.from(folderResult); return ResponseEntity.ok(response); } - @GetMapping - public ResponseEntity> getFolders( - @Auth Member member, @RequestParam(required = false) Long parentFolderId + @GetMapping("/{id}") + public ResponseEntity> getFolders( + @Auth Long memberId, @PathVariable Long id ) { - List folderResults = folderQueryService.getFolders(member, parentFolderId); - List response = folderResults.stream().map(FolderFindResponse::from).toList(); - return ResponseEntity.ok(response); + List result = new ArrayList<>(); + + insertFolderFindResponse(result, memberId, id); + insertDocumentFindResponse(result, memberId, id); + + return ResponseEntity.ok(result); } @DeleteMapping("/{id}") public ResponseEntity deleteFolder( - @Auth Member member, @PathVariable Long id + @Auth Long memberId, @PathVariable Long id ) { - folderService.deleteFolder(member, id); + folderService.deleteFolder(memberId, id); return ResponseEntity.noContent().build(); } - private FolderSaveResult saveFolderResult(Member member, FolderSaveRequest folderSaveRequest) { + private FolderSaveResult saveFolderResult(Long memberId, FolderSaveRequest folderSaveRequest) { if (folderSaveRequest.parentFolderId() != null) { - return folderService.saveSubFolder(member, folderSaveRequest); + return folderService.saveSubFolder(memberId, folderSaveRequest); } - return folderService.saveRootFolder(member, folderSaveRequest); + return folderService.saveRootFolder(memberId, folderSaveRequest); } - private FolderMoveResult moveFolderWithRequest(Member member, Long id, FolderMoveRequest folderMoveRequest) { + private FolderMoveResult moveFolderWithRequest(Long memberId, Long id, FolderMoveRequest folderMoveRequest) { if (folderMoveRequest.targetFolderId() != null) { - return folderService.moveNewParentFolder(member, id, folderMoveRequest); + return folderService.moveNewParentFolder(memberId, id, folderMoveRequest); + } + return folderService.moveRootFolder(memberId, id); + } + + private void insertFolderFindResponse(List result, Long memberId, Long folderId) { + List folderResults = folderQueryService.getFolders(memberId, folderId); + List folderResponses = folderResults.stream().map(FolderFindResponse::from).toList(); + + for (FolderFindResponse response : folderResponses) { + result.add(FindResponseWrapper.fromFolderFindResponse(response)); + } + } + + private void insertDocumentFindResponse(List result, Long memberId, Long folderId) { + List documentResults; + if (folderId == null || folderId.equals(ROOT_ID)) { + documentResults = documentQueryService.findRootDocuments(memberId); + } else { + documentResults = documentQueryService.findDocuments(folderId); + } + List documentResponses = + documentResults.stream().map(DocumentFindResponse::from).toList(); + + for (DocumentFindResponse response : documentResponses) { + result.add(FindResponseWrapper.fromDocumentFindResponse(response)); } - return folderService.moveRootFolder(member, id); } } diff --git a/src/main/java/notai/folder/presentation/response/FindResponseWrapper.java b/src/main/java/notai/folder/presentation/response/FindResponseWrapper.java new file mode 100644 index 0000000..9b1dabb --- /dev/null +++ b/src/main/java/notai/folder/presentation/response/FindResponseWrapper.java @@ -0,0 +1,29 @@ +package notai.folder.presentation.response; + +import notai.common.exception.ErrorMessages; +import notai.common.exception.type.BadRequestException; +import notai.document.presentation.response.DocumentFindResponse; + +public record FindResponseWrapper( + Object response, + FolderAndDocumentResponseType folderAndDocumentResponseType + +) { + public static FindResponseWrapper fromFolderFindResponse( + Object response + ) { + if (response instanceof FolderFindResponse) { + return new FindResponseWrapper(response, FolderAndDocumentResponseType.FOLDER); + } + throw new BadRequestException(ErrorMessages.FOLDER_AND_DOCUMENT_INVALID_RESPONSE); + } + + public static FindResponseWrapper fromDocumentFindResponse( + Object response + ) { + if (response instanceof DocumentFindResponse) { + return new FindResponseWrapper(response, FolderAndDocumentResponseType.DOCUMENT); + } + throw new BadRequestException(ErrorMessages.FOLDER_AND_DOCUMENT_INVALID_RESPONSE); + } +} diff --git a/src/main/java/notai/folder/presentation/response/FolderAndDocumentResponseType.java b/src/main/java/notai/folder/presentation/response/FolderAndDocumentResponseType.java new file mode 100644 index 0000000..d561de3 --- /dev/null +++ b/src/main/java/notai/folder/presentation/response/FolderAndDocumentResponseType.java @@ -0,0 +1,5 @@ +package notai.folder.presentation.response; + +public enum FolderAndDocumentResponseType { + FOLDER, DOCUMENT +} diff --git a/src/main/java/notai/llm/application/LlmTaskQueryService.java b/src/main/java/notai/llm/application/LlmTaskQueryService.java index ec55477..d1c9aad 100644 --- a/src/main/java/notai/llm/application/LlmTaskQueryService.java +++ b/src/main/java/notai/llm/application/LlmTaskQueryService.java @@ -16,6 +16,7 @@ import notai.llm.domain.TaskStatus; import notai.llm.query.LlmTaskQueryRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import notai.problem.domain.ProblemRepository; import notai.problem.query.result.ProblemPageContentResult; import notai.summary.domain.SummaryRepository; @@ -37,9 +38,11 @@ public class LlmTaskQueryService { private final DocumentRepository documentRepository; private final SummaryRepository summaryRepository; private final ProblemRepository problemRepository; + private final MemberRepository memberRepository; - public LlmTaskOverallStatusResult fetchOverallStatus(Member member, Long documentId) { + public LlmTaskOverallStatusResult fetchOverallStatus(Long memberId, Long documentId) { Document foundDocument = documentRepository.getById(documentId); + Member member = memberRepository.getById(memberId); foundDocument.validateOwner(member); List summaryIds = summaryRepository.getSummaryIdsByDocumentId(documentId); @@ -59,8 +62,9 @@ public LlmTaskOverallStatusResult fetchOverallStatus(Member member, Long documen return LlmTaskOverallStatusResult.of(documentId, IN_PROGRESS, totalPages, completedPages); } - public LlmTaskPageStatusResult fetchPageStatus(Member member, LlmTaskPageStatusCommand command) { // TODO: 페이지 번호 검증 추가 + public LlmTaskPageStatusResult fetchPageStatus(Long memberId, LlmTaskPageStatusCommand command) { // TODO: 페이지 번호 검증 추가 Document foundDocument = documentRepository.getById(command.documentId()); + Member member = memberRepository.getById(memberId); foundDocument.validateOwner(member); Long summaryId = @@ -72,8 +76,9 @@ public LlmTaskPageStatusResult fetchPageStatus(Member member, LlmTaskPageStatusC return LlmTaskPageStatusResult.from(llmTaskQueryRepository.getTaskStatusBySummaryId(summaryId)); } - public LlmTaskAllPagesResult findAllPagesResult(Member member, Long documentId) { + public LlmTaskAllPagesResult findAllPagesResult(Long memberId, Long documentId) { Document foundDocument = documentRepository.getById(documentId); + Member member = memberRepository.getById(memberId); foundDocument.validateOwner(member); List summaryResults = @@ -98,8 +103,9 @@ public LlmTaskAllPagesResult findAllPagesResult(Member member, Long documentId) return LlmTaskAllPagesResult.of(documentId, results); } - public LlmTaskPageResult findPageResult(Member member, LlmTaskPageResultCommand command) { // TODO: 페이지 번호 검증 추가 + public LlmTaskPageResult findPageResult(Long memberId, LlmTaskPageResultCommand command) { // TODO: 페이지 번호 검증 추가 Document foundDocument = documentRepository.getById(command.documentId()); + Member member = memberRepository.getById(memberId); foundDocument.validateOwner(member); String summaryResult = summaryRepository.getSummaryContentByDocumentIdAndPageNumber( diff --git a/src/main/java/notai/llm/application/LlmTaskService.java b/src/main/java/notai/llm/application/LlmTaskService.java index d5f56fb..f1344ba 100644 --- a/src/main/java/notai/llm/application/LlmTaskService.java +++ b/src/main/java/notai/llm/application/LlmTaskService.java @@ -13,8 +13,12 @@ import notai.llm.application.result.LlmTaskSubmitResult; import notai.llm.domain.LlmTask; import notai.llm.domain.LlmTaskRepository; +import notai.ocr.domain.OCR; +import notai.ocr.domain.OCRRepository; import notai.problem.domain.Problem; import notai.problem.domain.ProblemRepository; +import notai.stt.domain.Stt; +import notai.stt.domain.SttRepository; import notai.summary.domain.Summary; import notai.summary.domain.SummaryRepository; import org.springframework.stereotype.Service; @@ -43,6 +47,8 @@ public class LlmTaskService { private final ProblemRepository problemRepository; private final AnnotationRepository annotationRepository; private final AiClient aiClient; + private final OCRRepository ocrRepository; + private final SttRepository sttRepository; public LlmTaskSubmitResult submitTasks(LlmTaskSubmitCommand command) { // TODO: 페이지 번호 검증 추가 Document foundDocument = documentRepository.getById(command.documentId()); @@ -64,8 +70,17 @@ private void submitPageTask(Integer pageNumber, Map> a List.of() ).stream().map(Annotation::getContent).collect(Collectors.joining(", ")); - // Todo OCR, STT 결과 전달 - UUID taskId = sendRequestToAIServer("ocrText", "stt", annotationContents); + List sttResults = sttRepository.findAllByDocumentIdAndPageNumber(foundDocument.getId(), pageNumber); + String sttContents = sttResults.stream() + .map(Stt::getContent) + .collect(Collectors.joining(" ")); + + List ocrResults = ocrRepository.findAllByDocumentIdAndPageNumber(foundDocument.getId(), pageNumber); + String ocrContents = ocrResults.stream() + .map(OCR::getContent) + .collect(Collectors.joining(" ")); + + UUID taskId = sendRequestToAIServer(ocrContents, sttContents, annotationContents); Optional foundSummary = summaryRepository.findByDocumentAndPageNumber(foundDocument, pageNumber); Optional foundProblem = problemRepository.findByDocumentAndPageNumber(foundDocument, pageNumber); diff --git a/src/main/java/notai/llm/presentation/LlmTaskController.java b/src/main/java/notai/llm/presentation/LlmTaskController.java index e259d21..eed06e8 100644 --- a/src/main/java/notai/llm/presentation/LlmTaskController.java +++ b/src/main/java/notai/llm/presentation/LlmTaskController.java @@ -34,39 +34,39 @@ public ResponseEntity submitTask(@RequestBody @Valid LlmT @GetMapping("/status/{documentId}") public ResponseEntity fetchOverallStatus( - @Auth Member member, @PathVariable("documentId") Long documentId + @Auth Long memberId, @PathVariable("documentId") Long documentId ) { - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(memberId, documentId); return ResponseEntity.ok(LlmTaskOverallStatusResponse.from(result)); } @GetMapping("/status/{documentId}/{pageNumber}") public ResponseEntity fetchPageStatus( - @Auth Member member, + @Auth Long memberId, @PathVariable("documentId") Long documentId, @PathVariable("pageNumber") Integer pageNumber ) { LlmTaskPageStatusCommand command = LlmTaskPageStatusCommand.of(documentId, pageNumber); - LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member, command); + LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(memberId, command); return ResponseEntity.ok(LlmTaskPageStatusResponse.from(result)); } @GetMapping("/results/{documentId}") public ResponseEntity findAllPagesResult( - @Auth Member member, @PathVariable("documentId") Long documentId + @Auth Long memberId, @PathVariable("documentId") Long documentId ) { - LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(member, documentId); + LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(memberId, documentId); return ResponseEntity.ok(LlmTaskAllPagesResultResponse.from(result)); } @GetMapping("/results/{documentId}/{pageNumber}") public ResponseEntity findPageResult( - @Auth Member member, + @Auth Long memberId, @PathVariable("documentId") Long documentId, @PathVariable("pageNumber") Integer pageNumber ) { LlmTaskPageResultCommand command = LlmTaskPageResultCommand.of(documentId, pageNumber); - LlmTaskPageResult result = llmTaskQueryService.findPageResult(member, command); + LlmTaskPageResult result = llmTaskQueryService.findPageResult(memberId, command); return ResponseEntity.ok(LlmTaskPageResultResponse.from(result)); } diff --git a/src/main/java/notai/ocr/application/OCRQueryService.java b/src/main/java/notai/ocr/application/OCRQueryService.java index 102b5ca..51ac0ba 100644 --- a/src/main/java/notai/ocr/application/OCRQueryService.java +++ b/src/main/java/notai/ocr/application/OCRQueryService.java @@ -1,23 +1,30 @@ 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.member.domain.MemberRepository; 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; +import org.springframework.transaction.annotation.Transactional; @Service @RequiredArgsConstructor +@Transactional(readOnly = true) public class OCRQueryService { private final OCRRepository ocrRepository; + private final MemberRepository memberRepository; + + public OCRFindResult findOCR(Long memberId, Long documentId, Integer pageNumber) { + Member member = memberRepository.getById(memberId); - public OCRFindResult findOCR(Member member, Long documentId, Integer pageNumber) { - OCR ocr = ocrRepository.findOCRByDocumentIdAndPageNumber(documentId, pageNumber + OCR ocr = ocrRepository.findOCRByDocumentIdAndPageNumber( + documentId, + pageNumber ).orElseThrow(() -> new NotFoundException(OCR_RESULT_NOT_FOUND)); ocr.getDocument().validateOwner(member); diff --git a/src/main/java/notai/ocr/application/OCRService.java b/src/main/java/notai/ocr/application/OCRService.java index f5c9a21..971797a 100644 --- a/src/main/java/notai/ocr/application/OCRService.java +++ b/src/main/java/notai/ocr/application/OCRService.java @@ -13,12 +13,14 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.scheduling.annotation.Async; import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; import java.awt.image.BufferedImage; import java.io.File; @Service @RequiredArgsConstructor +@Transactional public class OCRService { private final OCRRepository ocrRepository; diff --git a/src/main/java/notai/ocr/domain/OCRRepository.java b/src/main/java/notai/ocr/domain/OCRRepository.java index 4211e79..8b8f393 100644 --- a/src/main/java/notai/ocr/domain/OCRRepository.java +++ b/src/main/java/notai/ocr/domain/OCRRepository.java @@ -3,11 +3,12 @@ import static notai.common.exception.ErrorMessages.OCR_RESULT_NOT_FOUND; import notai.common.exception.type.NotFoundException; import notai.document.domain.Document; +import notai.ocr.query.OCRQueryRepository; import org.springframework.data.jpa.repository.JpaRepository; import java.util.Optional; -public interface OCRRepository extends JpaRepository { +public interface OCRRepository extends JpaRepository, OCRQueryRepository { default OCR getById(Long id) { return findById(id).orElseThrow(() -> new NotFoundException(OCR_RESULT_NOT_FOUND)); } diff --git a/src/main/java/notai/ocr/presentation/OCRController.java b/src/main/java/notai/ocr/presentation/OCRController.java index 06786b9..082271d 100644 --- a/src/main/java/notai/ocr/presentation/OCRController.java +++ b/src/main/java/notai/ocr/presentation/OCRController.java @@ -18,9 +18,9 @@ public class OCRController { @GetMapping public ResponseEntity getDocuments( - @Auth Member member, @PathVariable Long documentId, @RequestParam Integer pageNumber + @Auth Long memberId, @PathVariable Long documentId, @RequestParam Integer pageNumber ) { - OCRFindResult result = ocrQueryService.findOCR(member, documentId, pageNumber); + OCRFindResult result = ocrQueryService.findOCR(memberId, documentId, pageNumber); OCRFindResponse response = OCRFindResponse.from(result); return ResponseEntity.ok(response); } diff --git a/src/main/java/notai/ocr/query/OCRQueryRepository.java b/src/main/java/notai/ocr/query/OCRQueryRepository.java new file mode 100644 index 0000000..8f3a1eb --- /dev/null +++ b/src/main/java/notai/ocr/query/OCRQueryRepository.java @@ -0,0 +1,9 @@ +package notai.ocr.query; + +import notai.ocr.domain.OCR; + +import java.util.List; + +public interface OCRQueryRepository { + List findAllByDocumentIdAndPageNumber(Long documentId, Integer pageNumber); +} diff --git a/src/main/java/notai/ocr/query/OCRQueryRepositoryImpl.java b/src/main/java/notai/ocr/query/OCRQueryRepositoryImpl.java new file mode 100644 index 0000000..c90d02b --- /dev/null +++ b/src/main/java/notai/ocr/query/OCRQueryRepositoryImpl.java @@ -0,0 +1,20 @@ +package notai.ocr.query; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import notai.ocr.domain.OCR; +import static notai.ocr.domain.QOCR.oCR; + +import java.util.List; + +@RequiredArgsConstructor +public class OCRQueryRepositoryImpl implements OCRQueryRepository { + + private final JPAQueryFactory queryFactory; + + public List findAllByDocumentIdAndPageNumber(Long documentId, Integer pageNumber) { + return queryFactory.selectFrom(oCR) + .where(oCR.document.id.eq(documentId).and(oCR.pageNumber.eq(pageNumber))) + .fetch(); + } +} diff --git a/src/main/java/notai/pageRecording/application/PageRecordingService.java b/src/main/java/notai/pageRecording/application/PageRecordingService.java index a468a69..e296c77 100644 --- a/src/main/java/notai/pageRecording/application/PageRecordingService.java +++ b/src/main/java/notai/pageRecording/application/PageRecordingService.java @@ -4,6 +4,7 @@ import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import notai.pageRecording.application.command.PageRecordingSaveCommand; import notai.pageRecording.domain.PageRecording; import notai.pageRecording.domain.PageRecordingRepository; @@ -20,10 +21,13 @@ public class PageRecordingService { private final PageRecordingRepository pageRecordingRepository; private final RecordingRepository recordingRepository; private final DocumentRepository documentRepository; + private final MemberRepository memberRepository; - public void savePageRecording(Member member, PageRecordingSaveCommand command) { + public void savePageRecording(Long memberId, PageRecordingSaveCommand command) { Recording foundRecording = recordingRepository.getById(command.recordingId()); Document foundDocument = documentRepository.getById(command.documentId()); + Member member = memberRepository.getById(memberId); + foundDocument.validateOwner(member); foundRecording.validateDocumentOwnership(foundDocument); diff --git a/src/main/java/notai/pageRecording/presentation/PageRecordingController.java b/src/main/java/notai/pageRecording/presentation/PageRecordingController.java index 6bfeced..6c41f4a 100644 --- a/src/main/java/notai/pageRecording/presentation/PageRecordingController.java +++ b/src/main/java/notai/pageRecording/presentation/PageRecordingController.java @@ -20,12 +20,12 @@ public class PageRecordingController { @PostMapping public ResponseEntity savePageRecording( - @Auth Member member, + @Auth Long memberId, @PathVariable("documentId") Long documentId, @RequestBody PageRecordingSaveRequest request ) { PageRecordingSaveCommand command = request.toCommand(documentId); - pageRecordingService.savePageRecording(member, command); + pageRecordingService.savePageRecording(memberId, 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 55602bf..4014fef 100644 --- a/src/main/java/notai/recording/application/RecordingService.java +++ b/src/main/java/notai/recording/application/RecordingService.java @@ -2,8 +2,6 @@ import lombok.RequiredArgsConstructor; import notai.common.domain.vo.FilePath; -import static notai.common.exception.ErrorMessages.FILE_SAVE_ERROR; -import static notai.common.exception.ErrorMessages.INVALID_AUDIO_ENCODING; import notai.common.exception.type.BadRequestException; import notai.common.exception.type.InternalServerErrorException; import notai.common.utils.AudioDecoder; @@ -11,6 +9,7 @@ import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import notai.recording.application.command.RecordingSaveCommand; import notai.recording.application.result.RecordingSaveResult; import notai.recording.domain.Recording; @@ -25,6 +24,9 @@ import java.nio.file.Path; import java.nio.file.Paths; +import static notai.common.exception.ErrorMessages.FILE_SAVE_ERROR; +import static notai.common.exception.ErrorMessages.INVALID_AUDIO_ENCODING; + @Service @Transactional @RequiredArgsConstructor @@ -35,12 +37,14 @@ public class RecordingService { private final AudioDecoder audioDecoder; private final FileManager fileManager; private final SttTaskService sttTaskService; + private final MemberRepository memberRepository; @Value("${file.audio.basePath}") private String audioBasePath; - public RecordingSaveResult saveRecording(Member member, RecordingSaveCommand command) { + public RecordingSaveResult saveRecording(Long memberId, RecordingSaveCommand command) { Document foundDocument = documentRepository.getById(command.documentId()); + Member member = memberRepository.getById(memberId); foundDocument.validateOwner(member); Recording recording = new Recording(foundDocument); diff --git a/src/main/java/notai/recording/presentation/RecordingController.java b/src/main/java/notai/recording/presentation/RecordingController.java index 4daf0dc..e470f12 100644 --- a/src/main/java/notai/recording/presentation/RecordingController.java +++ b/src/main/java/notai/recording/presentation/RecordingController.java @@ -23,12 +23,12 @@ public class RecordingController { @PostMapping public ResponseEntity saveRecording( - @Auth Member member, + @Auth Long memberId, @PathVariable("documentId") Long documentId, @RequestBody @Valid RecordingSaveRequest request ) { RecordingSaveCommand command = request.toCommand(documentId); - RecordingSaveResult result = recordingService.saveRecording(member, command); + RecordingSaveResult result = recordingService.saveRecording(memberId, command); return ResponseEntity.status(CREATED).body(RecordingSaveResponse.from(result)); } } diff --git a/src/main/java/notai/stt/application/SttQueryService.java b/src/main/java/notai/stt/application/SttQueryService.java new file mode 100644 index 0000000..1243f03 --- /dev/null +++ b/src/main/java/notai/stt/application/SttQueryService.java @@ -0,0 +1,33 @@ +package notai.stt.application; + +import lombok.RequiredArgsConstructor; +import notai.document.domain.Document; +import notai.document.domain.DocumentRepository; +import notai.member.domain.Member; +import notai.member.domain.MemberRepository; +import notai.stt.domain.Stt; +import notai.stt.domain.SttRepository; +import notai.stt.presentation.response.SttPageResponse; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.List; + +@Service +@Transactional(readOnly = true) +@RequiredArgsConstructor +public class SttQueryService { + + private final SttRepository sttRepository; + private final MemberRepository memberRepository; + private final DocumentRepository documentRepository; + + public SttPageResponse getSttByPage(Long memberId, Long documentId, Integer pageNumber) { + Member member = memberRepository.getById(memberId); + Document foundDocument = documentRepository.getById(documentId); + foundDocument.validateOwner(member); + + List sttResults = sttRepository.findAllByDocumentIdAndPageNumber(documentId, pageNumber); + return SttPageResponse.of(pageNumber, sttResults); + } +} diff --git a/src/main/java/notai/stt/domain/SttRepository.java b/src/main/java/notai/stt/domain/SttRepository.java index 88f2064..536c739 100644 --- a/src/main/java/notai/stt/domain/SttRepository.java +++ b/src/main/java/notai/stt/domain/SttRepository.java @@ -1,6 +1,7 @@ package notai.stt.domain; +import notai.stt.query.SttQueryRepository; import org.springframework.data.jpa.repository.JpaRepository; -public interface SttRepository extends JpaRepository { +public interface SttRepository extends JpaRepository, SttQueryRepository { } diff --git a/src/main/java/notai/stt/presentation/SttController.java b/src/main/java/notai/stt/presentation/SttController.java new file mode 100644 index 0000000..7c31ef0 --- /dev/null +++ b/src/main/java/notai/stt/presentation/SttController.java @@ -0,0 +1,26 @@ +package notai.stt.presentation; + +import lombok.RequiredArgsConstructor; +import notai.auth.Auth; +import notai.stt.application.SttQueryService; +import notai.stt.presentation.response.SttPageResponse; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RestController +@RequestMapping("/api/stt") +@RequiredArgsConstructor +public class SttController { + private final SttQueryService sttQueryService; + + @GetMapping("/documents/{documentId}/pages/{pageNumber}") + public SttPageResponse getSttByPage( + @Auth Long memberId, + @PathVariable Long documentId, + @PathVariable Integer pageNumber + ) { + return sttQueryService.getSttByPage(memberId, documentId, pageNumber); + } +} diff --git a/src/main/java/notai/stt/presentation/response/SttPageResponse.java b/src/main/java/notai/stt/presentation/response/SttPageResponse.java new file mode 100644 index 0000000..0cdc3cb --- /dev/null +++ b/src/main/java/notai/stt/presentation/response/SttPageResponse.java @@ -0,0 +1,30 @@ +package notai.stt.presentation.response; + +import notai.stt.domain.Stt; +import java.util.List; + +public record SttPageResponse( + Integer pageNumber, + List contents +) { + public record SttContent( + String content, + Integer startTime, + Integer endTime + ) { + public static SttContent from(Stt stt) { + return new SttContent( + stt.getContent(), + stt.getStartTime(), + stt.getEndTime() + ); + } + } + + public static SttPageResponse of(Integer pageNumber, List sttList) { + List contents = sttList.stream() + .map(SttContent::from) + .toList(); + return new SttPageResponse(pageNumber, contents); + } +} diff --git a/src/main/java/notai/stt/query/SttQueryRepository.java b/src/main/java/notai/stt/query/SttQueryRepository.java new file mode 100644 index 0000000..18b5d77 --- /dev/null +++ b/src/main/java/notai/stt/query/SttQueryRepository.java @@ -0,0 +1,10 @@ +package notai.stt.query; + +import notai.stt.domain.Stt; + +import java.util.List; + +public interface SttQueryRepository { + List findAllByDocumentIdAndPageNumber(Long documentId, Integer pageNumber); + List findAllByDocumentId(Long documentId); +} diff --git a/src/main/java/notai/stt/query/SttQueryRepositoryImpl.java b/src/main/java/notai/stt/query/SttQueryRepositoryImpl.java new file mode 100644 index 0000000..250e12f --- /dev/null +++ b/src/main/java/notai/stt/query/SttQueryRepositoryImpl.java @@ -0,0 +1,32 @@ +package notai.stt.query; + +import com.querydsl.jpa.impl.JPAQueryFactory; +import lombok.RequiredArgsConstructor; +import notai.stt.domain.Stt; +import static notai.stt.domain.QStt.stt; + +import java.util.List; + +@RequiredArgsConstructor +public class SttQueryRepositoryImpl implements SttQueryRepository { + private final JPAQueryFactory queryFactory; + + @Override + public List findAllByDocumentIdAndPageNumber(Long documentId, Integer pageNumber) { + return queryFactory + .selectFrom(stt) + .join(stt.recording).fetchJoin() + .where(stt.recording.document.id.eq(documentId) + .and(stt.pageNumber.eq(pageNumber))) + .fetch(); + } + + @Override + public List findAllByDocumentId(Long documentId) { + return queryFactory + .selectFrom(stt) + .join(stt.recording).fetchJoin() + .where(stt.recording.document.id.eq(documentId)) + .fetch(); + } +} diff --git a/src/main/java/notai/sttTask/application/SttTaskQueryService.java b/src/main/java/notai/sttTask/application/SttTaskQueryService.java new file mode 100644 index 0000000..133ccb5 --- /dev/null +++ b/src/main/java/notai/sttTask/application/SttTaskQueryService.java @@ -0,0 +1,53 @@ +package notai.sttTask.application; + +import lombok.RequiredArgsConstructor; +import notai.document.domain.Document; +import notai.document.domain.DocumentRepository; +import notai.llm.domain.TaskStatus; +import static notai.llm.domain.TaskStatus.*; +import notai.member.domain.Member; +import notai.member.domain.MemberRepository; +import notai.stt.domain.Stt; +import notai.stt.domain.SttRepository; +import notai.sttTask.application.result.SttTaskOverallStatusResult; +import notai.sttTask.domain.SttTask; +import notai.sttTask.domain.SttTaskRepository; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import java.util.Collections; +import java.util.List; + +@Transactional(readOnly = true) +@RequiredArgsConstructor +@Service +public class SttTaskQueryService { + + private final DocumentRepository documentRepository; + private final MemberRepository memberRepository; + private final SttTaskRepository sttTaskRepository; + private final SttRepository sttRepository; + + public SttTaskOverallStatusResult fetchOverallStatus(Long memberId, Long documentId) { + Document foundDocument = documentRepository.getById(documentId); + Member member = memberRepository.getById(memberId); + foundDocument.validateOwner(member); + + List sttResults = sttRepository.findAllByDocumentId(documentId); + + if (sttResults.isEmpty()) { + return SttTaskOverallStatusResult.of(documentId, NOT_REQUESTED, 0, 0); + } + List taskStatuses = + sttTaskRepository.findAllBySttIn(sttResults).stream().map(SttTask::getStatus).toList(); + + + int totalPages = taskStatuses.size(); + int completedPages = Collections.frequency(taskStatuses, COMPLETED); + + if (totalPages == completedPages) { + return SttTaskOverallStatusResult.of(documentId, COMPLETED, totalPages, completedPages); + } + return SttTaskOverallStatusResult.of(documentId, IN_PROGRESS, totalPages, completedPages); + } +} diff --git a/src/main/java/notai/sttTask/application/result/SttTaskOverallStatusResult.java b/src/main/java/notai/sttTask/application/result/SttTaskOverallStatusResult.java new file mode 100644 index 0000000..fe1ed73 --- /dev/null +++ b/src/main/java/notai/sttTask/application/result/SttTaskOverallStatusResult.java @@ -0,0 +1,19 @@ +package notai.sttTask.application.result; + +import notai.llm.domain.TaskStatus; + +public record SttTaskOverallStatusResult( + Long documentId, + TaskStatus overallStatus, + int totalPages, + int completedPages +) { + public static SttTaskOverallStatusResult of( + Long documentId, + TaskStatus taskStatus, + int totalPages, + int completedPages + ) { + return new SttTaskOverallStatusResult(documentId, taskStatus, totalPages, completedPages); + } +} diff --git a/src/main/java/notai/sttTask/domain/SttTaskRepository.java b/src/main/java/notai/sttTask/domain/SttTaskRepository.java index 08956f1..e2d6682 100644 --- a/src/main/java/notai/sttTask/domain/SttTaskRepository.java +++ b/src/main/java/notai/sttTask/domain/SttTaskRepository.java @@ -2,8 +2,10 @@ import static notai.common.exception.ErrorMessages.AI_SERVER_ERROR; import notai.common.exception.type.NotFoundException; +import notai.stt.domain.Stt; import org.springframework.data.jpa.repository.JpaRepository; +import java.util.List; import java.util.UUID; public interface SttTaskRepository extends JpaRepository { @@ -11,4 +13,6 @@ public interface SttTaskRepository extends JpaRepository { default SttTask getById(UUID id) { return findById(id).orElseThrow(() -> new NotFoundException(AI_SERVER_ERROR)); } + + List findAllBySttIn(List stts); } diff --git a/src/main/java/notai/sttTask/presentation/SttTaskController.java b/src/main/java/notai/sttTask/presentation/SttTaskController.java new file mode 100644 index 0000000..91f94ef --- /dev/null +++ b/src/main/java/notai/sttTask/presentation/SttTaskController.java @@ -0,0 +1,28 @@ +package notai.sttTask.presentation; + +import lombok.RequiredArgsConstructor; +import notai.auth.Auth; +import notai.sttTask.application.SttTaskQueryService; +import notai.sttTask.application.result.SttTaskOverallStatusResult; +import notai.sttTask.presentation.response.SttTaskOverallStatusResponse; +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +@RequiredArgsConstructor +@RequestMapping("/api/ai/stt") +@RestController +public class SttTaskController { + + private final SttTaskQueryService sttTaskQueryService; + + @GetMapping("/status/{documentId}") + public ResponseEntity fetchOverallStatus( + @Auth Long memberId, @PathVariable("documentId") Long documentId + ) { + SttTaskOverallStatusResult result = sttTaskQueryService.fetchOverallStatus(memberId, documentId); + return ResponseEntity.ok(SttTaskOverallStatusResponse.from(result)); + } +} diff --git a/src/main/java/notai/sttTask/presentation/response/SttTaskOverallStatusResponse.java b/src/main/java/notai/sttTask/presentation/response/SttTaskOverallStatusResponse.java new file mode 100644 index 0000000..61d10f0 --- /dev/null +++ b/src/main/java/notai/sttTask/presentation/response/SttTaskOverallStatusResponse.java @@ -0,0 +1,20 @@ +package notai.sttTask.presentation.response; + +import notai.llm.domain.TaskStatus; +import notai.sttTask.application.result.SttTaskOverallStatusResult; + +public record SttTaskOverallStatusResponse( + Long documentId, + TaskStatus overallStatus, + Integer totalPages, + Integer completedPages +) { + public static SttTaskOverallStatusResponse from(SttTaskOverallStatusResult result) { + return new SttTaskOverallStatusResponse( + result.documentId(), + result.overallStatus(), + result.totalPages(), + result.completedPages() + ); + } +} diff --git a/src/main/resources/application-local.yml b/src/main/resources/application-local.yml index 277fd4f..f7889f1 100644 --- a/src/main/resources/application-local.yml +++ b/src/main/resources/application-local.yml @@ -6,6 +6,11 @@ spring: h2: console: enabled: true + servlet: + multipart: + max-file-size: 10MB + max-request-size: 10MB + enabled: true datasource: driver-class-name: org.h2.Driver url: jdbc:h2:mem:test;MODE=MYSQL;DB_CLOSE_DELAY=-1 @@ -29,11 +34,6 @@ spring: mvc: converters: preferred-json-mapper: gson - servlet: - multipart: - max-file-size: 100MB - max-request-size: 100MB - enabled: true server: servlet: @@ -45,7 +45,7 @@ server-url: http://localhost:8080 ai-server-url: http://localhost:5000 # 실제 AI 서버주소는 prod에서만 사용 token: # todo production에서 secretKey 변경 - secretKey: "ZGQrT0tuZHZkRWRxeXJCamRYMDFKMnBaR2w5WXlyQm9HU2RqZHNha1gycFlkMWpLc0dObw==" + secretKey: "ZGQrT0tuZHZkRWRxeXJCamRYMDFKMnBaR2w5WXldfdsafsdagwqgdsfsafdwqbvsdvqyQm9HU2RqZHNha1gycFlkMWpLc0dObw==" accessTokenExpirationMillis: 10000000000 refreshTokenExpirationMillis: 10000000000 diff --git a/src/test/java/notai/annotation/presentation/AnnotationControllerTest.java b/src/test/java/notai/annotation/presentation/AnnotationControllerTest.java index fcdf64a..230f738 100644 --- a/src/test/java/notai/annotation/presentation/AnnotationControllerTest.java +++ b/src/test/java/notai/annotation/presentation/AnnotationControllerTest.java @@ -66,7 +66,7 @@ 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(any(Member.class), anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) + when(annotationService.createAnnotation(any(Long.class), anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) .thenReturn(response); mockMvc.perform(post("/api/documents/1/annotations") @@ -93,7 +93,7 @@ void testGetAnnotations_success() throws Exception { new AnnotationResponse(2L, 1L, 2, 150, 250, 350, 120, "", now.toString(), now.toString()) ); - when(annotationQueryService.getAnnotationsByDocumentAndPageNumbers(any(Member.class), anyLong(), anyList())).thenReturn(responses); + when(annotationQueryService.getAnnotationsByDocumentAndPageNumbers(any(Long.class), anyLong(), anyList())).thenReturn(responses); mockMvc.perform(get("/api/documents/1/annotations?pageNumbers=1,2") .contentType("application/json") @@ -122,7 +122,7 @@ 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(any(Member.class), anyLong(), anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) + when(annotationService.updateAnnotation(any(Long.class), anyLong(), anyLong(), anyInt(), anyInt(), anyInt(), anyInt(), anyString())) .thenReturn(response); mockMvc.perform(put("/api/documents/1/annotations/1") @@ -142,13 +142,13 @@ void testUpdateAnnotation_success() throws Exception { @Test void testDeleteAnnotation_success() throws Exception { - doNothing().when(annotationService).deleteAnnotation(any(Member.class), anyLong(), anyLong()); + doNothing().when(annotationService).deleteAnnotation(any(Long.class), anyLong(), anyLong()); mockMvc.perform(delete("/api/documents/1/annotations/1") .contentType("application/json") .header("Authorization", "Bearer token")) .andExpect(status().isOk()); - verify(annotationService, times(1)).deleteAnnotation(any(Member.class),anyLong(), anyLong()); + verify(annotationService, times(1)).deleteAnnotation(any(Long.class),anyLong(), anyLong()); } } diff --git a/src/test/java/notai/client/oauth/kakao/KakaoOauthClientTest.java b/src/test/java/notai/client/oauth/kakao/KakaoOauthClientTest.java index 880eb1b..718c6f6 100644 --- a/src/test/java/notai/client/oauth/kakao/KakaoOauthClientTest.java +++ b/src/test/java/notai/client/oauth/kakao/KakaoOauthClientTest.java @@ -7,6 +7,8 @@ import org.junit.jupiter.api.Test; import org.mockito.InjectMocks; import org.mockito.Mock; + +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.when; import org.mockito.MockitoAnnotations; @@ -47,7 +49,7 @@ public void testFetchMember() { KakaoMemberResponse kakaoMemberResponse = new KakaoMemberResponse(id, hasSignedUp, connectedAt, kakaoAccount); - when(kakaoClient.fetchMember(accessToken)).thenReturn(kakaoMemberResponse); + when(kakaoClient.fetchMember(eq("Bearer " + accessToken))).thenReturn(kakaoMemberResponse); Member member = kakaoOauthClient.fetchMember(accessToken); diff --git a/src/test/java/notai/folder/application/FolderQueryServiceTest.java b/src/test/java/notai/folder/application/FolderQueryServiceTest.java index 2071361..e879f8d 100644 --- a/src/test/java/notai/folder/application/FolderQueryServiceTest.java +++ b/src/test/java/notai/folder/application/FolderQueryServiceTest.java @@ -44,7 +44,7 @@ void getFolders_success_parentFolderIdIsNull() { when(folderRepository.findAllByMemberIdAndParentFolderIsNull(any(Long.class))).thenReturn(expectedResults); //when - List folders = folderQueryService.getFolders(member, null); + List folders = folderQueryService.getFolders(member.getId(), null); Assertions.assertThat(folders.size()).isEqualTo(1); } @@ -61,7 +61,7 @@ void getFolders_success_parentFolderId() { when(folderRepository.findAllByMemberIdAndParentFolderId(any(Long.class), any(Long.class))).thenReturn( expectedResults); //when - List folders = folderQueryService.getFolders(member, 1L); + List folders = folderQueryService.getFolders(member.getId(), 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 dd04d5b..7df7a2a 100644 --- a/src/test/java/notai/llm/application/LlmTaskQueryServiceTest.java +++ b/src/test/java/notai/llm/application/LlmTaskQueryServiceTest.java @@ -12,6 +12,7 @@ import notai.llm.application.result.LlmTaskPageStatusResult; import notai.llm.query.LlmTaskQueryRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import notai.problem.domain.ProblemRepository; import notai.problem.query.result.ProblemPageContentResult; import notai.summary.domain.SummaryRepository; @@ -28,6 +29,7 @@ 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.anyLong; import static org.mockito.ArgumentMatchers.eq; import static org.mockito.BDDMockito.given; import static org.mockito.BDDMockito.willDoNothing; @@ -51,6 +53,9 @@ class LlmTaskQueryServiceTest { @Mock private ProblemRepository problemRepository; + @Mock + private MemberRepository memberRepository; + @Mock private Member member; @@ -65,7 +70,7 @@ class LlmTaskQueryServiceTest { // when & then assertAll(() -> assertThrows( NotFoundException.class, - () -> llmTaskQueryService.fetchOverallStatus(member, 2L) + () -> llmTaskQueryService.fetchOverallStatus(member.getId(), 2L) )); } @@ -76,6 +81,7 @@ class LlmTaskQueryServiceTest { List summaryIds = List.of(1L, 2L, 3L); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getSummaryIdsByDocumentId(documentId)).willReturn(summaryIds); @@ -84,7 +90,7 @@ class LlmTaskQueryServiceTest { given(llmTaskQueryRepository.getTaskStatusBySummaryId(3L)).willReturn(COMPLETED); // when - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member.getId(), documentId); // then assertAll( @@ -103,6 +109,7 @@ class LlmTaskQueryServiceTest { List summaryIds = List.of(1L, 2L, 3L); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getSummaryIdsByDocumentId(documentId)).willReturn(summaryIds); @@ -111,7 +118,7 @@ class LlmTaskQueryServiceTest { given(llmTaskQueryRepository.getTaskStatusBySummaryId(3L)).willReturn(PENDING); // when - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member.getId(), documentId); // then assertAll( @@ -132,13 +139,14 @@ class LlmTaskQueryServiceTest { LlmTaskPageStatusCommand command = new LlmTaskPageStatusCommand(documentId, pageNumber); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getSummaryIdByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(summaryId); given(llmTaskQueryRepository.getTaskStatusBySummaryId(summaryId)).willReturn(IN_PROGRESS); // when - LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member, command); + LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member.getId(), command); // then assertThat(result.status()).isEqualTo(IN_PROGRESS); @@ -152,12 +160,13 @@ class LlmTaskQueryServiceTest { LlmTaskPageStatusCommand command = new LlmTaskPageStatusCommand(documentId, pageNumber); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getSummaryIdByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); // when - LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member, command); + LlmTaskPageStatusResult result = llmTaskQueryService.fetchPageStatus(member.getId(), command); // then assertThat(result.status()).isEqualTo(NOT_REQUESTED); @@ -171,7 +180,7 @@ class LlmTaskQueryServiceTest { // when & then assertAll(() -> assertThrows( NotFoundException.class, - () -> llmTaskQueryService.findAllPagesResult(member, 2L) + () -> llmTaskQueryService.findAllPagesResult(member.getId(), 2L) )); } @@ -186,6 +195,7 @@ class LlmTaskQueryServiceTest { ); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(summaryResults); @@ -195,7 +205,7 @@ class LlmTaskQueryServiceTest { assertAll( () -> assertThrows( InternalServerErrorException.class, - () -> llmTaskQueryService.findAllPagesResult(member, 1L) + () -> llmTaskQueryService.findAllPagesResult(member.getId(), 1L) ), () -> verify(summaryRepository).getPageNumbersAndContentByDocumentId(documentId), () -> verify(problemRepository).getPageNumbersAndContentByDocumentId(documentId) @@ -216,13 +226,14 @@ class LlmTaskQueryServiceTest { ); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(summaryResults); given(problemRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(problemResults); // when - LlmTaskAllPagesResult response = llmTaskQueryService.findAllPagesResult(member, documentId); + LlmTaskAllPagesResult response = llmTaskQueryService.findAllPagesResult(member.getId(), documentId); // then assertAll( @@ -243,6 +254,7 @@ class LlmTaskQueryServiceTest { LlmTaskPageResultCommand command = new LlmTaskPageResultCommand(documentId, pageNumber); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn( @@ -251,7 +263,7 @@ class LlmTaskQueryServiceTest { problemResult); // when - LlmTaskPageResult result = llmTaskQueryService.findPageResult(member, command); + LlmTaskPageResult result = llmTaskQueryService.findPageResult(member.getId(), command); // then assertAll( @@ -268,13 +280,14 @@ class LlmTaskQueryServiceTest { LlmTaskPageResultCommand command = new LlmTaskPageResultCommand(documentId, pageNumber); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); given(problemRepository.getProblemContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); // when - LlmTaskPageResult result = llmTaskQueryService.findPageResult(member, command); + LlmTaskPageResult result = llmTaskQueryService.findPageResult(member.getId(), command); // then assertAll( @@ -292,6 +305,7 @@ class LlmTaskQueryServiceTest { LlmTaskPageResultCommand command = new LlmTaskPageResultCommand(documentId, pageNumber); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); given(summaryRepository.getSummaryContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn( @@ -299,7 +313,7 @@ class LlmTaskQueryServiceTest { given(problemRepository.getProblemContentByDocumentIdAndPageNumber(documentId, pageNumber)).willReturn(null); // when & then - assertThrows(InternalServerErrorException.class, () -> llmTaskQueryService.findPageResult(member, command)); + assertThrows(InternalServerErrorException.class, () -> llmTaskQueryService.findPageResult(member.getId(), command)); } @Test @@ -310,10 +324,11 @@ class LlmTaskQueryServiceTest { given(summaryRepository.getSummaryIdsByDocumentId(documentId)).willReturn(Collections.emptyList()); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); // when - LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member, documentId); + LlmTaskOverallStatusResult result = llmTaskQueryService.fetchOverallStatus(member.getId(), documentId); // then assertAll( @@ -331,10 +346,11 @@ class LlmTaskQueryServiceTest { given(summaryRepository.getPageNumbersAndContentByDocumentId(documentId)).willReturn(Collections.emptyList()); given(documentRepository.getById(eq(1L))).willReturn(document); + given(memberRepository.getById(anyLong())).willReturn(member); willDoNothing().given(document).validateOwner(member); // when - LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(member, documentId); + LlmTaskAllPagesResult result = llmTaskQueryService.findAllPagesResult(member.getId(), documentId); // then assertAll( diff --git a/src/test/java/notai/llm/application/LlmTaskServiceTest.java b/src/test/java/notai/llm/application/LlmTaskServiceTest.java index 4082625..822a90b 100644 --- a/src/test/java/notai/llm/application/LlmTaskServiceTest.java +++ b/src/test/java/notai/llm/application/LlmTaskServiceTest.java @@ -17,8 +17,13 @@ import notai.member.domain.Member; import notai.member.domain.OauthId; import notai.member.domain.OauthProvider; +import notai.ocr.domain.OCR; +import notai.ocr.domain.OCRRepository; import notai.problem.domain.Problem; import notai.problem.domain.ProblemRepository; +import notai.recording.domain.Recording; +import notai.stt.domain.Stt; +import notai.stt.domain.SttRepository; import notai.summary.domain.Summary; import notai.summary.domain.SummaryRepository; import org.junit.jupiter.api.Test; @@ -57,6 +62,12 @@ class LlmTaskServiceTest { @Mock private AnnotationRepository annotationRepository; + @Mock + private SttRepository sttRepository; + + @Mock + private OCRRepository ocrRepository; + @Mock private AiClient aiClient; @@ -94,11 +105,17 @@ class LlmTaskServiceTest { new Annotation(document, 2, 50, 60, 120, 70, "Annotation 3") ); + Recording recording = new Recording(document); + List stts = List.of(new Stt(recording)); + List ocrs = List.of(new OCR(document, 1, "TestDocumentContent")); + UUID taskId = UUID.randomUUID(); TaskResponse taskResponse = new TaskResponse(taskId, "llm"); given(documentRepository.getById(anyLong())).willReturn(document); given(annotationRepository.findByDocumentId(anyLong())).willReturn(annotations); + given(sttRepository.findAllByDocumentIdAndPageNumber(any(), anyInt())).willReturn(stts); + given(ocrRepository.findAllByDocumentIdAndPageNumber(any(), anyInt())).willReturn(ocrs); given(aiClient.submitLlmTask(any(LlmTaskRequest.class))).willReturn(taskResponse); given(llmTaskRepository.save(any(LlmTask.class))).willAnswer(invocation -> invocation.getArgument(0)); diff --git a/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java b/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java index a57ec5f..7ce0586 100644 --- a/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java +++ b/src/test/java/notai/pageRecording/application/PageRecordingServiceTest.java @@ -3,6 +3,7 @@ import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import notai.pageRecording.application.command.PageRecordingSaveCommand; import notai.pageRecording.application.command.PageRecordingSaveCommand.PageRecordingSession; import notai.pageRecording.domain.PageRecording; @@ -34,6 +35,9 @@ class PageRecordingServiceTest { @Mock private DocumentRepository documentRepository; + @Mock + private MemberRepository memberRepository; + @Mock private Member member; @@ -54,13 +58,13 @@ class PageRecordingServiceTest { Recording foundRecording = mock(Recording.class); given(recordingRepository.getById(recordingId)).willReturn(foundRecording); - + given(memberRepository.getById(anyLong())).willReturn(member); given(documentRepository.getById(anyLong())).willReturn(document); willDoNothing().given(document).validateOwner(member); willDoNothing().given(foundRecording).validateDocumentOwnership(any(Document.class)); // when - pageRecordingService.savePageRecording(member, command); + pageRecordingService.savePageRecording(member.getId(), 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 d0545ad..59cc532 100644 --- a/src/test/java/notai/recording/application/RecordingServiceTest.java +++ b/src/test/java/notai/recording/application/RecordingServiceTest.java @@ -7,6 +7,7 @@ import notai.document.domain.Document; import notai.document.domain.DocumentRepository; import notai.member.domain.Member; +import notai.member.domain.MemberRepository; import notai.recording.application.command.RecordingSaveCommand; import notai.recording.application.result.RecordingSaveResult; import notai.recording.domain.Recording; @@ -47,6 +48,9 @@ class RecordingServiceTest { @Mock private SttTaskService sttTaskService; + @Mock + private MemberRepository memberRepository; + @Spy private final AudioDecoder audioDecoder = new AudioDecoder(); @@ -75,11 +79,12 @@ void setUp() { given(documentRepository.getById(anyLong())).willReturn(document); given(recordingRepository.save(any(Recording.class))).willReturn(savedRecording); + given(memberRepository.getById(anyLong())).willReturn(member); given(document.getName()).willReturn("안녕하세요백종원입니다"); // when & then assertThrows(BadRequestException.class, () -> { - recordingService.saveRecording(member, command); + recordingService.saveRecording(member.getId(), command); }); } @@ -98,12 +103,13 @@ void setUp() { given(documentRepository.getById(anyLong())).willReturn(document); given(recordingRepository.save(any(Recording.class))).willReturn(savedRecording); + given(memberRepository.getById(anyLong())).willReturn(member); given(document.getName()).willReturn("안녕하세요백종원입니다"); willDoNothing().given(sttTaskService).submitSttTask(any()); // when - RecordingSaveResult result = recordingService.saveRecording(member, command); + RecordingSaveResult result = recordingService.saveRecording(member.getId(), command); // then FilePath filePath = FilePath.from("안녕하세요백종원입니다_1.mp3"); @@ -111,4 +117,4 @@ void setUp() { assertAll(() -> assertTrue(Files.exists(expectedFilePath)), () -> assertTrue(Files.size(expectedFilePath) > 0)); } -} \ No newline at end of file +}