mirror of https://github.com/halo-dev/halo
Add a common theme addition service
parent
9e9bd1a377
commit
76b3310027
|
@ -7,6 +7,7 @@ import run.halo.app.handler.theme.support.ThemeProperty;
|
||||||
import run.halo.app.model.support.ThemeFile;
|
import run.halo.app.model.support.ThemeFile;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -204,9 +205,19 @@ public interface ThemeService {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload theme.
|
* Upload theme.
|
||||||
|
*
|
||||||
* @param file multipart file must not be null
|
* @param file multipart file must not be null
|
||||||
* @return theme info
|
* @return theme info
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
ThemeProperty upload(@NonNull MultipartFile file);
|
ThemeProperty upload(@NonNull MultipartFile file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new theme.
|
||||||
|
*
|
||||||
|
* @param themeTmpPath theme temporary path must not be null
|
||||||
|
* @return theme property
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
ThemeProperty add(@NonNull Path themeTmpPath) throws IOException;
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,6 @@ import freemarker.template.Configuration;
|
||||||
import freemarker.template.TemplateModelException;
|
import freemarker.template.TemplateModelException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.springframework.http.MediaType;
|
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.lang.Nullable;
|
import org.springframework.lang.Nullable;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
@ -20,7 +19,6 @@ import org.springframework.web.multipart.MultipartFile;
|
||||||
import run.halo.app.cache.StringCacheStore;
|
import run.halo.app.cache.StringCacheStore;
|
||||||
import run.halo.app.config.properties.HaloProperties;
|
import run.halo.app.config.properties.HaloProperties;
|
||||||
import run.halo.app.exception.*;
|
import run.halo.app.exception.*;
|
||||||
import run.halo.app.handler.file.FileHandler;
|
|
||||||
import run.halo.app.handler.theme.ThemeConfigResolver;
|
import run.halo.app.handler.theme.ThemeConfigResolver;
|
||||||
import run.halo.app.handler.theme.ThemePropertyResolver;
|
import run.halo.app.handler.theme.ThemePropertyResolver;
|
||||||
import run.halo.app.handler.theme.support.Group;
|
import run.halo.app.handler.theme.support.Group;
|
||||||
|
@ -28,14 +26,12 @@ import run.halo.app.handler.theme.support.ThemeProperty;
|
||||||
import run.halo.app.model.properties.PrimaryProperties;
|
import run.halo.app.model.properties.PrimaryProperties;
|
||||||
import run.halo.app.model.support.HaloConst;
|
import run.halo.app.model.support.HaloConst;
|
||||||
import run.halo.app.model.support.ThemeFile;
|
import run.halo.app.model.support.ThemeFile;
|
||||||
import run.halo.app.model.support.UploadResult;
|
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.ThemeService;
|
import run.halo.app.service.ThemeService;
|
||||||
|
import run.halo.app.utils.FileUtils;
|
||||||
import run.halo.app.utils.FilenameUtils;
|
import run.halo.app.utils.FilenameUtils;
|
||||||
import run.halo.app.utils.JsonUtils;
|
import run.halo.app.utils.JsonUtils;
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
|
@ -287,15 +283,6 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
return activatedThemeId;
|
return activatedThemeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Set activated theme id.
|
|
||||||
*
|
|
||||||
* @param themeId theme id
|
|
||||||
*/
|
|
||||||
private void setActivatedThemeId(@Nullable String themeId) {
|
|
||||||
this.activatedThemeId = themeId;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ThemeProperty activeTheme(String themeId) {
|
public ThemeProperty activeTheme(String themeId) {
|
||||||
// Check existence of the theme
|
// Check existence of the theme
|
||||||
|
@ -322,12 +309,6 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
return themeProperty;
|
return themeProperty;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Upload theme.
|
|
||||||
*
|
|
||||||
* @param file multipart file must not be null
|
|
||||||
* @return theme info
|
|
||||||
*/
|
|
||||||
@Override
|
@Override
|
||||||
public ThemeProperty upload(MultipartFile file) {
|
public ThemeProperty upload(MultipartFile file) {
|
||||||
Assert.notNull(file, "Multipart file must not be null");
|
Assert.notNull(file, "Multipart file must not be null");
|
||||||
|
@ -346,7 +327,7 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
file.transferTo(uploadPath);
|
file.transferTo(uploadPath);
|
||||||
|
|
||||||
// Unzip theme package
|
// Unzip theme package
|
||||||
ZipUtil.unzip(uploadPath.toFile(),uploadPath.getParent().toFile());
|
ZipUtil.unzip(uploadPath.toFile(), uploadPath.getParent().toFile());
|
||||||
|
|
||||||
// Delete theme package
|
// Delete theme package
|
||||||
FileUtil.del(uploadPath.toFile());
|
FileUtil.del(uploadPath.toFile());
|
||||||
|
@ -360,6 +341,36 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public ThemeProperty add(Path themeTmpPath) throws IOException {
|
||||||
|
Assert.notNull(themeTmpPath, "Theme temporary path must not be null");
|
||||||
|
Assert.isTrue(Files.isDirectory(themeTmpPath), "Theme temporary path must be a directory");
|
||||||
|
|
||||||
|
// Check property config
|
||||||
|
Path configPath = getThemePropertyPathOfNullable(themeTmpPath).orElseThrow(() -> new ThemePropertyMissingException("Theme property file is dismiss").setErrorData(themeTmpPath));
|
||||||
|
|
||||||
|
ThemeProperty tmpThemeProperty = getProperty(configPath);
|
||||||
|
|
||||||
|
// Copy the temporary path to current theme folder
|
||||||
|
Path targetThemePath = workDir.resolve(tmpThemeProperty.getId());
|
||||||
|
FileUtils.copyFolder(themeTmpPath, targetThemePath);
|
||||||
|
|
||||||
|
// Delete temp theme folder
|
||||||
|
FileUtils.deleteFolder(themeTmpPath);
|
||||||
|
|
||||||
|
// Get property again
|
||||||
|
return getProperty(targetThemePath);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set activated theme id.
|
||||||
|
*
|
||||||
|
* @param themeId theme id
|
||||||
|
*/
|
||||||
|
private void setActivatedThemeId(@Nullable String themeId) {
|
||||||
|
this.activatedThemeId = themeId;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Lists theme files as tree view.
|
* Lists theme files as tree view.
|
||||||
*
|
*
|
||||||
|
@ -446,8 +457,14 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
/**
|
||||||
private Path getPropertyPath(@NonNull Path themePath) {
|
* Gets property path of nullable.
|
||||||
|
*
|
||||||
|
* @param themePath theme path.
|
||||||
|
* @return an optional property path
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private Optional<Path> getThemePropertyPathOfNullable(@NonNull Path themePath) {
|
||||||
Assert.notNull(themePath, "Theme path must not be null");
|
Assert.notNull(themePath, "Theme path must not be null");
|
||||||
|
|
||||||
for (String propertyPathName : THEME_PROPERTY_FILE_NAMES) {
|
for (String propertyPathName : THEME_PROPERTY_FILE_NAMES) {
|
||||||
|
@ -456,28 +473,28 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
log.debug("Attempting to find property file: [{}]", propertyPath);
|
log.debug("Attempting to find property file: [{}]", propertyPath);
|
||||||
if (Files.exists(propertyPath) && Files.isReadable(propertyPath)) {
|
if (Files.exists(propertyPath) && Files.isReadable(propertyPath)) {
|
||||||
log.debug("Found property file: [{}]", propertyPath);
|
log.debug("Found property file: [{}]", propertyPath);
|
||||||
return propertyPath;
|
return Optional.of(propertyPath);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets theme property.
|
* Gets property path of non null.
|
||||||
*
|
*
|
||||||
* @param themePath must not be null
|
* @param themePath theme path.
|
||||||
* @return theme property
|
* @return property path won't be null
|
||||||
*/
|
*/
|
||||||
@NonNull
|
@NonNull
|
||||||
private ThemeProperty getProperty(@NonNull Path themePath) {
|
private Path getThemePropertyPath(@NonNull Path themePath) {
|
||||||
|
return getThemePropertyPathOfNullable(themePath).orElseThrow(() -> new ThemePropertyMissingException(themePath + " dose not exist any theme property file").setErrorData(themePath));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Optional<ThemeProperty> getPropertyOfNullable(Path themePath) {
|
||||||
Assert.notNull(themePath, "Theme path must not be null");
|
Assert.notNull(themePath, "Theme path must not be null");
|
||||||
|
|
||||||
Path propertyPath = getPropertyPath(themePath);
|
Path propertyPath = getThemePropertyPath(themePath);
|
||||||
|
|
||||||
if (propertyPath == null) {
|
|
||||||
throw new ThemePropertyMissingException(themePath + " dose not exist any theme property file").setErrorData(themePath);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get property content
|
// Get property content
|
||||||
|
@ -504,10 +521,24 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
themeProperty.setActivated(true);
|
themeProperty.setActivated(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return themeProperty;
|
return Optional.of(themeProperty);
|
||||||
|
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
throw new ThemePropertyMissingException("Cannot resolve theme property", e).setErrorData(propertyPath.toString());
|
log.error("Failed to load theme property file", e);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Optional.empty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets theme property.
|
||||||
|
*
|
||||||
|
* @param themePath must not be null
|
||||||
|
* @return theme property
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
private ThemeProperty getProperty(@NonNull Path themePath) {
|
||||||
|
return getPropertyOfNullable(themePath).orElseThrow(() -> new ThemePropertyMissingException("Cannot resolve theme property").setErrorData(themePath));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -517,6 +548,7 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
* @return screenshots file name or null if the given theme path has not screenshots
|
* @return screenshots file name or null if the given theme path has not screenshots
|
||||||
* @throws IOException throws when listing files
|
* @throws IOException throws when listing files
|
||||||
*/
|
*/
|
||||||
|
@NonNull
|
||||||
private Optional<String> getScreenshotsFileName(@NonNull Path themePath) throws IOException {
|
private Optional<String> getScreenshotsFileName(@NonNull Path themePath) throws IOException {
|
||||||
Assert.notNull(themePath, "Theme path must not be null");
|
Assert.notNull(themePath, "Theme path must not be null");
|
||||||
|
|
||||||
|
|
|
@ -3,9 +3,11 @@ package run.halo.app.utils;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.file.*;
|
import java.nio.file.*;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
|
import java.util.Comparator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File utilities.
|
* File utilities.
|
||||||
|
@ -46,4 +48,18 @@ public class FileUtils {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes folder recursively.
|
||||||
|
*
|
||||||
|
* @param deletingPath deleting path must not be null
|
||||||
|
*/
|
||||||
|
public static void deleteFolder(Path deletingPath) throws IOException {
|
||||||
|
Assert.notNull(deletingPath, "Deleting path must not be null");
|
||||||
|
|
||||||
|
Files.walk(deletingPath)
|
||||||
|
.sorted(Comparator.reverseOrder())
|
||||||
|
.map(Path::toFile)
|
||||||
|
.forEach(File::delete);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue