mirror of https://github.com/halo-dev/halo
Merge remote-tracking branch 'origin/v1' into v1
commit
1d95969198
|
@ -12,6 +12,8 @@ import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
@ConfigurationProperties("halo")
|
@ConfigurationProperties("halo")
|
||||||
public class HaloProperties {
|
public class HaloProperties {
|
||||||
|
|
||||||
|
private final static String USER_HOME = System.getProperty("user.home");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Doc api disabled. (Default is true)
|
* Doc api disabled. (Default is true)
|
||||||
*/
|
*/
|
||||||
|
@ -25,5 +27,5 @@ public class HaloProperties {
|
||||||
/**
|
/**
|
||||||
* Work directory.
|
* Work directory.
|
||||||
*/
|
*/
|
||||||
private String workDir = "${user.home}/halo/";
|
private String workDir = USER_HOME + "/halo/";
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package cc.ryanc.halo.model.entity;
|
package cc.ryanc.halo.model.entity;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.model.enums.AttachmentType;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.EqualsAndHashCode;
|
import lombok.EqualsAndHashCode;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
@ -37,7 +38,7 @@ public class Attachment extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 附件路径
|
* 附件路径
|
||||||
*/
|
*/
|
||||||
@Column(name = "path", columnDefinition = "varchar(1023) default ''")
|
@Column(name = "path", columnDefinition = "varchar(1023) not null")
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -49,7 +50,7 @@ public class Attachment extends BaseEntity {
|
||||||
/**
|
/**
|
||||||
* 附件类型
|
* 附件类型
|
||||||
*/
|
*/
|
||||||
@Column(name = "media_type", columnDefinition = "varchar(50) default ''")
|
@Column(name = "media_type", columnDefinition = "varchar(50) not null")
|
||||||
private String mediaType;
|
private String mediaType;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,27 +60,54 @@ public class Attachment extends BaseEntity {
|
||||||
private String suffix;
|
private String suffix;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 附件尺寸
|
* Attachment width.
|
||||||
*/
|
*/
|
||||||
@Column(name = "dimension", columnDefinition = "varchar(50) default ''")
|
@Column(name = "width", columnDefinition = "int default 0")
|
||||||
private String dimension;
|
private Integer width;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attachment height.
|
||||||
|
*/
|
||||||
|
@Column(name = "height", columnDefinition = "int default 0")
|
||||||
|
private Integer height;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 附件大小
|
* 附件大小
|
||||||
*/
|
*/
|
||||||
@Column(name = "size", columnDefinition = "varchar(50) default ''")
|
@Column(name = "size", columnDefinition = "bigint not null")
|
||||||
private String size;
|
private Long size;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 附件上传类型
|
* 附件上传类型
|
||||||
*/
|
*/
|
||||||
@Column(name = "type", columnDefinition = "int default 0")
|
@Column(name = "type", columnDefinition = "int default 0")
|
||||||
private Integer type;
|
private AttachmentType type;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void prePersist() {
|
public void prePersist() {
|
||||||
super.prePersist();
|
super.prePersist();
|
||||||
id = null;
|
id = null;
|
||||||
|
|
||||||
|
if (thumbPath == null) {
|
||||||
|
thumbPath = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (suffix == null) {
|
||||||
|
suffix = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (width == null) {
|
||||||
|
width = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (height == null) {
|
||||||
|
height = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type == null) {
|
||||||
|
type = AttachmentType.SERVER;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,7 +6,7 @@ package cc.ryanc.halo.model.enums;
|
||||||
* @author : RYAN0UP
|
* @author : RYAN0UP
|
||||||
* @date : 2019-03-12
|
* @date : 2019-03-12
|
||||||
*/
|
*/
|
||||||
public enum AttachOrigin implements ValueEnum<Integer> {
|
public enum AttachmentType implements ValueEnum<Integer> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 服务器
|
* 服务器
|
||||||
|
@ -25,7 +25,7 @@ public enum AttachOrigin implements ValueEnum<Integer> {
|
||||||
|
|
||||||
private Integer value;
|
private Integer value;
|
||||||
|
|
||||||
AttachOrigin(Integer value) {
|
AttachmentType(Integer value) {
|
||||||
this.value = value;
|
this.value = value;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
package cc.ryanc.halo.model.support;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload result dto.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class UploadResult {
|
||||||
|
|
||||||
|
private String filename;
|
||||||
|
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
private String thumbPath;
|
||||||
|
|
||||||
|
private String suffix;
|
||||||
|
|
||||||
|
private MediaType mediaType;
|
||||||
|
|
||||||
|
private Long size;
|
||||||
|
|
||||||
|
private Integer width;
|
||||||
|
|
||||||
|
private Integer height;
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
package cc.ryanc.halo.service;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.model.support.UploadResult;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File service interface.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
public interface FileService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload sub directory.
|
||||||
|
*/
|
||||||
|
String UPLOAD_SUB_DIR = "upload";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thumbnail width.
|
||||||
|
*/
|
||||||
|
int THUMB_WIDTH = 256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thumbnail height.
|
||||||
|
*/
|
||||||
|
int THUMB_HEIGHT = 256;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Uploads file to local storage.
|
||||||
|
*
|
||||||
|
* @param file multipart file must not be null
|
||||||
|
* @return upload result
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
UploadResult uploadToLocal(@NonNull MultipartFile file);
|
||||||
|
}
|
|
@ -11,6 +11,7 @@ import org.springframework.lang.NonNull;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
|
||||||
|
@ -200,4 +201,12 @@ public interface OptionService extends CrudService<Option, Integer> {
|
||||||
@NonNull
|
@NonNull
|
||||||
Zone getQiniuZone();
|
Zone getQiniuZone();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets locale.
|
||||||
|
*
|
||||||
|
* @return locale user set or default locale
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
Locale getLocale();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,205 @@
|
||||||
|
package cc.ryanc.halo.service.impl;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.config.properties.HaloProperties;
|
||||||
|
import cc.ryanc.halo.exception.ServiceException;
|
||||||
|
import cc.ryanc.halo.model.support.UploadResult;
|
||||||
|
import cc.ryanc.halo.service.FileService;
|
||||||
|
import cc.ryanc.halo.service.OptionService;
|
||||||
|
import cc.ryanc.halo.utils.FilenameUtils;
|
||||||
|
import cc.ryanc.halo.utils.HaloUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.lang.Nullable;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
|
import java.util.Calendar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* File service implementation.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class FileServiceImpl implements FileService {
|
||||||
|
|
||||||
|
private final OptionService optionService;
|
||||||
|
|
||||||
|
private final String workDir;
|
||||||
|
|
||||||
|
private final MediaType imageType = MediaType.valueOf("image/*");
|
||||||
|
|
||||||
|
public FileServiceImpl(HaloProperties haloProperties,
|
||||||
|
OptionService optionService) throws URISyntaxException {
|
||||||
|
this.optionService = optionService;
|
||||||
|
|
||||||
|
// Get work dir
|
||||||
|
workDir = normalizeDirectory(haloProperties.getWorkDir());
|
||||||
|
|
||||||
|
// Check directory
|
||||||
|
checkWorkDir();
|
||||||
|
|
||||||
|
log.info("Work directory: [{}]", workDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check work directory.
|
||||||
|
*
|
||||||
|
* @throws URISyntaxException throws when work directory is not a uri
|
||||||
|
*/
|
||||||
|
private void checkWorkDir() throws URISyntaxException {
|
||||||
|
// Get work path
|
||||||
|
Path workPath = Paths.get(workDir);
|
||||||
|
|
||||||
|
// Check file type
|
||||||
|
Assert.isTrue(Files.isDirectory(workPath), workDir + " isn't a directory");
|
||||||
|
|
||||||
|
// Check readable
|
||||||
|
Assert.isTrue(Files.isReadable(workPath), workDir + " isn't readable");
|
||||||
|
|
||||||
|
// Check writable
|
||||||
|
Assert.isTrue(Files.isWritable(workPath), workDir + " isn't writable");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalize directory full name, ensure the end path separator.
|
||||||
|
*
|
||||||
|
* @param dir directory full name must not be blank
|
||||||
|
* @return normalized directory full name with end path separator
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private String normalizeDirectory(@NonNull String dir) {
|
||||||
|
Assert.hasText(dir, "Directory full name must not be blank");
|
||||||
|
|
||||||
|
return StringUtils.appendIfMissing(dir, File.separator);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UploadResult uploadToLocal(MultipartFile file) {
|
||||||
|
Assert.notNull(file, "Multipart file must not be null");
|
||||||
|
|
||||||
|
// Get current time
|
||||||
|
Calendar current = Calendar.getInstance(optionService.getLocale());
|
||||||
|
// Get month and day of month
|
||||||
|
int year = current.get(Calendar.YEAR);
|
||||||
|
int month = current.get(Calendar.MONTH) + 1;
|
||||||
|
|
||||||
|
// Build directory
|
||||||
|
String subDir = UPLOAD_SUB_DIR + File.separator + year + File.separator + month + File.separator;
|
||||||
|
|
||||||
|
// Get basename
|
||||||
|
String basename = FilenameUtils.getBasename(file.getOriginalFilename()) + '-' + HaloUtils.randomUUIDWithoutDash();
|
||||||
|
|
||||||
|
// Get extension
|
||||||
|
String extension = FilenameUtils.getExtension(file.getOriginalFilename());
|
||||||
|
|
||||||
|
log.debug("Base name: [{}], extension: [{}] of original filename: [{}]", basename, extension, file.getOriginalFilename());
|
||||||
|
|
||||||
|
// Build sub file path
|
||||||
|
String subFilePath = subDir + basename + '.' + extension;
|
||||||
|
|
||||||
|
// Get upload path
|
||||||
|
Path uploadPath = Paths.get(workDir + subFilePath);
|
||||||
|
|
||||||
|
log.info("Uploading to directory: [{}]", uploadPath.getFileName());
|
||||||
|
|
||||||
|
try {
|
||||||
|
// TODO Synchronize here
|
||||||
|
// Create directory
|
||||||
|
Files.createDirectories(uploadPath.getParent());
|
||||||
|
Files.createFile(uploadPath);
|
||||||
|
|
||||||
|
// Upload this file
|
||||||
|
file.transferTo(uploadPath);
|
||||||
|
|
||||||
|
// Build upload result
|
||||||
|
UploadResult uploadResult = new UploadResult();
|
||||||
|
uploadResult.setFilename(basename);
|
||||||
|
uploadResult.setFilePath(subFilePath);
|
||||||
|
uploadResult.setSuffix(extension);
|
||||||
|
uploadResult.setMediaType(MediaType.valueOf(file.getContentType()));
|
||||||
|
uploadResult.setSize(file.getSize());
|
||||||
|
|
||||||
|
// Check file type
|
||||||
|
if (isImageType(file.getContentType())) {
|
||||||
|
// Upload a thumbnail
|
||||||
|
String thumbnailBasename = basename + '-' + "thumbnail";
|
||||||
|
String thumbnailSubFilePath = subDir + thumbnailBasename + '.' + extension;
|
||||||
|
Path thumbnailPath = Paths.get(workDir + thumbnailSubFilePath);
|
||||||
|
|
||||||
|
// Create the thumbnail
|
||||||
|
Files.createFile(thumbnailPath);
|
||||||
|
|
||||||
|
// Generate thumbnail
|
||||||
|
generateThumbnail(uploadPath, thumbnailPath);
|
||||||
|
|
||||||
|
// Set thumb path
|
||||||
|
uploadResult.setThumbPath(thumbnailSubFilePath);
|
||||||
|
|
||||||
|
// Read as image
|
||||||
|
BufferedImage image = ImageIO.read(Files.newInputStream(uploadPath));
|
||||||
|
|
||||||
|
// Set width and height
|
||||||
|
uploadResult.setWidth(image.getWidth());
|
||||||
|
uploadResult.setHeight(image.getHeight());
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates thumbnail image.
|
||||||
|
*
|
||||||
|
* @param imagePath image path must not be null
|
||||||
|
* @param thumbPath thumbnail path must not be null
|
||||||
|
* @throws IOException throws if image provided is not valid
|
||||||
|
*/
|
||||||
|
private void generateThumbnail(@NonNull Path imagePath, @NonNull Path thumbPath) throws IOException {
|
||||||
|
Assert.notNull(imagePath, "Image path must not be null");
|
||||||
|
Assert.notNull(thumbPath, "Thumb path must not be null");
|
||||||
|
|
||||||
|
log.info("Generating thumbnail: [{}] for image: [{}]", thumbPath.getFileName(), imagePath.getFileName());
|
||||||
|
|
||||||
|
// Convert to thumbnail and copy the thumbnail
|
||||||
|
Thumbnails.of(imagePath.toFile()).size(THUMB_WIDTH, THUMB_HEIGHT).keepAspectRatio(true).toFile(thumbPath.toFile());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether media type provided is an image type.
|
||||||
|
*
|
||||||
|
* @param mediaType media type provided
|
||||||
|
* @return true if it is an image type
|
||||||
|
*/
|
||||||
|
private boolean isImageType(@Nullable String mediaType) {
|
||||||
|
return mediaType != null && imageType.includes(MediaType.valueOf(mediaType));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether media type provided is an image type.
|
||||||
|
*
|
||||||
|
* @param mediaType media type provided
|
||||||
|
* @return true if it is an image type
|
||||||
|
*/
|
||||||
|
private boolean isImageType(@Nullable MediaType mediaType) {
|
||||||
|
return mediaType != null && imageType.includes(mediaType);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,6 +17,7 @@ import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
@ -249,5 +250,16 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
||||||
}).orElseGet(Zone::autoZone);
|
}).orElseGet(Zone::autoZone);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Locale getLocale() {
|
||||||
|
return getByProperty(BlogProperties.BLOG_LOCALE).map(localeStr -> {
|
||||||
|
try {
|
||||||
|
return Locale.forLanguageTag(localeStr);
|
||||||
|
} catch (Exception e) {
|
||||||
|
return Locale.getDefault();
|
||||||
|
}
|
||||||
|
}).orElseGet(Locale::getDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package cc.ryanc.halo.utils;
|
||||||
|
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.springframework.lang.NonNull;
|
||||||
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filename utilities.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
public class FilenameUtils {
|
||||||
|
|
||||||
|
private FilenameUtils() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getBasename(@NonNull String filename) {
|
||||||
|
Assert.hasText(filename, "Filename must not be blank");
|
||||||
|
|
||||||
|
// Find the last slash
|
||||||
|
int separatorLastIndex = StringUtils.lastIndexOf(filename, File.separatorChar);
|
||||||
|
|
||||||
|
if (separatorLastIndex == filename.length() - 1) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (separatorLastIndex >= 0 && separatorLastIndex < filename.length() - 1) {
|
||||||
|
filename = filename.substring(separatorLastIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find last dot
|
||||||
|
int dotLastIndex = StringUtils.lastIndexOf(filename, '.');
|
||||||
|
|
||||||
|
if (dotLastIndex < 0) {
|
||||||
|
return filename;
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename.substring(0, dotLastIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
public static String getExtension(@NonNull String filename) {
|
||||||
|
Assert.hasText(filename, "Filename must not be blank");
|
||||||
|
|
||||||
|
// Find the last slash
|
||||||
|
int separatorLastIndex = StringUtils.lastIndexOf(filename, File.separatorChar);
|
||||||
|
|
||||||
|
if (separatorLastIndex == filename.length() - 1) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
if (separatorLastIndex >= 0 && separatorLastIndex < filename.length() - 1) {
|
||||||
|
filename = filename.substring(separatorLastIndex + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Find last dot
|
||||||
|
int dotLastIndex = StringUtils.lastIndexOf(filename, '.');
|
||||||
|
|
||||||
|
if (dotLastIndex < 0) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return filename.substring(dotLastIndex + 1);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,7 @@ import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.Properties;
|
import java.util.Properties;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
|
@ -36,6 +37,16 @@ import java.util.Properties;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class HaloUtils {
|
public class HaloUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets random uuid without dash.
|
||||||
|
*
|
||||||
|
* @return random uuid without dash
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String randomUUIDWithoutDash() {
|
||||||
|
return StringUtils.remove(UUID.randomUUID().toString(), '-');
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize url if blank.
|
* Initialize url if blank.
|
||||||
*
|
*
|
||||||
|
|
|
@ -1,12 +1,15 @@
|
||||||
package cc.ryanc.halo.web.controller.admin.api;
|
package cc.ryanc.halo.web.controller.admin.api;
|
||||||
|
|
||||||
import cc.ryanc.halo.model.dto.AttachmentOutputDTO;
|
import cc.ryanc.halo.model.dto.AttachmentOutputDTO;
|
||||||
|
import cc.ryanc.halo.model.support.UploadResult;
|
||||||
import cc.ryanc.halo.service.AttachmentService;
|
import cc.ryanc.halo.service.AttachmentService;
|
||||||
|
import cc.ryanc.halo.service.FileService;
|
||||||
import io.swagger.annotations.ApiOperation;
|
import io.swagger.annotations.ApiOperation;
|
||||||
import org.springframework.data.domain.Page;
|
import org.springframework.data.domain.Page;
|
||||||
import org.springframework.data.domain.Pageable;
|
import org.springframework.data.domain.Pageable;
|
||||||
import org.springframework.data.web.PageableDefault;
|
import org.springframework.data.web.PageableDefault;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||||
|
|
||||||
|
@ -22,8 +25,12 @@ public class AttachmentController {
|
||||||
|
|
||||||
private final AttachmentService attachmentService;
|
private final AttachmentService attachmentService;
|
||||||
|
|
||||||
public AttachmentController(AttachmentService attachmentService) {
|
private final FileService fileService;
|
||||||
|
|
||||||
|
public AttachmentController(AttachmentService attachmentService,
|
||||||
|
FileService fileService) {
|
||||||
this.attachmentService = attachmentService;
|
this.attachmentService = attachmentService;
|
||||||
|
this.fileService = fileService;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -59,4 +66,10 @@ public class AttachmentController {
|
||||||
public void deletePermanently(@PathVariable("id") Integer id) {
|
public void deletePermanently(@PathVariable("id") Integer id) {
|
||||||
attachmentService.removeById(id);
|
attachmentService.removeById(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@PostMapping("upload")
|
||||||
|
public UploadResult uploadAttachment(@RequestParam("file") MultipartFile file) {
|
||||||
|
// TODO Just for test
|
||||||
|
return fileService.uploadToLocal(file);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,7 +2,7 @@ package cc.ryanc.halo.web.controller.core;
|
||||||
|
|
||||||
import cc.ryanc.halo.exception.BadRequestException;
|
import cc.ryanc.halo.exception.BadRequestException;
|
||||||
import cc.ryanc.halo.model.entity.*;
|
import cc.ryanc.halo.model.entity.*;
|
||||||
import cc.ryanc.halo.model.enums.AttachOrigin;
|
import cc.ryanc.halo.model.enums.AttachmentType;
|
||||||
import cc.ryanc.halo.model.enums.BlogProperties;
|
import cc.ryanc.halo.model.enums.BlogProperties;
|
||||||
import cc.ryanc.halo.model.params.InstallParam;
|
import cc.ryanc.halo.model.params.InstallParam;
|
||||||
import cc.ryanc.halo.model.support.BaseResponse;
|
import cc.ryanc.halo.model.support.BaseResponse;
|
||||||
|
@ -173,7 +173,7 @@ public class InstallController {
|
||||||
properties.put(BlogProperties.NEW_COMMENT_NOTICE, Boolean.FALSE.toString());
|
properties.put(BlogProperties.NEW_COMMENT_NOTICE, Boolean.FALSE.toString());
|
||||||
properties.put(BlogProperties.COMMENT_PASS_NOTICE, Boolean.FALSE.toString());
|
properties.put(BlogProperties.COMMENT_PASS_NOTICE, Boolean.FALSE.toString());
|
||||||
properties.put(BlogProperties.COMMENT_REPLY_NOTICE, Boolean.FALSE.toString());
|
properties.put(BlogProperties.COMMENT_REPLY_NOTICE, Boolean.FALSE.toString());
|
||||||
properties.put(BlogProperties.ATTACH_LOC, AttachOrigin.SERVER.getValue().toString());
|
properties.put(BlogProperties.ATTACH_LOC, AttachmentType.SERVER.getValue().toString());
|
||||||
|
|
||||||
// Create properties
|
// Create properties
|
||||||
optionService.saveProperties(properties, "system");
|
optionService.saveProperties(properties, "system");
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
package cc.ryanc.halo.model;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
public class MediaTypeTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void toStringTest() {
|
||||||
|
MediaType mediaType = MediaType.IMAGE_GIF;
|
||||||
|
|
||||||
|
assertThat(mediaType.toString(), equalTo("image/gif"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void parseTest() {
|
||||||
|
MediaType mediaType = MediaType.valueOf("image/gif");
|
||||||
|
|
||||||
|
assertNotNull(mediaType);
|
||||||
|
assertThat(mediaType, equalTo(MediaType.IMAGE_GIF));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void includesTest() {
|
||||||
|
MediaType mediaType = MediaType.valueOf("image/*");
|
||||||
|
boolean isInclude = mediaType.includes(MediaType.IMAGE_GIF);
|
||||||
|
assertTrue(isInclude);
|
||||||
|
|
||||||
|
isInclude = mediaType.includes(MediaType.IMAGE_JPEG);
|
||||||
|
assertTrue(isInclude);
|
||||||
|
|
||||||
|
isInclude = mediaType.includes(MediaType.IMAGE_PNG);
|
||||||
|
assertTrue(isInclude);
|
||||||
|
|
||||||
|
isInclude = mediaType.includes(MediaType.TEXT_HTML);
|
||||||
|
assertFalse(isInclude);
|
||||||
|
}
|
||||||
|
}
|
|
@ -17,15 +17,16 @@ import static org.junit.Assert.assertThat;
|
||||||
*/
|
*/
|
||||||
@RunWith(SpringRunner.class)
|
@RunWith(SpringRunner.class)
|
||||||
@SpringBootTest
|
@SpringBootTest
|
||||||
public class AttachOriginTest {
|
public class AttachmentTypeTest {
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ConversionService conversionService;
|
private ConversionService conversionService;
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void conversionTest() {
|
public void conversionTest() {
|
||||||
assertThat(conversionService.convert("SERVER", AttachOrigin.class), equalTo(AttachOrigin.SERVER));
|
assertThat(conversionService.convert("SERVER", AttachmentType.class), equalTo(AttachmentType.SERVER));
|
||||||
assertThat(conversionService.convert("server", AttachOrigin.class), equalTo(AttachOrigin.SERVER));
|
assertThat(conversionService.convert("server", AttachmentType.class), equalTo(AttachmentType.SERVER));
|
||||||
assertThat(conversionService.convert("Server", AttachOrigin.class), equalTo(AttachOrigin.SERVER));
|
assertThat(conversionService.convert("Server", AttachmentType.class), equalTo(AttachmentType.SERVER));
|
||||||
|
assertThat(conversionService.convert("SerVer", AttachmentType.class), equalTo(AttachmentType.SERVER));
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,40 @@
|
||||||
|
package cc.ryanc.halo.utils;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
|
import static org.junit.Assert.assertThat;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Filename utilities test.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
public class FilenameUtilsTest {
|
||||||
|
|
||||||
|
// a/b/c.txt --> c.txt
|
||||||
|
// a.txt --> a.txt
|
||||||
|
// a/b/c --> c
|
||||||
|
// a/b/c/ --> ""
|
||||||
|
@Test
|
||||||
|
public void getBasename() {
|
||||||
|
assertThat(FilenameUtils.getBasename("a/b/c.txt"), equalTo("c"));
|
||||||
|
assertThat(FilenameUtils.getBasename("a.txt"), equalTo("a"));
|
||||||
|
assertThat(FilenameUtils.getBasename("a/b/c"), equalTo("c"));
|
||||||
|
assertThat(FilenameUtils.getBasename("a/b/c/"), equalTo(""));
|
||||||
|
}
|
||||||
|
|
||||||
|
// foo.txt --> "txt"
|
||||||
|
// a/b/c.jpg --> "jpg"
|
||||||
|
// a/b.txt/c --> ""
|
||||||
|
// a/b/c --> ""
|
||||||
|
@Test
|
||||||
|
public void getExtension() {
|
||||||
|
assertThat(FilenameUtils.getExtension("foo.txt"), equalTo("txt"));
|
||||||
|
assertThat(FilenameUtils.getExtension("a/b/c.jpg"), equalTo("jpg"));
|
||||||
|
assertThat(FilenameUtils.getExtension("a/b.txt/c"), equalTo(""));
|
||||||
|
assertThat(FilenameUtils.getExtension("a/b/c"), equalTo(""));
|
||||||
|
assertThat(FilenameUtils.getExtension("a/b/c/"), equalTo(""));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
package cc.ryanc.halo.utils;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
|
||||||
|
import java.net.URI;
|
||||||
|
import java.net.URISyntaxException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* URI test.
|
||||||
|
*
|
||||||
|
* @author johnniang
|
||||||
|
* @date 3/26/19
|
||||||
|
*/
|
||||||
|
public class URITest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void createURITest() throws URISyntaxException {
|
||||||
|
String homeDir = System.getProperty("user.home");
|
||||||
|
URI uri = new URI(homeDir);
|
||||||
|
System.out.println(uri);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue