From 2184277120a9cd07058a97e0bc85667666006559 Mon Sep 17 00:00:00 2001 From: pear96 Date: Fri, 15 Dec 2023 00:20:02 +0900 Subject: [PATCH 01/15] =?UTF-8?q?refactor:=20DTO=20=ED=8F=B4=EB=8D=94=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - file과 folder의 DTO를 폴더로 분리했습니다. --- .../mystorage/controller/FileController.java | 22 +++++++++----- .../controller/FolderController.java | 29 ++++++++++++++----- .../mystorage/controller/UserController.java | 2 +- .../dto/request/{ => file}/FileReq.java | 2 +- .../dto/request/{ => file}/SignUpReq.java | 2 +- .../dto/request/{ => file}/UploadFileReq.java | 2 +- .../request/{ => folder}/CreateFolderReq.java | 2 +- .../request/{ => folder}/GetFolderReq.java | 2 +- .../{ => folder}/UpdateFolderNameReq.java | 2 +- .../response/{ => file}/FileDownloadRes.java | 2 +- .../response/{ => file}/FileMetaDataRes.java | 2 +- .../{ => folder}/CreateFolderRes.java | 2 +- .../{ => folder}/FolderMetaDataRes.java | 2 +- .../{ => folder}/FolderOverviewRes.java | 4 ++- .../mystorage/service/FileService.java | 8 +++-- .../mystorage/service/FolderService.java | 12 ++++---- .../controller/FileControllerTest.java | 6 ++-- .../controller/FolderControllerTest.java | 6 ++-- .../controller/UserControllerTest.java | 2 +- .../mystorage/service/FileServiceTest.java | 4 +-- .../mystorage/service/FolderServiceTest.java | 6 ++-- .../mystorage/service/UserServiceTest.java | 2 +- 22 files changed, 76 insertions(+), 47 deletions(-) rename src/main/java/com/c4cometrue/mystorage/dto/request/{ => file}/FileReq.java (88%) rename src/main/java/com/c4cometrue/mystorage/dto/request/{ => file}/SignUpReq.java (79%) rename src/main/java/com/c4cometrue/mystorage/dto/request/{ => file}/UploadFileReq.java (87%) rename src/main/java/com/c4cometrue/mystorage/dto/request/{ => folder}/CreateFolderReq.java (88%) rename src/main/java/com/c4cometrue/mystorage/dto/request/{ => folder}/GetFolderReq.java (83%) rename src/main/java/com/c4cometrue/mystorage/dto/request/{ => folder}/UpdateFolderNameReq.java (87%) rename src/main/java/com/c4cometrue/mystorage/dto/response/{ => file}/FileDownloadRes.java (87%) rename src/main/java/com/c4cometrue/mystorage/dto/response/{ => file}/FileMetaDataRes.java (93%) rename src/main/java/com/c4cometrue/mystorage/dto/response/{ => folder}/CreateFolderRes.java (87%) rename src/main/java/com/c4cometrue/mystorage/dto/response/{ => folder}/FolderMetaDataRes.java (87%) rename src/main/java/com/c4cometrue/mystorage/dto/response/{ => folder}/FolderOverviewRes.java (85%) diff --git a/src/main/java/com/c4cometrue/mystorage/controller/FileController.java b/src/main/java/com/c4cometrue/mystorage/controller/FileController.java index 36ca717..b393a10 100644 --- a/src/main/java/com/c4cometrue/mystorage/controller/FileController.java +++ b/src/main/java/com/c4cometrue/mystorage/controller/FileController.java @@ -8,15 +8,18 @@ import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.PatchMapping; 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.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import com.c4cometrue.mystorage.dto.request.FileReq; -import com.c4cometrue.mystorage.dto.request.UploadFileReq; -import com.c4cometrue.mystorage.dto.response.FileDownloadRes; -import com.c4cometrue.mystorage.dto.response.FileMetaDataRes; +import com.c4cometrue.mystorage.dto.request.file.FileReq; +import com.c4cometrue.mystorage.dto.request.file.MoveFileReq; +import com.c4cometrue.mystorage.dto.request.file.UploadFileReq; +import com.c4cometrue.mystorage.dto.response.file.FileDownloadRes; +import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; import com.c4cometrue.mystorage.service.FileService; import jakarta.validation.Valid; @@ -34,11 +37,11 @@ public class FileController { /** * 파일 업로드 요청 * @param req (파일, 사용자 이름, 폴더 기본키) - * @return {@link com.c4cometrue.mystorage.dto.response.FileMetaDataRes} + * @return {@link FileMetaDataRes} */ @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FileMetaDataRes uploadFile(@Valid UploadFileReq req + public FileMetaDataRes uploadFile(@RequestBody @Valid UploadFileReq req ) { return fileService.uploadFile(req.file(), req.userName(), req.folderId()); } @@ -49,7 +52,7 @@ public FileMetaDataRes uploadFile(@Valid UploadFileReq req */ @DeleteMapping @ResponseStatus(HttpStatus.NO_CONTENT) - public void deleteFile(@Valid FileReq req) { + public void deleteFile(@RequestBody @Valid FileReq req) { fileService.deleteFile(req.fileStorageName(), req.userName(), req.folderId()); } @@ -66,4 +69,9 @@ public ResponseEntity downloadFile(@Valid FileReq req) { .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.fileName() + "\"") .body(file.resource()); } + + @PatchMapping + public void moveFile(@RequestBody @Valid MoveFileReq moveFileReq) { + // TODO : 파일 이동 구현 + } } diff --git a/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java b/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java index c3f9821..de3b427 100644 --- a/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java +++ b/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java @@ -2,6 +2,7 @@ import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PatchMapping; import org.springframework.web.bind.annotation.PostMapping; @@ -10,11 +11,13 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import com.c4cometrue.mystorage.dto.request.CreateFolderReq; -import com.c4cometrue.mystorage.dto.request.GetFolderReq; -import com.c4cometrue.mystorage.dto.request.UpdateFolderNameReq; -import com.c4cometrue.mystorage.dto.response.CreateFolderRes; -import com.c4cometrue.mystorage.dto.response.FolderOverviewRes; +import com.c4cometrue.mystorage.dto.request.folder.CreateFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.DeleteFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.GetFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.MoveFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.UpdateFolderNameReq; +import com.c4cometrue.mystorage.dto.response.folder.CreateFolderRes; +import com.c4cometrue.mystorage.dto.response.folder.FolderOverviewRes; import com.c4cometrue.mystorage.service.FolderService; import jakarta.validation.Valid; @@ -31,7 +34,7 @@ public class FolderController { /** * 폴더의 개략적인 정보 요청 * @param req (폴더 기본키, 폴더 이름, 사용자 이름, 부모 폴더 기본키) - * @return {@link com.c4cometrue.mystorage.dto.response.FolderOverviewRes} + * @return {@link FolderOverviewRes} */ @GetMapping @ResponseStatus(HttpStatus.OK) @@ -42,7 +45,7 @@ public FolderOverviewRes getFolderData(@Valid GetFolderReq req) { /** * 폴더 생성 요청이 성공하면 해당 폴더 pk를 포함한 정보 반환 * @param req (폴더 이름, 사용자 이름, 부모 폴더 기본키) - * @return {@link com.c4cometrue.mystorage.dto.response.CreateFolderRes} + * @return {@link CreateFolderRes} */ @PostMapping @ResponseStatus(HttpStatus.CREATED) @@ -60,4 +63,16 @@ public void updateFolderName(@RequestBody @Valid UpdateFolderNameReq updateFolde folderService.updateFolderName(updateFolderNameReq.folderId(), updateFolderNameReq.parentFolderId(), updateFolderNameReq.userName(), updateFolderNameReq.newFolderName()); } + + @DeleteMapping + @ResponseStatus(HttpStatus.NO_CONTENT) + public void deleteFolder(@RequestBody @Valid DeleteFolderReq deleteFolderReq) { + // TODO: 폴더 삭제 구현 + } + + @PatchMapping + @ResponseStatus(HttpStatus.OK) + public void moveFolder(@RequestBody @Valid MoveFolderReq moveFolderReq) { + // TODO: 폴더 이동 구현 + } } diff --git a/src/main/java/com/c4cometrue/mystorage/controller/UserController.java b/src/main/java/com/c4cometrue/mystorage/controller/UserController.java index ebc6e82..de65f8d 100644 --- a/src/main/java/com/c4cometrue/mystorage/controller/UserController.java +++ b/src/main/java/com/c4cometrue/mystorage/controller/UserController.java @@ -8,7 +8,7 @@ import org.springframework.web.bind.annotation.ResponseStatus; import org.springframework.web.bind.annotation.RestController; -import com.c4cometrue.mystorage.dto.request.SignUpReq; +import com.c4cometrue.mystorage.dto.request.file.SignUpReq; import com.c4cometrue.mystorage.dto.response.SignUpRes; import com.c4cometrue.mystorage.service.UserService; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/FileReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java similarity index 88% rename from src/main/java/com/c4cometrue/mystorage/dto/request/FileReq.java rename to src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java index f55abd0..4c7e231 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/FileReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.request; +package com.c4cometrue.mystorage.dto.request.file; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/SignUpReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/SignUpReq.java similarity index 79% rename from src/main/java/com/c4cometrue/mystorage/dto/request/SignUpReq.java rename to src/main/java/com/c4cometrue/mystorage/dto/request/file/SignUpReq.java index 0fd68c2..c17e68b 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/SignUpReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/SignUpReq.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.request; +package com.c4cometrue.mystorage.dto.request.file; import jakarta.validation.constraints.NotBlank; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/UploadFileReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/UploadFileReq.java similarity index 87% rename from src/main/java/com/c4cometrue/mystorage/dto/request/UploadFileReq.java rename to src/main/java/com/c4cometrue/mystorage/dto/request/file/UploadFileReq.java index dbeb15d..222a46b 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/UploadFileReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/UploadFileReq.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.request; +package com.c4cometrue.mystorage.dto.request.file; import org.springframework.web.multipart.MultipartFile; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/CreateFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/CreateFolderReq.java similarity index 88% rename from src/main/java/com/c4cometrue/mystorage/dto/request/CreateFolderReq.java rename to src/main/java/com/c4cometrue/mystorage/dto/request/folder/CreateFolderReq.java index 1b4f88d..936a2ad 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/CreateFolderReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/CreateFolderReq.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.request; +package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/GetFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetFolderReq.java similarity index 83% rename from src/main/java/com/c4cometrue/mystorage/dto/request/GetFolderReq.java rename to src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetFolderReq.java index d8c9664..f15a820 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/GetFolderReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetFolderReq.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.request; +package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/UpdateFolderNameReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/UpdateFolderNameReq.java similarity index 87% rename from src/main/java/com/c4cometrue/mystorage/dto/request/UpdateFolderNameReq.java rename to src/main/java/com/c4cometrue/mystorage/dto/request/folder/UpdateFolderNameReq.java index 3a6296f..7563494 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/UpdateFolderNameReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/UpdateFolderNameReq.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.request; +package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/response/FileDownloadRes.java b/src/main/java/com/c4cometrue/mystorage/dto/response/file/FileDownloadRes.java similarity index 87% rename from src/main/java/com/c4cometrue/mystorage/dto/response/FileDownloadRes.java rename to src/main/java/com/c4cometrue/mystorage/dto/response/file/FileDownloadRes.java index 4c46f77..8d442e2 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/response/FileDownloadRes.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/response/file/FileDownloadRes.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.response; +package com.c4cometrue.mystorage.dto.response.file; import org.springframework.core.io.Resource; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/response/FileMetaDataRes.java b/src/main/java/com/c4cometrue/mystorage/dto/response/file/FileMetaDataRes.java similarity index 93% rename from src/main/java/com/c4cometrue/mystorage/dto/response/FileMetaDataRes.java rename to src/main/java/com/c4cometrue/mystorage/dto/response/file/FileMetaDataRes.java index fbefdea..fa9570f 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/response/FileMetaDataRes.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/response/file/FileMetaDataRes.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.response; +package com.c4cometrue.mystorage.dto.response.file; import com.c4cometrue.mystorage.entity.FileMetaData; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/response/CreateFolderRes.java b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/CreateFolderRes.java similarity index 87% rename from src/main/java/com/c4cometrue/mystorage/dto/response/CreateFolderRes.java rename to src/main/java/com/c4cometrue/mystorage/dto/response/folder/CreateFolderRes.java index c54819c..943e348 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/response/CreateFolderRes.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/CreateFolderRes.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.response; +package com.c4cometrue.mystorage.dto.response.folder; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/response/FolderMetaDataRes.java b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/FolderMetaDataRes.java similarity index 87% rename from src/main/java/com/c4cometrue/mystorage/dto/response/FolderMetaDataRes.java rename to src/main/java/com/c4cometrue/mystorage/dto/response/folder/FolderMetaDataRes.java index 5edc077..4c7647f 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/response/FolderMetaDataRes.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/FolderMetaDataRes.java @@ -1,4 +1,4 @@ -package com.c4cometrue.mystorage.dto.response; +package com.c4cometrue.mystorage.dto.response.folder; import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/c4cometrue/mystorage/dto/response/FolderOverviewRes.java b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/FolderOverviewRes.java similarity index 85% rename from src/main/java/com/c4cometrue/mystorage/dto/response/FolderOverviewRes.java rename to src/main/java/com/c4cometrue/mystorage/dto/response/folder/FolderOverviewRes.java index 9930d47..0ed773f 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/response/FolderOverviewRes.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/FolderOverviewRes.java @@ -1,7 +1,9 @@ -package com.c4cometrue.mystorage.dto.response; +package com.c4cometrue.mystorage.dto.response.folder; import java.util.List; +import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; + import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; diff --git a/src/main/java/com/c4cometrue/mystorage/service/FileService.java b/src/main/java/com/c4cometrue/mystorage/service/FileService.java index b20da4a..61d67c5 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FileService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FileService.java @@ -8,8 +8,8 @@ import org.springframework.stereotype.Service; import org.springframework.web.multipart.MultipartFile; -import com.c4cometrue.mystorage.dto.response.FileDownloadRes; -import com.c4cometrue.mystorage.dto.response.FileMetaDataRes; +import com.c4cometrue.mystorage.dto.response.file.FileDownloadRes; +import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; import com.c4cometrue.mystorage.entity.FileMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; import com.c4cometrue.mystorage.repository.FileRepository; @@ -172,4 +172,8 @@ private Resource getFileResource(Path filePath) { return file; } + + public void moveFile(long fileId, String userName, long targetFolderId) { + + } } diff --git a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java index a4812b6..c026610 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java @@ -6,10 +6,10 @@ import org.springframework.stereotype.Service; -import com.c4cometrue.mystorage.dto.response.CreateFolderRes; -import com.c4cometrue.mystorage.dto.response.FileMetaDataRes; -import com.c4cometrue.mystorage.dto.response.FolderMetaDataRes; -import com.c4cometrue.mystorage.dto.response.FolderOverviewRes; +import com.c4cometrue.mystorage.dto.response.folder.CreateFolderRes; +import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; +import com.c4cometrue.mystorage.dto.response.folder.FolderMetaDataRes; +import com.c4cometrue.mystorage.dto.response.folder.FolderOverviewRes; import com.c4cometrue.mystorage.entity.FileMetaData; import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; @@ -29,7 +29,7 @@ public class FolderService { * 특정 폴더의 대략적인 정보 반환 * @param folderId 해당 폴더 기본키 * @param userName 사용자 이름 - * @return {@link com.c4cometrue.mystorage.dto.response.FolderOverviewRes} + * @return {@link FolderOverviewRes} */ public FolderOverviewRes getFolderData(long folderId, String userName) { // 폴더 정보 조회 @@ -66,7 +66,7 @@ private void checkOwner(String ownerName, String userName) { * @param parentFolderId 부모 폴더 기본키 * @param userName 사용자 이름 * @param folderName 생성할 폴더 이름 - * @return {@link com.c4cometrue.mystorage.dto.response.CreateFolderRes} + * @return {@link CreateFolderRes} */ public CreateFolderRes createFolder(long parentFolderId, String userName, String folderName) { // 중복 폴더 존재 확인 diff --git a/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java b/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java index 8ab105b..0be4820 100644 --- a/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java @@ -11,9 +11,9 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.core.io.Resource; -import com.c4cometrue.mystorage.dto.request.FileReq; -import com.c4cometrue.mystorage.dto.request.UploadFileReq; -import com.c4cometrue.mystorage.dto.response.FileDownloadRes; +import com.c4cometrue.mystorage.dto.request.file.FileReq; +import com.c4cometrue.mystorage.dto.request.file.UploadFileReq; +import com.c4cometrue.mystorage.dto.response.file.FileDownloadRes; import com.c4cometrue.mystorage.service.FileService; @ExtendWith(MockitoExtension.class) diff --git a/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java b/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java index a8c8e0c..989aea7 100644 --- a/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java @@ -10,9 +10,9 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.c4cometrue.mystorage.dto.request.CreateFolderReq; -import com.c4cometrue.mystorage.dto.request.GetFolderReq; -import com.c4cometrue.mystorage.dto.request.UpdateFolderNameReq; +import com.c4cometrue.mystorage.dto.request.folder.CreateFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.GetFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.UpdateFolderNameReq; import com.c4cometrue.mystorage.service.FolderService; @ExtendWith(MockitoExtension.class) diff --git a/src/test/java/com/c4cometrue/mystorage/controller/UserControllerTest.java b/src/test/java/com/c4cometrue/mystorage/controller/UserControllerTest.java index b61bead..bb0df56 100644 --- a/src/test/java/com/c4cometrue/mystorage/controller/UserControllerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/controller/UserControllerTest.java @@ -10,7 +10,7 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import com.c4cometrue.mystorage.dto.request.SignUpReq; +import com.c4cometrue.mystorage.dto.request.file.SignUpReq; import com.c4cometrue.mystorage.service.UserService; @ExtendWith(MockitoExtension.class) diff --git a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java index f6ac76e..c553cbf 100644 --- a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java @@ -21,8 +21,8 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import com.c4cometrue.mystorage.dto.request.FileReq; -import com.c4cometrue.mystorage.dto.request.UploadFileReq; +import com.c4cometrue.mystorage.dto.request.file.FileReq; +import com.c4cometrue.mystorage.dto.request.file.UploadFileReq; import com.c4cometrue.mystorage.entity.FileMetaData; import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; diff --git a/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java b/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java index 38c6f2f..0d82dde 100644 --- a/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java @@ -17,9 +17,9 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; -import com.c4cometrue.mystorage.dto.request.CreateFolderReq; -import com.c4cometrue.mystorage.dto.request.GetFolderReq; -import com.c4cometrue.mystorage.dto.request.UpdateFolderNameReq; +import com.c4cometrue.mystorage.dto.request.folder.CreateFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.GetFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.UpdateFolderNameReq; import com.c4cometrue.mystorage.entity.FileMetaData; import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; diff --git a/src/test/java/com/c4cometrue/mystorage/service/UserServiceTest.java b/src/test/java/com/c4cometrue/mystorage/service/UserServiceTest.java index 29e1984..0fb8bcf 100644 --- a/src/test/java/com/c4cometrue/mystorage/service/UserServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/service/UserServiceTest.java @@ -19,7 +19,7 @@ import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.test.util.ReflectionTestUtils; -import com.c4cometrue.mystorage.dto.request.SignUpReq; +import com.c4cometrue.mystorage.dto.request.file.SignUpReq; import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.entity.UserData; import com.c4cometrue.mystorage.exception.ErrorCd; From 33c25d508b5dbbfc788fa2897c177cc631495ac7 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 17 Feb 2024 00:37:08 +0900 Subject: [PATCH 02/15] =?UTF-8?q?feat=20:=20=ED=8C=8C=EC=9D=BC=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [FileService] - 파일 이동시, 해당 파일의 `folderId` 값만 변경합니다. - 파일 삭제시 물리적 삭제 코드를 제거하고 삭제 로그(DeleteLog) 데이터를 생성하도록 수정했습니다. - 기존의 메서드를 역할에 맞게 더 작게 분리했습니다. [FileMetaData] - 파일의 폴더 기본키를 수정하는 setter를 추가했습니다. [FileReq] - 파일 업로드, 다운로드, 삭제시 파일의 '저장소명' 대신 '기본키'를 사용하도록 수정했습니다. --- .../mystorage/controller/FileController.java | 15 +- .../mystorage/dto/request/file/FileReq.java | 2 +- .../mystorage/entity/FileMetaData.java | 3 + .../mystorage/service/FileService.java | 143 +++++++++++------- 4 files changed, 101 insertions(+), 62 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/controller/FileController.java b/src/main/java/com/c4cometrue/mystorage/controller/FileController.java index b393a10..30ebf5b 100644 --- a/src/main/java/com/c4cometrue/mystorage/controller/FileController.java +++ b/src/main/java/com/c4cometrue/mystorage/controller/FileController.java @@ -41,7 +41,7 @@ public class FileController { */ @PostMapping @ResponseStatus(HttpStatus.CREATED) - public FileMetaDataRes uploadFile(@RequestBody @Valid UploadFileReq req + public FileMetaDataRes uploadFile(@Valid UploadFileReq req ) { return fileService.uploadFile(req.file(), req.userName(), req.folderId()); } @@ -53,7 +53,7 @@ public FileMetaDataRes uploadFile(@RequestBody @Valid UploadFileReq req @DeleteMapping @ResponseStatus(HttpStatus.NO_CONTENT) public void deleteFile(@RequestBody @Valid FileReq req) { - fileService.deleteFile(req.fileStorageName(), req.userName(), req.folderId()); + fileService.deleteFile(req.fileId(), req.userName(), req.folderId()); } /** @@ -63,15 +63,20 @@ public void deleteFile(@RequestBody @Valid FileReq req) { */ @GetMapping public ResponseEntity downloadFile(@Valid FileReq req) { - FileDownloadRes file = fileService.downloadFile(req.fileStorageName(), req.userName(), req.folderId()); + FileDownloadRes file = fileService.downloadFile(req.fileId(), req.userName(), req.folderId()); return ResponseEntity.ok() .contentType(MediaType.parseMediaType(file.mime())) .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=\"" + file.fileName() + "\"") .body(file.resource()); } + /** + * 파일 이동 요청 + * @param req (파일 기본키, 이동할 폴더 기본키) + */ @PatchMapping - public void moveFile(@RequestBody @Valid MoveFileReq moveFileReq) { - // TODO : 파일 이동 구현 + @ResponseStatus(HttpStatus.MOVED_PERMANENTLY) + public void moveFile(@RequestBody @Valid MoveFileReq req) { + fileService.moveFile(req.fileId(), req.folderId(), req.userName()); } } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java index 4c7e231..9f31469 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java @@ -7,7 +7,7 @@ * @see com.c4cometrue.mystorage.entity.FileMetaData */ public record FileReq( - @NotBlank(message = "file storage name is blank") String fileStorageName, + @NotNull(message = "file id is blank") long fileId, @NotBlank(message = "user name is blank") String userName, @NotNull(message = "folder id is blank") long folderId ) { diff --git a/src/main/java/com/c4cometrue/mystorage/entity/FileMetaData.java b/src/main/java/com/c4cometrue/mystorage/entity/FileMetaData.java index a70eee0..632dc90 100644 --- a/src/main/java/com/c4cometrue/mystorage/entity/FileMetaData.java +++ b/src/main/java/com/c4cometrue/mystorage/entity/FileMetaData.java @@ -53,4 +53,7 @@ public FileMetaData(String fileName, String fileStorageName, long size, String m this.folderId = folderId; } + public void setFolderId(Long folderId) { + this.folderId = folderId; + } } diff --git a/src/main/java/com/c4cometrue/mystorage/service/FileService.java b/src/main/java/com/c4cometrue/mystorage/service/FileService.java index 61d67c5..cfb60f3 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FileService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FileService.java @@ -10,8 +10,11 @@ import com.c4cometrue.mystorage.dto.response.file.FileDownloadRes; import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; +import com.c4cometrue.mystorage.entity.DeleteLog; import com.c4cometrue.mystorage.entity.FileMetaData; +import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; +import com.c4cometrue.mystorage.repository.DeleteLogRepository; import com.c4cometrue.mystorage.repository.FileRepository; import com.c4cometrue.mystorage.repository.FolderRepository; import com.c4cometrue.mystorage.util.FileUtil; @@ -22,10 +25,11 @@ @Service @RequiredArgsConstructor public class FileService { - private final FileRepository fileRepository; private final ResourceLoader resourceLoader; - private final FolderRepository folderRepository; private final StoragePathService storagePathService; + private final FolderRepository folderRepository; + private final FileRepository fileRepository; + private final DeleteLogRepository deleteLogRepository; /** * 파일 업로드 @@ -36,8 +40,8 @@ public class FileService { */ @Transactional public FileMetaDataRes uploadFile(MultipartFile file, String userName, long folderId) { - // 폴더 확인 - checkFolder(folderId); + // 폴더 유무 및 권한 확인 + checkFolder(folderId, userName); // 특정 사용자의 동일한 파일명 중복 처리 checkDuplicate(folderId, userName, file.getOriginalFilename()); // 파일 저장소 이름 @@ -62,48 +66,32 @@ public FileMetaDataRes uploadFile(MultipartFile file, String userName, long fold } /** - * 파일 삭제 - * @param fileStorageName 파일 저장소 이름 + * 폴더가 DB에 존재하는지 확인하고, 소유자를 확인한다. + * @param folderId 폴더 기본키 * @param userName 사용자 이름 - * @param folderId 파일이 존재하는 폴더 기본키 */ - @Transactional - public void deleteFile(String fileStorageName, String userName, long folderId) { - // 폴더 존재 확인 - checkFolder(folderId); - // 파일 데이터 조회 - FileMetaData fileMetaData = getFileMetaData(fileStorageName, userName); - // 파일 DB 정보 삭제 - fileRepository.delete(fileMetaData); - // 파일 물리적 삭제 - Path filePath = getFilePath(userName, fileStorageName); - FileUtil.deleteFile(filePath); + private void checkFolder(long folderId, String userName) { + FolderMetaData folderMetaData = getFolderInfo(folderId); + isOwner(folderMetaData.getUserName(), userName); } /** - * 파일 다운로드 - * @param fileStorageName 파일 저장소 이름 - * @param userName 사용자 이름 - * @param folderId 삭제할 파일이 존재하는 폴더 기본키 - * @return 파일 Resource 데이터 및 메타 데이터 + * 폴더 기본키로 특정 폴더가 존재하는지 확인한다. + * @param folderId 폴더 기본키 + * @return 해당 폴더 메타 데이터 */ - public FileDownloadRes downloadFile(String fileStorageName, String userName, long folderId) { - // 폴더 존재 확인 - checkFolder(folderId); - // 파일 메타 데이터 조회 - FileMetaData fileMetaData = getFileMetaData(fileStorageName, userName); - // 파일 물리적 경로 - Path filePath = getFilePath(userName, fileStorageName); - return new FileDownloadRes(getFileResource(filePath), fileMetaData.getFileName(), fileMetaData.getMime()); + private FolderMetaData getFolderInfo(long folderId) { + return folderRepository.findByFolderId(folderId).orElseThrow(ErrorCd.FOLDER_NOT_EXIST::serviceException); } /** - * 폴더가 DB에 존재하는지 확인한다. - * @param folderId 폴더 기본키 + * 폴더의 주인이 일치하는지 확인한다. + * @param ownerName 실제 소유자 이름 + * @param userName 요청한 사용자 이름 */ - private void checkFolder(long folderId) { - if (folderRepository.findByFolderId(folderId).isEmpty()) { - throw ErrorCd.FOLDER_NOT_EXIST.serviceException(); + private void isOwner(String ownerName, String userName) { + if (!ownerName.equals(userName)) { + throw ErrorCd.NO_PERMISSION.serviceException(); } } @@ -120,6 +108,56 @@ private void checkDuplicate(long folderId, String userName, String fileName) { } } + /** + * 파일 삭제 + * @param fileId 파일 기본키 + * @param userName 사용자 이름 + * @param folderId 파일이 존재하는 폴더 기본키 + */ + @Transactional + public void deleteFile(long fileId, String userName, long folderId) { + // 폴더 유무 및 권한 확인 + checkFolder(folderId, userName); + // 파일 메타 데이터 조회 및 권한 확인 + FileMetaData fileMetaData = getFileMetaData(fileId, userName); + // 파일 DB 정보 삭제 + fileRepository.delete(fileMetaData); + // 파일 물리적 삭제 예약 + deleteLogRepository.save(new DeleteLog(fileMetaData.getFileStorageName())); + } + + /** + * 파일이 DB에 존재하는지 확인하고 파일의 주인이 요청한 사용자명과 일치하는지 확인한다. + * @param fileId 파일 기본 키 + * @param userName 사용자 이름 + * @return 파일 메타 데이터 + */ + FileMetaData getFileMetaData(long fileId, String userName) { + FileMetaData fileMetaData = fileRepository.findById(fileId) + .orElseThrow(() -> ErrorCd.FILE_NOT_EXIST + .serviceException("[getFileMetaData] file not exist - fileId: {}", fileId)); + isOwner(fileMetaData.getUserName(), userName); + return fileMetaData; + } + + + /** + * 파일 다운로드 + * @param fileId 파일 기본키 + * @param userName 사용자 이름 + * @param folderId 삭제할 파일이 존재하는 폴더 기본키 + * @return 파일 Resource 데이터 및 메타 데이터 + */ + public FileDownloadRes downloadFile(long fileId, String userName, long folderId) { + // 폴더 유무 및 권한 확인 + checkFolder(folderId, userName); + // 파일 메타 데이터 조회 및 권한 확인 + FileMetaData fileMetaData = getFileMetaData(fileId, userName); + // 파일 물리적 경로 + Path filePath = getFilePath(userName, fileMetaData.getFileStorageName()); + return new FileDownloadRes(getFileResource(filePath), fileMetaData.getFileName(), fileMetaData.getMime()); + } + /** * 파일이 서버에 저장될 이름을 반환한다. * @param fileOriginalName 파일의 원래 이름 @@ -139,25 +177,6 @@ private Path getFilePath(String userName, String fileStorageName) { return storagePathService.createPathByUser(userName).resolve(fileStorageName); } - /** - * 파일이 DB에 존재하는지 확인 - * @param fileStorageName 파일 저장소 이름 - * @param username 사용자 이름 - * @return 파일 메타 데이터 - */ - FileMetaData getFileMetaData(String fileStorageName, String username) { - FileMetaData fileMetaData = fileRepository.findByFileStorageName(fileStorageName) - .orElseThrow(() -> ErrorCd.FILE_NOT_EXIST - .serviceException("[getFileMetaData] file not exist - fileStorageName: {}", fileStorageName)); - - if (!fileMetaData.getUserName().equals(username)) { - throw ErrorCd.NO_PERMISSION - .serviceException("[getFileMetaData] no permission - userName: {}", username); - } - - return fileMetaData; - } - /** * 파일 자체를 반환한다. * @param filePath 파일이 존재하는 경로 @@ -172,8 +191,20 @@ private Resource getFileResource(Path filePath) { return file; } + /** + * 해당 파일의 folderId를 변경한다. 물리적으로 파일을 옮기지 않는다. + * @param fileId 해당 파일의 기본키 + * @param targetFolderId 이동할 폴더의 기본키 + */ + @Transactional + public void moveFile(long fileId, long targetFolderId, String userName) { + // 파일 메타 데이터 조회 및 권한 확인 + FileMetaData fileMetaData = getFileMetaData(fileId, userName); - public void moveFile(long fileId, String userName, long targetFolderId) { + // 폴더 유무 및 권한 확인 + checkFolder(targetFolderId, userName); + // 파일의 폴더 값 업데이트 + fileMetaData.setFolderId(targetFolderId); } } From e1be1e6640b68d44a210a4bc69ab62126a8fcb67 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 17 Feb 2024 01:00:44 +0900 Subject: [PATCH 03/15] =?UTF-8?q?feat=20:=20=ED=8F=B4=EB=8D=94=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99,=20=EC=82=AD=EC=A0=9C=20=EA=B5=AC=ED=98=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [FolderService] - 폴더 삭제는 BFS로 진행합니다. 1. 삭제 요청받은 해당 폴더를 삭제합니다. 2. BFS로 해당 폴더의 모든 하위폴더들을 조회하도록 합니다. 3. 현재 삭제할 차례인 폴더의 모든 파일을 지웁니다. 3-1. `folderId`를 해당 폴더 기본키로 갖는 모든 파일을 찾습니다. 3-2. `DeleteLog`에 삭제할 파일들을 기록합니다. 3-3. 해당 파일들을 `deleteAllInBatch()`로 `FileMetaData`에서 전부 제거합니다. 4. 해당 폴더의 기본키를 `parentFolderId`로 갖는 모든 폴더를 조회합니다. 5. `deleteAllInBatch()`로 하위 폴더들을 DB에서 제거하고, `folderQueue`에 추가합니다. - 폴더 이동시 상위 폴더가 하위 폴더의 밑으로 이동할 수 없도록 방지하는 로직을 구현했습니다. - `checkFolderRelationship(folderId, targetFolderId)`는 `targetFolderId`(이동할 목적지)의 부모에 `folderId`(이동하려는 주체)가 있는지 검사합니다. - 이동하려는 폴더의 자녀에 목적지가 있는지 검사하는 것보다, 목적지의 부모에 이동하려는 폴더가 존재하는지 검사하는 것이 더 빠르다고 생각했습니다. - 폴더를 조회할 때 해당 폴더의 하위 폴더, 파일들을 조회할 때 대량의 데이터를 한번에 조회하는 위험을 방지하고자 Page를 적용했습니다. - Page의 크기는 50으로 설정했습니다. - `getFiles`는 하위 파일들을 ,`getFolders`는 하위 폴더들을 조회합니다. - 폴더 전체 조회하는 메서드의 이름을 `getFolderTotalInfo`로 수정했습니다. 기존의 `getFolderData`폴더 메타 데이터를 조회하는 `getFolderInfo`와 구별하기 어렵다고 생각했습니다. [FolderMetaData] - 폴더의 부모 폴더 기본키를 수정하는 setter를 추가했습니다. [FolderController] - 특정 폴더의 하위 폴더, 파일들을 page 단위로 조회할 수 있는 API를 추가했습니다. [FolderRepository] - 폴더 삭제 과정에서 폴더의 기본키로 BFS의 Queue를 사용했기 때문에 `parentFolderId`만 조회하는 JPQL을 작성했습니다. --- .../controller/FolderController.java | 61 +++++-- .../mystorage/entity/FolderMetaData.java | 4 + .../mystorage/repository/FileRepository.java | 6 +- .../repository/FolderRepository.java | 8 + .../mystorage/service/FolderService.java | 160 ++++++++++++++---- 5 files changed, 192 insertions(+), 47 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java b/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java index de3b427..a9464bc 100644 --- a/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java +++ b/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java @@ -1,5 +1,8 @@ package com.c4cometrue.mystorage.controller; +import java.util.List; + +import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; @@ -16,7 +19,9 @@ import com.c4cometrue.mystorage.dto.request.folder.GetFolderReq; import com.c4cometrue.mystorage.dto.request.folder.MoveFolderReq; import com.c4cometrue.mystorage.dto.request.folder.UpdateFolderNameReq; +import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; import com.c4cometrue.mystorage.dto.response.folder.CreateFolderRes; +import com.c4cometrue.mystorage.dto.response.folder.FolderMetaDataRes; import com.c4cometrue.mystorage.dto.response.folder.FolderOverviewRes; import com.c4cometrue.mystorage.service.FolderService; @@ -39,12 +44,36 @@ public class FolderController { @GetMapping @ResponseStatus(HttpStatus.OK) public FolderOverviewRes getFolderData(@Valid GetFolderReq req) { - return folderService.getFolderData(req.folderId(), req.userName()); + return folderService.getFolderTotalInfo(req.folderId(), req.userName()); + } + + /** + * 폴더의 하위 폴더들을 페이징으로 조회 + * @param folderId 폴더 기본키 + * @param pageable paging을 위한 파라미터 + * @return page 번호에 맞는 하위 폴더 목록 + */ + @GetMapping("/subFolder") + @ResponseStatus(HttpStatus.OK) + public List getSubFolders(long folderId, Pageable pageable) { + return folderService.getFolders(folderId, pageable.getPageNumber()); + } + + /** + * 폴더의 하위 파일들을 페이징으로 조회 + * @param folderId 폴더 기본키 + * @param pageable paging을 위한 파라미터 + * @return page 번호에 맞는 하위 파일 목록 + */ + @GetMapping("/subFile") + @ResponseStatus(HttpStatus.OK) + public List getSubFiles(long folderId, Pageable pageable) { + return folderService.getFiles(folderId, pageable.getPageNumber()); } /** * 폴더 생성 요청이 성공하면 해당 폴더 pk를 포함한 정보 반환 - * @param req (폴더 이름, 사용자 이름, 부모 폴더 기본키) + * @param req (폴더 기본키, 사용자 이름, 부모 폴더 기본키) * @return {@link CreateFolderRes} */ @PostMapping @@ -54,25 +83,33 @@ public CreateFolderRes createFolder(@RequestBody @Valid CreateFolderReq req) { } /** - * 폴더 이름 수정 요청 - * @param updateFolderNameReq (이전 폴더 이름, 사용자 이름, 새로운 폴더 이름, 부모 폴더 기본키) + * 폴더 이름을 수정하는 요청 + * @param req (폴더 기본키, 부모 폴더 기본키, 사용자 이름, 새로운 폴더 이름) */ @PatchMapping("/name") @ResponseStatus(HttpStatus.OK) - public void updateFolderName(@RequestBody @Valid UpdateFolderNameReq updateFolderNameReq) { - folderService.updateFolderName(updateFolderNameReq.folderId(), updateFolderNameReq.parentFolderId(), - updateFolderNameReq.userName(), updateFolderNameReq.newFolderName()); + public void updateFolderName(@RequestBody @Valid UpdateFolderNameReq req) { + folderService.updateFolderName(req.folderId(), req.parentFolderId(), + req.userName(), req.newFolderName()); } + /** + * 폴더를 삭제하는 요청 + * @param req (폴더 기본키) + */ @DeleteMapping @ResponseStatus(HttpStatus.NO_CONTENT) - public void deleteFolder(@RequestBody @Valid DeleteFolderReq deleteFolderReq) { - // TODO: 폴더 삭제 구현 + public void deleteFolder(@RequestBody @Valid DeleteFolderReq req) { + folderService.deleteFolder(req.folderId(), req.userName()); } + /** + * 폴더를 특정 폴더 위치로 이동하는 요청 + * @param req (폴더 기본키, 이동할 폴더 기본키, 사용자 이름) + */ @PatchMapping - @ResponseStatus(HttpStatus.OK) - public void moveFolder(@RequestBody @Valid MoveFolderReq moveFolderReq) { - // TODO: 폴더 이동 구현 + @ResponseStatus(HttpStatus.MOVED_PERMANENTLY) + public void moveFolder(@RequestBody @Valid MoveFolderReq req) { + folderService.moveFolder(req.folderId(), req.targetFolderId(), req.userName()); } } diff --git a/src/main/java/com/c4cometrue/mystorage/entity/FolderMetaData.java b/src/main/java/com/c4cometrue/mystorage/entity/FolderMetaData.java index 5cfda6a..7d8db59 100644 --- a/src/main/java/com/c4cometrue/mystorage/entity/FolderMetaData.java +++ b/src/main/java/com/c4cometrue/mystorage/entity/FolderMetaData.java @@ -42,4 +42,8 @@ public FolderMetaData(String folderName, String userName, long parentFolderId) { public void setFolderName(String folderName) { this.folderName = folderName; } + + public void setParentFolderId(Long parentFolderId) { + this.parentFolderId = parentFolderId; + } } diff --git a/src/main/java/com/c4cometrue/mystorage/repository/FileRepository.java b/src/main/java/com/c4cometrue/mystorage/repository/FileRepository.java index a9cd8cd..3736e1b 100644 --- a/src/main/java/com/c4cometrue/mystorage/repository/FileRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/repository/FileRepository.java @@ -3,6 +3,8 @@ import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import com.c4cometrue.mystorage.entity.FileMetaData; @@ -10,7 +12,7 @@ public interface FileRepository extends JpaRepository { Optional findByFolderIdAndUserNameAndFileName(long folderId, String username, String filename); - Optional findByFileStorageName(String fileStorageName); - Optional> findAllByFolderId(long folderId); + + Page findAllByFolderId(long folderId, Pageable pageable); } diff --git a/src/main/java/com/c4cometrue/mystorage/repository/FolderRepository.java b/src/main/java/com/c4cometrue/mystorage/repository/FolderRepository.java index 49a5397..9fdb23c 100644 --- a/src/main/java/com/c4cometrue/mystorage/repository/FolderRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/repository/FolderRepository.java @@ -3,15 +3,23 @@ import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Query; import com.c4cometrue.mystorage.entity.FolderMetaData; public interface FolderRepository extends JpaRepository { Optional findByFolderId(long folderId); + @Query("SELECT f.parentFolderId FROM FolderMetaData f where f.folderId=:folderId") + Long findParentFolderIdByFolderId(long folderId); + Optional findByFolderNameAndParentFolderIdAndUserName(String folderName, long parentFolderId, String userName); Optional> findAllByParentFolderId(long parentFolderId); + + Page findAllByParentFolderId(long parentFolderId, Pageable pageable); } diff --git a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java index c026610..405df4a 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java @@ -1,18 +1,23 @@ package com.c4cometrue.mystorage.service; +import java.util.ArrayDeque; import java.util.LinkedList; import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Page; +import org.springframework.data.domain.PageRequest; import org.springframework.stereotype.Service; -import com.c4cometrue.mystorage.dto.response.folder.CreateFolderRes; import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; +import com.c4cometrue.mystorage.dto.response.folder.CreateFolderRes; import com.c4cometrue.mystorage.dto.response.folder.FolderMetaDataRes; import com.c4cometrue.mystorage.dto.response.folder.FolderOverviewRes; +import com.c4cometrue.mystorage.entity.DeleteLog; import com.c4cometrue.mystorage.entity.FileMetaData; import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; +import com.c4cometrue.mystorage.repository.DeleteLogRepository; import com.c4cometrue.mystorage.repository.FileRepository; import com.c4cometrue.mystorage.repository.FolderRepository; @@ -24,6 +29,7 @@ public class FolderService { private final FolderRepository folderRepository; private final FileRepository fileRepository; + private final DeleteLogRepository deleteLogRepository; /** * 특정 폴더의 대략적인 정보 반환 @@ -31,14 +37,14 @@ public class FolderService { * @param userName 사용자 이름 * @return {@link FolderOverviewRes} */ - public FolderOverviewRes getFolderData(long folderId, String userName) { + public FolderOverviewRes getFolderTotalInfo(long folderId, String userName) { // 폴더 정보 조회 FolderMetaData folder = getFolderInfo(folderId); // 권한 확인 - checkOwner(folder.getUserName(), userName); + isOwner(folder.getUserName(), userName); return new FolderOverviewRes(folderId, folder.getFolderName(), userName, - getFiles(folderId), getFolders(folderId)); + getFiles(folderId, 0), getFolders(folderId, 0)); } /** @@ -55,7 +61,7 @@ private FolderMetaData getFolderInfo(long folderId) { * @param ownerName 실제 소유자 이름 * @param userName 요청한 사용자 이름 */ - private void checkOwner(String ownerName, String userName) { + private void isOwner(String ownerName, String userName) { if (!ownerName.equals(userName)) { throw ErrorCd.NO_PERMISSION.serviceException(); } @@ -78,10 +84,9 @@ public CreateFolderRes createFolder(long parentFolderId, String userName, String .userName(userName) .parentFolderId(parentFolderId) .build(); - folderMetaData = folderRepository.save(folderMetaData); - return new CreateFolderRes(folderMetaData.getFolderId(), folderName, userName); + return new CreateFolderRes(folderMetaData.getFolderId(), folderName); } /** @@ -109,47 +114,136 @@ public void updateFolderName(long folderId, long parentFolderId, String userName // 폴더 존재 여부 확인 FolderMetaData folder = getFolderInfo(folderId); - // 바꿀 권한이 있는가? - checkOwner(folder.getUserName(), userName); + // 권한 확인 + isOwner(folder.getUserName(), userName); - // 바꿀 폴더 이름이 이미 같은 위치에 존재하는가 + // 바꿀 폴더 이름이 이미 같은 위치에 존재하면 예외 처리 checkDuplicateFolder(newFolderName, parentFolderId, userName); // 폴더명 변경 folder.setFolderName(newFolderName); - folderRepository.save(folder); } /** - * 특정 폴더의 자식 폴더들의 목록을 반환한다. + * 폴더에 포함된 파일들을 pageSize만큼 반환한다. * @param folderId 특정 폴더 기본키 - * @return 자식 폴더 목록 + * @param page 페이지 번호 + * @return 파일 목록 */ - private List getFiles(long folderId) { - Optional> fileList = fileRepository.findAllByFolderId(folderId); + public List getFiles(long folderId, int page) { + Page filePage = fileRepository.findAllByFolderId(folderId, PageRequest.of(page, 50)); + LinkedList result = new LinkedList<>(); - return fileList.map(files -> - files.stream().map(fileMetaData -> new FileMetaDataRes( - fileMetaData.getFileStorageName(), - fileMetaData.getSize(), - fileMetaData.getMime(), - fileMetaData.getUserName())).toList()) - .orElseGet(LinkedList::new); + for (FileMetaData fileMetaData : filePage) { + result.add(new FileMetaDataRes(fileMetaData.getFileStorageName(), fileMetaData.getSize(), + fileMetaData.getMime(), fileMetaData.getUserName())); + } + return result; } /** - * 특정 폴더의 자식 폴더들의 목록을 반환한다. + * 폴더의 하위 폴더들을 pageSize만큼 반환한다. * @param folderId 특정 폴더 기본키 - * @return 자식 폴더 목록 + * @param page 페이지 번호 + * @return 하위 폴더 목록 + */ + public List getFolders(long folderId, int page) { + Page folderList = folderRepository.findAllByParentFolderId(folderId, PageRequest.of(page, 50)); + LinkedList result = new LinkedList<>(); + + for (FolderMetaData folderMetaData : folderList) { + result.add(new FolderMetaDataRes(folderMetaData.getFolderId(), folderMetaData.getFolderName(), + folderMetaData.getUserName())); + } + return result; + } + + /** + * 폴더의 + * @param folderId + */ + @Transactional + public void deleteFolder(long folderId, String userName) { + // folderId 권한 확인 후 삭제 + FolderMetaData folder = getFolderInfo(folderId); + isOwner(folder.getUserName(), userName); + folderRepository.delete(folder); + + // 하위 폴더 삭제 BFS + ArrayDeque folderQueue = new ArrayDeque<>(); + folderQueue.add(folderId); + + while (!folderQueue.isEmpty()) { + long parentFolderId = folderQueue.removeFirst(); + // 해당 폴더의 모든 파일 메타 데이터 삭제 + deleteAllFile(parentFolderId); + // 해당 폴더의 자식 폴더들 조회 + Optional> children = folderRepository.findAllByParentFolderId(parentFolderId); + if (children.isPresent()) { + folderRepository.deleteAllInBatch(children.get()); + for (FolderMetaData folderMetaData : children.get()) { + folderQueue.add(folderMetaData.getFolderId()); + } + } + } + } + + /** + * 특정 폴더에 속한 모든 파일 메타 데이터를 삭제한다. + * @param folderId 폴더 기본키 + */ + @Transactional + public void deleteAllFile(long folderId) { + Optional> fileList = fileRepository.findAllByFolderId(folderId); + + if (fileList.isPresent()) { + List deleteLogs = new LinkedList<>(); + for (FileMetaData fileMetaData : fileList.get()) { + deleteLogs.add(new DeleteLog(fileMetaData.getFileStorageName())); + } + deleteLogRepository.saveAll(deleteLogs); + fileRepository.deleteAllInBatch(fileList.get()); + } + } + + + /** + * 폴더를 이동한다. + * 논리적으로는 하위의 모든 폴더와 파일이 이동해야 하지만 일일이 수정 할 필요가 없다. + * 하위 폴더나 파일이나, 다 이동할 'folderId'를 보고 있기 때문에, 'folderId'를 조회할 때 어차피 따라온다. + * 'folderId'에게 화살표를 가리키고 있기 때문에, 'folderId'가 어디로 이동하던 상관 없는 것이다. + * 그러므로 'folderId'의 부모 폴더 pk만 바꾼다. + * @param folderId 이동하는 폴더 + * @param targetFolderId 이동할 위치의 폴더 기본키 */ - private List getFolders(long folderId) { - Optional> folderList = folderRepository.findAllByParentFolderId(folderId); - - return folderList.map(folders -> - folders.stream().map(folderMetaData -> new FolderMetaDataRes( - folderMetaData.getFolderId(), - folderMetaData.getFolderName(), - folderMetaData.getUserName())).toList()) - .orElseGet(LinkedList::new); + @Transactional + public void moveFolder(long folderId, long targetFolderId, String userName) { + // 이동할 폴더가 존재하는가 + FolderMetaData folder = getFolderInfo(folderId); + // 이동시킬 권한을 가졌는가 + isOwner(folder.getUserName(), userName); + // 이동할 수 있는가 (targetFolder의 부모에 folderId가 없는가) + checkFolderRelationship(folderId, targetFolderId); + // 이동 + folder.setParentFolderId(targetFolderId); + } + + /** + * targetFolderId가 folderId의 하위 폴더인지 확인한다. + * folderId가 targetFolderId의 하위 폴더라면 폴더 이동이 가능하므로 문제가 없다. + * @param folderId 움직일 폴더의 아이디 + * @param targetFolderId 도착 지점의 폴더 아이디 + */ + private void checkFolderRelationship(long folderId, long targetFolderId) { + long nowFolderId = targetFolderId; + + // 0은 root 값이며, 이에 도달하면 종료한다. + while (nowFolderId != 0) { + nowFolderId = folderRepository.findParentFolderIdByFolderId(nowFolderId); + if (nowFolderId == folderId) { + // 만약 부모 - 자식 관계에 있다면 경로에 사이클이 생긴다. + throw ErrorCd.FOLDER_CANT_BE_MOVED.serviceException(); + } + } } } From 71da3879562f8e642f836a55d90ce1bbda60b7e4 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 17 Feb 2024 01:02:42 +0900 Subject: [PATCH 04/15] =?UTF-8?q?feat=20:=20=EC=9D=B4=EB=8F=99,=20?= =?UTF-8?q?=EC=82=AD=EC=A0=9C=EC=97=90=20=ED=95=84=EC=9A=94=ED=95=9C=20DTO?= =?UTF-8?q?,=20Repository?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [DeleteLog] - 삭제할 파일의 저장소 명과 삭제를 요청한 날짜를 저장합니다. - 삭제 날짜는 한국 서버 시간 기준으로 통일하도록 했습니다. --- .../dto/request/file/MoveFileReq.java | 14 +++++++++ .../dto/request/folder/DeleteFolderReq.java | 12 +++++++ .../dto/request/folder/MoveFolderReq.java | 14 +++++++++ .../mystorage/entity/DeleteLog.java | 31 +++++++++++++++++++ .../repository/DeleteLogRepository.java | 8 +++++ 5 files changed, 79 insertions(+) create mode 100644 src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java create mode 100644 src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java create mode 100644 src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java create mode 100644 src/main/java/com/c4cometrue/mystorage/entity/DeleteLog.java create mode 100644 src/main/java/com/c4cometrue/mystorage/repository/DeleteLogRepository.java diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java new file mode 100644 index 0000000..60adf6f --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java @@ -0,0 +1,14 @@ +package com.c4cometrue.mystorage.dto.request.file; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +/** + * DTO for {@link com.c4cometrue.mystorage.entity.FileMetaData} + */ +public record MoveFileReq( + @NotNull(message = "file id is blank") long fileId, + @NotNull(message = "folder id is blank") long folderId, + @NotBlank(message = "user name is blank") String userName +) { +} diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java new file mode 100644 index 0000000..8aad413 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java @@ -0,0 +1,12 @@ +package com.c4cometrue.mystorage.dto.request.folder; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +/** + * @see com.c4cometrue.mystorage.entity.FolderMetaData + */ +public record DeleteFolderReq( + @NotNull(message = "folder id can't be null") long folderId, + @NotBlank(message = "user name is blank") String userName) { +} diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java new file mode 100644 index 0000000..08cb9f8 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java @@ -0,0 +1,14 @@ +package com.c4cometrue.mystorage.dto.request.folder; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; + +/** + * @see com.c4cometrue.mystorage.entity.FolderMetaData + */ +public record MoveFolderReq( + @NotNull(message = "folder id can't be null") long folderId, + @NotNull(message = "target folder can't be null") long targetFolderId, + @NotBlank(message = "user name is blank") String userName +) { +} diff --git a/src/main/java/com/c4cometrue/mystorage/entity/DeleteLog.java b/src/main/java/com/c4cometrue/mystorage/entity/DeleteLog.java new file mode 100644 index 0000000..29079fe --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/entity/DeleteLog.java @@ -0,0 +1,31 @@ +package com.c4cometrue.mystorage.entity; + +import java.time.ZoneId; +import java.time.ZonedDateTime; + +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; + +@Entity +@RequiredArgsConstructor +public class DeleteLog { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long logId; + + @NotBlank(message = "file storage name is blank") + private String fileStorageName; + + @NotNull + private ZonedDateTime deleteTime; + + public DeleteLog(String fileStorageName) { + this.fileStorageName = fileStorageName; + this.deleteTime = ZonedDateTime.now(ZoneId.of("Asia/Seoul")); + } +} diff --git a/src/main/java/com/c4cometrue/mystorage/repository/DeleteLogRepository.java b/src/main/java/com/c4cometrue/mystorage/repository/DeleteLogRepository.java new file mode 100644 index 0000000..17ed40f --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/repository/DeleteLogRepository.java @@ -0,0 +1,8 @@ +package com.c4cometrue.mystorage.repository; + +import org.springframework.data.jpa.repository.JpaRepository; + +import com.c4cometrue.mystorage.entity.DeleteLog; + +public interface DeleteLogRepository extends JpaRepository { +} From 89de494dc73350e20616565913101efaac7fe1fe Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 17 Feb 2024 01:04:31 +0900 Subject: [PATCH 05/15] =?UTF-8?q?test=20:=20=ED=8F=B4=EB=8D=94=20=EC=9D=B4?= =?UTF-8?q?=EB=8F=99,=20=EC=82=AD=EC=A0=9C,=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=BD=94?= =?UTF-8?q?=EB=93=9C=20=EC=9E=91=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../controller/FileControllerTest.java | 24 ++- .../controller/FolderControllerTest.java | 61 +++++- .../mystorage/service/FileServiceTest.java | 182 +++++++++++++----- .../mystorage/service/FolderServiceTest.java | 145 +++++++++++++- 4 files changed, 354 insertions(+), 58 deletions(-) diff --git a/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java b/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java index 0be4820..1f361ae 100644 --- a/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/controller/FileControllerTest.java @@ -12,6 +12,7 @@ import org.springframework.core.io.Resource; import com.c4cometrue.mystorage.dto.request.file.FileReq; +import com.c4cometrue.mystorage.dto.request.file.MoveFileReq; import com.c4cometrue.mystorage.dto.request.file.UploadFileReq; import com.c4cometrue.mystorage.dto.response.file.FileDownloadRes; import com.c4cometrue.mystorage.service.FileService; @@ -39,27 +40,40 @@ void uploadFile() { @DisplayName("파일 삭제") void deleteFile() { // given - var req = new FileReq(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L); + var req = new FileReq(1L, MOCK_USER_NAME, 1L); // when fileController.deleteFile(req); // then - verify(fileService, times(1)).deleteFile(req.fileStorageName(), req.userName(), req.folderId()); + verify(fileService, times(1)).deleteFile(req.fileId(), req.userName(), req.folderId()); } @Test @DisplayName("파일 다운로드") void downloadFile() { // given - var req = new FileReq(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L); - given(fileService.downloadFile(req.fileStorageName(), req.userName(), req.folderId())).willReturn( + var req = new FileReq(1L, MOCK_USER_NAME, 1L); + given(fileService.downloadFile(req.fileId(), req.userName(), req.folderId())).willReturn( new FileDownloadRes(mock(Resource.class), MOCK_FILE_NAME, MOCK_CONTENT_TYPE)); // when fileController.downloadFile(req); // then - verify(fileService, times(1)).downloadFile(req.fileStorageName(), req.userName(), req.folderId()); + verify(fileService, times(1)).downloadFile(req.fileId(), req.userName(), req.folderId()); + } + + @Test + @DisplayName("파일 이동") + void moveFile() { + // given + var req = new MoveFileReq(1L, 1L, MOCK_USER_NAME); + + // when + fileController.moveFile(req); + + // then + verify(fileService, times(1)).moveFile(req.fileId(), req.folderId(), req.userName()); } } diff --git a/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java b/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java index 989aea7..9b71dd2 100644 --- a/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java @@ -9,9 +9,12 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.PageRequest; import com.c4cometrue.mystorage.dto.request.folder.CreateFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.DeleteFolderReq; import com.c4cometrue.mystorage.dto.request.folder.GetFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.MoveFolderReq; import com.c4cometrue.mystorage.dto.request.folder.UpdateFolderNameReq; import com.c4cometrue.mystorage.service.FolderService; @@ -32,7 +35,37 @@ void getFolderData() { folderController.getFolderData(req); // then - verify(folderService, times(1)).getFolderData(req.folderId(), req.userName()); + verify(folderService, times(1)).getFolderTotalInfo(req.folderId(), req.userName()); + } + + @Test + @DisplayName("폴더의 하위 폴더 n 페이지 조회") + void getFolderSubFolders() { + // given + var folderId = 1L; + var pageRequest = PageRequest.of(0, 50); + + // when + folderController.getSubFolders(folderId, pageRequest); + + // then + verify(folderService, times(1)).getFolders(folderId, pageRequest.getPageNumber()); + + } + + + @Test + @DisplayName("폴더의 하위 파일 n 페이지 조회") + void getFolderSubFiles() { + // given + var folderId = 1L; + var pageRequest = PageRequest.of(0, 50); + + // when + folderController.getSubFiles(folderId, pageRequest); + + // then + verify(folderService, times(1)).getFiles(folderId, pageRequest.getPageNumber()); } @@ -63,4 +96,30 @@ void updateFolderName() { req.newFolderName()); } + @Test + @DisplayName("폴더 이동") + void moveFolder() { + // given + var req = new MoveFolderReq(1L, 99L, MOCK_USER_NAME); + + // when + folderController.moveFolder(req); + + // then + verify(folderService, times(1)).moveFolder(req.folderId(), req.targetFolderId(), req.userName()); + } + + @Test + @DisplayName("폴더 삭제") + void deleteFolder() { + // given + var req = new DeleteFolderReq(1L, MOCK_USER_NAME); + + // when + folderController.deleteFolder(req); + + // then + verify(folderService, times(1)).deleteFolder(req.folderId(), req.userName()); + } + } diff --git a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java index c553cbf..93ec00f 100644 --- a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java @@ -23,10 +23,12 @@ import com.c4cometrue.mystorage.dto.request.file.FileReq; import com.c4cometrue.mystorage.dto.request.file.UploadFileReq; +import com.c4cometrue.mystorage.entity.DeleteLog; import com.c4cometrue.mystorage.entity.FileMetaData; import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; import com.c4cometrue.mystorage.exception.ServiceException; +import com.c4cometrue.mystorage.repository.DeleteLogRepository; import com.c4cometrue.mystorage.repository.FileRepository; import com.c4cometrue.mystorage.repository.FolderRepository; import com.c4cometrue.mystorage.util.FileUtil; @@ -43,6 +45,8 @@ public class FileServiceTest { ResourceLoader mockResourceLoader; @Mock StoragePathService storagePathService; + @Mock + DeleteLogRepository deleteLogRepository; private static MockedStatic fileUtilMockedStatic; @@ -60,13 +64,14 @@ public static void tearDown() { @DisplayName("파일 업로드 성공") void uploadFile() { // given + var folderId = 1L; var mockFolderMetaData = FolderMetaData.builder() .folderName("folderName") .userName(MOCK_USER_NAME) .parentFolderId(1L) .build(); - given(folderRepository.findByFolderId(1L)).willReturn(Optional.of(mockFolderMetaData)); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); given(storagePathService.createPathByUser(MOCK_USER_NAME)).willReturn( Paths.get(MOCK_ROOT_PATH, MOCK_USER_NAME)); @@ -74,7 +79,7 @@ void uploadFile() { given(MOCK_MULTIPART_FILE.getSize()).willReturn(MOCK_SIZE); given(MOCK_MULTIPART_FILE.getContentType()).willReturn(MOCK_CONTENT_TYPE); - var req = new UploadFileReq(MOCK_MULTIPART_FILE, MOCK_USER_NAME, 1L); + var req = new UploadFileReq(MOCK_MULTIPART_FILE, MOCK_USER_NAME, folderId); // when var createFileRes = fileService.uploadFile(req.file(), req.userName(), req.folderId()); @@ -92,21 +97,22 @@ void uploadFile() { @DisplayName("파일 업로드 실패 - 중복 파일명") void uploadFileFailDuplicateName() { // given + var folderId = 1L; var mockFolderMetaData = FolderMetaData.builder() .folderName("folderName") .userName(MOCK_USER_NAME) - .parentFolderId(1L) + .parentFolderId(folderId) .build(); - given(folderRepository.findByFolderId(1L)).willReturn(Optional.of(mockFolderMetaData)); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); given(MOCK_MULTIPART_FILE.getOriginalFilename()).willReturn(MOCK_FILE_NAME); - given(fileRepository.findByFolderIdAndUserNameAndFileName(1L, MOCK_USER_NAME, MOCK_FILE_NAME)) + given(fileRepository.findByFolderIdAndUserNameAndFileName(folderId, MOCK_USER_NAME, MOCK_FILE_NAME)) .willReturn(Optional.of(new FileMetaData())); - var req = new UploadFileReq(MOCK_MULTIPART_FILE, MOCK_USER_NAME, 1L); + var req = new UploadFileReq(MOCK_MULTIPART_FILE, MOCK_USER_NAME, folderId); // when var exception = assertThrows(ServiceException.class, - () -> fileService.uploadFile(MOCK_MULTIPART_FILE, MOCK_USER_NAME, 1L)); + () -> fileService.uploadFile(MOCK_MULTIPART_FILE, MOCK_USER_NAME, folderId)); // then assertEquals(ErrorCd.DUPLICATE_FILE.name(), exception.getErrCode()); @@ -116,6 +122,8 @@ void uploadFileFailDuplicateName() { @DisplayName("파일 데이터 DB 확인") void getFileMetaData() { // given + var fileId = 1L; + var folderId = 1L; var mockFileMetaData = FileMetaData.builder() .fileName(MOCK_FILE_NAME) .fileStorageName(MOCK_FILE_STORAGE_NAME) @@ -124,10 +132,10 @@ void getFileMetaData() { .mime(MOCK_CONTENT_TYPE) .folderId(1L) .build(); - given(fileRepository.findByFileStorageName(MOCK_FILE_STORAGE_NAME)).willReturn(Optional.of(mockFileMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); // when - var fileMetadata = fileService.getFileMetaData(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME); + var fileMetadata = fileService.getFileMetaData(folderId, MOCK_USER_NAME); // then assertThat(fileMetadata) @@ -141,12 +149,12 @@ void getFileMetaData() { @DisplayName("파일 데이터 DB 확인 실패 - 파일 없음") void getFileMetaDataFailWrongFileStorageName() { // given - var wrongFileStorageName = "wrong_file_path.txt"; - given(fileRepository.findByFileStorageName(wrongFileStorageName)).willReturn(Optional.empty()); + var wrongFileId = -1L; + given(fileRepository.findById(wrongFileId)).willReturn(Optional.empty()); // when var exception = assertThrows(ServiceException.class, - () -> fileService.getFileMetaData(wrongFileStorageName, MOCK_USER_NAME)); + () -> fileService.getFileMetaData(wrongFileId, MOCK_USER_NAME)); // then assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); @@ -156,19 +164,21 @@ void getFileMetaDataFailWrongFileStorageName() { @DisplayName("파일 데이터 DB 확인 실패 - 요청자가 주인이 아님") void getFileMetaDataFailNotOwner() { // given + var fileId = 1L; + var folderId = 1L; var mockFileMetaData = FileMetaData.builder() .fileName(MOCK_FILE_NAME) .fileStorageName(MOCK_FILE_STORAGE_NAME) .userName(MOCK_USER_NAME) .size(MOCK_SIZE) .mime(MOCK_CONTENT_TYPE) - .folderId(1L) + .folderId(folderId) .build(); - given(fileRepository.findByFileStorageName(MOCK_FILE_STORAGE_NAME)).willReturn(Optional.of(mockFileMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); // when var exception = assertThrows(ServiceException.class, - () -> fileService.getFileMetaData(MOCK_FILE_STORAGE_NAME, "anonymous")); + () -> fileService.getFileMetaData(fileId, "anonymous")); // then assertEquals(ErrorCd.NO_PERMISSION.name(), exception.getErrCode()); @@ -178,40 +188,41 @@ void getFileMetaDataFailNotOwner() { @DisplayName("파일 삭제") void deleteFile() { // given - var req = new FileReq(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L); + var fileId = 1L; + var folderId = 1L; var mockFileMetaData = FileMetaData.builder() .fileName(MOCK_FILE_NAME) .fileStorageName(MOCK_FILE_STORAGE_NAME) .userName(MOCK_USER_NAME) .size(MOCK_SIZE) .mime(MOCK_CONTENT_TYPE) - .folderId(1L) + .folderId(folderId) .build(); var mockFolderMetaData = FolderMetaData.builder() .folderName("folderName") .userName(MOCK_USER_NAME) - .parentFolderId(1L) + .parentFolderId(0L) .build(); - given(folderRepository.findByFolderId(1L)).willReturn(Optional.of(mockFolderMetaData)); - given(storagePathService.createPathByUser(MOCK_USER_NAME)).willReturn( - Paths.get(MOCK_ROOT_PATH, MOCK_USER_NAME)); - given(fileRepository.findByFileStorageName(MOCK_FILE_STORAGE_NAME)).willReturn(Optional.of(mockFileMetaData)); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); // when - fileService.deleteFile(req.fileStorageName(), req.userName(), req.folderId()); + fileService.deleteFile(fileId, MOCK_USER_NAME, folderId); // then - verify(folderRepository, times(1)).findByFolderId(1L); - verify(fileRepository, times(1)).findByFileStorageName(any()); - verify(fileRepository, times(1)).delete(any()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(fileRepository, times(1)).findById(fileId); + verify(fileRepository, times(1)).delete(mockFileMetaData); + verify(deleteLogRepository, times(1)).save(any()); } @Test @DisplayName("파일 다운로드") void downloadFile() { // given - var req = new FileReq(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L); + var fileId = 1L; + var folderId = 1L; var mockResource = mock(Resource.class); var mockFileMetaData = FileMetaData.builder() .fileName(MOCK_FILE_NAME) @@ -219,16 +230,16 @@ void downloadFile() { .userName(MOCK_USER_NAME) .size(MOCK_SIZE) .mime(MOCK_CONTENT_TYPE) - .folderId(1L) + .folderId(folderId) .build(); var mockFolderMetaData = FolderMetaData.builder() .folderName("folderName") .userName(MOCK_USER_NAME) - .parentFolderId(1L) + .parentFolderId(folderId) .build(); - given(fileRepository.findByFileStorageName(MOCK_FILE_STORAGE_NAME)).willReturn(Optional.of(mockFileMetaData)); - given(folderRepository.findByFolderId(1L)).willReturn(Optional.of(mockFolderMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); given(mockResourceLoader.getResource(any())).willReturn(mockResource); given(storagePathService.createPathByUser(MOCK_USER_NAME)).willReturn( Paths.get(MOCK_ROOT_PATH, MOCK_USER_NAME)); @@ -236,18 +247,19 @@ void downloadFile() { given(mockResource.exists()).willReturn(true); // when - fileService.downloadFile(req.fileStorageName(), req.userName(), req.folderId()); + fileService.downloadFile(fileId, MOCK_USER_NAME, folderId); // then - verify(folderRepository, times(1)).findByFolderId(1L); - verify(fileRepository, times(1)).findByFileStorageName(any()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(fileRepository, times(1)).findById(fileId); } @Test @DisplayName("파일 다운로드 실패") void downloadFileFail() { // given - var req = new FileReq(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L); + var fileId = 1L; + var folderId = 1L; var mockResource = mock(Resource.class); var mockFileMetaData = FileMetaData.builder() .fileName(MOCK_FILE_NAME) @@ -255,7 +267,7 @@ void downloadFileFail() { .userName(MOCK_USER_NAME) .size(MOCK_SIZE) .mime(MOCK_CONTENT_TYPE) - .folderId(1L) + .folderId(folderId) .build(); var mockFolderMetaData = FolderMetaData.builder() @@ -264,8 +276,8 @@ void downloadFileFail() { .parentFolderId(0L) .build(); - given(fileRepository.findByFileStorageName(MOCK_FILE_STORAGE_NAME)).willReturn(Optional.of(mockFileMetaData)); - given(folderRepository.findByFolderId(1L)).willReturn(Optional.of(mockFolderMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); given(mockResourceLoader.getResource(any())).willReturn(mockResource); given(storagePathService.createPathByUser(MOCK_USER_NAME)).willReturn( Paths.get(MOCK_ROOT_PATH, MOCK_USER_NAME)); @@ -274,11 +286,11 @@ void downloadFileFail() { // when var exception = assertThrows(ServiceException.class, - () -> fileService.downloadFile(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L)); + () -> fileService.downloadFile(fileId, MOCK_USER_NAME, folderId)); // then - verify(folderRepository, times(1)).findByFolderId(1L); - verify(fileRepository, times(1)).findByFileStorageName(any()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(fileRepository, times(1)).findById(fileId); assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); } @@ -286,15 +298,97 @@ void downloadFileFail() { @DisplayName("파일이 있어야할 폴더가 없다") void folderNotExist() { // given - var req = new FileReq(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L); - given(folderRepository.findByFolderId(1L)).willReturn(Optional.empty()); + var fileId = 1L; + var folderId = 1L; + given(folderRepository.findByFolderId(fileId)).willReturn(Optional.empty()); + + // when + var exception = assertThrows(ServiceException.class, + () -> fileService.downloadFile(fileId, MOCK_USER_NAME, folderId)); + + // then + assertEquals(ErrorCd.FOLDER_NOT_EXIST.name(), exception.getErrCode()); + } + + @Test + @DisplayName("파일 이동 성공") + void moveFile() { + // given + var fileId = 1L; + var targetFolderId = 1234L; + + var mockFileMetaData = FileMetaData.builder() + .fileName(MOCK_FILE_NAME) + .fileStorageName(MOCK_FILE_STORAGE_NAME) + .userName(MOCK_USER_NAME) + .size(MOCK_SIZE) + .mime(MOCK_CONTENT_TYPE) + .folderId(1L) + .build(); + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + + given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); + given(folderRepository.findByFolderId(targetFolderId)).willReturn(Optional.of(mockFolderMetaData)); + + // when + fileService.moveFile(fileId, targetFolderId, MOCK_USER_NAME); + + // then + assertEquals(mockFileMetaData.getFolderId(), targetFolderId); + verify(fileRepository, times(1)).findById(fileId); + verify(folderRepository, times(1)).findByFolderId(targetFolderId); + } + + @Test + @DisplayName("파일 이동 실패 - 파일 정보 없음") + void moveFileFailByFileNotFound() { + // given + var fileId = 1L; + var targetFolderId = 1234L; + + given(fileRepository.findById(fileId)).willReturn(Optional.empty()); + + // when + var exception = assertThrows(ServiceException.class, + () -> fileService.moveFile(fileId, targetFolderId, MOCK_USER_NAME)); + + // then + assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); + verify(fileRepository, times(1)).findById(fileId); + verify(folderRepository, times(0)).findByFolderId(targetFolderId); + } + + @Test + @DisplayName("파일 이동 실패 - 이동할 폴더가 없음") + void moveFileFailByFolderNotFound() { + // given + var fileId = 1L; + var targetFolderId = 1234L; + + var mockFileMetaData = FileMetaData.builder() + .fileName(MOCK_FILE_NAME) + .fileStorageName(MOCK_FILE_STORAGE_NAME) + .userName(MOCK_USER_NAME) + .size(MOCK_SIZE) + .mime(MOCK_CONTENT_TYPE) + .folderId(1L) + .build(); + + given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); + given(folderRepository.findByFolderId(targetFolderId)).willReturn(Optional.empty()); // when var exception = assertThrows(ServiceException.class, - () -> fileService.downloadFile(MOCK_FILE_STORAGE_NAME, MOCK_USER_NAME, 1L)); + () -> fileService.moveFile(fileId, targetFolderId, MOCK_USER_NAME)); // then assertEquals(ErrorCd.FOLDER_NOT_EXIST.name(), exception.getErrCode()); + verify(fileRepository, times(1)).findById(fileId); + verify(folderRepository, times(1)).findByFolderId(targetFolderId); } } diff --git a/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java b/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java index 0d82dde..5e33228 100644 --- a/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/service/FolderServiceTest.java @@ -15,6 +15,8 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.PageImpl; +import org.springframework.data.domain.PageRequest; import org.springframework.test.util.ReflectionTestUtils; import com.c4cometrue.mystorage.dto.request.folder.CreateFolderReq; @@ -24,6 +26,7 @@ import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; import com.c4cometrue.mystorage.exception.ServiceException; +import com.c4cometrue.mystorage.repository.DeleteLogRepository; import com.c4cometrue.mystorage.repository.FileRepository; import com.c4cometrue.mystorage.repository.FolderRepository; @@ -31,11 +34,12 @@ class FolderServiceTest { @InjectMocks FolderService folderService; - @Mock FolderRepository folderRepository; @Mock FileRepository fileRepository; + @Mock + DeleteLogRepository deleteLogRepository; @Test @DisplayName("폴더 정보 조회 성공") @@ -74,11 +78,12 @@ void getFolderData() { ReflectionTestUtils.setField(subFolder, "folderId", 3L); folderList.add(subFolder); - given(fileRepository.findAllByFolderId(2L)).willReturn(Optional.of(fileList)); - given(folderRepository.findAllByParentFolderId(2L)).willReturn(Optional.of(folderList)); + var pageRequest = PageRequest.of(0, 50); + given(fileRepository.findAllByFolderId(2L, pageRequest)).willReturn(new PageImpl<>(fileList)); + given(folderRepository.findAllByParentFolderId(2L, pageRequest)).willReturn(new PageImpl<>(folderList)); // when - var folderOverviewRes = folderService.getFolderData(req.folderId(), req.userName()); + var folderOverviewRes = folderService.getFolderTotalInfo(req.folderId(), req.userName()); // then assertThat(folderOverviewRes) @@ -96,7 +101,7 @@ void getFolderDataFailNoFolder() { // when var exception = assertThrows(ServiceException.class, - () -> folderService.getFolderData(1L, MOCK_USER_NAME)); + () -> folderService.getFolderTotalInfo(1L, MOCK_USER_NAME)); // then assertEquals(exception.getErrCode(), ErrorCd.FOLDER_NOT_EXIST.name()); @@ -118,7 +123,7 @@ void getFolderDataFailNotOwner() { // when var exception = assertThrows(ServiceException.class, - () -> folderService.getFolderData(1L, "Anonymous")); + () -> folderService.getFolderTotalInfo(1L, "Anonymous")); // then assertEquals(exception.getErrCode(), ErrorCd.NO_PERMISSION.name()); @@ -151,8 +156,7 @@ void createFolder() { // then assertThat(createFolderRes) - .matches(res -> StringUtils.equals(res.folderName(), folderName)) - .matches(res -> StringUtils.equals(res.userName(), MOCK_USER_NAME)); + .matches(res -> StringUtils.equals(res.folderName(), folderName)); } @Test @@ -236,4 +240,129 @@ void updateFolderNameFail() { verify(folderRepository, times(1)).findByFolderNameAndParentFolderIdAndUserName(mockNewFolderName, 1L, MOCK_USER_NAME); } + + @Test + @DisplayName("폴더 이동") + void moveFolder() { + // given + var folderId = 1L; + var targetFolderId = 99L; + + var mockFolderMetaData = FolderMetaData.builder() + .folderName("my_folder") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); + given(folderRepository.findParentFolderIdByFolderId(targetFolderId)).willReturn(0L); + + // when + folderService.moveFolder(folderId, targetFolderId, MOCK_USER_NAME); + + // then + assertEquals(targetFolderId, mockFolderMetaData.getParentFolderId()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(folderRepository, times(1)).findParentFolderIdByFolderId(targetFolderId); + } + + @Test + @DisplayName("폴더 이동 실패 - 폴더가 존재하지 않음") + void moveFolderFailByFolderNotFound() { + // given + var folderId = 1L; + var targetFolderId = 99L; + + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.empty()); + + // when + var exception = assertThrows(ServiceException.class, + () -> folderService.moveFolder(folderId, targetFolderId, MOCK_USER_NAME)); + + // then + assertEquals(ErrorCd.FOLDER_NOT_EXIST.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(folderRepository, times(0)).findParentFolderIdByFolderId(targetFolderId); + } + + @Test + @DisplayName("폴더 이동 실패 - 폴더 경로에 사이클이 생김") + void moveFolderFailByLoopRelation() { + // given + var folderId = 1L; + var targetFolderId = 99L; + + var mockFolderMetaData = FolderMetaData.builder() + .folderName("my_folder") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); + // targetFolderId의 부모 폴더가 folderId라면, 자식 폴더에 이동하는 셈이므로 막아야한다. + given(folderRepository.findParentFolderIdByFolderId(targetFolderId)).willReturn(folderId); + + // when + var exception = assertThrows(ServiceException.class, + () -> folderService.moveFolder(folderId, targetFolderId, MOCK_USER_NAME)); + + // then + assertEquals(ErrorCd.FOLDER_CANT_BE_MOVED.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(folderRepository, times(1)).findParentFolderIdByFolderId(targetFolderId); + } + + @Test + @DisplayName("폴더 삭제") + void deleteFolder() { + // given + // 1. 삭제할 폴더 + var folderId = 1L; + var mockFolderMetaData = FolderMetaData.builder() + .folderName("my_folder") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); + + // 2. 삭제할 폴더의 하위 파일 목록 + var fileList = new ArrayList(); + fileList.add(FileMetaData.builder() + .fileName(MOCK_FILE_NAME) + .fileStorageName(MOCK_FILE_STORAGE_NAME) + .userName(MOCK_USER_NAME) + .size(MOCK_SIZE) + .mime(MOCK_CONTENT_TYPE) + .folderId(2L) + .build()); + given(fileRepository.findAllByFolderId(folderId)).willReturn(Optional.of(fileList)); + + // 3. 삭제할 폴더의 하위 폴더 목록 + var folderList = new ArrayList(); + var subFolderId = 2L; + var subFolder = FolderMetaData.builder() + .folderName("childFolder") + .userName(MOCK_USER_NAME) + .parentFolderId(folderId) + .build(); + ReflectionTestUtils.setField(subFolder, "folderId", subFolderId); + folderList.add(subFolder); + given(folderRepository.findAllByParentFolderId(folderId)).willReturn(Optional.of(folderList)); + given(fileRepository.findAllByFolderId(subFolderId)).willReturn(Optional.empty()); + given(folderRepository.findAllByParentFolderId(subFolderId)).willReturn(Optional.empty()); + + // when + folderService.deleteFolder(folderId, MOCK_USER_NAME); + + // then + verify(folderRepository, times(1)).delete(mockFolderMetaData); + + verify(fileRepository, times(1)).findAllByFolderId(folderId); + verify(deleteLogRepository, times(1)).saveAll(any()); + verify(fileRepository, times(1)).deleteAllInBatch(any()); + + verify(folderRepository, times(1)).findAllByParentFolderId(subFolderId); + verify(fileRepository, times(1)).findAllByFolderId(subFolderId); + } + } From ad35811c8bb4ebcc120afe9087895211bc0aec34 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 17 Feb 2024 01:07:38 +0900 Subject: [PATCH 06/15] =?UTF-8?q?style=20:=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EC=88=98=EC=A0=95=20=EB=B0=8F=20=EC=BD=94=EB=93=9C=20=EC=8A=A4?= =?UTF-8?q?=ED=83=80=EC=9D=BC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/c4cometrue/mystorage/entity/UserData.java | 3 ++- .../java/com/c4cometrue/mystorage/service/FolderService.java | 4 ++-- src/main/java/com/c4cometrue/mystorage/util/FileUtil.java | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/entity/UserData.java b/src/main/java/com/c4cometrue/mystorage/entity/UserData.java index e26e939..cf38311 100644 --- a/src/main/java/com/c4cometrue/mystorage/entity/UserData.java +++ b/src/main/java/com/c4cometrue/mystorage/entity/UserData.java @@ -13,7 +13,8 @@ @RequiredArgsConstructor @Getter public class UserData { - @Id @GeneratedValue(strategy = GenerationType.IDENTITY) + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) private Long userId; @NotBlank(message = "user name is blank") diff --git a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java index 405df4a..b6d76ff 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java @@ -159,8 +159,8 @@ public List getFolders(long folderId, int page) { } /** - * 폴더의 - * @param folderId + * 폴더를 삭제하고, 해당 폴더의 모든 하위 폴더와 파일들을 삭제한다. + * @param folderId 폴더 기본키 */ @Transactional public void deleteFolder(long folderId, String userName) { diff --git a/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java b/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java index 33fc7ce..f43f302 100644 --- a/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java +++ b/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java @@ -58,7 +58,7 @@ public static void createFolder(Path folderPath) { public static void renameFolder(Path oldPath, Path newPath) { if (!Files.exists(oldPath)) { - throw ErrorCd.FOLDER_NOT_EXIST.serviceException("[Rename Folder] folder name is duplicate"); + throw ErrorCd.FOLDER_NOT_EXIST.serviceException("[Rename Folder] folder name is duplicated"); } try { From 4724bb681921c2d3b0446e561df503c20079637c Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 17 Feb 2024 01:09:04 +0900 Subject: [PATCH 07/15] =?UTF-8?q?refactor=20:=20=EC=9E=90=EC=9E=98?= =?UTF-8?q?=ED=95=9C=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit [CreateFolderRes] - 폴더를 생성한 사용자 명을 반환할 필요가 없어서 제거했습니다. [ErrorCd] - 폴더 이동시 사이클이 생기는 경우 예외를 추가했습니다. [FileServiceTest] - 불필요한 변수를 삭제했습니다. --- .../mystorage/dto/response/folder/CreateFolderRes.java | 3 +-- src/main/java/com/c4cometrue/mystorage/exception/ErrorCd.java | 2 +- .../java/com/c4cometrue/mystorage/service/FileServiceTest.java | 3 --- 3 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/dto/response/folder/CreateFolderRes.java b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/CreateFolderRes.java index 943e348..b129efb 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/response/folder/CreateFolderRes.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/response/folder/CreateFolderRes.java @@ -8,7 +8,6 @@ */ public record CreateFolderRes( @NotNull(message = "folder Number can't be null") long folderId, - @NotBlank(message = "folder name is blank") String folderName, - @NotBlank(message = "user name is blank") String userName + @NotBlank(message = "folder name is blank") String folderName ) { } diff --git a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCd.java b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCd.java index 431cdf9..20abb2c 100644 --- a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCd.java +++ b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCd.java @@ -17,7 +17,7 @@ public enum ErrorCd { // Folder 관련 에러 FOLDER_NOT_EXIST(HttpStatus.NOT_FOUND, "Folder doesn't exist"), // 폴더가 존재하지 않는 경우 DUPLICATE_FOLDER(HttpStatus.BAD_REQUEST, "Duplicate Folder"), // 이미 존재하는 폴더명 - + FOLDER_CANT_BE_MOVED(HttpStatus.BAD_REQUEST, "folder route might have cycle"), // 하위 폴더로 이동하려는 경우 // User 관련 에러 DUPLICATE_USER(HttpStatus.BAD_REQUEST, "User name Duplicate"), // 이미 존재하는 유저 이름 diff --git a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java index 93ec00f..d55dfcc 100644 --- a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java @@ -21,9 +21,7 @@ import org.springframework.core.io.Resource; import org.springframework.core.io.ResourceLoader; -import com.c4cometrue.mystorage.dto.request.file.FileReq; import com.c4cometrue.mystorage.dto.request.file.UploadFileReq; -import com.c4cometrue.mystorage.entity.DeleteLog; import com.c4cometrue.mystorage.entity.FileMetaData; import com.c4cometrue.mystorage.entity.FolderMetaData; import com.c4cometrue.mystorage.exception.ErrorCd; @@ -108,7 +106,6 @@ void uploadFileFailDuplicateName() { given(MOCK_MULTIPART_FILE.getOriginalFilename()).willReturn(MOCK_FILE_NAME); given(fileRepository.findByFolderIdAndUserNameAndFileName(folderId, MOCK_USER_NAME, MOCK_FILE_NAME)) .willReturn(Optional.of(new FileMetaData())); - var req = new UploadFileReq(MOCK_MULTIPART_FILE, MOCK_USER_NAME, folderId); // when var exception = assertThrows(ServiceException.class, From c207e3f9ded4200eb01d2745ab4e603577dc4794 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 03:47:00 +0900 Subject: [PATCH 08/15] =?UTF-8?q?refactor=20:=20DTO=EC=9D=98=20long=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=9C=A0=ED=9A=A8=EC=84=B1=20=EA=B2=80?= =?UTF-8?q?=EC=82=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `long id`(파일, 폴더 등) 에 대해 `@NotNull` 유효성을 설정했던 것에서 `@Positive`로 변경했습니다. - 변경해야하는 이유는 우선 `long`이기 때문에 어차피 null 값을 사용할 수 없습니다. - 또한 -1 과 같이 정상적이지 않은 경우를 처리할 수 없습니다. --- .../com/c4cometrue/mystorage/dto/request/file/FileReq.java | 6 +++--- .../c4cometrue/mystorage/dto/request/file/MoveFileReq.java | 6 +++--- .../mystorage/dto/request/file/UploadFileReq.java | 3 ++- .../mystorage/dto/request/folder/CreateFolderReq.java | 4 ++-- .../mystorage/dto/request/folder/DeleteFolderReq.java | 4 ++-- .../mystorage/dto/request/folder/GetFolderReq.java | 4 ++-- .../mystorage/dto/request/folder/MoveFolderReq.java | 6 +++--- .../mystorage/dto/request/folder/UpdateFolderNameReq.java | 6 +++--- 8 files changed, 20 insertions(+), 19 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java index 9f31469..ce7a5dd 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/FileReq.java @@ -1,14 +1,14 @@ package com.c4cometrue.mystorage.dto.request.file; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; /** * @see com.c4cometrue.mystorage.entity.FileMetaData */ public record FileReq( - @NotNull(message = "file id is blank") long fileId, + @Positive(message = "file id should be positive") long fileId, @NotBlank(message = "user name is blank") String userName, - @NotNull(message = "folder id is blank") long folderId + @Positive(message = "folder id should be positive") long folderId ) { } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java index 60adf6f..73c8be8 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/MoveFileReq.java @@ -1,14 +1,14 @@ package com.c4cometrue.mystorage.dto.request.file; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; /** * DTO for {@link com.c4cometrue.mystorage.entity.FileMetaData} */ public record MoveFileReq( - @NotNull(message = "file id is blank") long fileId, - @NotNull(message = "folder id is blank") long folderId, + @Positive(message = "file id should be positive") long fileId, + @Positive(message = "folder id should be positive") long folderId, @NotBlank(message = "user name is blank") String userName ) { } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/file/UploadFileReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/file/UploadFileReq.java index 222a46b..7372865 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/file/UploadFileReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/file/UploadFileReq.java @@ -4,10 +4,11 @@ import jakarta.validation.constraints.NotBlank; import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; public record UploadFileReq( @NotNull(message = "file doesn't exist") MultipartFile file, @NotBlank(message = "user name is blank") String userName, - @NotNull(message = "folder id is null") long folderId + @Positive(message = "folder id should be positive") long folderId ) { } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/CreateFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/CreateFolderReq.java index 936a2ad..6a714da 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/CreateFolderReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/CreateFolderReq.java @@ -1,13 +1,13 @@ package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; /** * @see com.c4cometrue.mystorage.entity.FolderMetaData */ public record CreateFolderReq( - @NotNull(message = "parent folder can't be null") long parentFolderId, + @Positive(message = "parent folder should be positive") long parentFolderId, @NotBlank(message = "user name is blank") String userName, @NotBlank(message = "folder name is blank") String folderName ) { diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java index 8aad413..a8f023b 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/DeleteFolderReq.java @@ -1,12 +1,12 @@ package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; /** * @see com.c4cometrue.mystorage.entity.FolderMetaData */ public record DeleteFolderReq( - @NotNull(message = "folder id can't be null") long folderId, + @Positive(message = "folder id should be positive") long folderId, @NotBlank(message = "user name is blank") String userName) { } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetFolderReq.java index f15a820..415a3d0 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetFolderReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetFolderReq.java @@ -1,13 +1,13 @@ package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; /** * @see com.c4cometrue.mystorage.entity.FolderMetaData */ public record GetFolderReq( - @NotNull long folderId, + @Positive(message = "folder id should be positive") long folderId, @NotBlank(message = "user name is blank") String userName ) { } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java index 08cb9f8..7698b27 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/MoveFolderReq.java @@ -1,14 +1,14 @@ package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; /** * @see com.c4cometrue.mystorage.entity.FolderMetaData */ public record MoveFolderReq( - @NotNull(message = "folder id can't be null") long folderId, - @NotNull(message = "target folder can't be null") long targetFolderId, + @Positive(message = "folder id should be positive") long folderId, + @Positive(message = "target folder should be positive") long targetFolderId, @NotBlank(message = "user name is blank") String userName ) { } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/UpdateFolderNameReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/UpdateFolderNameReq.java index 7563494..0cbb63e 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/UpdateFolderNameReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/UpdateFolderNameReq.java @@ -1,14 +1,14 @@ package com.c4cometrue.mystorage.dto.request.folder; import jakarta.validation.constraints.NotBlank; -import jakarta.validation.constraints.NotNull; +import jakarta.validation.constraints.Positive; /** * @see com.c4cometrue.mystorage.entity.FolderMetaData */ public record UpdateFolderNameReq( - @NotNull long folderId, - @NotNull long parentFolderId, + @Positive(message = "folder id should be positive") long folderId, + @Positive(message = "parent folder id should be positive") long parentFolderId, @NotBlank(message = "user name is blank") String userName, @NotBlank(message = "new folder name is blank") String newFolderName ) { From dd8c115e27f638f50c4cf6c86b85b20d3a1f9313 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 03:49:52 +0900 Subject: [PATCH 09/15] =?UTF-8?q?refactor=20:=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=EC=9D=98=20=ED=95=98=EC=9C=84=20=ED=8F=B4=EB=8D=94,=20?= =?UTF-8?q?=ED=8C=8C=EC=9D=BC=20=EB=AA=A9=EB=A1=9D=20=EC=A1=B0=ED=9A=8C=20?= =?UTF-8?q?DTO=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 폴더의 하위 폴더, 파일 목록 조회시 필요한 값을 전달받는 DTO를 추가했습니다. - Pageable에서 페이지 번호만 사용하고 있었기 때문에 Pageable의 객체는 서비스 레이어에서 생성하고, 페이지 번호만 클라이언트에서 전달받도록 수정했습니다. - 폴더 이동시 응답 코드를 200으로 수정했습니다. --- .../mystorage/controller/FolderController.java | 18 ++++++++---------- .../dto/request/folder/GetSubInfoReq.java | 10 ++++++++++ 2 files changed, 18 insertions(+), 10 deletions(-) create mode 100644 src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java diff --git a/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java b/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java index a9464bc..5cc17a4 100644 --- a/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java +++ b/src/main/java/com/c4cometrue/mystorage/controller/FolderController.java @@ -2,7 +2,6 @@ import java.util.List; -import org.springframework.data.domain.Pageable; import org.springframework.http.HttpStatus; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.DeleteMapping; @@ -17,6 +16,7 @@ import com.c4cometrue.mystorage.dto.request.folder.CreateFolderReq; import com.c4cometrue.mystorage.dto.request.folder.DeleteFolderReq; import com.c4cometrue.mystorage.dto.request.folder.GetFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.GetSubInfoReq; import com.c4cometrue.mystorage.dto.request.folder.MoveFolderReq; import com.c4cometrue.mystorage.dto.request.folder.UpdateFolderNameReq; import com.c4cometrue.mystorage.dto.response.file.FileMetaDataRes; @@ -49,26 +49,24 @@ public FolderOverviewRes getFolderData(@Valid GetFolderReq req) { /** * 폴더의 하위 폴더들을 페이징으로 조회 - * @param folderId 폴더 기본키 - * @param pageable paging을 위한 파라미터 + * @param req (폴더 기본키, 페이지 번호) * @return page 번호에 맞는 하위 폴더 목록 */ @GetMapping("/subFolder") @ResponseStatus(HttpStatus.OK) - public List getSubFolders(long folderId, Pageable pageable) { - return folderService.getFolders(folderId, pageable.getPageNumber()); + public List getSubFolders(@Valid GetSubInfoReq req) { + return folderService.getFolders(req.folderId(), req.page()); } /** * 폴더의 하위 파일들을 페이징으로 조회 - * @param folderId 폴더 기본키 - * @param pageable paging을 위한 파라미터 + * @param req (폴더 기본키, 페이지 번호) * @return page 번호에 맞는 하위 파일 목록 */ @GetMapping("/subFile") @ResponseStatus(HttpStatus.OK) - public List getSubFiles(long folderId, Pageable pageable) { - return folderService.getFiles(folderId, pageable.getPageNumber()); + public List getSubFiles(@Valid GetSubInfoReq req) { + return folderService.getFiles(req.folderId(), req.page()); } /** @@ -108,7 +106,7 @@ public void deleteFolder(@RequestBody @Valid DeleteFolderReq req) { * @param req (폴더 기본키, 이동할 폴더 기본키, 사용자 이름) */ @PatchMapping - @ResponseStatus(HttpStatus.MOVED_PERMANENTLY) + @ResponseStatus(HttpStatus.OK) public void moveFolder(@RequestBody @Valid MoveFolderReq req) { folderService.moveFolder(req.folderId(), req.targetFolderId(), req.userName()); } diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java new file mode 100644 index 0000000..b75d4c7 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java @@ -0,0 +1,10 @@ +package com.c4cometrue.mystorage.dto.request.folder; + +import jakarta.validation.constraints.Min; +import jakarta.validation.constraints.Positive; + +public record GetSubInfoReq( + @Positive(message = "folder id should be positive") long folderId, + @Min(value = 0, message = "page number should be 0 or positive") int page +) { +} \ No newline at end of file From bbde7428a3250fb556105225ac1f900a27dbd156 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 03:59:18 +0900 Subject: [PATCH 10/15] =?UTF-8?q?refactor=20:=20Validation=20=EA=B4=80?= =?UTF-8?q?=EB=A0=A8=20=EC=97=90=EB=9F=AC=20=EB=A9=94=EC=84=B8=EC=A7=80=20?= =?UTF-8?q?=ED=95=B8=EB=93=A4=EB=9F=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - DTO에 설정한 각 필드의 유효성을 통과하지 못할 경우 400 에러를 반환하도록 핸들러를 추가했습니다. - 유효성을 어겼을 시 기존에 설정해둔 메세지가 log에 나오도록 하고, 클라이언트에는 통합된 메세지를 반환하도록 했습니다. --- .../ExceptionHandlingController.java | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/exception/ExceptionHandlingController.java b/src/main/java/com/c4cometrue/mystorage/exception/ExceptionHandlingController.java index 1e7eb89..0380520 100644 --- a/src/main/java/com/c4cometrue/mystorage/exception/ExceptionHandlingController.java +++ b/src/main/java/com/c4cometrue/mystorage/exception/ExceptionHandlingController.java @@ -6,6 +6,7 @@ import org.slf4j.LoggerFactory; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; @@ -16,7 +17,7 @@ public class ExceptionHandlingController { private final Logger logger = (Logger) LoggerFactory.getLogger(this.getClass().getSimpleName()); final ZoneId timeZone = ZoneId.of("Asia/Seoul"); - // value에 포함된 예외들 처리함 + @ExceptionHandler(ServiceException.class) public ResponseEntity handleServiceException(ServiceException exception) { if (exception.getDebugMessage() != null) { @@ -32,6 +33,28 @@ public ResponseEntity handleServiceException(ServiceException e return new ResponseEntity<>(apiExceptionRes, httpStatus); } + @ExceptionHandler(MethodArgumentNotValidException.class) + public ResponseEntity handleValidException(MethodArgumentNotValidException exception) { + StringBuilder errorMessageBuilder = new StringBuilder(); + exception.getBindingResult().getFieldErrors().forEach(error -> { + String fieldName = error.getField(); + String errorMessage = error.getDefaultMessage(); + errorMessageBuilder.append(fieldName).append(" : ").append(errorMessage).append("\n"); + }); + + if (!errorMessageBuilder.isEmpty()) { + String errorMessages = errorMessageBuilder.toString(); + logger.error(errorMessages); + } + + var apiExceptionRes = new ApiExceptionRes( + "Request is not Valid. Please Check Again", + ZonedDateTime.now(timeZone) + ); + + return new ResponseEntity<>(apiExceptionRes, HttpStatus.BAD_REQUEST); + } + @ExceptionHandler() public ResponseEntity handleException(Exception exception) { logger.error(exception.getMessage()); From 2e85d4941276c0276878f8e111ee22c932f045b2 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 04:02:01 +0900 Subject: [PATCH 11/15] =?UTF-8?q?refactor=20:=20fileService=EC=9D=98=20pri?= =?UTF-8?q?vate=20Method=20=ED=85=8C=EC=8A=A4=ED=8A=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `getFileMetaData()`메서드가 `private` 접근자를 설정해야하는데, 테스트 코드를 작성할 수 없어 default로 설정했었습니다. - `public`으로 바꾸는 것은 FileService 외부에서 사용하지 않기 때문에 적합하지 않다고 생각했습니다. - 따라서 `private`으로 바꾸고, `getFileMetaData()`를 호출하는 public 메서드들에 대해 실패 테스트 케이스 코드를 전부 추가했습니다. --- .../mystorage/service/FileService.java | 8 +- .../mystorage/service/FileServiceTest.java | 200 ++++++++++++------ 2 files changed, 140 insertions(+), 68 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/service/FileService.java b/src/main/java/com/c4cometrue/mystorage/service/FileService.java index cfb60f3..c408fcc 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FileService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FileService.java @@ -132,7 +132,7 @@ public void deleteFile(long fileId, String userName, long folderId) { * @param userName 사용자 이름 * @return 파일 메타 데이터 */ - FileMetaData getFileMetaData(long fileId, String userName) { + private FileMetaData getFileMetaData(long fileId, String userName) { FileMetaData fileMetaData = fileRepository.findById(fileId) .orElseThrow(() -> ErrorCd.FILE_NOT_EXIST .serviceException("[getFileMetaData] file not exist - fileId: {}", fileId)); @@ -198,12 +198,12 @@ private Resource getFileResource(Path filePath) { */ @Transactional public void moveFile(long fileId, long targetFolderId, String userName) { - // 파일 메타 데이터 조회 및 권한 확인 - FileMetaData fileMetaData = getFileMetaData(fileId, userName); - // 폴더 유무 및 권한 확인 checkFolder(targetFolderId, userName); + // 파일 메타 데이터 조회 및 권한 확인 + FileMetaData fileMetaData = getFileMetaData(fileId, userName); + // 파일의 폴더 값 업데이트 fileMetaData.setFolderId(targetFolderId); } diff --git a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java index d55dfcc..61065c1 100644 --- a/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/service/FileServiceTest.java @@ -116,8 +116,8 @@ void uploadFileFailDuplicateName() { } @Test - @DisplayName("파일 데이터 DB 확인") - void getFileMetaData() { + @DisplayName("파일 삭제") + void deleteFile() { // given var fileId = 1L; var folderId = 1L; @@ -127,66 +127,81 @@ void getFileMetaData() { .userName(MOCK_USER_NAME) .size(MOCK_SIZE) .mime(MOCK_CONTENT_TYPE) - .folderId(1L) + .folderId(folderId) .build(); + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); // when - var fileMetadata = fileService.getFileMetaData(folderId, MOCK_USER_NAME); + fileService.deleteFile(fileId, MOCK_USER_NAME, folderId); // then - assertThat(fileMetadata) - .matches(metadata -> StringUtils.equals(metadata.getFileName(), MOCK_FILE_NAME)) - .matches(metadata -> metadata.getSize() == MOCK_SIZE) - .matches(metadata -> StringUtils.equals(metadata.getMime(), MOCK_CONTENT_TYPE)) - .matches(metadata -> StringUtils.equals(metadata.getUserName(), MOCK_USER_NAME)); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(fileRepository, times(1)).findById(fileId); + verify(fileRepository, times(1)).delete(mockFileMetaData); + verify(deleteLogRepository, times(1)).save(any()); } @Test - @DisplayName("파일 데이터 DB 확인 실패 - 파일 없음") - void getFileMetaDataFailWrongFileStorageName() { + @DisplayName("파일 삭제 실패 - 파일 데이터 조회 실패") + void deleteFileFailByFileMetaDataNotFound() { // given - var wrongFileId = -1L; - given(fileRepository.findById(wrongFileId)).willReturn(Optional.empty()); + var fileId = 1L; + var folderId = 1L; + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.empty()); // when var exception = assertThrows(ServiceException.class, - () -> fileService.getFileMetaData(wrongFileId, MOCK_USER_NAME)); + () -> fileService.deleteFile(fileId, MOCK_USER_NAME, folderId)); // then assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(fileRepository, times(1)).findById(fileId); } @Test - @DisplayName("파일 데이터 DB 확인 실패 - 요청자가 주인이 아님") - void getFileMetaDataFailNotOwner() { + @DisplayName("파일 삭제 실패 - 권한이 없음") + void deleteFileFailByNoAuthority() { // given var fileId = 1L; var folderId = 1L; - var mockFileMetaData = FileMetaData.builder() - .fileName(MOCK_FILE_NAME) - .fileStorageName(MOCK_FILE_STORAGE_NAME) + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") .userName(MOCK_USER_NAME) - .size(MOCK_SIZE) - .mime(MOCK_CONTENT_TYPE) - .folderId(folderId) + .parentFolderId(0L) .build(); - given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); // when var exception = assertThrows(ServiceException.class, - () -> fileService.getFileMetaData(fileId, "anonymous")); + () -> fileService.deleteFile(fileId, "anonymous", folderId)); // then assertEquals(ErrorCd.NO_PERMISSION.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(folderId); } @Test - @DisplayName("파일 삭제") - void deleteFile() { + @DisplayName("파일 다운로드") + void downloadFile() { // given var fileId = 1L; var folderId = 1L; + var mockResource = mock(Resource.class); var mockFileMetaData = FileMetaData.builder() .fileName(MOCK_FILE_NAME) .fileStorageName(MOCK_FILE_STORAGE_NAME) @@ -198,62 +213,77 @@ void deleteFile() { var mockFolderMetaData = FolderMetaData.builder() .folderName("folderName") .userName(MOCK_USER_NAME) - .parentFolderId(0L) + .parentFolderId(folderId) .build(); - given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); + given(mockResourceLoader.getResource(any())).willReturn(mockResource); + given(storagePathService.createPathByUser(MOCK_USER_NAME)).willReturn( + Paths.get(MOCK_ROOT_PATH, MOCK_USER_NAME)); + + given(mockResource.exists()).willReturn(true); // when - fileService.deleteFile(fileId, MOCK_USER_NAME, folderId); + fileService.downloadFile(fileId, MOCK_USER_NAME, folderId); // then verify(folderRepository, times(1)).findByFolderId(folderId); verify(fileRepository, times(1)).findById(fileId); - verify(fileRepository, times(1)).delete(mockFileMetaData); - verify(deleteLogRepository, times(1)).save(any()); } @Test - @DisplayName("파일 다운로드") - void downloadFile() { + @DisplayName("파일 다운로드 실패 - 파일 데이터 조회 실패") + void downloadFileFailByFileMetaDataNotFound() { // given var fileId = 1L; var folderId = 1L; - var mockResource = mock(Resource.class); - var mockFileMetaData = FileMetaData.builder() - .fileName(MOCK_FILE_NAME) - .fileStorageName(MOCK_FILE_STORAGE_NAME) + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") .userName(MOCK_USER_NAME) - .size(MOCK_SIZE) - .mime(MOCK_CONTENT_TYPE) - .folderId(folderId) + .parentFolderId(0L) .build(); + + given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.empty()); + + // when + var exception = assertThrows(ServiceException.class, + () -> fileService.downloadFile(fileId, MOCK_USER_NAME, folderId)); + + // then + assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(folderId); + verify(fileRepository, times(1)).findById(fileId); + } + + @Test + @DisplayName("파일 다운로드 실패 - 권한이 없음") + void downloadFileFailByNoAuthority() { + // given + var fileId = 1L; + var folderId = 1L; var mockFolderMetaData = FolderMetaData.builder() .folderName("folderName") .userName(MOCK_USER_NAME) - .parentFolderId(folderId) + .parentFolderId(0L) .build(); - given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); given(folderRepository.findByFolderId(folderId)).willReturn(Optional.of(mockFolderMetaData)); - given(mockResourceLoader.getResource(any())).willReturn(mockResource); - given(storagePathService.createPathByUser(MOCK_USER_NAME)).willReturn( - Paths.get(MOCK_ROOT_PATH, MOCK_USER_NAME)); - - given(mockResource.exists()).willReturn(true); // when - fileService.downloadFile(fileId, MOCK_USER_NAME, folderId); + var exception = assertThrows(ServiceException.class, + () -> fileService.downloadFile(fileId, "anonymous", folderId)); // then + assertEquals(ErrorCd.NO_PERMISSION.name(), exception.getErrCode()); verify(folderRepository, times(1)).findByFolderId(folderId); - verify(fileRepository, times(1)).findById(fileId); } + @Test @DisplayName("파일 다운로드 실패") - void downloadFileFail() { + void downloadFileFailByFileNotExist() { // given var fileId = 1L; var folderId = 1L; @@ -286,9 +316,9 @@ void downloadFileFail() { () -> fileService.downloadFile(fileId, MOCK_USER_NAME, folderId)); // then + assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); verify(folderRepository, times(1)).findByFolderId(folderId); verify(fileRepository, times(1)).findById(fileId); - assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); } @Test @@ -340,13 +370,67 @@ void moveFile() { verify(folderRepository, times(1)).findByFolderId(targetFolderId); } + @Test + @DisplayName("파일 이동 실패 - 파일 데이터 조회 실패") + void moveFileFailByFileMetaDataNotFound() { + // given + var fileId = 1L; + var targetFolderId = 1L; + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + + given(folderRepository.findByFolderId(targetFolderId)).willReturn(Optional.of(mockFolderMetaData)); + given(fileRepository.findById(fileId)).willReturn(Optional.empty()); + + // when + var exception = assertThrows(ServiceException.class, + () -> fileService.moveFile(fileId, targetFolderId, MOCK_USER_NAME)); + + // then + assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(targetFolderId); + verify(fileRepository, times(1)).findById(fileId); + } + + @Test + @DisplayName("파일 이동 실패 - 권한이 없음") + void moveFileFailByNoAuthority() { + // given + var fileId = 1L; + var targetFolderId = 1L; + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + + given(folderRepository.findByFolderId(targetFolderId)).willReturn(Optional.of(mockFolderMetaData)); + + // when + var exception = assertThrows(ServiceException.class, + () -> fileService.moveFile(fileId, targetFolderId, "anonymous")); + + // then + assertEquals(ErrorCd.NO_PERMISSION.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(targetFolderId); + } + @Test @DisplayName("파일 이동 실패 - 파일 정보 없음") void moveFileFailByFileNotFound() { // given var fileId = 1L; var targetFolderId = 1234L; + var mockFolderMetaData = FolderMetaData.builder() + .folderName("folderName") + .userName(MOCK_USER_NAME) + .parentFolderId(0L) + .build(); + given(folderRepository.findByFolderId(targetFolderId)).willReturn(Optional.of(mockFolderMetaData)); given(fileRepository.findById(fileId)).willReturn(Optional.empty()); // when @@ -355,8 +439,8 @@ void moveFileFailByFileNotFound() { // then assertEquals(ErrorCd.FILE_NOT_EXIST.name(), exception.getErrCode()); + verify(folderRepository, times(1)).findByFolderId(targetFolderId); verify(fileRepository, times(1)).findById(fileId); - verify(folderRepository, times(0)).findByFolderId(targetFolderId); } @Test @@ -365,17 +449,6 @@ void moveFileFailByFolderNotFound() { // given var fileId = 1L; var targetFolderId = 1234L; - - var mockFileMetaData = FileMetaData.builder() - .fileName(MOCK_FILE_NAME) - .fileStorageName(MOCK_FILE_STORAGE_NAME) - .userName(MOCK_USER_NAME) - .size(MOCK_SIZE) - .mime(MOCK_CONTENT_TYPE) - .folderId(1L) - .build(); - - given(fileRepository.findById(fileId)).willReturn(Optional.of(mockFileMetaData)); given(folderRepository.findByFolderId(targetFolderId)).willReturn(Optional.empty()); // when @@ -384,7 +457,6 @@ void moveFileFailByFolderNotFound() { // then assertEquals(ErrorCd.FOLDER_NOT_EXIST.name(), exception.getErrCode()); - verify(fileRepository, times(1)).findById(fileId); verify(folderRepository, times(1)).findByFolderId(targetFolderId); } From d9796b06aba04b24490b68597cfb40668c7f681b Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 04:07:35 +0900 Subject: [PATCH 12/15] =?UTF-8?q?style=20:=20=EC=BD=94=EB=93=9C=20?= =?UTF-8?q?=EC=8A=A4=ED=83=80=EC=9D=BC=EC=97=90=20=EB=A7=9E=EC=B6=B0=20?= =?UTF-8?q?=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java index b75d4c7..eec6194 100644 --- a/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java +++ b/src/main/java/com/c4cometrue/mystorage/dto/request/folder/GetSubInfoReq.java @@ -7,4 +7,4 @@ public record GetSubInfoReq( @Positive(message = "folder id should be positive") long folderId, @Min(value = 0, message = "page number should be 0 or positive") int page ) { -} \ No newline at end of file +} From 7d48a93c099fe986458d9a4a99c56bfe5c57dfda Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 04:21:03 +0900 Subject: [PATCH 13/15] =?UTF-8?q?refactor=20:=20Pageable=20=EA=B0=9D?= =?UTF-8?q?=EC=B2=B4=20=EC=84=9C=EB=B2=84=20=EB=82=B4=EB=B6=80=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Pageable을 Client에서 전달받지 않고, pageNumber에 따라 PageRequest 객체를 생성합니다. - 이때 pageSize는 상수로 추출했습니다. --- .../mystorage/service/FolderService.java | 5 ++++- .../controller/FolderControllerTest.java | 20 ++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java index b6d76ff..a1e5af4 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java @@ -30,6 +30,7 @@ public class FolderService { private final FolderRepository folderRepository; private final FileRepository fileRepository; private final DeleteLogRepository deleteLogRepository; + private static final int PAGE_SIZE = 50; /** * 특정 폴더의 대략적인 정보 반환 @@ -132,6 +133,7 @@ public void updateFolderName(long folderId, long parentFolderId, String userName */ public List getFiles(long folderId, int page) { Page filePage = fileRepository.findAllByFolderId(folderId, PageRequest.of(page, 50)); + Page filePage = fileRepository.findAllByFolderId(folderId, PageRequest.of(page, PAGE_SIZE)); LinkedList result = new LinkedList<>(); for (FileMetaData fileMetaData : filePage) { @@ -149,6 +151,8 @@ public List getFiles(long folderId, int page) { */ public List getFolders(long folderId, int page) { Page folderList = folderRepository.findAllByParentFolderId(folderId, PageRequest.of(page, 50)); + Page folderList = folderRepository.findAllByParentFolderId(folderId, + PageRequest.of(page, PAGE_SIZE)); LinkedList result = new LinkedList<>(); for (FolderMetaData folderMetaData : folderList) { @@ -206,7 +210,6 @@ public void deleteAllFile(long folderId) { } } - /** * 폴더를 이동한다. * 논리적으로는 하위의 모든 폴더와 파일이 이동해야 하지만 일일이 수정 할 필요가 없다. diff --git a/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java b/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java index 9b71dd2..02203a6 100644 --- a/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/controller/FolderControllerTest.java @@ -9,11 +9,11 @@ import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.data.domain.PageRequest; import com.c4cometrue.mystorage.dto.request.folder.CreateFolderReq; import com.c4cometrue.mystorage.dto.request.folder.DeleteFolderReq; import com.c4cometrue.mystorage.dto.request.folder.GetFolderReq; +import com.c4cometrue.mystorage.dto.request.folder.GetSubInfoReq; import com.c4cometrue.mystorage.dto.request.folder.MoveFolderReq; import com.c4cometrue.mystorage.dto.request.folder.UpdateFolderNameReq; import com.c4cometrue.mystorage.service.FolderService; @@ -43,13 +43,14 @@ void getFolderData() { void getFolderSubFolders() { // given var folderId = 1L; - var pageRequest = PageRequest.of(0, 50); + var pageNumber = 1; + var req = new GetSubInfoReq(folderId, pageNumber); // when - folderController.getSubFolders(folderId, pageRequest); + folderController.getSubFolders(req); // then - verify(folderService, times(1)).getFolders(folderId, pageRequest.getPageNumber()); + verify(folderService, times(1)).getFolders(folderId, pageNumber); } @@ -59,13 +60,14 @@ void getFolderSubFolders() { void getFolderSubFiles() { // given var folderId = 1L; - var pageRequest = PageRequest.of(0, 50); + var pageNumber = 1; + var req = new GetSubInfoReq(folderId, pageNumber); // when - folderController.getSubFiles(folderId, pageRequest); + folderController.getSubFiles(req); // then - verify(folderService, times(1)).getFiles(folderId, pageRequest.getPageNumber()); + verify(folderService, times(1)).getFiles(folderId, pageNumber); } @@ -73,7 +75,7 @@ void getFolderSubFiles() { @DisplayName("폴더 생성") void createFolder() { // given - var req = new CreateFolderReq(0L, MOCK_USER_NAME, "my_folder"); + var req = new CreateFolderReq(1L, MOCK_USER_NAME, "my_folder"); // when folderController.createFolder(req); @@ -86,7 +88,7 @@ void createFolder() { @DisplayName("폴더 이름 수정") void updateFolderName() { // given - var req = new UpdateFolderNameReq(1L, 0L, MOCK_USER_NAME, "new_folder"); + var req = new UpdateFolderNameReq(2L, 1L, MOCK_USER_NAME, "new_folder"); // when folderController.updateFolderName(req); From 3f2c19cf20cf9f5a8f9b3bf1056a9da1ed8ed7e3 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 04:23:14 +0900 Subject: [PATCH 14/15] =?UTF-8?q?fix=20:=20=EC=BD=94=EB=93=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/c4cometrue/mystorage/service/FolderService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java index a1e5af4..b99e634 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java @@ -150,7 +150,6 @@ public List getFiles(long folderId, int page) { * @return 하위 폴더 목록 */ public List getFolders(long folderId, int page) { - Page folderList = folderRepository.findAllByParentFolderId(folderId, PageRequest.of(page, 50)); Page folderList = folderRepository.findAllByParentFolderId(folderId, PageRequest.of(page, PAGE_SIZE)); LinkedList result = new LinkedList<>(); From 230ce8db9894dce5c313ada19b695e89854a9571 Mon Sep 17 00:00:00 2001 From: pear96 Date: Sat, 2 Mar 2024 04:26:34 +0900 Subject: [PATCH 15/15] =?UTF-8?q?fix=20:=20=EC=BD=94=EB=93=9C=20=EC=98=A4?= =?UTF-8?q?=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../java/com/c4cometrue/mystorage/service/FolderService.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java index b99e634..c22daa8 100644 --- a/src/main/java/com/c4cometrue/mystorage/service/FolderService.java +++ b/src/main/java/com/c4cometrue/mystorage/service/FolderService.java @@ -132,7 +132,6 @@ public void updateFolderName(long folderId, long parentFolderId, String userName * @return 파일 목록 */ public List getFiles(long folderId, int page) { - Page filePage = fileRepository.findAllByFolderId(folderId, PageRequest.of(page, 50)); Page filePage = fileRepository.findAllByFolderId(folderId, PageRequest.of(page, PAGE_SIZE)); LinkedList result = new LinkedList<>();