From cdd8868275c53973c6f06f270a16f766f1037603 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:14:44 +0900 Subject: [PATCH 01/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=9A=94=EC=B2=AD=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존: 파일 정보 + 엔티티 타입 + 해당 엔티티의 아이디 - 변경: 유저 + 파일 정보 --- .../java/com/back/domain/file/dto/FileUploadRequestDto.java | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/main/java/com/back/domain/file/dto/FileUploadRequestDto.java b/src/main/java/com/back/domain/file/dto/FileUploadRequestDto.java index 4ef8d60f..516dfc6e 100644 --- a/src/main/java/com/back/domain/file/dto/FileUploadRequestDto.java +++ b/src/main/java/com/back/domain/file/dto/FileUploadRequestDto.java @@ -10,8 +10,4 @@ public class FileUploadRequestDto { @NotNull(message = "파일 입력은 필수입니다.") private MultipartFile multipartFile; - - private EntityType entityType; - - private Long entityId; } From 16468d26f4cbfdb5d762cd776cfd4e6befdd4e0d Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:16:04 +0900 Subject: [PATCH 02/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 요청 데이터 변경에 따른 로직 변경 --- .../java/com/back/domain/file/service/FileService.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/back/domain/file/service/FileService.java b/src/main/java/com/back/domain/file/service/FileService.java index 77f1b836..760fb8f2 100644 --- a/src/main/java/com/back/domain/file/service/FileService.java +++ b/src/main/java/com/back/domain/file/service/FileService.java @@ -40,8 +40,6 @@ public class FileService { @Transactional public FileUploadResponseDto uploadFile( MultipartFile multipartFile, - EntityType entityType, - Long entityId, Long userId ) { User user = userRepository.findById(userId) @@ -56,18 +54,16 @@ public FileUploadResponseDto uploadFile( String filePath = s3Upload(storedFileName, multipartFile); // FileAttachment 정보 저장 - fileAttachmentRepository.save( + FileAttachment fileAttachment = fileAttachmentRepository.save( new FileAttachment( storedFileName, multipartFile, user, - entityType, - entityId, filePath ) ); - return new FileUploadResponseDto(filePath); + return new FileUploadResponseDto(fileAttachment.getId(), filePath); } From a4e827c08c477b244a5fcf510c496eeb8e10d72d Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:19:37 +0900 Subject: [PATCH 03/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=9D=91=EB=8B=B5=20=EB=8D=B0=EC=9D=B4?= =?UTF-8?q?=ED=84=B0=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존: publicURL - 변경: attachmentId + publicURL --- .../java/com/back/domain/file/dto/FileUploadResponseDto.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java b/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java index bee746c6..4f66e080 100644 --- a/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java +++ b/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java @@ -4,9 +4,11 @@ @Data public class FileUploadResponseDto { + private Long attachmentId; private String imageUrl; - public FileUploadResponseDto(String imageUrl) { + public FileUploadResponseDto(Long attachmentId, String imageUrl) { + this.attachmentId = attachmentId; this.imageUrl = imageUrl; } } \ No newline at end of file From 21dad3279f8aea568e1bdc509cd77f6753129d49 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:20:29 +0900 Subject: [PATCH 04/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=97=85?= =?UTF-8?q?=EB=A1=9C=EB=93=9C=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 파일 업로드 요청 및 응답 데이터 변경에 따른 컨트롤러 메서드 변경 --- .../java/com/back/domain/file/controller/FileController.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/main/java/com/back/domain/file/controller/FileController.java b/src/main/java/com/back/domain/file/controller/FileController.java index df0e4a60..b1e273ab 100644 --- a/src/main/java/com/back/domain/file/controller/FileController.java +++ b/src/main/java/com/back/domain/file/controller/FileController.java @@ -29,8 +29,6 @@ public ResponseEntity> uploadFile( ) { FileUploadResponseDto res = fileService.uploadFile( req.getMultipartFile(), - req.getEntityType(), - req.getEntityId(), user.getUserId() ); From 246fa3c1b290fc025140042227585a86b42edb8c Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:23:01 +0900 Subject: [PATCH 05/19] =?UTF-8?q?Fix:=20FileAttachment=20=EC=97=94?= =?UTF-8?q?=ED=8B=B0=ED=8B=B0=20=ED=95=84=EB=93=9C=EB=AA=85=20=EB=B3=80?= =?UTF-8?q?=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 : filePath - 변경 : publicURL --- .../domain/file/entity/FileAttachment.java | 22 ++++++++----------- .../back/domain/file/service/FileService.java | 6 ++--- 2 files changed, 12 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/back/domain/file/entity/FileAttachment.java b/src/main/java/com/back/domain/file/entity/FileAttachment.java index 3bd63417..195da19d 100644 --- a/src/main/java/com/back/domain/file/entity/FileAttachment.java +++ b/src/main/java/com/back/domain/file/entity/FileAttachment.java @@ -18,7 +18,7 @@ public class FileAttachment extends BaseEntity { private String originalName; - private String filePath; + private String publicURL; private long fileSize; @@ -36,25 +36,21 @@ public FileAttachment( String storedName, MultipartFile multipartFile, User user, - EntityType entityType, - Long entityId, - String filePath + String publicURL ) { this.storedName = storedName; - originalName = multipartFile.getOriginalFilename(); - this.filePath = filePath; - fileSize = multipartFile.getSize(); + this.originalName = multipartFile.getOriginalFilename(); + this.publicURL = publicURL; + this.fileSize = multipartFile.getSize(); this.contentType = multipartFile.getContentType(); this.user = user; - - attachmentMappings.add(new AttachmentMapping(this ,entityType, entityId)); } - public void update(String storedName, MultipartFile multipartFile, String filePath) { + public void update(String storedName, MultipartFile multipartFile, String publicURL) { this.storedName = storedName; - originalName = multipartFile.getOriginalFilename(); - this.filePath = filePath; - fileSize = multipartFile.getSize(); + this.originalName = multipartFile.getOriginalFilename(); + this.publicURL = publicURL; + this.fileSize = multipartFile.getSize(); this.contentType = multipartFile.getContentType(); } } diff --git a/src/main/java/com/back/domain/file/service/FileService.java b/src/main/java/com/back/domain/file/service/FileService.java index 760fb8f2..4958e4ae 100644 --- a/src/main/java/com/back/domain/file/service/FileService.java +++ b/src/main/java/com/back/domain/file/service/FileService.java @@ -51,7 +51,7 @@ public FileUploadResponseDto uploadFile( String storedFileName = createFileName(multipartFile.getOriginalFilename()); // S3의 저장된 파일의 PublicURL - String filePath = s3Upload(storedFileName, multipartFile); + String publicURL = s3Upload(storedFileName, multipartFile); // FileAttachment 정보 저장 FileAttachment fileAttachment = fileAttachmentRepository.save( @@ -59,11 +59,11 @@ public FileUploadResponseDto uploadFile( storedFileName, multipartFile, user, - filePath + publicURL ) ); - return new FileUploadResponseDto(fileAttachment.getId(), filePath); + return new FileUploadResponseDto(fileAttachment.getId(), publicURL); } From 0024b827c6861a49698c2e4931949df1ebd4b685 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:33:21 +0900 Subject: [PATCH 06/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EC=97=94=EB=93=9C=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존: /api/file/read?entityType=POST&entityId=1 - 변경: /api/file/read/{attachmentId} --- .../java/com/back/domain/file/controller/FileController.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/back/domain/file/controller/FileController.java b/src/main/java/com/back/domain/file/controller/FileController.java index b1e273ab..dda1a9b5 100644 --- a/src/main/java/com/back/domain/file/controller/FileController.java +++ b/src/main/java/com/back/domain/file/controller/FileController.java @@ -39,10 +39,9 @@ public ResponseEntity> uploadFile( @GetMapping(value = "/read") public ResponseEntity> getFile( - @RequestParam("entityType") @NotBlank(message = "entityType은 필수입니다.") EntityType entityType, - @RequestParam("entityId") @NotBlank(message = "entityId는 필수입니다.") Long entityId + @PathVariable("attachmentId") Long attachmentId ) { - FileReadResponseDto res = fileService.getFile(entityType, entityId); + FileReadResponseDto res = fileService.getFile(attachmentId); return ResponseEntity .status(HttpStatus.OK) From bca300a3e6a16cd9adf296eb2a6a910c874c6e8a Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:34:30 +0900 Subject: [PATCH 07/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 엔드 포인트 변경에 따른 파일 조회 비즈니스 로직 변경 --- .../back/domain/file/service/FileService.java | 16 +++++++++------- .../com/back/global/exception/ErrorCode.java | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/back/domain/file/service/FileService.java b/src/main/java/com/back/domain/file/service/FileService.java index 4958e4ae..3b1597fe 100644 --- a/src/main/java/com/back/domain/file/service/FileService.java +++ b/src/main/java/com/back/domain/file/service/FileService.java @@ -20,6 +20,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; +import org.springframework.web.bind.annotation.PathVariable; +import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import java.io.IOException; @@ -68,15 +70,15 @@ public FileUploadResponseDto uploadFile( @Transactional(readOnly = true) - public FileReadResponseDto getFile( - EntityType entityType, - Long entityId - ) { - FileAttachment fileAttachment = getFileAttachmentOrThrow(entityType, entityId); + public FileReadResponseDto getFile(Long attachmentId) { + FileAttachment fileAttachment = fileAttachmentRepository.findById(attachmentId) + .orElseThrow(() -> + new CustomException(ErrorCode.FILE_NOT_FOUND) + ); - String filePath = fileAttachment.getFilePath(); + String publicURL = fileAttachment.getPublicURL(); - return new FileReadResponseDto(filePath); + return new FileReadResponseDto(publicURL); } @Transactional diff --git a/src/main/java/com/back/global/exception/ErrorCode.java b/src/main/java/com/back/global/exception/ErrorCode.java index 9c6daf1e..051c2eef 100644 --- a/src/main/java/com/back/global/exception/ErrorCode.java +++ b/src/main/java/com/back/global/exception/ErrorCode.java @@ -143,6 +143,7 @@ public enum ErrorCode { FILE_UPLOAD_FAILED(HttpStatus.INTERNAL_SERVER_ERROR, "FILE_001", "파일 업로드에 실패했습니다."), ATTACHMENT_MAPPING_NOT_FOUND(HttpStatus.NOT_FOUND, "FILE_002", "매핑된 파일 정보를 찾을 수 없습니다."), FILE_ACCESS_DENIED(HttpStatus.FORBIDDEN, "FILE_003", "파일을 접근할 권한이 없습니다."), + FILE_NOT_FOUND(HttpStatus.NOT_FOUND, "FILE_004", "파일 정보를 찾을 수 없습니다."), // ======================== 토큰 관련 ======================== INVALID_EMAIL_TOKEN(HttpStatus.UNAUTHORIZED, "TOKEN_001", "유효하지 않은 이메일 인증 토큰입니다."), From a7455efa413948cf7d37af03d2b61608388b85a7 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:38:04 +0900 Subject: [PATCH 08/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=97=85?= =?UTF-8?q?=EB=8D=B0=EC=9D=B4=ED=8A=B8=20=EC=97=94=ED=8A=B8=ED=8F=AC?= =?UTF-8?q?=EC=9D=B8=ED=8A=B8=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존 : /api/file/update - 변경 : /api/file/update/{attachmentId} --- .../com/back/domain/file/controller/FileController.java | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/back/domain/file/controller/FileController.java b/src/main/java/com/back/domain/file/controller/FileController.java index dda1a9b5..661b5f0d 100644 --- a/src/main/java/com/back/domain/file/controller/FileController.java +++ b/src/main/java/com/back/domain/file/controller/FileController.java @@ -37,7 +37,7 @@ public ResponseEntity> uploadFile( .body(RsData.success("파일 업로드 성공", res)); } - @GetMapping(value = "/read") + @GetMapping(value = "/read/{attachmentId}") public ResponseEntity> getFile( @PathVariable("attachmentId") Long attachmentId ) { @@ -48,15 +48,14 @@ public ResponseEntity> getFile( .body(RsData.success("파일 조회 성공", res)); } - @PutMapping(value = "/update", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) + @PutMapping(value = "/update/{attachmentId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) public ResponseEntity> updateFile( + @PathVariable("attachmentId") Long attachmentId, @ModelAttribute @Valid FileUpdateRequestDto req, @AuthenticationPrincipal CustomUserDetails user ) { fileService.updateFile( req.getMultipartFile(), - req.getEntityType(), - req.getEntityId(), user.getUserId() ); From e73059d39dcca9e10d559bdda9c5032ef7c3f98a Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:53:17 +0900 Subject: [PATCH 09/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EC=BB=A8=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=84=9C=EB=93=9C=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 엔드 포인트 변경에 따른 파일 수정 컨트롤러 메서드 변경 --- .../com/back/domain/file/controller/FileController.java | 9 +++++---- .../com/back/domain/file/dto/FileUpdateResponseDto.java | 2 ++ 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java diff --git a/src/main/java/com/back/domain/file/controller/FileController.java b/src/main/java/com/back/domain/file/controller/FileController.java index 661b5f0d..27957718 100644 --- a/src/main/java/com/back/domain/file/controller/FileController.java +++ b/src/main/java/com/back/domain/file/controller/FileController.java @@ -49,22 +49,23 @@ public ResponseEntity> getFile( } @PutMapping(value = "/update/{attachmentId}", consumes = MediaType.MULTIPART_FORM_DATA_VALUE) - public ResponseEntity> updateFile( + public ResponseEntity> updateFile( @PathVariable("attachmentId") Long attachmentId, @ModelAttribute @Valid FileUpdateRequestDto req, @AuthenticationPrincipal CustomUserDetails user ) { - fileService.updateFile( + FileUpdateResponseDto res = fileService.updateFile( + attachmentId, req.getMultipartFile(), user.getUserId() ); return ResponseEntity .status(HttpStatus.OK) - .body(RsData.success("파일 업데이트 성공")); + .body(RsData.success("파일 업데이트 성공", res)); } - @DeleteMapping(value = "/delete") + @DeleteMapping(value = "/delete/{attachmentId}") public ResponseEntity> deleteFile( @RequestParam("entityType") @NotBlank(message = "entityType은 필수입니다.") EntityType entityType, @RequestParam("entityId") @NotBlank(message = "entityId는 필수입니다.") Long entityId, diff --git a/src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java b/src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java new file mode 100644 index 00000000..2572edd4 --- /dev/null +++ b/src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java @@ -0,0 +1,2 @@ +package com.back.domain.file.dto;public class FileUpdateResponseDto { +} From 98e7fb7115ac5ec49ea0850ff3aad21c189c7ebd Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:54:23 +0900 Subject: [PATCH 10/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=88=98?= =?UTF-8?q?=EC=A0=95=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 엔드 포인트 변경에 따른 파일 수정 로직 변경 --- .../back/domain/file/service/FileService.java | 21 +++++++++---------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/src/main/java/com/back/domain/file/service/FileService.java b/src/main/java/com/back/domain/file/service/FileService.java index 3b1597fe..e8c1a059 100644 --- a/src/main/java/com/back/domain/file/service/FileService.java +++ b/src/main/java/com/back/domain/file/service/FileService.java @@ -5,6 +5,7 @@ import com.amazonaws.services.s3.model.ObjectMetadata; import com.amazonaws.services.s3.model.PutObjectRequest; import com.back.domain.file.dto.FileReadResponseDto; +import com.back.domain.file.dto.FileUpdateResponseDto; import com.back.domain.file.dto.FileUploadResponseDto; import com.back.domain.file.entity.AttachmentMapping; import com.back.domain.file.entity.EntityType; @@ -37,7 +38,6 @@ public class FileService { private final FileAttachmentRepository fileAttachmentRepository; private final UserRepository userRepository; private final AttachmentMappingRepository attachmentMappingRepository; - private final EntityValidator entityValidator; @Transactional public FileUploadResponseDto uploadFile( @@ -82,15 +82,15 @@ public FileReadResponseDto getFile(Long attachmentId) { } @Transactional - public void updateFile( + public FileUpdateResponseDto updateFile( + Long attachmentId, MultipartFile multipartFile, - EntityType entityType, - Long entityId, Long userId ) { - entityValidator.validate(entityType, entityId); - - FileAttachment fileAttachment = getFileAttachmentOrThrow(entityType, entityId); + FileAttachment fileAttachment = fileAttachmentRepository.findById(attachmentId) + .orElseThrow(() -> + new CustomException(ErrorCode.FILE_NOT_FOUND) + ); checkAccessPermission(fileAttachment, userId); @@ -100,18 +100,17 @@ public void updateFile( // S3에 새롭게 저장할 파일 이름 String newStoredName = createFileName(multipartFile.getOriginalFilename()); - String filePath = s3Upload(newStoredName, multipartFile); + String publicURL = s3Upload(newStoredName, multipartFile); s3Delete(oldStoredName); // fileAttachment 정보 업데이트 - fileAttachment.update(newStoredName, multipartFile, filePath); + fileAttachment.update(newStoredName, multipartFile, publicURL); + return new FileUpdateResponseDto(publicURL); } @Transactional public void deleteFile(EntityType entityType, Long entityId, Long userId) { - entityValidator.validate(entityType, entityId); - AttachmentMapping attachmentMapping = attachmentMappingRepository .findByEntityTypeAndEntityId(entityType, entityId) .orElseThrow(() -> From 4f16f352c26d38533ce876e19b2ca889b0904fe9 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:55:53 +0900 Subject: [PATCH 11/19] =?UTF-8?q?Fix:=20=EC=9D=91=EB=8B=B5=20=EB=8D=B0?= =?UTF-8?q?=EC=9D=B4=ED=84=B0=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존: null - 변경: publicURL --- .../back/domain/file/dto/FileUpdateRequestDto.java | 4 ---- .../back/domain/file/dto/FileUpdateResponseDto.java | 12 +++++++++++- 2 files changed, 11 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/back/domain/file/dto/FileUpdateRequestDto.java b/src/main/java/com/back/domain/file/dto/FileUpdateRequestDto.java index 6b84d6af..c7c6de3c 100644 --- a/src/main/java/com/back/domain/file/dto/FileUpdateRequestDto.java +++ b/src/main/java/com/back/domain/file/dto/FileUpdateRequestDto.java @@ -10,8 +10,4 @@ public class FileUpdateRequestDto { @NotNull(message = "파일 입력은 필수입니다.") private MultipartFile multipartFile; - - private EntityType entityType; - - private Long entityId; } \ No newline at end of file diff --git a/src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java b/src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java index 2572edd4..caa4fa35 100644 --- a/src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java +++ b/src/main/java/com/back/domain/file/dto/FileUpdateResponseDto.java @@ -1,2 +1,12 @@ -package com.back.domain.file.dto;public class FileUpdateResponseDto { +package com.back.domain.file.dto; + +import lombok.Data; + +@Data +public class FileUpdateResponseDto { + private String publicURL; + + public FileUpdateResponseDto(String publicURL) { + this.publicURL = publicURL; + } } From 3dc59320b194654fe3f36f442a79e7ebbc5158cc Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 17:58:05 +0900 Subject: [PATCH 12/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EC=97=94=EB=93=9C=20=ED=8F=AC=EC=9D=B8=ED=8A=B8=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존: /api/file/delete?entityType=POST&entityId=1 - 변경: /api/file/delete/{attachmentId} --- .../com/back/domain/file/controller/FileController.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/main/java/com/back/domain/file/controller/FileController.java b/src/main/java/com/back/domain/file/controller/FileController.java index 27957718..6a45dd5f 100644 --- a/src/main/java/com/back/domain/file/controller/FileController.java +++ b/src/main/java/com/back/domain/file/controller/FileController.java @@ -67,13 +67,11 @@ public ResponseEntity> updateFile( @DeleteMapping(value = "/delete/{attachmentId}") public ResponseEntity> deleteFile( - @RequestParam("entityType") @NotBlank(message = "entityType은 필수입니다.") EntityType entityType, - @RequestParam("entityId") @NotBlank(message = "entityId는 필수입니다.") Long entityId, + @PathVariable("attachmentId") Long attachmentId, @AuthenticationPrincipal CustomUserDetails user ) { fileService.deleteFile( - entityType, - entityId, + attachmentId, user.getUserId() ); From dafa2098ad1cf6e683d761dd306c665fb5da2063 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 18:00:36 +0900 Subject: [PATCH 13/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=82=AD?= =?UTF-8?q?=EC=A0=9C=20=EB=A1=9C=EC=A7=81=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 엔드 포인트 변경에 따른 파일 삭제 로직 변경 --- .../java/com/back/domain/file/service/FileService.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/back/domain/file/service/FileService.java b/src/main/java/com/back/domain/file/service/FileService.java index e8c1a059..a0dd522d 100644 --- a/src/main/java/com/back/domain/file/service/FileService.java +++ b/src/main/java/com/back/domain/file/service/FileService.java @@ -110,15 +110,12 @@ public FileUpdateResponseDto updateFile( } @Transactional - public void deleteFile(EntityType entityType, Long entityId, Long userId) { - AttachmentMapping attachmentMapping = attachmentMappingRepository - .findByEntityTypeAndEntityId(entityType, entityId) + public void deleteFile(Long attachmentId, Long userId) { + FileAttachment fileAttachment = fileAttachmentRepository.findById(attachmentId) .orElseThrow(() -> - new CustomException(ErrorCode.ATTACHMENT_MAPPING_NOT_FOUND) + new CustomException(ErrorCode.FILE_NOT_FOUND) ); - FileAttachment fileAttachment = attachmentMapping.getFileAttachment(); - checkAccessPermission(fileAttachment, userId); s3Delete(fileAttachment.getStoredName()); From edeb2eabe8578b3a513300457e2c8e1ee7557ad8 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 18:01:29 +0900 Subject: [PATCH 14/19] =?UTF-8?q?Chore:=20=ED=8C=8C=EC=9D=BC=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=EC=93=B0=EC=A7=80=EC=95=8A=EB=8A=94=20?= =?UTF-8?q?=EB=A9=94=EC=84=9C=EB=93=9C/=20=EC=9D=98=EC=A1=B4=EC=84=B1=20?= =?UTF-8?q?=ED=95=84=EB=93=9C=20=EC=82=AD=EC=A0=9C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - AttachmentMappingRepository 삭제 - getFileAttachmentOrThrow(AttachmentMapping으로부터 파일정보 추출하는 함수) 삭제 --- .../com/back/domain/file/service/FileService.java | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/src/main/java/com/back/domain/file/service/FileService.java b/src/main/java/com/back/domain/file/service/FileService.java index a0dd522d..dc342e96 100644 --- a/src/main/java/com/back/domain/file/service/FileService.java +++ b/src/main/java/com/back/domain/file/service/FileService.java @@ -37,7 +37,6 @@ public class FileService { private final AmazonS3 amazonS3; private final FileAttachmentRepository fileAttachmentRepository; private final UserRepository userRepository; - private final AttachmentMappingRepository attachmentMappingRepository; @Transactional public FileUploadResponseDto uploadFile( @@ -171,15 +170,4 @@ private void checkAccessPermission(FileAttachment fileAttachment, Long userId) { throw new CustomException(ErrorCode.FILE_ACCESS_DENIED); } } - - // AttachmentMapping -> fileAttachment 추출 - private FileAttachment getFileAttachmentOrThrow(EntityType entityType, Long entityId) { - AttachmentMapping attachmentMapping = attachmentMappingRepository - .findByEntityTypeAndEntityId(entityType, entityId) - .orElseThrow(() -> - new CustomException(ErrorCode.ATTACHMENT_MAPPING_NOT_FOUND) - ); - - return attachmentMapping.getFileAttachment(); - } } \ No newline at end of file From ed1c240c2e77e06ce76dc30f9edb4c8e522bd170 Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 22:11:38 +0900 Subject: [PATCH 15/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=84=9C?= =?UTF-8?q?=EB=B9=84=EC=8A=A4=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 파일 서비스 변경에 따른 테스트 수정 --- .../domain/file/service/FileServiceTest.java | 38 ++++++------------- 1 file changed, 12 insertions(+), 26 deletions(-) diff --git a/src/test/java/com/back/domain/file/service/FileServiceTest.java b/src/test/java/com/back/domain/file/service/FileServiceTest.java index 00fb020b..e883d1cb 100644 --- a/src/test/java/com/back/domain/file/service/FileServiceTest.java +++ b/src/test/java/com/back/domain/file/service/FileServiceTest.java @@ -49,9 +49,6 @@ class FileServiceTest { @Autowired private PasswordEncoder passwordEncoder; - @Autowired - private PostRepository postRepository; - @AfterEach public void tearDown() { s3Mock.stop(); @@ -65,9 +62,6 @@ void uploadFile() { user.setUserStatus(UserStatus.ACTIVE); userRepository.save(user); - Post post = new Post(user, "제목", "내용", null); - postRepository.save(post); - String path = "test.png"; String contentType = "image/png"; String dirName = "test"; @@ -75,9 +69,10 @@ void uploadFile() { MockMultipartFile file = new MockMultipartFile("test", path, contentType, "test".getBytes()); // when - FileUploadResponseDto res = fileService.uploadFile(file, EntityType.POST, post.getId(), user.getId()); + FileUploadResponseDto res = fileService.uploadFile(file, user.getId()); // then + assertThat(res.getAttachmentId()).isPositive(); assertThat(res.getImageUrl()).contains(path); assertThat(res.getImageUrl()).contains(dirName); } @@ -90,17 +85,14 @@ void readFile() { user.setUserStatus(UserStatus.ACTIVE); userRepository.save(user); - Post post = new Post(user, "제목", "내용", null); - postRepository.save(post); - String path = "test.png"; String contentType = "image/png"; String dirName = "test"; MockMultipartFile file = new MockMultipartFile("test", path, contentType, "test".getBytes()); - fileService.uploadFile(file, EntityType.POST, post.getId(), user.getId()); + Long attachmentId = fileService.uploadFile(file, user.getId()).getAttachmentId(); //when - FileReadResponseDto res = fileService.getFile(EntityType.POST, post.getId()); + FileReadResponseDto res = fileService.getFile(attachmentId); // then assertThat(res.getImageUrl()).contains(path); @@ -115,15 +107,11 @@ void updateFile() { user.setUserStatus(UserStatus.ACTIVE); userRepository.save(user); - Post post = new Post(user, "제목", "내용", null); - postRepository.save(post); - // 기존(삭제할) 파일 정보 String path = "test.png"; String contentType = "image/png"; - String dirName = "test"; MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); - fileService.uploadFile(oldFile, EntityType.POST, post.getId(), user.getId()); + Long attachmentId = fileService.uploadFile(oldFile, user.getId()).getAttachmentId(); // 새 파일 정보 String newPath = "newTest.png"; @@ -131,8 +119,8 @@ void updateFile() { MockMultipartFile newFile = new MockMultipartFile("newTest", newPath, contentType, "newTest".getBytes()); // when - fileService.updateFile(newFile, EntityType.POST, post.getId(), user.getId()); - FileReadResponseDto res = fileService.getFile(EntityType.POST, post.getId()); + fileService.updateFile(attachmentId, newFile, user.getId()); + FileReadResponseDto res = fileService.getFile(attachmentId); // then assertThat(res.getImageUrl()).contains(newPath); @@ -147,23 +135,21 @@ void deleteFile() { user.setUserStatus(UserStatus.ACTIVE); userRepository.save(user); - Post post = new Post(user, "제목", "내용", null); - postRepository.save(post); - // 기존(삭제할) 파일 정보 String path = "test.png"; String contentType = "image/png"; String dirName = "test"; MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); - fileService.uploadFile(oldFile, EntityType.POST, post.getId(), user.getId()); + Long attachmentId = fileService.uploadFile(oldFile, user.getId()).getAttachmentId(); + // when - fileService.deleteFile(EntityType.POST, post.getId(), user.getId()); + fileService.deleteFile(attachmentId, user.getId()); CustomException exception = assertThrows(CustomException.class, () -> { - fileService.getFile(EntityType.POST, post.getId()); + fileService.getFile(attachmentId); }); // then - assertEquals(ErrorCode.ATTACHMENT_MAPPING_NOT_FOUND, exception.getErrorCode()); + assertEquals(ErrorCode.FILE_NOT_FOUND, exception.getErrorCode()); } } \ No newline at end of file From cb3fca36a31e23a7197d36cdae9462e938f1ae8e Mon Sep 17 00:00:00 2001 From: namgigun Date: Sun, 12 Oct 2025 23:14:31 +0900 Subject: [PATCH 16/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=A1=B0?= =?UTF-8?q?=ED=9A=8C/=EC=88=98=EC=A0=95=20=EC=9D=91=EB=8B=B5=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 기존: imageUrl = "S3 퍼블릭 URL" - 변경: publicURL = "S3 퍼블릭 URL" --- .../back/domain/file/dto/FileReadResponseDto.java | 6 +++--- .../back/domain/file/dto/FileUploadResponseDto.java | 6 +++--- .../back/domain/file/service/FileServiceTest.java | 13 ++++++------- 3 files changed, 12 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/back/domain/file/dto/FileReadResponseDto.java b/src/main/java/com/back/domain/file/dto/FileReadResponseDto.java index 574c200b..1eb3d5c2 100644 --- a/src/main/java/com/back/domain/file/dto/FileReadResponseDto.java +++ b/src/main/java/com/back/domain/file/dto/FileReadResponseDto.java @@ -4,9 +4,9 @@ @Data public class FileReadResponseDto { - private String imageUrl; + private String publicURL; - public FileReadResponseDto(String imageUrl) { - this.imageUrl = imageUrl; + public FileReadResponseDto(String publicURL) { + this.publicURL = publicURL; } } diff --git a/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java b/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java index 4f66e080..d4c00f93 100644 --- a/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java +++ b/src/main/java/com/back/domain/file/dto/FileUploadResponseDto.java @@ -5,10 +5,10 @@ @Data public class FileUploadResponseDto { private Long attachmentId; - private String imageUrl; + private String publicURL; - public FileUploadResponseDto(Long attachmentId, String imageUrl) { + public FileUploadResponseDto(Long attachmentId, String publicURL) { this.attachmentId = attachmentId; - this.imageUrl = imageUrl; + this.publicURL = publicURL; } } \ No newline at end of file diff --git a/src/test/java/com/back/domain/file/service/FileServiceTest.java b/src/test/java/com/back/domain/file/service/FileServiceTest.java index e883d1cb..2d6124d8 100644 --- a/src/test/java/com/back/domain/file/service/FileServiceTest.java +++ b/src/test/java/com/back/domain/file/service/FileServiceTest.java @@ -73,8 +73,8 @@ void uploadFile() { // then assertThat(res.getAttachmentId()).isPositive(); - assertThat(res.getImageUrl()).contains(path); - assertThat(res.getImageUrl()).contains(dirName); + assertThat(res.getPublicURL()).contains(path); + assertThat(res.getPublicURL()).contains(dirName); } @Test @@ -95,8 +95,8 @@ void readFile() { FileReadResponseDto res = fileService.getFile(attachmentId); // then - assertThat(res.getImageUrl()).contains(path); - assertThat(res.getImageUrl()).contains(dirName); + assertThat(res.getPublicURL()).contains(path); + assertThat(res.getPublicURL()).contains(dirName); } @Test @@ -123,8 +123,8 @@ void updateFile() { FileReadResponseDto res = fileService.getFile(attachmentId); // then - assertThat(res.getImageUrl()).contains(newPath); - assertThat(res.getImageUrl()).contains(newDirName); + assertThat(res.getPublicURL()).contains(newPath); + assertThat(res.getPublicURL()).contains(newDirName); } @Test @@ -138,7 +138,6 @@ void deleteFile() { // 기존(삭제할) 파일 정보 String path = "test.png"; String contentType = "image/png"; - String dirName = "test"; MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); Long attachmentId = fileService.uploadFile(oldFile, user.getId()).getAttachmentId(); From ff0f7dcfd24848d407c9a812a5afa96b6248b34e Mon Sep 17 00:00:00 2001 From: namgigun Date: Mon, 13 Oct 2025 09:32:55 +0900 Subject: [PATCH 17/19] =?UTF-8?q?Fix:=20CORS=20=EC=84=A4=EC=A0=95=20?= =?UTF-8?q?=EB=B3=80=EA=B2=BD=20=ED=94=84=EB=A1=A0=ED=8A=B8=20=EC=9A=B4?= =?UTF-8?q?=EC=98=81=EC=84=9C=EB=B2=84=20=EB=B0=98=EC=98=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/main/java/com/back/global/security/SecurityConfig.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/back/global/security/SecurityConfig.java b/src/main/java/com/back/global/security/SecurityConfig.java index fdd13498..edcde415 100644 --- a/src/main/java/com/back/global/security/SecurityConfig.java +++ b/src/main/java/com/back/global/security/SecurityConfig.java @@ -89,7 +89,7 @@ public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") .allowedOrigins( "http://localhost:3000", // Catfe 프론트 개발 서버 - "https://www.catfe.com" // Catfe 프론트 운영 서버 + "https://www.catfe.site" // Catfe 프론트 운영 서버 ) .allowedMethods("GET", "POST", "PUT", "DELETE", "PATCH", "OPTIONS") .allowedHeaders("*") From 9342c47607052da7c4b148e90a2ed1b24419da75 Mon Sep 17 00:00:00 2001 From: namgigun Date: Mon, 13 Oct 2025 09:33:57 +0900 Subject: [PATCH 18/19] =?UTF-8?q?Test:=20=ED=8C=8C=EC=9D=BC=20=EC=BB=A8?= =?UTF-8?q?=ED=8A=B8=EB=A1=A4=EB=9F=AC=20=ED=85=8C=EC=8A=A4=ED=8A=B8=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../file/controller/FileControllerTest.java | 333 +++++++++++++++++- 1 file changed, 317 insertions(+), 16 deletions(-) diff --git a/src/test/java/com/back/domain/file/controller/FileControllerTest.java b/src/test/java/com/back/domain/file/controller/FileControllerTest.java index 874644ae..93970213 100644 --- a/src/test/java/com/back/domain/file/controller/FileControllerTest.java +++ b/src/test/java/com/back/domain/file/controller/FileControllerTest.java @@ -1,8 +1,8 @@ package com.back.domain.file.controller; -import com.back.domain.board.post.entity.Post; -import com.back.domain.board.post.repository.PostRepository; import com.back.domain.file.config.S3MockConfig; +import com.back.domain.file.dto.FileUploadResponseDto; +import com.back.domain.file.service.FileService; import com.back.domain.user.entity.User; import com.back.domain.user.entity.UserProfile; import com.back.domain.user.entity.UserStatus; @@ -25,7 +25,8 @@ import java.time.LocalDate; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.multipart; +import static org.hamcrest.Matchers.not; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -49,10 +50,10 @@ class FileControllerTest { private PasswordEncoder passwordEncoder; @Autowired - private PostRepository postRepository; + private TestJwtTokenProvider testJwtTokenProvider; @Autowired - private TestJwtTokenProvider testJwtTokenProvider; + private FileService fileService; private String generateAccessToken(User user) { return testJwtTokenProvider.createAccessToken( @@ -78,9 +79,6 @@ void uploadFile_success() throws Exception { String accessToken = generateAccessToken(user); - Post post = new Post(user, "첫 글", "내용", null); - postRepository.save(post); - MockMultipartFile multipartFile = new MockMultipartFile( "multipartFile", "test.png", @@ -92,8 +90,6 @@ void uploadFile_success() throws Exception { ResultActions resultActions = mvc.perform( multipart("/api/file/upload") // 👈 post() 대신 multipart() 사용 .file(multipartFile) // 파일 필드 - .param("entityType", "POST") // DTO 필드 매핑 - .param("entityId", post.getId().toString()) .header("Authorization", "Bearer " + accessToken) .characterEncoding("UTF-8") ); @@ -105,7 +101,7 @@ void uploadFile_success() throws Exception { } @Test - @DisplayName("파일 업로드 실패 - 파일이 없는 경우") + @DisplayName("파일 업로드 실패 - 파일 입력이 없는 경우") void uploadFile_fail_noFile() throws Exception { // given User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); @@ -115,14 +111,9 @@ void uploadFile_fail_noFile() throws Exception { String accessToken = generateAccessToken(user); - Post post = new Post(user, "첫 글", "내용", null); - postRepository.save(post); - // when ResultActions resultActions = mvc.perform( multipart("/api/file/upload") // 👈 post() 대신 multipart() 사용 - .param("entityType", "POST") // DTO 필드 매핑 - .param("entityId", post.getId().toString()) .header("Authorization", "Bearer " + accessToken) .characterEncoding("UTF-8") ); @@ -133,4 +124,314 @@ void uploadFile_fail_noFile() throws Exception { .andExpect(jsonPath("$.message").value("잘못된 요청입니다.")) .andDo(print()); } + + @Test + @DisplayName("파일 조회 성공") + void readFile_success() throws Exception { + // given + User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + user.setUserProfile(new UserProfile(user, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + user.setUserStatus(UserStatus.ACTIVE); + userRepository.save(user); + + String accessToken = generateAccessToken(user); + + MockMultipartFile multipartFile = new MockMultipartFile( + "multipartFile", + "test.png", + "image/png", + "test".getBytes() + ); + + FileUploadResponseDto fileUploadResponseDto = fileService.uploadFile(multipartFile, user.getId()); + + // when + ResultActions resultActions = mvc.perform( + get("/api/file/read/" + fileUploadResponseDto.getAttachmentId()) + .header("Authorization", "Bearer " + accessToken) + ); + + // then + resultActions.andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value("SUCCESS_200")) + .andExpect(jsonPath("$.message").value("파일 조회 성공")) + .andExpect(jsonPath("$.data.publicURL").value(fileUploadResponseDto.getPublicURL())) + .andDo(print()); + + } + + @Test + @DisplayName("파일 조회 실패 - 없는 파일 정보 조회") + void readFile_failWhenFileNotFound() throws Exception { + // given + User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + user.setUserProfile(new UserProfile(user, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + user.setUserStatus(UserStatus.ACTIVE); + userRepository.save(user); + + String accessToken = generateAccessToken(user); + + Long attachmentId = 10000000L; + + // when + ResultActions resultActions = mvc.perform( + get("/api/file/read/" + attachmentId) + .header("Authorization", "Bearer " + accessToken) + ); + + // then + resultActions.andExpect(status().isNotFound()) + .andExpect(jsonPath("$.code").value("FILE_004")) + .andExpect(jsonPath("$.message").value("파일 정보를 찾을 수 없습니다.")) + .andDo(print()); + } + + @Test + @DisplayName("파일 수정 성공") + void updateFile_success() throws Exception { + // given + User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + user.setUserProfile(new UserProfile(user, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + user.setUserStatus(UserStatus.ACTIVE); + userRepository.save(user); + + String accessToken = generateAccessToken(user); + + // 기존(삭제할) 파일 정보 + String path = "test.png"; + String contentType = "image/png"; + MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); + FileUploadResponseDto fileUploadResponseDto = fileService.uploadFile(oldFile, user.getId()); + + // 새 파일 정보 + String newPath = "newTest.png"; + MockMultipartFile newFile = new MockMultipartFile("multipartFile", newPath, contentType, "newTest".getBytes()); + + // when + ResultActions resultActions = mvc.perform( + multipart("/api/file/update/" + fileUploadResponseDto.getAttachmentId()) + .file(newFile) // 파일 필드 + .header("Authorization", "Bearer " + accessToken) + .characterEncoding("UTF-8") + .with(request -> { + request.setMethod("PUT"); + return request; + }) // PUT 매핑인 것을 나타낸다. + ); + + // then + resultActions.andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value("SUCCESS_200")) + .andExpect(jsonPath("$.message").value("파일 업데이트 성공")) + .andExpect(jsonPath("$.data.publicURL", not(fileUploadResponseDto.getPublicURL()))) + .andDo(print()); + } + + @Test + @DisplayName("파일 수정 실패 - 없는 아이디 조회") + void updateFile_failWhenFileNotFound() throws Exception { + // given + User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + user.setUserProfile(new UserProfile(user, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + user.setUserStatus(UserStatus.ACTIVE); + userRepository.save(user); + + String accessToken = generateAccessToken(user); + + // 새 파일 정보 + String newPath = "newTest.png"; + String contentType = "image/png"; + MockMultipartFile newFile = new MockMultipartFile("multipartFile", newPath, contentType, "newTest".getBytes()); + + Long attachmentId = 1000000L; + + // when + ResultActions resultActions = mvc.perform( + multipart("/api/file/update/" + attachmentId) + .file(newFile) // 파일 필드 + .header("Authorization", "Bearer " + accessToken) + .characterEncoding("UTF-8") + .with(request -> { + request.setMethod("PUT"); + return request; + }) // PUT 매핑인 것을 나타낸다. + ); + + // then + resultActions.andExpect(status().isNotFound()) + .andExpect(jsonPath("$.code").value("FILE_004")) + .andExpect(jsonPath("$.message").value("파일 정보를 찾을 수 없습니다.")) + .andDo(print()); + } + + @Test + @DisplayName("파일 수정 실패 - 파일 입력이 없는 경우") + void updateFile_fail_noFile() throws Exception { + // given + User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + user.setUserProfile(new UserProfile(user, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + user.setUserStatus(UserStatus.ACTIVE); + userRepository.save(user); + + String accessToken = generateAccessToken(user); + + // 기존(삭제할) 파일 정보 + String path = "test.png"; + String contentType = "image/png"; + MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); + FileUploadResponseDto fileUploadResponseDto = fileService.uploadFile(oldFile, user.getId()); + + // when + ResultActions resultActions = mvc.perform( + multipart("/api/file/update/" + fileUploadResponseDto.getAttachmentId()) + .header("Authorization", "Bearer " + accessToken) + .characterEncoding("UTF-8") + .with(request -> { + request.setMethod("PUT"); + return request; + }) // PUT 매핑인 것을 나타낸다. + ); + + // then + resultActions.andExpect(status().isBadRequest()) + .andExpect(jsonPath("$.code").value("COMMON_400")) + .andExpect(jsonPath("$.message").value("잘못된 요청입니다.")) + .andDo(print()); + } + + @Test + @DisplayName("파일 수정 성공 - 파일 접근 권한 없음") + void updateFile_failWhenAccessDenied() throws Exception { + // given + User writer = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + writer.setUserProfile(new UserProfile(writer, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + writer.setUserStatus(UserStatus.ACTIVE); + userRepository.save(writer); + + User reader = User.createUser("reader", "reader@example.com", passwordEncoder.encode("P@ssw0rd!")); + reader.setUserProfile(new UserProfile(reader, "홍길순", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + reader.setUserStatus(UserStatus.ACTIVE); + userRepository.save(reader); + + String accessToken = generateAccessToken(reader); + + // 기존(삭제할) 파일 정보 + String path = "test.png"; + String contentType = "image/png"; + MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); + FileUploadResponseDto fileUploadResponseDto = fileService.uploadFile(oldFile, writer.getId()); + + // 새 파일 정보 + String newPath = "newTest.png"; + MockMultipartFile newFile = new MockMultipartFile("multipartFile", newPath, contentType, "newTest".getBytes()); + + // when + ResultActions resultActions = mvc.perform( + multipart("/api/file/update/" + fileUploadResponseDto.getAttachmentId()) + .file(newFile) // 파일 필드 + .header("Authorization", "Bearer " + accessToken) + .characterEncoding("UTF-8") + .with(request -> { + request.setMethod("PUT"); + return request; + }) // PUT 매핑인 것을 나타낸다. + ); + + // then + resultActions.andExpect(status().isForbidden()) + .andExpect(jsonPath("$.code").value("FILE_003")) + .andExpect(jsonPath("$.message").value("파일을 접근할 권한이 없습니다.")) + .andDo(print()); + } + + @Test + @DisplayName("파일 삭제 성공") + void deleteFile_success() throws Exception { + // given + User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + user.setUserProfile(new UserProfile(user, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + user.setUserStatus(UserStatus.ACTIVE); + userRepository.save(user); + + String accessToken = generateAccessToken(user); + + // 기존(삭제할) 파일 정보 + String path = "test.png"; + String contentType = "image/png"; + MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); + FileUploadResponseDto fileUploadResponseDto = fileService.uploadFile(oldFile, user.getId()); + + // when + ResultActions resultActions = mvc.perform( + delete("/api/file/delete/" + fileUploadResponseDto.getAttachmentId()) + .header("Authorization", "Bearer " + accessToken) + ); + + // then + resultActions.andExpect(status().isOk()) + .andExpect(jsonPath("$.code").value("SUCCESS_200")) + .andExpect(jsonPath("$.message").value("파일 삭제 성공")) + .andDo(print()); + } + + @Test + @DisplayName("파일 삭제 실패 - 파일 접근 권한 없음") + void deleteFile_failWhenAccessDenied() throws Exception { + // given + User writer = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + writer.setUserProfile(new UserProfile(writer, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + writer.setUserStatus(UserStatus.ACTIVE); + userRepository.save(writer); + + User reader = User.createUser("reader", "reader@example.com", passwordEncoder.encode("P@ssw0rd!")); + reader.setUserProfile(new UserProfile(reader, "홍길순", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + reader.setUserStatus(UserStatus.ACTIVE); + userRepository.save(reader); + + String accessToken = generateAccessToken(reader); + + // 기존(삭제할) 파일 정보 + String path = "test.png"; + String contentType = "image/png"; + MockMultipartFile oldFile = new MockMultipartFile("test", path, contentType, "test".getBytes()); + FileUploadResponseDto fileUploadResponseDto = fileService.uploadFile(oldFile, writer.getId()); + + // when + ResultActions resultActions = mvc.perform( + delete("/api/file/delete/" + fileUploadResponseDto.getAttachmentId()) + .header("Authorization", "Bearer " + accessToken) + ); + + // then + resultActions.andExpect(status().isForbidden()) + .andExpect(jsonPath("$.code").value("FILE_003")) + .andExpect(jsonPath("$.message").value("파일을 접근할 권한이 없습니다.")) + .andDo(print()); + } + + @Test + @DisplayName("파일 삭제 실패 - 없는 파일 정보 조회") + void deleteFile_failWhenFileNotFound() throws Exception { + // given + User user = User.createUser("writer", "writer@example.com", passwordEncoder.encode("P@ssw0rd!")); + user.setUserProfile(new UserProfile(user, "홍길동", null, "소개글", LocalDate.of(2000, 1, 1), 1000)); + user.setUserStatus(UserStatus.ACTIVE); + userRepository.save(user); + + String accessToken = generateAccessToken(user); + + Long attachmentId = 1000000L; + + // when + ResultActions resultActions = mvc.perform( + delete("/api/file/delete/" + attachmentId) + .header("Authorization", "Bearer " + accessToken) + ); + + // then + resultActions.andExpect(status().isNotFound()) + .andExpect(jsonPath("$.code").value("FILE_004")) + .andExpect(jsonPath("$.message").value("파일 정보를 찾을 수 없습니다.")) + .andDo(print()); + } } \ No newline at end of file From bbda68aa317ece7db97a423eb6c6bb3046a84536 Mon Sep 17 00:00:00 2001 From: namgigun Date: Mon, 13 Oct 2025 12:03:00 +0900 Subject: [PATCH 19/19] =?UTF-8?q?Fix:=20=ED=8C=8C=EC=9D=BC=20=EC=A0=91?= =?UTF-8?q?=EA=B7=BC=20=EA=B6=8C=ED=95=9C=20=EC=B2=B4=ED=81=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 기존 : "!=" 비교 변경 : "equals" 비교 --- src/main/java/com/back/domain/file/service/FileService.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/back/domain/file/service/FileService.java b/src/main/java/com/back/domain/file/service/FileService.java index dc342e96..74b03023 100644 --- a/src/main/java/com/back/domain/file/service/FileService.java +++ b/src/main/java/com/back/domain/file/service/FileService.java @@ -166,7 +166,7 @@ private String createFileName(String fileName) { // 파일 접근 권한 체크 private void checkAccessPermission(FileAttachment fileAttachment, Long userId) { - if (fileAttachment.getUser().getId() != userId) { + if (!fileAttachment.getUser().getId().equals(userId)) { throw new CustomException(ErrorCode.FILE_ACCESS_DENIED); } }