Add a common theme addition service

pull/146/head
johnniang 2019-04-18 23:32:44 +08:00
parent 9e9bd1a377
commit 76b3310027
3 changed files with 95 additions and 36 deletions

View File

@ -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;
} }

View File

@ -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");

View File

@ -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);
}
} }