diff --git a/src/main/java/cc/ryanc/halo/exception/FileOperationException.java b/src/main/java/cc/ryanc/halo/exception/FileOperationException.java new file mode 100644 index 000000000..15b562bf0 --- /dev/null +++ b/src/main/java/cc/ryanc/halo/exception/FileOperationException.java @@ -0,0 +1,17 @@ +package cc.ryanc.halo.exception; + +/** + * File operation exception. + * + * @author johnniang + * @date 3/27/19 + */ +public class FileOperationException extends ServiceException { + public FileOperationException(String message) { + super(message); + } + + public FileOperationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/src/main/java/cc/ryanc/halo/exception/FileUploadException.java b/src/main/java/cc/ryanc/halo/exception/FileUploadException.java deleted file mode 100644 index 67e3068d1..000000000 --- a/src/main/java/cc/ryanc/halo/exception/FileUploadException.java +++ /dev/null @@ -1,17 +0,0 @@ -package cc.ryanc.halo.exception; - -/** - * File upload exception. - * - * @author johnniang - * @date 3/27/19 - */ -public class FileUploadException extends ServiceException { - public FileUploadException(String message) { - super(message); - } - - public FileUploadException(String message, Throwable cause) { - super(message, cause); - } -} diff --git a/src/main/java/cc/ryanc/halo/filehandler/FileHandler.java b/src/main/java/cc/ryanc/halo/filehandler/FileHandler.java index d7013aea1..a64b3bc40 100644 --- a/src/main/java/cc/ryanc/halo/filehandler/FileHandler.java +++ b/src/main/java/cc/ryanc/halo/filehandler/FileHandler.java @@ -1,6 +1,6 @@ package cc.ryanc.halo.filehandler; -import cc.ryanc.halo.exception.FileUploadException; +import cc.ryanc.halo.exception.FileOperationException; import cc.ryanc.halo.model.enums.AttachmentType; import cc.ryanc.halo.model.support.UploadResult; import org.apache.commons.lang3.StringUtils; @@ -27,7 +27,7 @@ public interface FileHandler { * * @param file multipart file must not be null * @return upload result - * @throws FileUploadException throws when fail to upload the file + * @throws FileOperationException throws when fail to upload the file */ @NonNull UploadResult upload(@NonNull MultipartFile file); @@ -37,7 +37,7 @@ public interface FileHandler { * * @param key file key must not be null */ - boolean delete(@NonNull String key); + void delete(@NonNull String key); /** * Checks if the given type is supported. @@ -45,7 +45,7 @@ public interface FileHandler { * @param type attachment type * @return true if supported; false or else */ - boolean supportType(AttachmentType type); + boolean supportType(@Nullable AttachmentType type); /** diff --git a/src/main/java/cc/ryanc/halo/filehandler/FileHandlers.java b/src/main/java/cc/ryanc/halo/filehandler/FileHandlers.java index fd0deaacb..7633d249f 100644 --- a/src/main/java/cc/ryanc/halo/filehandler/FileHandlers.java +++ b/src/main/java/cc/ryanc/halo/filehandler/FileHandlers.java @@ -1,6 +1,6 @@ package cc.ryanc.halo.filehandler; -import cc.ryanc.halo.exception.FileUploadException; +import cc.ryanc.halo.exception.FileOperationException; import cc.ryanc.halo.model.enums.AttachmentType; import cc.ryanc.halo.model.support.UploadResult; import lombok.extern.slf4j.Slf4j; @@ -42,18 +42,19 @@ public class FileHandlers { } log.error("There is no available file handle for attachment type: [{}]", attachmentType); - throw new FileUploadException("No available file handler to filehandler the file").setErrorData(attachmentType); + throw new FileOperationException("No available file handler to filehandler the file").setErrorData(attachmentType); } - public boolean delete(String key, AttachmentType attachmentType) { + public void delete(String key, AttachmentType attachmentType) { for (FileHandler fileHandler : fileHandlers) { if (fileHandler.supportType(attachmentType)) { - return fileHandler.delete(key); + fileHandler.delete(key); + return; } } log.error("There is no available file handle for attachment type: [{}]", attachmentType); - throw new FileUploadException("No available file handler to delete the file").setErrorData(attachmentType); + throw new FileOperationException("No available file handler to delete the file").setErrorData(attachmentType); } /** diff --git a/src/main/java/cc/ryanc/halo/filehandler/LocalFileHandler.java b/src/main/java/cc/ryanc/halo/filehandler/LocalFileHandler.java index 9f9b9f4f0..578d21fae 100644 --- a/src/main/java/cc/ryanc/halo/filehandler/LocalFileHandler.java +++ b/src/main/java/cc/ryanc/halo/filehandler/LocalFileHandler.java @@ -1,6 +1,7 @@ package cc.ryanc.halo.filehandler; import cc.ryanc.halo.config.properties.HaloProperties; +import cc.ryanc.halo.exception.FileOperationException; import cc.ryanc.halo.exception.ServiceException; import cc.ryanc.halo.model.enums.AttachmentType; import cc.ryanc.halo.model.support.UploadResult; @@ -36,7 +37,9 @@ public class LocalFileHandler implements FileHandler { /** * Upload sub directory. */ - private final static String UPLOAD_SUB_DIR = "upload"; + private final static String UPLOAD_SUB_DIR = "upload/"; + + private final static String THUMBNAIL_SUFFIX = "-thumbnail"; /** * Thumbnail width. @@ -59,6 +62,8 @@ public class LocalFileHandler implements FileHandler { // Get work dir workDir = FileHandler.normalizeDirectory(haloProperties.getWorkDir()); + // Check work directory + checkWorkDir(); } /** @@ -89,7 +94,7 @@ public class LocalFileHandler implements FileHandler { int month = current.get(Calendar.MONTH) + 1; // Build directory - String subDir = UPLOAD_SUB_DIR + File.separator + year + File.separator + month + File.separator; + String subDir = UPLOAD_SUB_DIR + year + File.separator + month + File.separator; // Get basename String basename = FilenameUtils.getBasename(file.getOriginalFilename()) + '-' + HaloUtils.randomUUIDWithoutDash(); @@ -103,9 +108,9 @@ public class LocalFileHandler implements FileHandler { String subFilePath = subDir + basename + '.' + extension; // Get upload path - Path uploadPath = Paths.get(workDir + subFilePath); + Path uploadPath = Paths.get(workDir, subFilePath); - log.info("Uploading to directory: [{}]", uploadPath.getFileName()); + log.info("Uploading to directory: [{}]", uploadPath.toString()); try { // TODO Synchronize here @@ -128,7 +133,7 @@ public class LocalFileHandler implements FileHandler { // Check file type if (FileHandler.isImageType(uploadResult.getMediaType())) { // Upload a thumbnail - String thumbnailBasename = basename + '-' + "thumbnail"; + String thumbnailBasename = basename + THUMBNAIL_SUFFIX; String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension; Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath); @@ -151,14 +156,44 @@ public class LocalFileHandler implements FileHandler { return uploadResult; } catch (IOException e) { - log.error("Failed to upload file to local: " + uploadPath.getFileName(), e); - throw new ServiceException("Failed to upload file to local").setErrorData(uploadPath.getFileName()); + log.error("Failed to upload file to local: " + uploadPath, e); + throw new ServiceException("Failed to upload file to local").setErrorData(uploadPath); } } @Override - public boolean delete(String key) { - return false; + public void delete(String key) { + Assert.hasText(key, "File key must not be blank"); + // Get path + Path path = Paths.get(workDir, key); + + + // Delete the file key + try { + Files.delete(path); + } catch (IOException e) { + throw new FileOperationException("Failed to delete " + key + " file", e); + } + + // Delete thumb if necessary + String basename = FilenameUtils.getBasename(key); + String extension = FilenameUtils.getExtension(key); + + // Get thumbnail name + String thumbnailName = basename + THUMBNAIL_SUFFIX + '.' + extension; + + // Get thumbnail path + Path thumbnailPath = Paths.get(path.getParent().toString(), thumbnailName); + + // Delete thumbnail file + try { + boolean deleteResult = Files.deleteIfExists(thumbnailPath); + if (!deleteResult) { + log.warn("Thumbnail: [{}] way not exist", thumbnailPath.toString()); + } + } catch (IOException e) { + throw new FileOperationException("Failed to delete " + thumbnailName + " thumbnail", e); + } } @Override @@ -182,4 +217,5 @@ public class LocalFileHandler implements FileHandler { // Convert to thumbnail and copy the thumbnail Thumbnails.of(imagePath.toFile()).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true).toFile(thumbPath.toFile()); } + } diff --git a/src/main/java/cc/ryanc/halo/filehandler/QnYunFileHandler.java b/src/main/java/cc/ryanc/halo/filehandler/QnYunFileHandler.java index 55a2471e0..7fc54f76d 100644 --- a/src/main/java/cc/ryanc/halo/filehandler/QnYunFileHandler.java +++ b/src/main/java/cc/ryanc/halo/filehandler/QnYunFileHandler.java @@ -1,6 +1,6 @@ package cc.ryanc.halo.filehandler; -import cc.ryanc.halo.exception.FileUploadException; +import cc.ryanc.halo.exception.FileOperationException; import cc.ryanc.halo.model.enums.AttachmentType; import cc.ryanc.halo.model.enums.QnYunProperties; import cc.ryanc.halo.model.support.QiNiuPutSet; @@ -118,13 +118,13 @@ public class QnYunFileHandler implements FileHandler { log.error("QnYun error response: [{}]", ((QiniuException) e).response); } - throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to QnYun", e); + throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to QnYun", e); } } @Override - public boolean delete(String key) { - return false; + public void delete(String key) { + // TODO Handle file deletion } @Override diff --git a/src/main/java/cc/ryanc/halo/filehandler/UpYunFileHandler.java b/src/main/java/cc/ryanc/halo/filehandler/UpYunFileHandler.java index 22b17f3d2..8fa7c01e6 100644 --- a/src/main/java/cc/ryanc/halo/filehandler/UpYunFileHandler.java +++ b/src/main/java/cc/ryanc/halo/filehandler/UpYunFileHandler.java @@ -1,6 +1,6 @@ package cc.ryanc.halo.filehandler; -import cc.ryanc.halo.exception.FileUploadException; +import cc.ryanc.halo.exception.FileOperationException; import cc.ryanc.halo.exception.PropertyFormatException; import cc.ryanc.halo.model.enums.AttachmentType; import cc.ryanc.halo.model.enums.UpYunProperties; @@ -72,7 +72,7 @@ public class UpYunFileHandler implements FileHandler { // Write file boolean uploadSuccess = upYun.writeFile(upFilePath, file.getInputStream(), true, null); if (!uploadSuccess) { - throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun " + upFilePath); + throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to UpYun " + upFilePath); } String filePath = StringUtils.removeEnd(ossDomain, "/") + upFilePath; @@ -96,13 +96,14 @@ public class UpYunFileHandler implements FileHandler { return uploadResult; } catch (Exception e) { - throw new FileUploadException("Failed to upload file " + file.getOriginalFilename() + " to UpYun", e); + throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to UpYun", e); } } @Override - public boolean delete(String key) { - return false; + public void delete(String key) { + + // TODO Handle file deletion } @Override diff --git a/src/main/java/cc/ryanc/halo/service/AttachmentService.java b/src/main/java/cc/ryanc/halo/service/AttachmentService.java index 404914832..b548faeae 100644 --- a/src/main/java/cc/ryanc/halo/service/AttachmentService.java +++ b/src/main/java/cc/ryanc/halo/service/AttachmentService.java @@ -1,6 +1,6 @@ package cc.ryanc.halo.service; -import cc.ryanc.halo.exception.FileUploadException; +import cc.ryanc.halo.exception.FileOperationException; import cc.ryanc.halo.model.dto.AttachmentOutputDTO; import cc.ryanc.halo.model.entity.Attachment; import cc.ryanc.halo.service.base.CrudService; @@ -30,7 +30,7 @@ public interface AttachmentService extends CrudService { * * @param file multipart file must not be null * @return attachment info - * @throws FileUploadException throws when failed to filehandler the file + * @throws FileOperationException throws when failed to filehandler the file */ @NonNull Attachment upload(@NonNull MultipartFile file); diff --git a/src/main/java/cc/ryanc/halo/utils/FilenameUtils.java b/src/main/java/cc/ryanc/halo/utils/FilenameUtils.java index 455c54c6f..1d7c2a726 100644 --- a/src/main/java/cc/ryanc/halo/utils/FilenameUtils.java +++ b/src/main/java/cc/ryanc/halo/utils/FilenameUtils.java @@ -66,4 +66,5 @@ public class FilenameUtils { return filename.substring(dotLastIndex + 1); } + } diff --git a/src/test/java/cc/ryanc/halo/utils/PathsTest.java b/src/test/java/cc/ryanc/halo/utils/PathsTest.java new file mode 100644 index 000000000..ba9adb5ce --- /dev/null +++ b/src/test/java/cc/ryanc/halo/utils/PathsTest.java @@ -0,0 +1,26 @@ +package cc.ryanc.halo.utils; + +import org.junit.Test; + +import java.nio.file.Path; +import java.nio.file.Paths; + +import static org.hamcrest.Matchers.equalTo; +import static org.junit.Assert.assertThat; + +/** + * Paths test. + * + * @author johnniang + * @date 3/27/19 + */ +public class PathsTest { + + + @Test + public void getTest() { + Path path = Paths.get("/home/test/", "/upload/test.txt"); + assertThat(path.toString(), equalTo("/home/test/upload/test.txt")); + assertThat(path.getParent().toString(), equalTo("/home/test/upload")); + } +}