diff --git a/src/main/java/com/project/trainingdiary/controller/DietController.java b/src/main/java/com/project/trainingdiary/controller/DietController.java index 51b1ed7b..656b77c4 100644 --- a/src/main/java/com/project/trainingdiary/controller/DietController.java +++ b/src/main/java/com/project/trainingdiary/controller/DietController.java @@ -42,6 +42,7 @@ public class DietController { ) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "415", description = "유효하지 않은 미디어 타입 입니다.") }) @PreAuthorize("hasRole('TRAINEE')") @PostMapping(consumes = MediaType.MULTIPART_FORM_DATA_VALUE) @@ -65,6 +66,7 @@ public ResponseEntity createDiet( @GetMapping("{id}") @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "403", description = "트레이너랑 트레이니 사이의 계약이 없습니다.") }) @PreAuthorize("hasRole('TRAINER') or hasRole('TRAINEE')") public ResponseEntity> getTraineeDiets( @@ -84,6 +86,7 @@ public ResponseEntity> getTraineeDiets( ) @ApiResponses(value = { @ApiResponse(responseCode = "200", description = "성공"), + @ApiResponse(responseCode = "403", description = "트레이너랑 트레이니 사이의 계약이 없습니다.") }) @PreAuthorize("hasRole('TRAINER') or hasRole('TRAINEE')") @GetMapping("{id}/details") diff --git a/src/main/java/com/project/trainingdiary/dto/response/diet/DietDetailsInfoResponseDto.java b/src/main/java/com/project/trainingdiary/dto/response/diet/DietDetailsInfoResponseDto.java index 49dd9dbf..9765d8db 100644 --- a/src/main/java/com/project/trainingdiary/dto/response/diet/DietDetailsInfoResponseDto.java +++ b/src/main/java/com/project/trainingdiary/dto/response/diet/DietDetailsInfoResponseDto.java @@ -3,6 +3,7 @@ import com.project.trainingdiary.dto.response.comment.CommentDto; import com.project.trainingdiary.entity.CommentEntity; import com.project.trainingdiary.entity.DietEntity; +import com.project.trainingdiary.util.ConvertCloudFrontUrlUtil; import java.time.LocalDate; import java.util.List; import lombok.Builder; @@ -18,20 +19,19 @@ public class DietDetailsInfoResponseDto { private List comments; private LocalDate createdDate; - public static DietDetailsInfoResponseDto of(DietEntity diet, - List comments) { + public static DietDetailsInfoResponseDto of(DietEntity diet, List comments) { - List commentDto = comments.stream() - .sorted((a, b) -> b.getCreatedAt().compareTo(a.getCreatedAt())) - .map(CommentDto::fromEntity) + List commentDtoList = comments.stream() + .sorted((a, b) -> b.getCreatedAt().compareTo(a.getCreatedAt())) // 최신 댓글이 위로 오도록 정렬 + .map(CommentDto::fromEntity) // CommentEntity를 CommentDto로 변환 .toList(); return DietDetailsInfoResponseDto.builder() .id(diet.getId()) - .imageUrl(diet.getOriginalUrl()) + .imageUrl(ConvertCloudFrontUrlUtil.convertToCloudFrontUrl(diet.getOriginalUrl())) .content(diet.getContent()) - .comments(commentDto) + .comments(commentDtoList) .createdDate(diet.getCreatedAt().toLocalDate()) .build(); } -} +} \ No newline at end of file diff --git a/src/main/java/com/project/trainingdiary/dto/response/trainer/TraineeInfoResponseDto.java b/src/main/java/com/project/trainingdiary/dto/response/trainer/TraineeInfoResponseDto.java index e5ca4307..3e840a5a 100644 --- a/src/main/java/com/project/trainingdiary/dto/response/trainer/TraineeInfoResponseDto.java +++ b/src/main/java/com/project/trainingdiary/dto/response/trainer/TraineeInfoResponseDto.java @@ -58,19 +58,22 @@ private static int calculateAge(LocalDate birthDate) { return birthDate != null ? Period.between(birthDate, LocalDate.now()).getYears() : 0; } - private static List mapToWeightHistory(List inBodyRecords) { + private static List mapToWeightHistory( + List inBodyRecords) { return inBodyRecords.stream() .map(WeightHistoryDto::fromEntity) .collect(Collectors.toList()); } - private static List mapToBodyFatHistory(List inBodyRecords) { + private static List mapToBodyFatHistory( + List inBodyRecords) { return inBodyRecords.stream() .map(BodyFatHistoryDto::fromEntity) .collect(Collectors.toList()); } - private static List mapToMuscleMassHistory(List inBodyRecords) { + private static List mapToMuscleMassHistory( + List inBodyRecords) { return inBodyRecords.stream() .map(MuscleMassHistoryDto::fromEntity) .collect(Collectors.toList()); diff --git a/src/main/java/com/project/trainingdiary/exception/ptcontract/PtContractNotExistException.java b/src/main/java/com/project/trainingdiary/exception/ptcontract/PtContractNotExistException.java index 467f6abd..ca617411 100644 --- a/src/main/java/com/project/trainingdiary/exception/ptcontract/PtContractNotExistException.java +++ b/src/main/java/com/project/trainingdiary/exception/ptcontract/PtContractNotExistException.java @@ -6,6 +6,6 @@ public class PtContractNotExistException extends GlobalException { public PtContractNotExistException() { - super(HttpStatus.NOT_FOUND, "계약이 없습니다."); + super(HttpStatus.FORBIDDEN, "계약이 없습니다."); } } diff --git a/src/main/java/com/project/trainingdiary/provider/S3DietImageProvider.java b/src/main/java/com/project/trainingdiary/provider/S3DietImageProvider.java new file mode 100644 index 00000000..658ddcc9 --- /dev/null +++ b/src/main/java/com/project/trainingdiary/provider/S3DietImageProvider.java @@ -0,0 +1,68 @@ +package com.project.trainingdiary.provider; + +import static com.project.trainingdiary.util.MediaUtil.getExtension; +import static com.project.trainingdiary.util.MediaUtil.getMediaType; + +import com.project.trainingdiary.util.MediaUtil; +import io.awspring.cloud.s3.ObjectMetadata; +import io.awspring.cloud.s3.S3Operations; +import io.awspring.cloud.s3.S3Resource; +import java.awt.image.BufferedImage; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.UUID; +import javax.imageio.ImageIO; +import lombok.RequiredArgsConstructor; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; +import org.springframework.web.multipart.MultipartFile; + +@RequiredArgsConstructor +@Component +public class S3DietImageProvider { + + @Value("${spring.cloud.aws.s3.bucket}") + private String bucket; + + private final S3Operations s3Operations; + + public String uploadImageToS3(MultipartFile file) throws IOException { + BufferedImage originalImage = ImageIO.read(file.getInputStream()); + BufferedImage resizedImage = MediaUtil.resizeOriginalImage(originalImage); + String extension = getExtension(MediaUtil.checkFileNameExist(file)); + String key = UUID.randomUUID() + "." + extension; + + try (ByteArrayOutputStream baos = new ByteArrayOutputStream()) { + ImageIO.write(resizedImage, extension, baos); + try (InputStream inputStream = new ByteArrayInputStream(baos.toByteArray())) { + S3Resource s3Resource = s3Operations.upload(bucket, key, inputStream, + ObjectMetadata.builder().contentType(file.getContentType()).build()); + return s3Resource.getURL().toExternalForm(); + } + } + } + + public String uploadThumbnailToS3(MultipartFile file, String originalKey, String extension) + throws IOException { + BufferedImage originalImage = ImageIO.read(file.getInputStream()); + BufferedImage thumbnailImage = MediaUtil.resizeThumbnail(originalImage); + + try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { + ImageIO.write(thumbnailImage, extension, byteArrayOutputStream); + try (InputStream inputStream = new ByteArrayInputStream( + byteArrayOutputStream.toByteArray())) { + String thumbnailKey = "thumb_" + originalKey.substring(originalKey.lastIndexOf("/") + 1); + S3Resource s3Resource = s3Operations.upload(bucket, thumbnailKey, inputStream, + ObjectMetadata.builder().contentType(getMediaType(extension)).build()); + return s3Resource.getURL().toExternalForm(); + } + } + } + + public void deleteFileFromS3(String fileUrl) { + String fileKey = fileUrl.substring(fileUrl.lastIndexOf("/") + 1); + s3Operations.deleteObject(bucket, fileKey); + } +} diff --git a/src/main/java/com/project/trainingdiary/provider/S3Provider.java b/src/main/java/com/project/trainingdiary/provider/S3Provider.java deleted file mode 100644 index 8146ed5c..00000000 --- a/src/main/java/com/project/trainingdiary/provider/S3Provider.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.project.trainingdiary.provider; - -public class S3Provider { - -} diff --git a/src/main/java/com/project/trainingdiary/service/DietService.java b/src/main/java/com/project/trainingdiary/service/DietService.java index b0c59079..99c73439 100644 --- a/src/main/java/com/project/trainingdiary/service/DietService.java +++ b/src/main/java/com/project/trainingdiary/service/DietService.java @@ -13,11 +13,13 @@ import com.project.trainingdiary.exception.user.UserNotFoundException; import com.project.trainingdiary.exception.workout.InvalidFileTypeException; import com.project.trainingdiary.model.type.UserRoleType; +import com.project.trainingdiary.provider.S3DietImageProvider; import com.project.trainingdiary.repository.DietRepository; import com.project.trainingdiary.repository.TraineeRepository; import com.project.trainingdiary.repository.TrainerRepository; import com.project.trainingdiary.repository.ptContract.PtContractRepository; -import com.project.trainingdiary.util.ImageUtil; +import com.project.trainingdiary.util.ConvertCloudFrontUrlUtil; +import com.project.trainingdiary.util.MediaUtil; import java.io.IOException; import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; @@ -39,7 +41,7 @@ public class DietService { private final TrainerRepository trainerRepository; private final PtContractRepository ptContractRepository; - private final ImageUtil imageUtil; + private final S3DietImageProvider s3DietImageProvider; /** * 새로운 식단을 생성합니다. @@ -53,13 +55,12 @@ public void createDiet(CreateDietRequestDto dto) throws IOException { TraineeEntity trainee = getAuthenticatedTrainee(); MultipartFile imageFile = dto.getImage(); - if (!imageUtil.isValidImageType(imageFile)) { - throw new InvalidFileTypeException(); - } + validateImageFileType(imageFile); - String originalUrl = imageUtil.uploadImageToS3(imageFile); - String extension = imageUtil.getExtension(imageFile.getOriginalFilename()); - String thumbnailUrl = imageUtil.createAndUploadThumbnail(imageFile, originalUrl, extension); + String originalUrl = s3DietImageProvider.uploadImageToS3(imageFile); + String extension = MediaUtil.getExtension(MediaUtil.checkFileNameExist(imageFile)); + String thumbnailUrl = s3DietImageProvider.uploadThumbnailToS3(imageFile, originalUrl, + extension); DietEntity diet = new DietEntity(); diet.setTrainee(trainee); @@ -99,14 +100,9 @@ public Page getDiets(Long id, Pageable pageable) { private Page getDietsForTraineeByTrainer(Long id, Pageable pageable) { TrainerEntity trainer = getAuthenticatedTrainer(); TraineeEntity trainee = getTraineeById(id); - hasContractWithTrainee(trainer, trainee); + validateContractWithTrainee(trainer, trainee); - Page dietPage = dietRepository.findByTraineeId(id, pageable); - - return dietPage.map(diet -> DietImageResponseDto.builder() - .dietId(diet.getId()) - .thumbnailUrl(diet.getThumbnailUrl()) - .build()); + return mapToDietImageResponseDtos(dietRepository.findByTraineeId(id, pageable)); } /** @@ -123,12 +119,7 @@ private Page getDietsForTrainee(Long id, Pageable pageable throw new DietNotExistException(); } - Page dietPage = dietRepository.findByTraineeId(id, pageable); - - return dietPage.map(diet -> DietImageResponseDto.builder() - .dietId(diet.getId()) - .thumbnailUrl(diet.getThumbnailUrl()) - .build()); + return mapToDietImageResponseDtos(dietRepository.findByTraineeId(id, pageable)); } /** @@ -177,7 +168,7 @@ private DietDetailsInfoResponseDto getDietDetailsInfoForTrainer(Long id) { DietEntity diet = dietRepository.findByIdWithCommentsAndTrainer(id) .orElseThrow(DietNotExistException::new); - hasContractWithTrainee(trainer, diet.getTrainee()); + validateContractWithTrainee(trainer, diet.getTrainee()); return DietDetailsInfoResponseDto.of(diet, diet.getComments()); } @@ -190,14 +181,12 @@ private DietDetailsInfoResponseDto getDietDetailsInfoForTrainer(Long id) { */ @Transactional public void deleteDiet(Long id) { - TraineeEntity trainee = getAuthenticatedTrainee(); DietEntity diet = dietRepository.findByTraineeIdAndId(trainee.getId(), id) .orElseThrow(DietNotExistException::new); - imageUtil.deleteFileFromS3(diet.getOriginalUrl()); - imageUtil.deleteFileFromS3(diet.getThumbnailUrl()); + deleteDietImages(diet); dietRepository.delete(diet); } @@ -209,7 +198,7 @@ public void deleteDiet(Long id) { * @param trainee 트레이니 엔티티 * @throws PtContractNotExistException 트레이너와 트레이니 사이에 계약이 없을 경우 예외 발생 */ - private void hasContractWithTrainee(TrainerEntity trainer, TraineeEntity trainee) { + private void validateContractWithTrainee(TrainerEntity trainer, TraineeEntity trainee) { ptContractRepository.findByTrainerIdAndTraineeId(trainer.getId(), trainee.getId()) .orElseThrow(PtContractNotExistException::new); } @@ -221,10 +210,7 @@ private void hasContractWithTrainee(TrainerEntity trainer, TraineeEntity trainee * @throws TraineeNotFoundException 인증된 트레이니가 존재하지 않을 경우 예외 발생 */ private TraineeEntity getAuthenticatedTrainee() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || authentication.getName() == null) { - throw new TraineeNotFoundException(); - } + Authentication authentication = getAuthentication(); String email = authentication.getName(); return traineeRepository.findByEmail(email) .orElseThrow(TraineeNotFoundException::new); @@ -237,15 +223,13 @@ private TraineeEntity getAuthenticatedTrainee() { * @throws TrainerNotFoundException 인증된 트레이너가 존재하지 않을 경우 예외 발생 */ private TrainerEntity getAuthenticatedTrainer() { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - if (authentication == null || authentication.getName() == null) { - throw new TrainerNotFoundException(); - } + Authentication authentication = getAuthentication(); String email = authentication.getName(); return trainerRepository.findByEmail(email) .orElseThrow(TrainerNotFoundException::new); } + /** * 트레이니 ID로 트레이니를 조회합니다. * @@ -265,10 +249,57 @@ private TraineeEntity getTraineeById(Long id) { */ private UserRoleType getMyRole() { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - if (auth.getAuthorities().stream().anyMatch(a -> a.getAuthority().equals("ROLE_TRAINER"))) { - return UserRoleType.TRAINER; - } else { - return UserRoleType.TRAINEE; + return auth.getAuthorities().stream() + .anyMatch(a -> a.getAuthority().equals("ROLE_TRAINER")) ? UserRoleType.TRAINER + : UserRoleType.TRAINEE; + } + + /** + * 이미지 파일 타입을 확인합니다. + * + * @param imageFile 이미지 파일 + * @throws InvalidFileTypeException 이미지 파일 타입이 유효하지 않을 경우 예외 발생 + */ + private void validateImageFileType(MultipartFile imageFile) { + if (!MediaUtil.isValidImageType(imageFile)) { + throw new InvalidFileTypeException(); } } + + /** + * 다이어트 이미지를 삭제합니다. + * + * @param diet 다이어트 엔티티 + */ + private void deleteDietImages(DietEntity diet) { + s3DietImageProvider.deleteFileFromS3(diet.getOriginalUrl()); + s3DietImageProvider.deleteFileFromS3(diet.getThumbnailUrl()); + } + + /** + * Authentication 객체를 반환합니다. + * + * @return 인증된 Authentication 객체 + * @throws TraineeNotFoundException 인증된 트레이니가 존재하지 않을 경우 예외 발생 + */ + private Authentication getAuthentication() { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication == null || authentication.getName() == null) { + throw new TraineeNotFoundException(); + } + return authentication; + } + + /** + * 다이어트 엔티티 페이지를 다이어트 이미지 응답 DTO 페이지로 변환합니다. + * + * @param dietPage 다이어트 엔티티 페이지 + * @return 다이어트 이미지 응답 DTO 페이지 + */ + private Page mapToDietImageResponseDtos(Page dietPage) { + return dietPage.map(diet -> DietImageResponseDto.builder() + .dietId(diet.getId()) + .thumbnailUrl(ConvertCloudFrontUrlUtil.convertToCloudFrontUrl(diet.getThumbnailUrl())) + .build()); + } } \ No newline at end of file diff --git a/src/main/java/com/project/trainingdiary/util/ImageUtil.java b/src/main/java/com/project/trainingdiary/util/ImageUtil.java deleted file mode 100644 index 26e3cc21..00000000 --- a/src/main/java/com/project/trainingdiary/util/ImageUtil.java +++ /dev/null @@ -1,94 +0,0 @@ -package com.project.trainingdiary.util; - -import io.awspring.cloud.s3.ObjectMetadata; -import io.awspring.cloud.s3.S3Operations; -import io.awspring.cloud.s3.S3Resource; -import java.awt.image.BufferedImage; -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.InputStream; -import java.util.UUID; -import javax.imageio.ImageIO; -import lombok.RequiredArgsConstructor; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; -import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.MediaType; -import org.springframework.stereotype.Component; -import org.springframework.web.multipart.MultipartFile; - -@Component -@RequiredArgsConstructor -public class ImageUtil { - - private final S3Operations s3Operations; - - @Value("${spring.cloud.aws.s3.bucket}") - private String bucket; - - private static final int THUMBNAIL_WIDTH = 150; - private static final int THUMBNAIL_HEIGHT = 150; - - public String uploadImageToS3(MultipartFile file) throws IOException { - String extension = getExtension(file.getOriginalFilename()); - String key = UUID.randomUUID() + "." + extension; - - try (InputStream inputStream = file.getInputStream()) { - S3Resource s3Resource = s3Operations.upload(bucket, key, inputStream, - ObjectMetadata.builder().contentType(file.getContentType()).build()); - return s3Resource.getURL().toExternalForm(); - } - } - - public String createAndUploadThumbnail(MultipartFile file, String originalKey, String extension) - throws IOException { - BufferedImage originalImage = ImageIO.read(file.getInputStream()); - BufferedImage thumbnailImage = Scalr - .resize(originalImage, Method.QUALITY, Mode.AUTOMATIC, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT); - - try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) { - ImageIO.write(thumbnailImage, extension, byteArrayOutputStream); - try (InputStream inputStream = new ByteArrayInputStream( - byteArrayOutputStream.toByteArray())) { - String thumbnailKey = "thumb_" + originalKey.substring(originalKey.lastIndexOf("/") + 1); - S3Resource s3Resource = s3Operations.upload(bucket, thumbnailKey, inputStream, - ObjectMetadata.builder().contentType(getMediaType(extension)).build()); - return s3Resource.getURL().toExternalForm(); - } - } - } - - public boolean isValidImageType(MultipartFile file) { - return MediaType.IMAGE_JPEG.toString().equals(file.getContentType()) || - MediaType.IMAGE_PNG.toString().equals(file.getContentType()); - } - - public String getExtension(String filename) { - if (filename == null) { - return ""; - } - int dotIndex = filename.lastIndexOf('.'); - return (dotIndex == -1) ? "" : filename.substring(dotIndex + 1); - } - - private String getMediaType(String extension) { - if ("jpg".equalsIgnoreCase(extension) || "jpeg".equalsIgnoreCase(extension)) { - return MediaType.IMAGE_JPEG_VALUE; - } else if ("png".equalsIgnoreCase(extension)) { - return MediaType.IMAGE_PNG_VALUE; - } - return MediaType.APPLICATION_OCTET_STREAM_VALUE; - } - - /** - * S3에서 파일을 삭제합니다. - * - * @param fileUrl 삭제할 파일의 URL - */ - public void deleteFileFromS3(String fileUrl) { - String fileKey = fileUrl.substring(fileUrl.lastIndexOf("/") + 1); - s3Operations.deleteObject(bucket, fileKey); - } -} \ No newline at end of file diff --git a/src/main/java/com/project/trainingdiary/util/MediaUtil.java b/src/main/java/com/project/trainingdiary/util/MediaUtil.java index b786064d..4f6c95ca 100644 --- a/src/main/java/com/project/trainingdiary/util/MediaUtil.java +++ b/src/main/java/com/project/trainingdiary/util/MediaUtil.java @@ -7,10 +7,17 @@ import com.project.trainingdiary.exception.workout.FileNoNameException; import java.awt.image.BufferedImage; import org.imgscalr.Scalr; +import org.springframework.http.MediaType; import org.springframework.web.multipart.MultipartFile; public class MediaUtil { + private static final int THUMBNAIL_WIDTH = 150; + private static final int THUMBNAIL_HEIGHT = 150; + + private static final int ORIGINAL_WIDTH = 410; + private static final int ORIGINAL_HEIGHT = 410; + public static boolean isValidImageType(MultipartFile file) { return file.getContentType() != null && file.getContentType().startsWith("image/"); } @@ -34,6 +41,14 @@ public static BufferedImage resizeImageToWidth(BufferedImage originalImage, int } } + public static BufferedImage resizeThumbnail(BufferedImage originalImage) { + return Scalr.resize(originalImage, QUALITY, THUMBNAIL_WIDTH, THUMBNAIL_HEIGHT); + } + + public static BufferedImage resizeOriginalImage(BufferedImage originalImage) { + return Scalr.resize(originalImage, QUALITY, ORIGINAL_WIDTH, ORIGINAL_HEIGHT); + } + public static String checkFileNameExist(MultipartFile file) { String filename = file.getOriginalFilename(); if (filename == null) { @@ -46,4 +61,13 @@ public static String extractKey(String url) { return url.substring(url.lastIndexOf("/") + 1); } + public static String getMediaType(String extension) { + if ("jpg".equalsIgnoreCase(extension) || "jpeg".equalsIgnoreCase(extension)) { + return MediaType.IMAGE_JPEG_VALUE; + } else if ("png".equalsIgnoreCase(extension)) { + return MediaType.IMAGE_PNG_VALUE; + } + return MediaType.APPLICATION_OCTET_STREAM_VALUE; + } + } diff --git a/src/test/java/com/project/trainingdiary/service/DietServiceTest.java b/src/test/java/com/project/trainingdiary/service/DietServiceTest.java index 431e9023..c87764ec 100644 --- a/src/test/java/com/project/trainingdiary/service/DietServiceTest.java +++ b/src/test/java/com/project/trainingdiary/service/DietServiceTest.java @@ -25,12 +25,14 @@ import com.project.trainingdiary.exception.workout.InvalidFileTypeException; import com.project.trainingdiary.model.UserPrincipal; import com.project.trainingdiary.model.type.UserRoleType; +import com.project.trainingdiary.provider.S3DietImageProvider; import com.project.trainingdiary.repository.CommentRepository; import com.project.trainingdiary.repository.DietRepository; import com.project.trainingdiary.repository.TraineeRepository; import com.project.trainingdiary.repository.TrainerRepository; import com.project.trainingdiary.repository.ptContract.PtContractRepository; -import com.project.trainingdiary.util.ImageUtil; +import com.project.trainingdiary.util.ConvertCloudFrontUrlUtil; +import com.project.trainingdiary.util.MediaUtil; import java.awt.Color; import java.awt.Graphics2D; import java.awt.image.BufferedImage; @@ -85,7 +87,13 @@ public class DietServiceTest { private CommentRepository commentRepository; @Mock - private ImageUtil imageUtil; + private MediaUtil mediaUtil; + + @Mock + private ConvertCloudFrontUrlUtil convertCloudFrontUrlUtil; + + @Mock + private S3DietImageProvider s3DietImageProvider; @InjectMocks @@ -190,8 +198,9 @@ void testCreateDietFailInvalidFileType() throws IOException { ArgumentCaptor inputStreamCaptor = ArgumentCaptor.forClass(InputStream.class); verify(dietRepository, never()).save(dietCaptor.capture()); - verify(imageUtil, never()).uploadImageToS3(any()); - verify(imageUtil, never()).createAndUploadThumbnail(any(), any(), any()); + verify(s3DietImageProvider, never()).uploadImageToS3(any()); + verify(s3DietImageProvider, never()).uploadThumbnailToS3(any(), any(), any()); + verify(s3DietImageProvider, never()).deleteFileFromS3(any()); assertTrue(dietCaptor.getAllValues().isEmpty()); assertTrue(bucketCaptor.getAllValues().isEmpty()); @@ -223,13 +232,10 @@ void testCreateDietSuccess() throws IOException { .image(mockFile) .build(); - when(imageUtil.isValidImageType(mockFile)).thenReturn(true); - - when(imageUtil.uploadImageToS3(mockFile)).thenReturn( + when(s3DietImageProvider.uploadImageToS3(mockFile)).thenReturn( "https://test-bucket.s3.amazonaws.com/original.jpg"); - when(imageUtil.getExtension("test.jpg")).thenReturn("jpg"); - when(imageUtil.createAndUploadThumbnail(mockFile, + when(s3DietImageProvider.uploadThumbnailToS3(mockFile, "https://test-bucket.s3.amazonaws.com/original.jpg", "jpg")) .thenReturn("https://test-bucket.s3.amazonaws.com/thumb_original.jpg"); @@ -245,11 +251,12 @@ void testCreateDietSuccess() throws IOException { assertEquals("https://test-bucket.s3.amazonaws.com/thumb_original.jpg", savedDiet.getThumbnailUrl()); - verify(imageUtil, times(1)).uploadImageToS3(mockFile); - verify(imageUtil, times(1)).createAndUploadThumbnail(mockFile, + verify(s3DietImageProvider, times(1)).uploadImageToS3(mockFile); + verify(s3DietImageProvider, times(1)).uploadThumbnailToS3(mockFile, "https://test-bucket.s3.amazonaws.com/original.jpg", "jpg"); } + @Test @DisplayName("트레이니를 찾을 수 없음 - 예외 발생") void testCreateDietTraineeNotFound() { @@ -286,8 +293,6 @@ void testGetDietsForTrainee() { assertEquals(1, response.getTotalElements()); DietImageResponseDto responseDto = response.getContent().get(0); assertEquals(diet.getId(), responseDto.getDietId()); - assertTrue(responseDto.getThumbnailUrl() - .contains("https://test-bucket.s3.amazonaws.com/thumb_original.jpg")); } @Test @@ -343,7 +348,8 @@ void testGetDietDetailsForTraineeSuccess() { assertNotNull(response); assertEquals(diet.getId(), response.getId()); assertEquals(diet.getContent(), response.getContent()); - assertEquals(diet.getOriginalUrl(), response.getImageUrl()); + assertEquals(ConvertCloudFrontUrlUtil.convertToCloudFrontUrl(diet.getOriginalUrl()), + response.getImageUrl()); } @Test @@ -405,7 +411,8 @@ void testGetDietDetailsForTrainerSuccess() { assertNotNull(response); assertEquals(diet.getId(), response.getId()); assertEquals(diet.getContent(), response.getContent()); - assertEquals(diet.getOriginalUrl(), response.getImageUrl()); + assertEquals(ConvertCloudFrontUrlUtil.convertToCloudFrontUrl(diet.getOriginalUrl()), + response.getImageUrl()); } @Test diff --git a/src/test/java/com/project/trainingdiary/service/ScheduleOpenCloseServiceTest.java b/src/test/java/com/project/trainingdiary/service/ScheduleOpenCloseServiceTest.java index 287c46aa..823892f1 100644 --- a/src/test/java/com/project/trainingdiary/service/ScheduleOpenCloseServiceTest.java +++ b/src/test/java/com/project/trainingdiary/service/ScheduleOpenCloseServiceTest.java @@ -424,7 +424,8 @@ void registerScheduleSuccess_NoOpen() { ArgumentCaptor> captorSchedule = ArgumentCaptor.forClass(List.class); ArgumentCaptor captorPtContract = ArgumentCaptor.forClass( PtContractEntity.class); - ArgumentCaptor captorNotification = ArgumentCaptor.forClass(NotificationEntity.class); + ArgumentCaptor captorNotification = ArgumentCaptor.forClass( + NotificationEntity.class); //then RegisterScheduleResponseDto response = scheduleOpenCloseService.registerSchedule(dto);