From dbdd8e9f803db26b75dbf7d930c1231afd403adc Mon Sep 17 00:00:00 2001 From: kcc Date: Mon, 13 May 2024 23:38:32 +0900 Subject: [PATCH 01/24] feat : Add shareLink MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - link는 LocalDate.now + UUID로 구성 - link에 대한 중복 검사 진행 - link에 인덱스 설정 --- settings.gradle | 1 + .../mystorage/exception/ErrorCode.java | 48 +++++++------- .../mystorage/file/FileRepository.java | 19 +++--- .../mystorage/fileshare/FileShare.java | 45 ++++++++++++++ .../fileshare/FileShareController.java | 25 ++++++++ .../fileshare/FileShareRepository.java | 7 +++ .../mystorage/fileshare/FileShareService.java | 48 ++++++++++++++ .../fileshare/dto/CreateShareFileReq.java | 9 +++ .../fileshare/dto/CreateShareFileRes.java | 10 +++ todo/Todo.txt | 62 ++++--------------- 10 files changed, 191 insertions(+), 83 deletions(-) create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java diff --git a/settings.gradle b/settings.gradle index d045f9c..b9e209f 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1,2 @@ rootProject.name = 'mystorage' + diff --git a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java index a1846b8..f12d04e 100644 --- a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java +++ b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java @@ -8,37 +8,39 @@ @Getter @AllArgsConstructor public enum ErrorCode { - UNAUTHORIZED_FILE_ACCESS(HttpStatus.FORBIDDEN, "비정상적인 요청입니다."), + UNAUTHORIZED_FILE_ACCESS(HttpStatus.FORBIDDEN, "비정상적인 요청입니다."), - CANNOT_FOUND_FILE(HttpStatus.NOT_FOUND, "해당 파일을 찾을 수 없습니다."), + CANNOT_FOUND_FILE(HttpStatus.NOT_FOUND, "해당 파일을 찾을 수 없습니다."), - FILE_COPY_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파일 복사 중 오류가 발생했습니다."), + FILE_COPY_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파일 복사 중 오류가 발생했습니다."), - FILE_DELETE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파일 삭제 중 오류가 발생했습니다."), + FILE_DELETE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "파일 삭제 중 오류가 발생했습니다."), - DUPLICATE_FILE_NAME(HttpStatus.BAD_REQUEST, "파일 업로드에 중복이 발생 했습니다"), + DUPLICATE_FILE_NAME(HttpStatus.BAD_REQUEST, "파일 업로드에 중복이 발생 했습니다"), - FOLDER_CREATE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "폴더 생성 중 오류가 발생했습니다"), - UNAUTHORIZED_FOLDER_ACCESS(HttpStatus.FORBIDDEN, "비정상적인 요청입니다."), - DUPLICATE_FOLDER_NAME(HttpStatus.BAD_REQUEST, "폴더 업로드에 중복이 발생 했습니다"), - DUPLICATE_SERVER_FOLDER_NAME(HttpStatus.BAD_REQUEST, "폴더 UUID 중복이 발생 했습니다"), - CANNOT_FOUND_FOLDER(HttpStatus.NOT_FOUND, "해당 폴더를 찾을 수 없습니다."), + FOLDER_CREATE_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "폴더 생성 중 오류가 발생했습니다"), + UNAUTHORIZED_FOLDER_ACCESS(HttpStatus.FORBIDDEN, "비정상적인 요청입니다."), + DUPLICATE_FOLDER_NAME(HttpStatus.BAD_REQUEST, "폴더 업로드에 중복이 발생 했습니다"), + DUPLICATE_SERVER_FOLDER_NAME(HttpStatus.BAD_REQUEST, "폴더 UUID 중복이 발생 했습니다"), + CANNOT_FOUND_FOLDER(HttpStatus.NOT_FOUND, "해당 폴더를 찾을 수 없습니다."), - DUPLICATE_BASE_PATH(HttpStatus.BAD_REQUEST, "기본 경로 생성에 중복이 발생했습니다"), + DUPLICATE_BASE_PATH(HttpStatus.BAD_REQUEST, "기본 경로 생성에 중복이 발생했습니다"), - MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 맴버를 찾지 못했습니다"), - EXCEEDED_CAPACITY(HttpStatus.INSUFFICIENT_STORAGE, "더 이상 업로드 할 수 없습니다"), - INVALID_OPERATION(HttpStatus.BAD_REQUEST, "사용 중인 공간보다 많은 공간은 해제할 수 없습니다"), - VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "유효하지 않은 요청입니다."); + MEMBER_NOT_FOUND(HttpStatus.NOT_FOUND, "해당 맴버를 찾지 못했습니다"), + EXCEEDED_CAPACITY(HttpStatus.INSUFFICIENT_STORAGE, "더 이상 업로드 할 수 없습니다"), + INVALID_OPERATION(HttpStatus.BAD_REQUEST, "사용 중인 공간보다 많은 공간은 해제할 수 없습니다"), + VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "유효하지 않은 요청입니다."), - private final HttpStatus httpStatus; - private final String message; + DUPLICATE_SHARE_LINK(HttpStatus.INTERNAL_SERVER_ERROR, "링크 생성에 중복이 발생했습니다"); - public ServiceException serviceException() { - return new ServiceException(this.name(), message); - } + private final HttpStatus httpStatus; + private final String message; - public ServiceException serviceException(String debugMessage, Object... debugMessageArgs) { - return new ServiceException(this.name(), message, String.format(debugMessage, debugMessageArgs)); - } + public ServiceException serviceException() { + return new ServiceException(this.name(), message); + } + + public ServiceException serviceException(String debugMessage, Object... debugMessageArgs) { + return new ServiceException(this.name(), message, String.format(debugMessage, debugMessageArgs)); + } } diff --git a/src/main/java/com/c4cometrue/mystorage/file/FileRepository.java b/src/main/java/com/c4cometrue/mystorage/file/FileRepository.java index 661d0b1..9200080 100644 --- a/src/main/java/com/c4cometrue/mystorage/file/FileRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/file/FileRepository.java @@ -5,23 +5,22 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Query; public interface FileRepository extends JpaRepository { - Optional findByIdAndUploaderId(Long id, Long uploaderId); + Optional findByIdAndUploaderId(Long id, Long uploaderId); - boolean existsByParentIdAndOriginalFileName(Long parentId, String fileName); + boolean existsByParentIdAndOriginalFileName(Long parentId, String fileName); - List findByParentIdAndUploaderId(Long parentId, Long userId); + List findByParentIdAndUploaderId(Long parentId, Long userId); - Boolean existsByIdAndUploaderId(Long parentId, Long userId); + Boolean existsByIdAndUploaderId(Long parentId, Long userId); - List findAllByParentIdAndUploaderIdOrderByIdDesc(Long parentId, Long uploaderId, Pageable page); + List findAllByParentIdAndUploaderIdOrderByIdDesc(Long parentId, Long uploaderId, Pageable page); - List findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(Long parentId, Long userId, Long cursorId, - Pageable pageable); + List findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(Long parentId, Long userId, Long cursorId, + Pageable pageable); - Boolean existsByParentIdAndUploaderIdAndIdLessThan(Long parentId, Long uploaderId, Long id); + Boolean existsByParentIdAndUploaderIdAndIdLessThan(Long parentId, Long uploaderId, Long id); - List findAllByParentId(Long parentId); + List findAllByParentId(Long parentId); } diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java new file mode 100644 index 0000000..11d4bdf --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java @@ -0,0 +1,45 @@ +package com.c4cometrue.mystorage.fileshare; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Index; +import jakarta.persistence.PrePersist; +import jakarta.persistence.Table; +import lombok.AccessLevel; +import lombok.Builder; +import lombok.Getter; +import lombok.NoArgsConstructor; + +@Entity +@Getter +@NoArgsConstructor(access = AccessLevel.PROTECTED) +@Table(name = "file_share", indexes = { + @Index(name = "idx_share_link", columnList = "shareLink") +}) +public class FileShare { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + private Long fileId; + @Column(nullable = false, unique = true) + private String shareLink; + @Column(updatable = false) + private ZonedDateTime createdAt; + + @Builder + public FileShare(Long fileId, String shareLink) { + this.fileId = fileId; + this.shareLink = shareLink; + } + + @PrePersist + public void prePersist() { + createdAt = ZonedDateTime.now(ZoneOffset.UTC); + } +} diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java new file mode 100644 index 0000000..733cc47 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java @@ -0,0 +1,25 @@ +package com.c4cometrue.mystorage.fileshare; + +import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; + +import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileReq; +import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileRes; + +import jakarta.validation.Valid; +import lombok.RequiredArgsConstructor; + +@RestController +@RequestMapping("/files/share") +@RequiredArgsConstructor +public class FileShareController { + private final FileShareService fileShareService; + + @PostMapping + public ResponseEntity createShareFile(@Valid CreateShareFileReq req) { + CreateShareFileRes res = fileShareService.createShareFileLink(req.fileId(), req.userId()); + return ResponseEntity.ok(res); + } +} diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java new file mode 100644 index 0000000..9f557c7 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java @@ -0,0 +1,7 @@ +package com.c4cometrue.mystorage.fileshare; + +import org.springframework.data.jpa.repository.JpaRepository; + +public interface FileShareRepository extends JpaRepository { + boolean existsByShareLink(String shareLink); +} diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java new file mode 100644 index 0000000..15426a5 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -0,0 +1,48 @@ +package com.c4cometrue.mystorage.fileshare; + +import java.time.LocalDateTime; +import java.util.UUID; + +import org.springframework.stereotype.Service; + +import com.c4cometrue.mystorage.exception.ErrorCode; +import com.c4cometrue.mystorage.file.FileDataHandlerService; +import com.c4cometrue.mystorage.file.FileMetadata; +import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileRes; + +import lombok.RequiredArgsConstructor; + +@Service +@RequiredArgsConstructor +public class FileShareService { + private final FileShareRepository fileShareRepository; + private final FileDataHandlerService fileRepository; + + public CreateShareFileRes createShareFileLink(Long fileId, Long userId) { + // 파일 찾기 + FileMetadata file = fileRepository.findBy(fileId, userId); + + // shareLink 생성 + String shareLink = LocalDateTime.now() + UUID.randomUUID().toString(); + checkDuplicate(shareLink); + + // 저장 + persist(fileId, shareLink); + + return CreateShareFileRes.of(file.getOriginalFileName(), shareLink); + } + + private void checkDuplicate(String sharedLink) { + if (fileShareRepository.existsByShareLink(sharedLink)) { + throw ErrorCode.DUPLICATE_SHARE_LINK.serviceException(); + } + } + + public void persist(Long fileId, String shareLink) { + FileShare fileShare = FileShare.builder() + .shareLink(shareLink) + .fileId(fileId) + .build(); + fileShareRepository.save(fileShare); + } +} diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java new file mode 100644 index 0000000..17a52c4 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java @@ -0,0 +1,9 @@ +package com.c4cometrue.mystorage.fileshare.dto; + +import jakarta.validation.constraints.Positive; + +public record CreateShareFileReq( + @Positive Long fileId, + @Positive Long userId +) { +} diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java new file mode 100644 index 0000000..e454d4d --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java @@ -0,0 +1,10 @@ +package com.c4cometrue.mystorage.fileshare.dto; + +public record CreateShareFileRes( + String fileName, + String sharedLink +) { + public static CreateShareFileRes of(String fileName, String sharedLink) { + return new CreateShareFileRes(fileName, sharedLink); + } +} diff --git a/todo/Todo.txt b/todo/Todo.txt index 36cd322..b65d200 100644 --- a/todo/Todo.txt +++ b/todo/Todo.txt @@ -1,50 +1,12 @@ -# 구현 해야할 것 -- [x] 일반 폴더 요약 -- [x] 루트 폴더 생성 로직 -- [x] 파일 업로드, 폴더 삭제 시 루트 폴더 사용 용량 변화 -- [x] 루트 폴더 요약 - -# 요구 사항 - -## 폴더 요약 -폴더 요약에는 다음 정보가 담겨야 한다 -1. 폴더 명 -2. 생성 날짜 -2. 수정 날짜 (하위 폴더 과업 발생 시에도 바뀌어야 한다) - -루트 폴더의 경우에는 -1. 하위 폴더 개수 -2. 하위 파일 개수 -3. 전체 파일 용량 -4. 가용 용량 (즉, 전체 파일의 크기가 2GB를 넘어간다면, 더 이상 파일 업로드가 불가능 합니다.) - -# 내 설계 -1. 파일 경로에 루트 폴더 이름(서버 저장명)이 들어간다 -2. 루트 폴더는 하나만 생성 가능하다 -3. 사용자 로그인 로직 만들면서 루트 폴더 생성하기 - -## 작업 순위 및 설계 -1. 사용자 로그인 (루트 로직 생성 로직) -2. 기존 폴더 생성 로직에서 parentId Long -> long - -3. 일반 폴더 요약 로직 만들기 (하위 폴더에서 변경 사항 생기면 상위 폴더 타서 수정 날짜 변경) - -4. 루트 폴더 요약 로직 만들기 -4-0. 테이블 분리 `루트 테이블 생성`, 폴더 테이블이 루트 테이블을 의존한다. 즉, 루트 테이블을 위한 별도의 서비스 레이어는 생성하지 않는 다 -4-1. 필드 : 유저 id(많이 조회되는 것이니 파일과 폴더에도 놔둔다), 경로, 최대 용량 (본 프로젝트에선 2GB로 제한, 별도의 enum , 상품 테이블 ㄴㄴ), 사용 용량 -루트 폴더 저장 경로(루트 폴더 저장 경로는 UUID + zoneTime -> 이 이유는 단순 UUID 만 할 경우 4-2 4-3 로직에서 파일과 폴더 개수를 체크하는 데 예상치 못한 문제가 발생 할 수 있기 때문 (다른 사용자의 폴더, 파일 개수를 체킹) 사용 용량도 이런 문제가 발생할 수 있기에) -4-2. 하위 파일 개수 -> 서버 저장 경로 인덱스 설정 그리고 검색 (루트 폴더는 스토리지위치/루트폴더 로 되어 있고 나머지는 스토리지위치/루트폴더/파일서버저장명) -4-3. 하위 폴더 개수 -> 서버 저장 경로 인덱스 설정 그리고 검색 (루트 폴더는 스토리지위치/루트폴더 로 되어 있고 나머지는 스토리지위치/루트폴더/파일서버저장명) - - -## 번외 : 루트 테이블을 만든 이유 -모든 폴더에 폴더 용량 필드 만들면 이에 따른 수정(parent Id를 타고타고 다 수정해야하니) (업로드, 삭제 시 수정) 이러면 아찔해지죠 - -> `루트 폴더`만 폴더 가용 용량 필드 가지고 있게 만들기 (업로드, 삭제 시 수정) - -> 그리고 루트 폴더는 자주 조회되니 && 루트 폴더만 가진 필드를 위해 다른 필드는 null 이 들어갈 필요가 없으니 - - -## 일반 파일과 폴더에 루트 폴더id가 있을 필요가 있을까? -사용자는 루트 폴더 하나만 가질 수 있다. 즉, 사용자id를 통해서 루트 폴더 정보를 뽑아 낼 수 있다. -기존 파일, 폴더에는 사용자id가 있기 때문에 이를 활용해서 루트 폴더 정보를 뽑는 다. - -폴더 공유 로직에는 파일 -> 소유자id, 업로드id 로 구성해야 할 듯 \ No newline at end of file +# Todo +- [x] 파일 공유 링크 생성 +- [] 공유 파일 다운 로드 + +# 설계 +- 공유 파일 데이터는 오전 3시에 일괄 삭제 + - 사용자 요청이 적은 시간 + - 별도 모듈에서 진행 + +- 시간 지역성 고려 + - 파일 공유의 경우 시간 지역성으로 성능 이점을 볼 수 있다 + - 캐시 사용 (현재 프로젝트 규모 상 memcache) From 4df23eed7ffed92edc7a94faa45320741b3171d7 Mon Sep 17 00:00:00 2001 From: kcc Date: Tue, 14 May 2024 00:31:16 +0900 Subject: [PATCH 02/24] test: Add create shareLink --- .../mystorage/fileshare/FileShareService.java | 4 +- .../fileshare/dto/CreateShareFileReq.java | 3 + .../fileshare/FileShareControllerTest.java | 33 +++++++++++ .../fileshare/FileShareServiceTest.java | 55 +++++++++++++++++++ 4 files changed, 93 insertions(+), 2 deletions(-) create mode 100644 src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java create mode 100644 src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java index 15426a5..609000c 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -16,11 +16,11 @@ @RequiredArgsConstructor public class FileShareService { private final FileShareRepository fileShareRepository; - private final FileDataHandlerService fileRepository; + private final FileDataHandlerService fileDataHandlerService; public CreateShareFileRes createShareFileLink(Long fileId, Long userId) { // 파일 찾기 - FileMetadata file = fileRepository.findBy(fileId, userId); + FileMetadata file = fileDataHandlerService.findBy(fileId, userId); // shareLink 생성 String shareLink = LocalDateTime.now() + UUID.randomUUID().toString(); diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java index 17a52c4..3e76ead 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileReq.java @@ -6,4 +6,7 @@ public record CreateShareFileReq( @Positive Long fileId, @Positive Long userId ) { + public static CreateShareFileReq of(Long fileId, Long userId) { + return new CreateShareFileReq(fileId, userId); + } } diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java new file mode 100644 index 0000000..59a0df2 --- /dev/null +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java @@ -0,0 +1,33 @@ +package com.c4cometrue.mystorage.fileshare; + +import static com.c4cometrue.mystorage.TestConstants.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileReq; + +@DisplayName("공유파일 컨트롤러 테스트") +class FileShareControllerTest { + @InjectMocks + private FileShareController fileShareController; + @Mock + private FileShareService fileShareService; + + @BeforeEach + public void setUp() { + MockitoAnnotations.openMocks(this); + } + + @Test + @DisplayName("공유링크 생성 테스트") + void createShareLink() { + fileShareController.createShareFile(CreateShareFileReq.of(FILE_ID, USER_ID)); + verify(fileShareService, times(1)).createShareFileLink(FILE_ID, USER_ID); + } +} diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java new file mode 100644 index 0000000..16c4f32 --- /dev/null +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java @@ -0,0 +1,55 @@ +package com.c4cometrue.mystorage.fileshare; + +import static com.c4cometrue.mystorage.TestConstants.*; +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +import com.c4cometrue.mystorage.exception.ErrorCode; +import com.c4cometrue.mystorage.exception.ServiceException; +import com.c4cometrue.mystorage.file.FileDataHandlerService; +import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileRes; + +@DisplayName("공유파일 서비스 테스트") +@ExtendWith(MockitoExtension.class) +class FileShareServiceTest { + @InjectMocks + private FileShareService fileShareService; + @Mock + private FileShareRepository fileShareRepository; + @Mock + private FileDataHandlerService fileDataHandlerService; + + @Test + @DisplayName("공유링크 생성 성공 테스트") + void createShareLink() { + when(fileDataHandlerService.findBy(FILE_ID, USER_ID)).thenReturn(FILE_METADATA); + when(fileShareRepository.existsByShareLink(anyString())).thenReturn(false); + + CreateShareFileRes res = fileShareService.createShareFileLink(FILE_ID, USER_ID); + + verify(fileDataHandlerService, times(1)).findBy(FILE_ID, USER_ID); + verify(fileShareRepository, times(1)).existsByShareLink(any()); + assertNotNull(res); + assertEquals(FILE_METADATA.getOriginalFileName(), res.fileName()); + assertNotNull(res.sharedLink()); + } + + @Test + @DisplayName("공유링크 생성 실패 테스트 : 중복된 링크 생성") + void createShareLinkFailTestNotAuthorize() { + when(fileDataHandlerService.findBy(FILE_ID, USER_ID)).thenReturn(FILE_METADATA); + when(fileShareRepository.existsByShareLink(anyString())).thenReturn(true); + + ServiceException thrown = assertThrows(ServiceException.class, + () -> fileShareService.createShareFileLink(FILE_ID, USER_ID)); + + assertEquals(ErrorCode.DUPLICATE_SHARE_LINK.name(), thrown.getErrCode()); + } +} From fd174008f5122a8344e5aac95e4c9c6f950dc60b Mon Sep 17 00:00:00 2001 From: kcc Date: Tue, 14 May 2024 01:06:40 +0900 Subject: [PATCH 03/24] feat: Add downloadShareFile --- .../mystorage/exception/ErrorCode.java | 3 +- .../file/FileDataHandlerService.java | 96 ++++++++++--------- .../fileshare/FileShareController.java | 13 ++- .../fileshare/FileShareRepository.java | 4 + .../mystorage/fileshare/FileShareService.java | 40 +++++++- .../fileshare/dto/DownloadShareFileReq.java | 12 +++ .../fileshare/dto/DownloadShareFileRes.java | 9 ++ 7 files changed, 125 insertions(+), 52 deletions(-) create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileReq.java create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java diff --git a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java index f12d04e..c8447d8 100644 --- a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java +++ b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java @@ -31,7 +31,8 @@ public enum ErrorCode { INVALID_OPERATION(HttpStatus.BAD_REQUEST, "사용 중인 공간보다 많은 공간은 해제할 수 없습니다"), VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "유효하지 않은 요청입니다."), - DUPLICATE_SHARE_LINK(HttpStatus.INTERNAL_SERVER_ERROR, "링크 생성에 중복이 발생했습니다"); + DUPLICATE_SHARE_LINK(HttpStatus.INTERNAL_SERVER_ERROR, "링크 생성에 중복이 발생했습니다"), + NOT_FRESH_LINK(HttpStatus.BAD_REQUEST, "만료된 링크입니다."); private final HttpStatus httpStatus; private final String message; diff --git a/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java b/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java index eefe8ee..7901673 100644 --- a/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java +++ b/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java @@ -13,50 +13,54 @@ @Service @RequiredArgsConstructor public class FileDataHandlerService { - private final FileRepository fileRepository; - - @Transactional - public void deleteBy(Long fileId) { - existBy(fileId); - fileRepository.deleteById(fileId); - } - - private void existBy(Long fileId) { - if (!fileRepository.existsById(fileId)) { - throw ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}", fileId); - } - } - - public FileMetadata findBy(Long fileId, Long userId) { - return fileRepository.findByIdAndUploaderId(fileId, userId) - .orElseThrow(() -> ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}, userId : {}", fileId, - userId)); - } - - public void persist(FileMetadata fileMetadata) { - fileRepository.save(fileMetadata); - } - - public void duplicateBy(Long parentId, String fileName) { - if (fileRepository.existsByParentIdAndOriginalFileName(parentId, fileName)) { - throw ErrorCode.DUPLICATE_FILE_NAME.serviceException("fileName : {}", fileName); - } - } - - public List getFileList(Long parentId, Long cursorId, Long userId, Pageable page) { - return cursorId == null ? fileRepository.findAllByParentIdAndUploaderIdOrderByIdDesc(parentId, userId, page) - : fileRepository.findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(parentId, cursorId, userId, page); - } - - public Boolean hashNext(Long parentId, Long userId, Long lastIdOfList) { - return fileRepository.existsByParentIdAndUploaderIdAndIdLessThan(parentId, userId, lastIdOfList); - } - - public List findAllBy(Long parentId) { - return fileRepository.findAllByParentId(parentId); - } - - public void deleteAll(List fileMetadataList) { - fileRepository.deleteAll(fileMetadataList); - } + private final FileRepository fileRepository; + + @Transactional + public void deleteBy(Long fileId) { + existBy(fileId); + fileRepository.deleteById(fileId); + } + + private void existBy(Long fileId) { + if (!fileRepository.existsById(fileId)) { + throw ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}", fileId); + } + } + + public FileMetadata findBy(Long fileId, Long userId) { + return fileRepository.findByIdAndUploaderId(fileId, userId) + .orElseThrow(() -> ErrorCode.CANNOT_FOUND_FILE.serviceException("fileId : {}, userId : {}", fileId, + userId)); + } + + public void persist(FileMetadata fileMetadata) { + fileRepository.save(fileMetadata); + } + + public void duplicateBy(Long parentId, String fileName) { + if (fileRepository.existsByParentIdAndOriginalFileName(parentId, fileName)) { + throw ErrorCode.DUPLICATE_FILE_NAME.serviceException("fileName : {}", fileName); + } + } + + public List getFileList(Long parentId, Long cursorId, Long userId, Pageable page) { + return cursorId == null ? fileRepository.findAllByParentIdAndUploaderIdOrderByIdDesc(parentId, userId, page) + : fileRepository.findByParentIdAndUploaderIdAndIdLessThanOrderByIdDesc(parentId, cursorId, userId, page); + } + + public Boolean hashNext(Long parentId, Long userId, Long lastIdOfList) { + return fileRepository.existsByParentIdAndUploaderIdAndIdLessThan(parentId, userId, lastIdOfList); + } + + public List findAllBy(Long parentId) { + return fileRepository.findAllByParentId(parentId); + } + + public void deleteAll(List fileMetadataList) { + fileRepository.deleteAll(fileMetadataList); + } + + public FileMetadata findBy(Long fileId) { + return fileRepository.findById(fileId).orElseThrow(ErrorCode.CANNOT_FOUND_FILE::serviceException); + } } diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java index 733cc47..9e58a2c 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java @@ -1,12 +1,17 @@ package com.c4cometrue.mystorage.fileshare; import org.springframework.http.ResponseEntity; +import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileReq; import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileRes; +import com.c4cometrue.mystorage.fileshare.dto.DownloadShareFileReq; +import com.c4cometrue.mystorage.fileshare.dto.DownloadShareFileRes; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; @@ -18,8 +23,14 @@ public class FileShareController { private final FileShareService fileShareService; @PostMapping - public ResponseEntity createShareFile(@Valid CreateShareFileReq req) { + public ResponseEntity createShareFile(@Valid @RequestBody CreateShareFileReq req) { CreateShareFileRes res = fileShareService.createShareFileLink(req.fileId(), req.userId()); return ResponseEntity.ok(res); } + + @GetMapping("/download") + public ResponseEntity downloadShareFile(@Valid @RequestBody DownloadShareFileReq req) { + DownloadShareFileRes res = fileShareService.downloadShareFile(req.shareLink(), req.userPath()); + return ResponseEntity.ok(res); + } } diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java index 9f557c7..8df76eb 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java @@ -1,7 +1,11 @@ package com.c4cometrue.mystorage.fileshare; +import java.util.Optional; + import org.springframework.data.jpa.repository.JpaRepository; public interface FileShareRepository extends JpaRepository { boolean existsByShareLink(String shareLink); + + Optional findByShareLink(String shareLink); } diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java index 609000c..0ae2f72 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -1,14 +1,21 @@ package com.c4cometrue.mystorage.fileshare; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.time.Duration; import java.time.LocalDateTime; +import java.time.ZonedDateTime; import java.util.UUID; +import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.c4cometrue.mystorage.exception.ErrorCode; import com.c4cometrue.mystorage.file.FileDataHandlerService; import com.c4cometrue.mystorage.file.FileMetadata; import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileRes; +import com.c4cometrue.mystorage.fileshare.dto.DownloadShareFileRes; +import com.c4cometrue.mystorage.util.FileUtil; import lombok.RequiredArgsConstructor; @@ -18,6 +25,9 @@ public class FileShareService { private final FileShareRepository fileShareRepository; private final FileDataHandlerService fileDataHandlerService; + @Value("${file.buffer}") + private int bufferSize; + public CreateShareFileRes createShareFileLink(Long fileId, Long userId) { // 파일 찾기 FileMetadata file = fileDataHandlerService.findBy(fileId, userId); @@ -39,10 +49,32 @@ private void checkDuplicate(String sharedLink) { } public void persist(Long fileId, String shareLink) { - FileShare fileShare = FileShare.builder() - .shareLink(shareLink) - .fileId(fileId) - .build(); + FileShare fileShare = FileShare.builder().shareLink(shareLink).fileId(fileId).build(); fileShareRepository.save(fileShare); } + + public DownloadShareFileRes downloadShareFile(String sharedLink, String userPath) { + FileShare fileShare = fileShareRepository.findByShareLink(sharedLink) + .orElseThrow(ErrorCode.DUPLICATE_SHARE_LINK::serviceException); + + isValid(fileShare.getCreatedAt()); + FileMetadata fileMetadata = fileDataHandlerService.findBy(fileShare.getFileId()); + + Path originalPath = Paths.get(fileMetadata.getFilePath()); + Path userDesignatedPath = Paths.get(userPath).resolve(fileMetadata.getOriginalFileName()).normalize(); + + FileUtil.download(originalPath, userDesignatedPath, bufferSize); + + return DownloadShareFileRes.of(fileMetadata.getOriginalFileName()); + } + + private void isValid(ZonedDateTime createTimeInLink) { + ZonedDateTime now = ZonedDateTime.now(); + Duration duration = Duration.between(createTimeInLink, now); + Duration maxTime = Duration.ofHours(3); + + if (duration.compareTo(maxTime) > 0) { + throw ErrorCode.NOT_FRESH_LINK.serviceException(); + } + } } diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileReq.java b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileReq.java new file mode 100644 index 0000000..428b90b --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileReq.java @@ -0,0 +1,12 @@ +package com.c4cometrue.mystorage.fileshare.dto; + +import jakarta.validation.constraints.NotBlank; + +public record DownloadShareFileReq( + @NotBlank String shareLink, + @NotBlank String userPath +) { + public static DownloadShareFileReq of(String shareLink, String userPath) { + return new DownloadShareFileReq(shareLink, userPath); + } +} diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java new file mode 100644 index 0000000..102d07c --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java @@ -0,0 +1,9 @@ +package com.c4cometrue.mystorage.fileshare.dto; + +public record DownloadShareFileRes( + String fileName +) { + public static DownloadShareFileRes of(String fileName) { + return new DownloadShareFileRes(fileName); + } +} From 916c1533a718ac3973c8def13bfe6e572192d2cc Mon Sep 17 00:00:00 2001 From: kcc Date: Tue, 14 May 2024 01:37:31 +0900 Subject: [PATCH 04/24] refacot: FileUtil.download --- .../com/c4cometrue/mystorage/file/FileService.java | 5 +---- .../mystorage/fileshare/FileShareService.java | 6 +----- .../java/com/c4cometrue/mystorage/util/FileUtil.java | 12 ++++++++++++ 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/file/FileService.java b/src/main/java/com/c4cometrue/mystorage/file/FileService.java index d39a2b4..d828cdc 100644 --- a/src/main/java/com/c4cometrue/mystorage/file/FileService.java +++ b/src/main/java/com/c4cometrue/mystorage/file/FileService.java @@ -61,10 +61,7 @@ protected void uploadFile(Long userId, Long rootId, BigDecimal fileSize, FileMet public void downloadFile(Long fileId, String userPath, Long userId) { FileMetadata fileMetadata = fileDataHandlerService.findBy(fileId, userId); - Path originalPath = Paths.get(fileMetadata.getFilePath()); - Path userDesignatedPath = Paths.get(userPath).resolve(fileMetadata.getOriginalFileName()).normalize(); - - FileUtil.download(originalPath, userDesignatedPath, bufferSize); + FileUtil.download(fileMetadata, userPath); } @Transactional diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java index 0ae2f72..08777c7 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -60,11 +60,7 @@ public DownloadShareFileRes downloadShareFile(String sharedLink, String userPath isValid(fileShare.getCreatedAt()); FileMetadata fileMetadata = fileDataHandlerService.findBy(fileShare.getFileId()); - Path originalPath = Paths.get(fileMetadata.getFilePath()); - Path userDesignatedPath = Paths.get(userPath).resolve(fileMetadata.getOriginalFileName()).normalize(); - - FileUtil.download(originalPath, userDesignatedPath, bufferSize); - + FileUtil.download(fileMetadata, userPath); return DownloadShareFileRes.of(fileMetadata.getOriginalFileName()); } diff --git a/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java b/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java index e09e8d5..db2b189 100644 --- a/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java +++ b/src/main/java/com/c4cometrue/mystorage/util/FileUtil.java @@ -5,16 +5,22 @@ import java.io.OutputStream; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; +import org.springframework.beans.factory.annotation.Value; import org.springframework.web.multipart.MultipartFile; import com.c4cometrue.mystorage.exception.ErrorCode; +import com.c4cometrue.mystorage.file.FileMetadata; public class FileUtil { private FileUtil() { throw new AssertionError("should not be invoke"); } + @Value("${file.buffer}") + private static int bufferSize; + public static void uploadFile(MultipartFile file, Path path, int bufferSize) { try (InputStream is = file.getInputStream(); OutputStream os = Files.newOutputStream(path)) { byte[] buffer = new byte[bufferSize]; @@ -47,4 +53,10 @@ public static void delete(Path path) { throw ErrorCode.FILE_DELETE_ERROR.serviceException(); } } + + public static void download(FileMetadata fileMetadata, String userPath) { + Path originalPath = Paths.get(fileMetadata.getFilePath()); + Path userDesignatedPath = Paths.get(userPath).resolve(fileMetadata.getOriginalFileName()).normalize(); + FileUtil.download(originalPath, userDesignatedPath, bufferSize); + } } From 4f3be8a1d4d86f06d4a79545506995b087de24b7 Mon Sep 17 00:00:00 2001 From: kcc Date: Tue, 14 May 2024 02:24:41 +0900 Subject: [PATCH 05/24] test: Add download shareFile --- .../mystorage/fileshare/FileShareService.java | 5 -- .../c4cometrue/mystorage/TestConstants.java | 1 + .../fileshare/FileShareControllerTest.java | 10 +++- .../fileshare/FileShareServiceTest.java | 57 +++++++++++++++++++ 4 files changed, 67 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java index 08777c7..6d407ba 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -1,7 +1,5 @@ package com.c4cometrue.mystorage.fileshare; -import java.nio.file.Path; -import java.nio.file.Paths; import java.time.Duration; import java.time.LocalDateTime; import java.time.ZonedDateTime; @@ -25,9 +23,6 @@ public class FileShareService { private final FileShareRepository fileShareRepository; private final FileDataHandlerService fileDataHandlerService; - @Value("${file.buffer}") - private int bufferSize; - public CreateShareFileRes createShareFileLink(Long fileId, Long userId) { // 파일 찾기 FileMetadata file = fileDataHandlerService.findBy(fileId, userId); diff --git a/src/test/java/com/c4cometrue/mystorage/TestConstants.java b/src/test/java/com/c4cometrue/mystorage/TestConstants.java index edbfbbc..b667d88 100644 --- a/src/test/java/com/c4cometrue/mystorage/TestConstants.java +++ b/src/test/java/com/c4cometrue/mystorage/TestConstants.java @@ -21,6 +21,7 @@ public class TestConstants { public static final String STORED_ROOT_FOLDER_NAME = RootFolderMetadata.storedName(); public static final Long FILE_ID = 1L; public static final String USER_PATH = "C:\\Users\\g2c10\\OneDrive\\C4\\down"; + public static final String SHARE_Link = "alskdjiopqjwnioen1222lnm"; public static final String ORIGINAL_FILE_NAME = "청천"; public static final String STORED_FILE_NAME = "청천12345"; public static final String USER_FOLDER_NAME = "폴더"; diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java index 59a0df2..9acec89 100644 --- a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareControllerTest.java @@ -11,6 +11,7 @@ import org.mockito.MockitoAnnotations; import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileReq; +import com.c4cometrue.mystorage.fileshare.dto.DownloadShareFileReq; @DisplayName("공유파일 컨트롤러 테스트") class FileShareControllerTest { @@ -26,8 +27,15 @@ public void setUp() { @Test @DisplayName("공유링크 생성 테스트") - void createShareLink() { + void createShareLinkTest() { fileShareController.createShareFile(CreateShareFileReq.of(FILE_ID, USER_ID)); verify(fileShareService, times(1)).createShareFileLink(FILE_ID, USER_ID); } + + @Test + @DisplayName("공유파일 다운로드 테스트") + void downloadShareFileTest() { + fileShareController.downloadShareFile(DownloadShareFileReq.of(anyString(), anyString())); + verify(fileShareService, times(1)).downloadShareFile(anyString(), anyString()); + } } diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java index 16c4f32..896367c 100644 --- a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java @@ -2,19 +2,33 @@ import static com.c4cometrue.mystorage.TestConstants.*; import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.BDDMockito.*; import static org.mockito.Mockito.*; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.file.Files; +import java.time.ZonedDateTime; +import java.util.Optional; + import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedStatic; +import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.web.multipart.MultipartFile; import com.c4cometrue.mystorage.exception.ErrorCode; import com.c4cometrue.mystorage.exception.ServiceException; import com.c4cometrue.mystorage.file.FileDataHandlerService; +import com.c4cometrue.mystorage.file.FileMetadata; import com.c4cometrue.mystorage.fileshare.dto.CreateShareFileRes; +import com.c4cometrue.mystorage.fileshare.dto.DownloadShareFileRes; +import com.c4cometrue.mystorage.util.FileUtil; @DisplayName("공유파일 서비스 테스트") @ExtendWith(MockitoExtension.class) @@ -52,4 +66,47 @@ void createShareLinkFailTestNotAuthorize() { assertEquals(ErrorCode.DUPLICATE_SHARE_LINK.name(), thrown.getErrCode()); } + + @Test + @DisplayName("공유파일 다운로드 성공 테스트") + void downloadShareFileTest() { + FileShare fileShare = mock(FileShare.class); + FileMetadata fileMetadata = mock(FileMetadata.class); + + when(fileShare.getCreatedAt()).thenReturn(ZonedDateTime.now().minusHours(1)); + when(fileShare.getFileId()).thenReturn(FILE_ID); + when(fileMetadata.getOriginalFileName()).thenReturn(ORIGINAL_FILE_NAME); + + when(fileShareRepository.findByShareLink(anyString())).thenReturn(Optional.of(fileShare)); + when(fileDataHandlerService.findBy(anyLong())).thenReturn(fileMetadata); + + try (MockedStatic mockedStatic = Mockito.mockStatic(FileUtil.class)) { + DownloadShareFileRes result = fileShareService.downloadShareFile(SHARE_Link, USER_PATH); + + assertEquals(ORIGINAL_FILE_NAME, result.fileName()); + verify(fileShareRepository).findByShareLink(SHARE_Link); + verify(fileDataHandlerService).findBy(FILE_ID); + + mockedStatic.verify(() -> FileUtil.download(fileMetadata, USER_PATH), times(1)); + } + } + + @Test + @DisplayName("공유파일 다운로드 실패 테스트 - 링크 만료") + void downloadShareFileExpiredLinkTest() { + FileShare fileShare = mock(FileShare.class); + + ZonedDateTime expiredCreationTime = ZonedDateTime.now().minusHours(4); + + when(fileShare.getCreatedAt()).thenReturn(expiredCreationTime); + when(fileShareRepository.findByShareLink(anyString())).thenReturn(Optional.of(fileShare)); + + ServiceException thrown = assertThrows(ServiceException.class, + () -> fileShareService.downloadShareFile(SHARE_Link, USER_PATH)); + + assertEquals(ErrorCode.NOT_FRESH_LINK.name(), thrown.getErrCode()); + verify(fileShareRepository).findByShareLink(SHARE_Link); + verify(fileDataHandlerService, never()).findBy(any()); + } + } From 3335d28803f529a269851a67631d3ee954b35a82 Mon Sep 17 00:00:00 2001 From: kcc Date: Fri, 17 May 2024 01:07:03 +0900 Subject: [PATCH 06/24] =?UTF-8?q?test=20:=20=EA=B3=B5=EC=9C=A0=ED=8C=8C?= =?UTF-8?q?=EC=9D=BC=20=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20=EC=8B=A4?= =?UTF-8?q?=ED=8C=A8=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 - 삭제된 파일 다운 시 다운 받지 못함 --- .../file/FileDataHandlerService.java | 2 +- .../fileshare/FileShareServiceTest.java | 21 +++++++++++++------ todo/Todo.txt | 4 ++++ 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java b/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java index 7901673..da07cb3 100644 --- a/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java +++ b/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java @@ -59,7 +59,7 @@ public List findAllBy(Long parentId) { public void deleteAll(List fileMetadataList) { fileRepository.deleteAll(fileMetadataList); } - + // 파일이 삭제된 경우에는 파일 공유 링크로 다운 받을 수 없다. public FileMetadata findBy(Long fileId) { return fileRepository.findById(fileId).orElseThrow(ErrorCode.CANNOT_FOUND_FILE::serviceException); } diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java index 896367c..03e09a2 100644 --- a/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/FileShareServiceTest.java @@ -3,12 +3,7 @@ import static com.c4cometrue.mystorage.TestConstants.*; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.BDDMockito.*; -import static org.mockito.Mockito.*; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.nio.file.Files; import java.time.ZonedDateTime; import java.util.Optional; @@ -20,7 +15,6 @@ import org.mockito.MockedStatic; import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.web.multipart.MultipartFile; import com.c4cometrue.mystorage.exception.ErrorCode; import com.c4cometrue.mystorage.exception.ServiceException; @@ -109,4 +103,19 @@ void downloadShareFileExpiredLinkTest() { verify(fileDataHandlerService, never()).findBy(any()); } + @Test + @DisplayName("공유파일 다운로드 실패 테스트 - 파일 삭제") + void downloadShareFileFailDeleteFileTest() { + FileShare fileShare = mock(FileShare.class); + when(fileShare.getCreatedAt()).thenReturn(ZonedDateTime.now().minusHours(1)); + when(fileShare.getFileId()).thenReturn(FILE_ID); + when(fileShareRepository.findByShareLink(anyString())).thenReturn(Optional.of(fileShare)); + when(fileDataHandlerService.findBy(FILE_ID)).thenThrow(ErrorCode.CANNOT_FOUND_FILE.serviceException()); + + ServiceException thrown = assertThrows(ServiceException.class, + () -> fileShareService.downloadShareFile(SHARE_Link, USER_PATH)); + + assertEquals(ErrorCode.CANNOT_FOUND_FILE.name(), thrown.getErrCode()); + } + } diff --git a/todo/Todo.txt b/todo/Todo.txt index b65d200..f0cc7cb 100644 --- a/todo/Todo.txt +++ b/todo/Todo.txt @@ -10,3 +10,7 @@ - 시간 지역성 고려 - 파일 공유의 경우 시간 지역성으로 성능 이점을 볼 수 있다 - 캐시 사용 (현재 프로젝트 규모 상 memcache) + + +- 우려 사항 + - 링크 만료 전 파일이 삭제 될 경우 어떻게 처리? -> 접근 불가하게 처리 From 28c28d2ecf2c2e0bddb35278430f6d0eaec92e6a Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 00:21:29 +0900 Subject: [PATCH 07/24] =?UTF-8?q?feat=20:=20Add=20=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EA=B3=B5=EC=9C=A0=EB=A7=81=ED=81=AC=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fileshare/DeleteLinkScheduler.java | 31 +++++++++++++++++++ .../fileshare/FileShareRepository.java | 12 +++++++ src/main/resources/application.yml | 2 ++ 3 files changed, 45 insertions(+) create mode 100644 src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java new file mode 100644 index 0000000..dd36059 --- /dev/null +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -0,0 +1,31 @@ +package com.c4cometrue.mystorage.fileshare; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.List; + +import org.springframework.data.domain.PageRequest; +import org.springframework.scheduling.annotation.Scheduled; +import org.springframework.stereotype.Component; + +import lombok.RequiredArgsConstructor; + +@Component +@RequiredArgsConstructor +public class DeleteLinkScheduler { + private final FileShareRepository fileShareRepository; + private int deleteSize = 100; + + @Scheduled(cron = "0 0 3 * * ?") + public void deleteExpiredLinks() { + ZonedDateTime expirationTime = ZonedDateTime.now(ZoneOffset.UTC).minusHours(3); + List expirationLinkIds; + + do { + expirationLinkIds = fileShareRepository.findExpirations(expirationTime, PageRequest.of(0, deleteSize)); + if (!expirationLinkIds.isEmpty()) { + fileShareRepository.deleteByIds(expirationLinkIds); + } + } while (expirationLinkIds.size() == deleteSize); + } +} diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java index 8df76eb..c1f449a 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java @@ -1,11 +1,23 @@ package com.c4cometrue.mystorage.fileshare; +import java.time.ZonedDateTime; +import java.util.List; import java.util.Optional; +import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.Modifying; +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.query.Param; public interface FileShareRepository extends JpaRepository { boolean existsByShareLink(String shareLink); Optional findByShareLink(String shareLink); + + @Query("SELECT fs.id FROM FileShare fs WHERE fs.createdAt < :expirationTime") + List findExpirations(@Param("expirationTime") ZonedDateTime expirationTime, Pageable pageable); + + @Query("DELETE FROM FileShare fs WHERE fs.id IN :ids") + void deleteByIds(@Param("ids") List ids); } diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index d2d3bae..4ef233f 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -33,3 +33,5 @@ logging: + + From 4432e2c6800b0b6b817a3021948b2d1f446cc9c1 Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 00:40:38 +0900 Subject: [PATCH 08/24] =?UTF-8?q?test=20:=20=EB=A7=81=ED=81=AC=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=8A=A4=EC=BC=80=EC=A4=84=EB=9F=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../fileshare/DeleteLinkScheduler.java | 2 +- .../fileshare/DeleteLinkSchedulerTest.java | 48 +++++++++++++++++++ 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index dd36059..fc28f84 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -14,7 +14,7 @@ @RequiredArgsConstructor public class DeleteLinkScheduler { private final FileShareRepository fileShareRepository; - private int deleteSize = 100; + private final int deleteSize = 100; @Scheduled(cron = "0 0 3 * * ?") public void deleteExpiredLinks() { diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java new file mode 100644 index 0000000..4b43012 --- /dev/null +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java @@ -0,0 +1,48 @@ +package com.c4cometrue.mystorage.fileshare; + +import static org.mockito.Mockito.*; + +import java.time.ZoneOffset; +import java.time.ZonedDateTime; +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.data.domain.PageRequest; + +@ExtendWith(MockitoExtension.class) +@DisplayName("파일공유 링크삭제 스케줄러 테스트") +class DeleteLinkSchedulerTest { + @Mock + private FileShareRepository fileShareRepository; + + @InjectMocks + private DeleteLinkScheduler deleteLinkScheduler; + + private ZonedDateTime expirationTime; + + @BeforeEach + void setUp() { + expirationTime = ZonedDateTime.now(ZoneOffset.UTC).minusHours(3); + } + + @Test + @DisplayName("파일공유 링크 삭제 성공 테스트") + void deleteExpiredLinksSuccess() { + List expiredLinkIds = Arrays.asList(1L, 2L, 3L); + + when(fileShareRepository.findExpirations(any(ZonedDateTime.class), any(PageRequest.class))) + .thenReturn(expiredLinkIds); + + deleteLinkScheduler.deleteExpiredLinks(); + + verify(fileShareRepository, times(1)).findExpirations(any(ZonedDateTime.class), any(PageRequest.class)); + verify(fileShareRepository, times(1)).deleteByIds(expiredLinkIds); + } +} From fc21cc3128ab3804816ad6b59d4cbc7663a8b22e Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 00:50:21 +0900 Subject: [PATCH 09/24] =?UTF-8?q?refactor=20:=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EA=B3=B5=EC=9C=A0=20=EB=8B=A4=EC=9A=B4=EB=A1=9C=EB=93=9C=20?= =?UTF-8?q?=EC=97=90=EB=9F=AC=EC=BD=94=EB=93=9C=20=EC=A0=95=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../c4cometrue/mystorage/exception/ErrorCode.java | 1 + .../mystorage/fileshare/FileShareService.java | 2 +- todo/Todo.txt | 15 --------------- 3 files changed, 2 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java index c8447d8..d2c6998 100644 --- a/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java +++ b/src/main/java/com/c4cometrue/mystorage/exception/ErrorCode.java @@ -32,6 +32,7 @@ public enum ErrorCode { VALIDATION_ERROR(HttpStatus.BAD_REQUEST, "유효하지 않은 요청입니다."), DUPLICATE_SHARE_LINK(HttpStatus.INTERNAL_SERVER_ERROR, "링크 생성에 중복이 발생했습니다"), + NOT_FOUND_SHARE_LINK(HttpStatus.NOT_FOUND, "링크를 찾을 수 없습니다"), NOT_FRESH_LINK(HttpStatus.BAD_REQUEST, "만료된 링크입니다."); private final HttpStatus httpStatus; diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java index 6d407ba..b110f6e 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -50,7 +50,7 @@ public void persist(Long fileId, String shareLink) { public DownloadShareFileRes downloadShareFile(String sharedLink, String userPath) { FileShare fileShare = fileShareRepository.findByShareLink(sharedLink) - .orElseThrow(ErrorCode.DUPLICATE_SHARE_LINK::serviceException); + .orElseThrow(ErrorCode.NOT_FOUND_SHARE_LINK::serviceException); isValid(fileShare.getCreatedAt()); FileMetadata fileMetadata = fileDataHandlerService.findBy(fileShare.getFileId()); diff --git a/todo/Todo.txt b/todo/Todo.txt index f0cc7cb..d3f5a12 100644 --- a/todo/Todo.txt +++ b/todo/Todo.txt @@ -1,16 +1 @@ -# Todo -- [x] 파일 공유 링크 생성 -- [] 공유 파일 다운 로드 -# 설계 -- 공유 파일 데이터는 오전 3시에 일괄 삭제 - - 사용자 요청이 적은 시간 - - 별도 모듈에서 진행 - -- 시간 지역성 고려 - - 파일 공유의 경우 시간 지역성으로 성능 이점을 볼 수 있다 - - 캐시 사용 (현재 프로젝트 규모 상 memcache) - - -- 우려 사항 - - 링크 만료 전 파일이 삭제 될 경우 어떻게 처리? -> 접근 불가하게 처리 From 733c6aded1ce84e3973cb4a5996c83b569fdd92b Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 00:54:44 +0900 Subject: [PATCH 10/24] =?UTF-8?q?chore=20:=20=EC=BD=94=EB=93=9C=EC=8A=A4?= =?UTF-8?q?=EB=A9=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/c4cometrue/mystorage/file/FileDataHandlerService.java | 1 + .../com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java | 2 +- .../com/c4cometrue/mystorage/fileshare/FileShareController.java | 1 - .../com/c4cometrue/mystorage/fileshare/FileShareRepository.java | 1 - 4 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java b/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java index da07cb3..57dd948 100644 --- a/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java +++ b/src/main/java/com/c4cometrue/mystorage/file/FileDataHandlerService.java @@ -59,6 +59,7 @@ public List findAllBy(Long parentId) { public void deleteAll(List fileMetadataList) { fileRepository.deleteAll(fileMetadataList); } + // 파일이 삭제된 경우에는 파일 공유 링크로 다운 받을 수 없다. public FileMetadata findBy(Long fileId) { return fileRepository.findById(fileId).orElseThrow(ErrorCode.CANNOT_FOUND_FILE::serviceException); diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index fc28f84..01eb25e 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -14,7 +14,7 @@ @RequiredArgsConstructor public class DeleteLinkScheduler { private final FileShareRepository fileShareRepository; - private final int deleteSize = 100; + private final static int deleteSize = 100; @Scheduled(cron = "0 0 3 * * ?") public void deleteExpiredLinks() { diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java index 9e58a2c..71bb13b 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java @@ -4,7 +4,6 @@ import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; -import org.springframework.web.bind.annotation.RequestHeader; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java index c1f449a..5e7f53c 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java @@ -6,7 +6,6 @@ import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; -import org.springframework.data.jpa.repository.Modifying; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; From dc7a49f6c6102290164c0d07fc78f15959130d76 Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 01:02:00 +0900 Subject: [PATCH 11/24] =?UTF-8?q?chore=20:=20=EC=BD=94=EB=93=9C=EC=8A=A4?= =?UTF-8?q?=EB=A9=9C=20=EC=A0=9C=EA=B1=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mystorage/fileshare/DeleteLinkScheduler.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index 01eb25e..62fb943 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -13,8 +13,9 @@ @Component @RequiredArgsConstructor public class DeleteLinkScheduler { + private static final int DELETE_SIZE = 100; + private final FileShareRepository fileShareRepository; - private final static int deleteSize = 100; @Scheduled(cron = "0 0 3 * * ?") public void deleteExpiredLinks() { @@ -22,10 +23,10 @@ public void deleteExpiredLinks() { List expirationLinkIds; do { - expirationLinkIds = fileShareRepository.findExpirations(expirationTime, PageRequest.of(0, deleteSize)); + expirationLinkIds = fileShareRepository.findExpirations(expirationTime, PageRequest.of(0, DELETE_SIZE)); if (!expirationLinkIds.isEmpty()) { fileShareRepository.deleteByIds(expirationLinkIds); } - } while (expirationLinkIds.size() == deleteSize); + } while (expirationLinkIds.size() == DELETE_SIZE); } } From ada94027db11a796aab7ab453c091b80b2fcb600 Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 20:00:18 +0900 Subject: [PATCH 12/24] refactor : PageRequest -> limit --- .../mystorage/fileshare/DeleteLinkScheduler.java | 3 +-- .../mystorage/fileshare/FileShareRepository.java | 6 +++--- .../fileshare/DeleteLinkSchedulerTest.java | 14 ++------------ 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index 62fb943..dd2ff8d 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -4,7 +4,6 @@ import java.time.ZonedDateTime; import java.util.List; -import org.springframework.data.domain.PageRequest; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; @@ -23,7 +22,7 @@ public void deleteExpiredLinks() { List expirationLinkIds; do { - expirationLinkIds = fileShareRepository.findExpirations(expirationTime, PageRequest.of(0, DELETE_SIZE)); + expirationLinkIds = fileShareRepository.findExpirations(expirationTime, DELETE_SIZE); if (!expirationLinkIds.isEmpty()) { fileShareRepository.deleteByIds(expirationLinkIds); } diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java index 5e7f53c..b0e1142 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java @@ -4,7 +4,6 @@ import java.util.List; import java.util.Optional; -import org.springframework.data.domain.Pageable; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.data.jpa.repository.Query; import org.springframework.data.repository.query.Param; @@ -14,8 +13,9 @@ public interface FileShareRepository extends JpaRepository { Optional findByShareLink(String shareLink); - @Query("SELECT fs.id FROM FileShare fs WHERE fs.createdAt < :expirationTime") - List findExpirations(@Param("expirationTime") ZonedDateTime expirationTime, Pageable pageable); + @Query(value = "SELECT fs.id FROM FileShare fs WHERE fs.createdAt < :expirationTime LIMIT :limit", + nativeQuery = true) + List findExpirations(@Param("expirationTime") ZonedDateTime expirationTime, @Param("limit") int limit); @Query("DELETE FROM FileShare fs WHERE fs.id IN :ids") void deleteByIds(@Param("ids") List ids); diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java index 4b43012..84a581e 100644 --- a/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java @@ -2,19 +2,16 @@ import static org.mockito.Mockito.*; -import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.util.Arrays; import java.util.List; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; -import org.springframework.data.domain.PageRequest; @ExtendWith(MockitoExtension.class) @DisplayName("파일공유 링크삭제 스케줄러 테스트") @@ -25,24 +22,17 @@ class DeleteLinkSchedulerTest { @InjectMocks private DeleteLinkScheduler deleteLinkScheduler; - private ZonedDateTime expirationTime; - - @BeforeEach - void setUp() { - expirationTime = ZonedDateTime.now(ZoneOffset.UTC).minusHours(3); - } - @Test @DisplayName("파일공유 링크 삭제 성공 테스트") void deleteExpiredLinksSuccess() { List expiredLinkIds = Arrays.asList(1L, 2L, 3L); - when(fileShareRepository.findExpirations(any(ZonedDateTime.class), any(PageRequest.class))) + when(fileShareRepository.findExpirations(any(ZonedDateTime.class), anyInt())) .thenReturn(expiredLinkIds); deleteLinkScheduler.deleteExpiredLinks(); - verify(fileShareRepository, times(1)).findExpirations(any(ZonedDateTime.class), any(PageRequest.class)); + verify(fileShareRepository, times(1)).findExpirations(any(ZonedDateTime.class), anyInt()); verify(fileShareRepository, times(1)).deleteByIds(expiredLinkIds); } } From 4d1e597379c283a64937f7128b3fd12acf956e9e Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 20:07:01 +0900 Subject: [PATCH 13/24] refactor : Duration.ofHours -> duration.toHours() --- .../c4cometrue/mystorage/fileshare/FileShareService.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java index b110f6e..7532d17 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -5,7 +5,6 @@ import java.time.ZonedDateTime; import java.util.UUID; -import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import com.c4cometrue.mystorage.exception.ErrorCode; @@ -20,6 +19,7 @@ @Service @RequiredArgsConstructor public class FileShareService { + private final FileShareRepository fileShareRepository; private final FileDataHandlerService fileDataHandlerService; @@ -62,9 +62,9 @@ public DownloadShareFileRes downloadShareFile(String sharedLink, String userPath private void isValid(ZonedDateTime createTimeInLink) { ZonedDateTime now = ZonedDateTime.now(); Duration duration = Duration.between(createTimeInLink, now); - Duration maxTime = Duration.ofHours(3); - if (duration.compareTo(maxTime) > 0) { + int maxTime = 3; + if (duration.toHours() > maxTime) { throw ErrorCode.NOT_FRESH_LINK.serviceException(); } } From b53fe7cfa9fa0fc00695eca4abd99c9d7241185a Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 20:19:29 +0900 Subject: [PATCH 14/24] refactor : requestBody -> modelAttribute - Get request --- .../c4cometrue/mystorage/fileshare/FileShareController.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java index 71bb13b..dd139e2 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java @@ -2,6 +2,8 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; +import org.springframework.web.bind.annotation.ModelAttribute; +import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; @@ -28,7 +30,7 @@ public ResponseEntity createShareFile(@Valid @RequestBody Cr } @GetMapping("/download") - public ResponseEntity downloadShareFile(@Valid @RequestBody DownloadShareFileReq req) { + public ResponseEntity downloadShareFile(@Valid @ModelAttribute DownloadShareFileReq req) { DownloadShareFileRes res = fileShareService.downloadShareFile(req.shareLink(), req.userPath()); return ResponseEntity.ok(res); } From d87cae524be2b93d6d5a285674bf4fa5df14ebff Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 20:28:32 +0900 Subject: [PATCH 15/24] refactor : createAt index --- .../java/com/c4cometrue/mystorage/fileshare/FileShare.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java index 11d4bdf..e25c31b 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShare.java @@ -20,7 +20,8 @@ @Getter @NoArgsConstructor(access = AccessLevel.PROTECTED) @Table(name = "file_share", indexes = { - @Index(name = "idx_share_link", columnList = "shareLink") + @Index(name = "idx_share_link", columnList = "shareLink"), + @Index(name = "idx_share_created_at", columnList = "createAt") }) public class FileShare { @Id From 3949129ee9387a5fbe7a7a7dedde9903b1082456 Mon Sep 17 00:00:00 2001 From: kcc Date: Sat, 18 May 2024 20:31:46 +0900 Subject: [PATCH 16/24] chore : code smell --- .../com/c4cometrue/mystorage/fileshare/FileShareController.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java index dd139e2..73de311 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java @@ -3,7 +3,6 @@ import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.ModelAttribute; -import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; From f3fd49089b73a354c4e3a167ad0732bf07a80dad Mon Sep 17 00:00:00 2001 From: kcc Date: Mon, 20 May 2024 00:39:53 +0900 Subject: [PATCH 17/24] =?UTF-8?q?refactor=20:=20=ED=8C=8C=EC=9D=BC=20?= =?UTF-8?q?=EA=B3=B5=EC=9C=A0=20Response=20Dto=EC=97=90=20=EC=9C=A0?= =?UTF-8?q?=ED=9A=A8=EC=84=B1=20=EA=B2=80=EC=82=AC=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mystorage/fileshare/dto/CreateShareFileRes.java | 6 ++++-- .../mystorage/fileshare/dto/DownloadShareFileRes.java | 4 +++- src/main/resources/application.yml | 2 -- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java index e454d4d..d3c0d92 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/CreateShareFileRes.java @@ -1,8 +1,10 @@ package com.c4cometrue.mystorage.fileshare.dto; +import jakarta.validation.constraints.NotBlank; + public record CreateShareFileRes( - String fileName, - String sharedLink + @NotBlank String fileName, + @NotBlank String sharedLink ) { public static CreateShareFileRes of(String fileName, String sharedLink) { return new CreateShareFileRes(fileName, sharedLink); diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java index 102d07c..b8dcae9 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/dto/DownloadShareFileRes.java @@ -1,7 +1,9 @@ package com.c4cometrue.mystorage.fileshare.dto; +import jakarta.validation.constraints.NotBlank; + public record DownloadShareFileRes( - String fileName + @NotBlank String fileName ) { public static DownloadShareFileRes of(String fileName) { return new DownloadShareFileRes(fileName); diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml index 4ef233f..d2d3bae 100644 --- a/src/main/resources/application.yml +++ b/src/main/resources/application.yml @@ -33,5 +33,3 @@ logging: - - From 7c43fed40521f79465ba581df247c1557d5aa8cb Mon Sep 17 00:00:00 2001 From: kcc Date: Mon, 20 May 2024 18:29:45 +0900 Subject: [PATCH 18/24] chore : remove line - settings.gradle --- settings.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/settings.gradle b/settings.gradle index b9e209f..d045f9c 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1 @@ rootProject.name = 'mystorage' - From 70010f13cef93ab4350667a8c7897130c885721c Mon Sep 17 00:00:00 2001 From: kcc Date: Wed, 22 May 2024 23:46:58 +0900 Subject: [PATCH 19/24] =?UTF-8?q?refactor=20:=20mapping=20=ED=98=95?= =?UTF-8?q?=EC=8B=9D=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../c4cometrue/mystorage/fileshare/FileShareController.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java index 73de311..c603bc0 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareController.java @@ -17,18 +17,18 @@ import lombok.RequiredArgsConstructor; @RestController -@RequestMapping("/files/share") +@RequestMapping("/files") @RequiredArgsConstructor public class FileShareController { private final FileShareService fileShareService; - @PostMapping + @PostMapping("/share") public ResponseEntity createShareFile(@Valid @RequestBody CreateShareFileReq req) { CreateShareFileRes res = fileShareService.createShareFileLink(req.fileId(), req.userId()); return ResponseEntity.ok(res); } - @GetMapping("/download") + @GetMapping("/share/download") public ResponseEntity downloadShareFile(@Valid @ModelAttribute DownloadShareFileReq req) { DownloadShareFileRes res = fileShareService.downloadShareFile(req.shareLink(), req.userPath()); return ResponseEntity.ok(res); From a3be9b6fdab0f29a13a031cbfed88c8039f400c8 Mon Sep 17 00:00:00 2001 From: kcc Date: Wed, 22 May 2024 23:51:59 +0900 Subject: [PATCH 20/24] =?UTF-8?q?refactor=20:=20shareLink=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1=20=EB=B0=A9=EB=B2=95=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/c4cometrue/mystorage/fileshare/FileShareService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java index 7532d17..7a8fecd 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareService.java @@ -28,7 +28,7 @@ public CreateShareFileRes createShareFileLink(Long fileId, Long userId) { FileMetadata file = fileDataHandlerService.findBy(fileId, userId); // shareLink 생성 - String shareLink = LocalDateTime.now() + UUID.randomUUID().toString(); + String shareLink = UUID.randomUUID().toString(); checkDuplicate(shareLink); // 저장 From 85002ab90e0dcabe721b5c0346b6810c64502e30 Mon Sep 17 00:00:00 2001 From: kcc Date: Wed, 22 May 2024 23:56:23 +0900 Subject: [PATCH 21/24] =?UTF-8?q?refactor=20:=20cron=20=EB=A7=A4=EC=9D=BC?= =?UTF-8?q?=203=EC=8B=9C=EA=B0=84=20=EB=8B=A8=EC=9C=84=EB=A1=9C=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 --- .../com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index dd2ff8d..b0c936f 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -16,7 +16,7 @@ public class DeleteLinkScheduler { private final FileShareRepository fileShareRepository; - @Scheduled(cron = "0 0 3 * * ?") + @Scheduled(cron = "* */3 * * * ?") public void deleteExpiredLinks() { ZonedDateTime expirationTime = ZonedDateTime.now(ZoneOffset.UTC).minusHours(3); List expirationLinkIds; From 26be5edb88fef851b728f0294699c62014d229c4 Mon Sep 17 00:00:00 2001 From: kcc Date: Thu, 23 May 2024 00:08:02 +0900 Subject: [PATCH 22/24] refactor : findExpirations -> deleteByExpirations - delete return id --- .../c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java | 2 +- .../c4cometrue/mystorage/fileshare/FileShareRepository.java | 5 ++--- .../mystorage/fileshare/DeleteLinkSchedulerTest.java | 4 ++-- 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index b0c936f..1045a80 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -22,7 +22,7 @@ public void deleteExpiredLinks() { List expirationLinkIds; do { - expirationLinkIds = fileShareRepository.findExpirations(expirationTime, DELETE_SIZE); + expirationLinkIds = fileShareRepository.deleteByExpirations(expirationTime, DELETE_SIZE); if (!expirationLinkIds.isEmpty()) { fileShareRepository.deleteByIds(expirationLinkIds); } diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java index b0e1142..02f8a0b 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/FileShareRepository.java @@ -13,9 +13,8 @@ public interface FileShareRepository extends JpaRepository { Optional findByShareLink(String shareLink); - @Query(value = "SELECT fs.id FROM FileShare fs WHERE fs.createdAt < :expirationTime LIMIT :limit", - nativeQuery = true) - List findExpirations(@Param("expirationTime") ZonedDateTime expirationTime, @Param("limit") int limit); + @Query(value = "DELETE FROM FileShare fs WHERE fs.createdAt < :expirationTime LIMIT :limit", nativeQuery = true) + List deleteByExpirations(@Param("expirationTime") ZonedDateTime expirationTime, @Param("limit") int limit); @Query("DELETE FROM FileShare fs WHERE fs.id IN :ids") void deleteByIds(@Param("ids") List ids); diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java index 84a581e..87db739 100644 --- a/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java @@ -27,12 +27,12 @@ class DeleteLinkSchedulerTest { void deleteExpiredLinksSuccess() { List expiredLinkIds = Arrays.asList(1L, 2L, 3L); - when(fileShareRepository.findExpirations(any(ZonedDateTime.class), anyInt())) + when(fileShareRepository.deleteByExpirations(any(ZonedDateTime.class), anyInt())) .thenReturn(expiredLinkIds); deleteLinkScheduler.deleteExpiredLinks(); - verify(fileShareRepository, times(1)).findExpirations(any(ZonedDateTime.class), anyInt()); + verify(fileShareRepository, times(1)).deleteByExpirations(any(ZonedDateTime.class), anyInt()); verify(fileShareRepository, times(1)).deleteByIds(expiredLinkIds); } } From 38ed73f1e14c7d1913f71f0bc3c2b3e252baf112 Mon Sep 17 00:00:00 2001 From: kcc Date: Thu, 23 May 2024 00:12:39 +0900 Subject: [PATCH 23/24] =?UTF-8?q?refactor=20:=20DeleteLinkSchedler=203?= =?UTF-8?q?=EC=8B=9C=EA=B0=84=20=EB=8B=A8=EC=9C=84=20=EC=82=AD=EC=A0=9C=20?= =?UTF-8?q?->=205=EB=B6=84=20=EB=8B=A8=EC=9C=84=20=EC=82=AD=EC=A0=9C=20-?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=20=EB=B9=88=EB=8F=84=20=EC=83=81=EC=8A=B9?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=82=AD=EC=A0=9C=20=EB=8B=B9=20=EB=B6=80?= =?UTF-8?q?=ED=95=98=EB=A5=BC=20=EB=82=AE=EC=B6=94=EA=B8=B0=20=EC=9C=84?= =?UTF-8?q?=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index 1045a80..3250833 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -16,7 +16,7 @@ public class DeleteLinkScheduler { private final FileShareRepository fileShareRepository; - @Scheduled(cron = "* */3 * * * ?") + @Scheduled(cron = "*/5 * * * * ?") public void deleteExpiredLinks() { ZonedDateTime expirationTime = ZonedDateTime.now(ZoneOffset.UTC).minusHours(3); List expirationLinkIds; From 32737ab683ffa67eaac07ebbe59880789e587efb Mon Sep 17 00:00:00 2001 From: kcc Date: Thu, 23 May 2024 00:20:36 +0900 Subject: [PATCH 24/24] =?UTF-8?q?refactor=20:=20deleteByExpirations=20?= =?UTF-8?q?=EB=8F=84=EC=9E=85=EC=97=90=20=EB=94=B0=EB=A5=B8=20deleteById?= =?UTF-8?q?=20=EC=82=AD=EC=A0=9C=20-=20=EC=A4=91=EB=B3=B5=EB=90=9C=20?= =?UTF-8?q?=EA=B8=B0=EB=8A=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java | 3 --- .../mystorage/fileshare/DeleteLinkSchedulerTest.java | 1 - 2 files changed, 4 deletions(-) diff --git a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java index 3250833..6abed57 100644 --- a/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java +++ b/src/main/java/com/c4cometrue/mystorage/fileshare/DeleteLinkScheduler.java @@ -23,9 +23,6 @@ public void deleteExpiredLinks() { do { expirationLinkIds = fileShareRepository.deleteByExpirations(expirationTime, DELETE_SIZE); - if (!expirationLinkIds.isEmpty()) { - fileShareRepository.deleteByIds(expirationLinkIds); - } } while (expirationLinkIds.size() == DELETE_SIZE); } } diff --git a/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java index 87db739..50f3c1e 100644 --- a/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java +++ b/src/test/java/com/c4cometrue/mystorage/fileshare/DeleteLinkSchedulerTest.java @@ -33,6 +33,5 @@ void deleteExpiredLinksSuccess() { deleteLinkScheduler.deleteExpiredLinks(); verify(fileShareRepository, times(1)).deleteByExpirations(any(ZonedDateTime.class), anyInt()); - verify(fileShareRepository, times(1)).deleteByIds(expiredLinkIds); } }