mirror of https://github.com/halo-dev/halo
Add screenshots and isActivated into ThemeProperties
parent
a68431b09f
commit
b8fd0e4841
|
@ -107,7 +107,7 @@ public class StartedListener implements ApplicationListener<ApplicationStartedEv
|
||||||
}
|
}
|
||||||
|
|
||||||
private void printStartInfo() {
|
private void printStartInfo() {
|
||||||
String blogUrl = getBaseUrl();
|
String blogUrl = optionService.getBlogBaseUrl();
|
||||||
|
|
||||||
log.info("Halo started at {}", blogUrl);
|
log.info("Halo started at {}", blogUrl);
|
||||||
// TODO admin may be changeable
|
// TODO admin may be changeable
|
||||||
|
@ -117,26 +117,6 @@ public class StartedListener implements ApplicationListener<ApplicationStartedEv
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets blog url.
|
|
||||||
*
|
|
||||||
* @return blog url (If blog url isn't present, current machine IP address will be default)
|
|
||||||
*/
|
|
||||||
private String getBaseUrl() {
|
|
||||||
// Get server port
|
|
||||||
String serverPort = applicationContext.getEnvironment().getProperty("server.port", "8080");
|
|
||||||
|
|
||||||
String blogUrl = optionService.getByPropertyOfNullable(BlogProperties.BLOG_URL);
|
|
||||||
|
|
||||||
if (StrUtil.isNotBlank(blogUrl)) {
|
|
||||||
blogUrl = StrUtil.removeSuffix(blogUrl, "/");
|
|
||||||
} else {
|
|
||||||
blogUrl = String.format("http://%s:%s", HaloUtils.getMachineIP(), serverPort);
|
|
||||||
}
|
|
||||||
|
|
||||||
return blogUrl;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cache Owo
|
* Cache Owo
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,6 +3,8 @@ package run.halo.app.model.support;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Theme property.
|
||||||
|
*
|
||||||
* @author : RYAN0UP
|
* @author : RYAN0UP
|
||||||
* @date : 2019-03-22
|
* @date : 2019-03-22
|
||||||
*/
|
*/
|
||||||
|
@ -57,5 +59,15 @@ public class ThemeProperty {
|
||||||
/**
|
/**
|
||||||
* Has options.
|
* Has options.
|
||||||
*/
|
*/
|
||||||
private Boolean hasOptions;
|
private boolean hasOptions;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Is activated.
|
||||||
|
*/
|
||||||
|
private boolean isActivated;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Screenshots url.
|
||||||
|
*/
|
||||||
|
private String screenshots;
|
||||||
}
|
}
|
||||||
|
|
|
@ -274,4 +274,12 @@ public interface OptionService extends CrudService<Option, Integer> {
|
||||||
@NonNull
|
@NonNull
|
||||||
Locale getLocale();
|
Locale getLocale();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets blog base url. (Without /)
|
||||||
|
*
|
||||||
|
* @return blog base url (If blog url isn't present, current machine IP address will be default)
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
String getBlogBaseUrl();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -42,6 +42,11 @@ public interface ThemeService {
|
||||||
*/
|
*/
|
||||||
String THEME_FOLDER = "templates/themes";
|
String THEME_FOLDER = "templates/themes";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme screenshots name.
|
||||||
|
*/
|
||||||
|
String THEME_SCREENSHOTS_NAME = "screenshot";
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render template.
|
* Render template.
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package run.halo.app.service.impl;
|
package run.halo.app.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.qiniu.common.Zone;
|
import com.qiniu.common.Zone;
|
||||||
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.context.ApplicationContext;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
|
@ -15,6 +17,7 @@ import run.halo.app.model.properties.*;
|
||||||
import run.halo.app.repository.OptionRepository;
|
import run.halo.app.repository.OptionRepository;
|
||||||
import run.halo.app.service.OptionService;
|
import run.halo.app.service.OptionService;
|
||||||
import run.halo.app.service.base.AbstractCrudService;
|
import run.halo.app.service.base.AbstractCrudService;
|
||||||
|
import run.halo.app.utils.HaloUtils;
|
||||||
import run.halo.app.utils.ServiceUtils;
|
import run.halo.app.utils.ServiceUtils;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -35,9 +38,13 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
||||||
|
|
||||||
private final OptionRepository optionRepository;
|
private final OptionRepository optionRepository;
|
||||||
|
|
||||||
public OptionServiceImpl(OptionRepository optionRepository) {
|
private final ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
public OptionServiceImpl(OptionRepository optionRepository,
|
||||||
|
ApplicationContext applicationContext) {
|
||||||
super(optionRepository);
|
super(optionRepository);
|
||||||
this.optionRepository = optionRepository;
|
this.optionRepository = optionRepository;
|
||||||
|
this.applicationContext = applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -266,4 +273,20 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
||||||
}
|
}
|
||||||
}).orElseGet(Locale::getDefault);
|
}).orElseGet(Locale::getDefault);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getBlogBaseUrl() {
|
||||||
|
// Get server port
|
||||||
|
String serverPort = applicationContext.getEnvironment().getProperty("server.port", "8080");
|
||||||
|
|
||||||
|
String blogUrl = getByPropertyOfNullable(BlogProperties.BLOG_URL);
|
||||||
|
|
||||||
|
if (StrUtil.isNotBlank(blogUrl)) {
|
||||||
|
blogUrl = StrUtil.removeSuffix(blogUrl, "/");
|
||||||
|
} else {
|
||||||
|
blogUrl = String.format("http://%s:%s", HaloUtils.getMachineIP(), serverPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
return blogUrl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,7 @@ import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
|
||||||
import freemarker.template.Configuration;
|
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.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;
|
||||||
|
@ -16,6 +17,7 @@ import org.springframework.util.Assert;
|
||||||
import org.springframework.util.CollectionUtils;
|
import org.springframework.util.CollectionUtils;
|
||||||
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.BadRequestException;
|
||||||
import run.halo.app.exception.ForbiddenException;
|
import run.halo.app.exception.ForbiddenException;
|
||||||
import run.halo.app.exception.NotFoundException;
|
import run.halo.app.exception.NotFoundException;
|
||||||
import run.halo.app.exception.ServiceException;
|
import run.halo.app.exception.ServiceException;
|
||||||
|
@ -25,6 +27,7 @@ import run.halo.app.model.support.ThemeFile;
|
||||||
import run.halo.app.model.support.ThemeProperty;
|
import run.halo.app.model.support.ThemeProperty;
|
||||||
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.FilenameUtils;
|
||||||
import run.halo.app.utils.JsonUtils;
|
import run.halo.app.utils.JsonUtils;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
@ -52,6 +55,11 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
*/
|
*/
|
||||||
private final Path workDir;
|
private final Path workDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Activated theme id.
|
||||||
|
*/
|
||||||
|
private String activatedThemeId;
|
||||||
|
|
||||||
private final ObjectMapper yamlMapper;
|
private final ObjectMapper yamlMapper;
|
||||||
|
|
||||||
private final OptionService optionService;
|
private final OptionService optionService;
|
||||||
|
@ -199,6 +207,11 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
// Get the theme property
|
// Get the theme property
|
||||||
ThemeProperty themeProperty = getThemeOfNonNullBy(themeId);
|
ThemeProperty themeProperty = getThemeOfNonNullBy(themeId);
|
||||||
|
|
||||||
|
if (themeId.equals(getActivatedThemeId())) {
|
||||||
|
// Prevent to delete the activated theme
|
||||||
|
throw new BadRequestException("You can't delete the activated theme").setErrorData(themeId);
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Delete the folder
|
// Delete the folder
|
||||||
Files.deleteIfExists(Paths.get(themeProperty.getThemePath()));
|
Files.deleteIfExists(Paths.get(themeProperty.getThemePath()));
|
||||||
|
@ -217,7 +230,7 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
// Get theme property
|
// Get theme property
|
||||||
ThemeProperty themeProperty = getThemeOfNonNullBy(themeId);
|
ThemeProperty themeProperty = getThemeOfNonNullBy(themeId);
|
||||||
|
|
||||||
if (!themeProperty.getHasOptions()) {
|
if (!themeProperty.isHasOptions()) {
|
||||||
// If this theme dose not has an option, then return null
|
// If this theme dose not has an option, then return null
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -252,7 +265,24 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getActivatedThemeId() {
|
public String getActivatedThemeId() {
|
||||||
return optionService.getByProperty(PrimaryProperties.THEME).orElse(DEFAULT_THEME_NAME);
|
if (StringUtils.isBlank(activatedThemeId)) {
|
||||||
|
synchronized (this) {
|
||||||
|
if (StringUtils.isBlank(activatedThemeId)) {
|
||||||
|
return optionService.getByProperty(PrimaryProperties.THEME).orElse(DEFAULT_THEME_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return activatedThemeId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set activated theme id.
|
||||||
|
*
|
||||||
|
* @param themeId theme id
|
||||||
|
*/
|
||||||
|
private void setActivatedThemeId(@Nullable String themeId) {
|
||||||
|
this.activatedThemeId = themeId;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -263,6 +293,10 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
// Save the theme to database
|
// Save the theme to database
|
||||||
optionService.saveProperty(PrimaryProperties.THEME, themeId);
|
optionService.saveProperty(PrimaryProperties.THEME, themeId);
|
||||||
|
|
||||||
|
|
||||||
|
// Set the activated theme id
|
||||||
|
setActivatedThemeId(themeId);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// TODO Refactor here in the future
|
// TODO Refactor here in the future
|
||||||
configuration.setSharedVariable("themeName", themeId);
|
configuration.setSharedVariable("themeName", themeId);
|
||||||
|
@ -388,8 +422,23 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
themeProperty.setVersion(properties.getProperty("theme.version"));
|
themeProperty.setVersion(properties.getProperty("theme.version"));
|
||||||
themeProperty.setAuthor(properties.getProperty("theme.author"));
|
themeProperty.setAuthor(properties.getProperty("theme.author"));
|
||||||
themeProperty.setAuthorWebsite(properties.getProperty("theme.author.website"));
|
themeProperty.setAuthorWebsite(properties.getProperty("theme.author.website"));
|
||||||
|
|
||||||
themeProperty.setThemePath(themePath.toString());
|
themeProperty.setThemePath(themePath.toString());
|
||||||
themeProperty.setHasOptions(hasOptions(themePath));
|
themeProperty.setHasOptions(hasOptions(themePath));
|
||||||
|
themeProperty.setActivated(false);
|
||||||
|
|
||||||
|
// Set screenshots
|
||||||
|
getScreenshotsFileName(themePath).ifPresent(screenshotsName ->
|
||||||
|
themeProperty.setScreenshots(StringUtils.join(optionService.getBlogBaseUrl(),
|
||||||
|
"/",
|
||||||
|
FilenameUtils.getBasename(themeProperty.getThemePath()),
|
||||||
|
"/",
|
||||||
|
screenshotsName)));
|
||||||
|
|
||||||
|
if (themeProperty.getId().equals(getActivatedThemeId())) {
|
||||||
|
// Set activation
|
||||||
|
themeProperty.setActivated(true);
|
||||||
|
}
|
||||||
|
|
||||||
return themeProperty;
|
return themeProperty;
|
||||||
} catch (IOException e) {
|
} catch (IOException e) {
|
||||||
|
@ -398,6 +447,24 @@ public class ThemeServiceImpl implements ThemeService {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets screenshots file name.
|
||||||
|
*
|
||||||
|
* @param themePath theme path must not be null
|
||||||
|
* @return screenshots file name or null if the given theme path has not screenshots
|
||||||
|
* @throws IOException throws when listing files
|
||||||
|
*/
|
||||||
|
private Optional<String> getScreenshotsFileName(@NonNull Path themePath) throws IOException {
|
||||||
|
Assert.notNull(themePath, "Theme path must not be null");
|
||||||
|
|
||||||
|
return Files.list(themePath)
|
||||||
|
.filter(path -> Files.isRegularFile(path)
|
||||||
|
&& Files.isReadable(path)
|
||||||
|
&& FilenameUtils.getBasename(path.toString()).equalsIgnoreCase(THEME_SCREENSHOTS_NAME))
|
||||||
|
.findFirst()
|
||||||
|
.map(path -> path.getFileName().toString());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check existence of the options.
|
* Check existence of the options.
|
||||||
*
|
*
|
||||||
|
|
|
@ -67,7 +67,7 @@ public class ThemeController {
|
||||||
|
|
||||||
@PostMapping("{themeId}/activation")
|
@PostMapping("{themeId}/activation")
|
||||||
@ApiOperation("Activates a theme")
|
@ApiOperation("Activates a theme")
|
||||||
public ThemeProperty active(@RequestParam("themeId") String themeId) {
|
public ThemeProperty active(@PathVariable("themeId") String themeId) {
|
||||||
return themeService.activeTheme(themeId);
|
return themeService.activeTheme(themeId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
package run.halo.app.utils;
|
package run.halo.app.utils;
|
||||||
|
|
||||||
|
import io.micrometer.core.annotation.TimedSet;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -7,6 +8,7 @@ import java.nio.file.Paths;
|
||||||
|
|
||||||
import static org.hamcrest.Matchers.equalTo;
|
import static org.hamcrest.Matchers.equalTo;
|
||||||
import static org.junit.Assert.assertThat;
|
import static org.junit.Assert.assertThat;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Paths test.
|
* Paths test.
|
||||||
|
@ -22,5 +24,14 @@ public class PathsTest {
|
||||||
Path path = Paths.get("/home/test/", "/upload/test.txt");
|
Path path = Paths.get("/home/test/", "/upload/test.txt");
|
||||||
assertThat(path.toString(), equalTo("/home/test/upload/test.txt"));
|
assertThat(path.toString(), equalTo("/home/test/upload/test.txt"));
|
||||||
assertThat(path.getParent().toString(), equalTo("/home/test/upload"));
|
assertThat(path.getParent().toString(), equalTo("/home/test/upload"));
|
||||||
|
assertThat(path.getFileName().toString(), equalTo("test.txt"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void startWithTest() {
|
||||||
|
Path path = Paths.get("/test/test.txt");
|
||||||
|
assertThat(path.getFileName().toString(), equalTo("test.txt"));
|
||||||
|
boolean isStartWith = FilenameUtils.getBasename(path.toString()).equalsIgnoreCase("test");
|
||||||
|
assertTrue(isStartWith);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue