mirror of https://github.com/halo-dev/halo
Merge remote-tracking branch 'origin/v1' into v1
commit
0e45f06a50
|
@ -1,8 +1,19 @@
|
||||||
package cc.ryanc.halo.config;
|
package cc.ryanc.halo.config;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.model.freemarker.method.RandomMethod;
|
||||||
|
import cc.ryanc.halo.model.freemarker.method.RecentCommentsMethod;
|
||||||
|
import cc.ryanc.halo.model.freemarker.method.RecentPostsMethod;
|
||||||
|
import cc.ryanc.halo.model.freemarker.tag.ArticleTagDirective;
|
||||||
|
import cc.ryanc.halo.model.freemarker.tag.CommonTagDirective;
|
||||||
|
import cc.ryanc.halo.service.OptionService;
|
||||||
|
import cc.ryanc.halo.service.UserService;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
import javax.annotation.PostConstruct;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
* FreeMarker配置
|
* FreeMarker配置
|
||||||
|
@ -15,43 +26,43 @@ import org.springframework.context.annotation.Configuration;
|
||||||
@Configuration
|
@Configuration
|
||||||
public class FreeMarkerAutoConfiguration {
|
public class FreeMarkerAutoConfiguration {
|
||||||
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private freemarker.template.Configuration configuration;
|
private freemarker.template.Configuration configuration;
|
||||||
//
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private OptionsService optionsService;
|
private OptionService optionsService;
|
||||||
//
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private UserService userService;
|
private UserService userService;
|
||||||
//
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private CommonTagDirective commonTagDirective;
|
private CommonTagDirective commonTagDirective;
|
||||||
//
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private ArticleTagDirective articleTagDirective;
|
private ArticleTagDirective articleTagDirective;
|
||||||
//
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private RandomMethod randomMethod;
|
private RandomMethod randomMethod;
|
||||||
//
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private RecentPostsMethod recentPostsMethod;
|
private RecentPostsMethod recentPostsMethod;
|
||||||
//
|
|
||||||
// @Autowired
|
@Autowired
|
||||||
// private RecentCommentsMethod recentCommentsMethod;
|
private RecentCommentsMethod recentCommentsMethod;
|
||||||
//
|
|
||||||
// @PostConstruct
|
@PostConstruct
|
||||||
// public void setSharedVariable() {
|
public void setSharedVariable() {
|
||||||
// try {
|
try {
|
||||||
// //自定义标签
|
//自定义标签
|
||||||
// configuration.setSharedVariable("commonTag", commonTagDirective);
|
configuration.setSharedVariable("commonTag", commonTagDirective);
|
||||||
// configuration.setSharedVariable("articleTag", articleTagDirective);
|
configuration.setSharedVariable("articleTag", articleTagDirective);
|
||||||
// configuration.setSharedVariable("options", optionsService.findAllOptions());
|
configuration.setSharedVariable("options", optionsService.listOptions());
|
||||||
// configuration.setSharedVariable("user", userService.findUser());
|
// configuration.setSharedVariable("user", userService.findUser());
|
||||||
// configuration.setSharedVariable("randomMethod", randomMethod);
|
configuration.setSharedVariable("randomMethod", randomMethod);
|
||||||
// configuration.setSharedVariable("recentPostsMethod", recentPostsMethod);
|
configuration.setSharedVariable("recentPostsMethod", recentPostsMethod);
|
||||||
// configuration.setSharedVariable("recentCommentsMethod", recentCommentsMethod);
|
configuration.setSharedVariable("recentCommentsMethod", recentCommentsMethod);
|
||||||
// } catch (TemplateModelException e) {
|
} catch (TemplateModelException e) {
|
||||||
// log.error("Custom tags failed to load:{}", e.getMessage());
|
log.error("Custom tags failed to load:{}", e.getMessage());
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,8 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer {
|
||||||
registry.addResourceHandler("/static/**")
|
registry.addResourceHandler("/static/**")
|
||||||
.addResourceLocations("classpath:/static/");
|
.addResourceLocations("classpath:/static/");
|
||||||
registry.addResourceHandler("/**")
|
registry.addResourceHandler("/**")
|
||||||
.addResourceLocations("classpath:/templates/themes/");
|
.addResourceLocations("classpath:/templates/themes/")
|
||||||
|
.addResourceLocations("file:///" + System.getProperties().getProperty("user.home") + "/halo/templates/themes/");
|
||||||
registry.addResourceHandler("/upload/**")
|
registry.addResourceHandler("/upload/**")
|
||||||
.addResourceLocations("file:///" + System.getProperties().getProperty("user.home") + "/halo/upload/");
|
.addResourceLocations("file:///" + System.getProperties().getProperty("user.home") + "/halo/upload/");
|
||||||
registry.addResourceHandler("/favicon.ico")
|
registry.addResourceHandler("/favicon.ico")
|
||||||
|
|
|
@ -1,14 +1,27 @@
|
||||||
package cc.ryanc.halo.listener;
|
package cc.ryanc.halo.listener;
|
||||||
|
|
||||||
import cc.ryanc.halo.config.properties.HaloProperties;
|
import cc.ryanc.halo.config.properties.HaloProperties;
|
||||||
|
import cc.ryanc.halo.model.support.HaloConst;
|
||||||
|
import cc.ryanc.halo.model.support.Theme;
|
||||||
|
import cc.ryanc.halo.service.OptionService;
|
||||||
import cc.ryanc.halo.utils.HaloUtils;
|
import cc.ryanc.halo.utils.HaloUtils;
|
||||||
|
import cc.ryanc.halo.utils.ThemeUtils;
|
||||||
|
import cc.ryanc.halo.web.controller.content.base.BaseContentController;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.json.JSONUtil;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationListener;
|
import org.springframework.context.ApplicationListener;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.nio.charset.Charset;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* <pre>
|
||||||
|
@ -31,18 +44,54 @@ public class StartedListener implements ApplicationListener<ApplicationStartedEv
|
||||||
@Autowired
|
@Autowired
|
||||||
private HaloProperties haloProperties;
|
private HaloProperties haloProperties;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OptionService optionService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onApplicationEvent(ApplicationStartedEvent event) {
|
public void onApplicationEvent(ApplicationStartedEvent event) {
|
||||||
// save halo version to database
|
// save halo version to database
|
||||||
// TODO Complete cache option value
|
// TODO Complete cache option value
|
||||||
// TODO Complete load active theme
|
this.cacheOptions();
|
||||||
// TODO Complete load option
|
this.cacheThemes();
|
||||||
// TODO Load themes
|
this.cacheOwo();
|
||||||
// TODO Load owo
|
this.getActiveTheme();
|
||||||
|
|
||||||
this.printStartInfo();
|
this.printStartInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache options to map
|
||||||
|
*/
|
||||||
|
private void cacheOptions() {
|
||||||
|
HaloConst.OPTIONS = optionService.listOptions();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache themes to map
|
||||||
|
*/
|
||||||
|
private void cacheThemes() {
|
||||||
|
final List<Theme> themes = ThemeUtils.getThemes();
|
||||||
|
if (null != themes) {
|
||||||
|
HaloConst.THEMES = themes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get active theme
|
||||||
|
*/
|
||||||
|
private void getActiveTheme() {
|
||||||
|
final String themeValue = optionService.getByKey("theme");
|
||||||
|
if (StrUtil.isNotEmpty(themeValue) && !StrUtil.equals(themeValue, null)) {
|
||||||
|
BaseContentController.THEME = themeValue;
|
||||||
|
} else {
|
||||||
|
BaseContentController.THEME = "anatole";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
configuration.setSharedVariable("themeName", BaseContentController.THEME);
|
||||||
|
} catch (TemplateModelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void printStartInfo() {
|
private void printStartInfo() {
|
||||||
// Get server port
|
// Get server port
|
||||||
String serverPort = applicationContext.getEnvironment().getProperty("server.port");
|
String serverPort = applicationContext.getEnvironment().getProperty("server.port");
|
||||||
|
@ -75,4 +124,16 @@ public class StartedListener implements ApplicationListener<ApplicationStartedEv
|
||||||
|
|
||||||
return blogUrl;
|
return blogUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Cache Owo
|
||||||
|
*/
|
||||||
|
private void cacheOwo() {
|
||||||
|
try {
|
||||||
|
File file = new File(ResourceUtils.getURL("classpath:").getPath(), "static/halo-common/OwO/OwO.path.json");
|
||||||
|
HaloConst.OWO = JSONUtil.readJSONObject(file, Charset.forName("UTF-8"));
|
||||||
|
} catch (FileNotFoundException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -46,6 +46,12 @@ public class Comment {
|
||||||
@Column(name = "ip_address", columnDefinition = "varchar(127) default ''")
|
@Column(name = "ip_address", columnDefinition = "varchar(127) default ''")
|
||||||
private String ipAddress;
|
private String ipAddress;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 评论者网址
|
||||||
|
*/
|
||||||
|
@Column(name = "author_url",columnDefinition = "varchar(512) default ''")
|
||||||
|
private String authorUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gavatar md5
|
* Gavatar md5
|
||||||
*/
|
*/
|
||||||
|
@ -55,7 +61,7 @@ public class Comment {
|
||||||
/**
|
/**
|
||||||
* 评论内容
|
* 评论内容
|
||||||
*/
|
*/
|
||||||
@Column(name = "content", columnDefinition = "varchar(1024) not null")
|
@Column(name = "content", columnDefinition = "varchar(1023) not null")
|
||||||
private String content;
|
private String content;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
package cc.ryanc.halo.model.freemarker.tag;
|
package cc.ryanc.halo.model.freemarker.tag;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.service.*;
|
||||||
import freemarker.core.Environment;
|
import freemarker.core.Environment;
|
||||||
import freemarker.template.TemplateDirectiveBody;
|
import freemarker.template.*;
|
||||||
import freemarker.template.TemplateDirectiveModel;
|
|
||||||
import freemarker.template.TemplateException;
|
|
||||||
import freemarker.template.TemplateModel;
|
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -23,9 +21,55 @@ public class CommonTagDirective implements TemplateDirectiveModel {
|
||||||
|
|
||||||
private static final String METHOD_KEY = "method";
|
private static final String METHOD_KEY = "method";
|
||||||
|
|
||||||
|
private final MenuService menuService;
|
||||||
|
|
||||||
|
private final CategoryService categoryService;
|
||||||
|
|
||||||
|
private final TagService tagService;
|
||||||
|
|
||||||
|
private final LinkService linkService;
|
||||||
|
|
||||||
|
private final CommentService commentService;
|
||||||
|
|
||||||
|
public CommonTagDirective(MenuService menuService,
|
||||||
|
CategoryService categoryService,
|
||||||
|
TagService tagService,
|
||||||
|
LinkService linkService,
|
||||||
|
CommentService commentService) {
|
||||||
|
this.menuService = menuService;
|
||||||
|
this.categoryService = categoryService;
|
||||||
|
this.tagService = tagService;
|
||||||
|
this.linkService = linkService;
|
||||||
|
this.commentService = commentService;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
|
public void execute(Environment env, Map params, TemplateModel[] loopVars, TemplateDirectiveBody body) throws TemplateException, IOException {
|
||||||
// TODO Complete comment tag directive.
|
final DefaultObjectWrapperBuilder builder = new DefaultObjectWrapperBuilder(Configuration.VERSION_2_3_25);
|
||||||
|
|
||||||
|
if (params.containsKey(METHOD_KEY)) {
|
||||||
|
String method = params.get(METHOD_KEY).toString();
|
||||||
|
switch (method) {
|
||||||
|
case "menus":
|
||||||
|
env.setVariable("menus", builder.build().wrap(menuService.listAll()));
|
||||||
|
break;
|
||||||
|
case "categories":
|
||||||
|
env.setVariable("categories", builder.build().wrap(categoryService.listAll()));
|
||||||
|
break;
|
||||||
|
case "tags":
|
||||||
|
env.setVariable("tags", builder.build().wrap(tagService.listAll()));
|
||||||
|
break;
|
||||||
|
case "links":
|
||||||
|
env.setVariable("links", builder.build().wrap(linkService.listAll()));
|
||||||
|
break;
|
||||||
|
case "newComments":
|
||||||
|
env.setVariable("newComments", builder.build().wrap(commentService.listAll()));
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
body.render(env.getOut());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
package cc.ryanc.halo.model.support;
|
package cc.ryanc.halo.model.support;
|
||||||
|
|
||||||
|
import cn.hutool.json.JSONObject;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -21,22 +23,22 @@ public class HaloConst {
|
||||||
public static final String HALO_VERSION = "0.4.2";
|
public static final String HALO_VERSION = "0.4.2";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token key
|
* Token of header param
|
||||||
*/
|
*/
|
||||||
public static final String TOKEN_HEADER = "token";
|
public static final String TOKEN_HEADER = "token";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有设置选项(key,value)
|
* All of the options
|
||||||
*/
|
*/
|
||||||
public static Map<String, String> OPTIONS = new HashMap<>();
|
public static Map<String, String> OPTIONS = new HashMap<>();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OwO表情
|
* All of the Owo
|
||||||
*/
|
*/
|
||||||
public static Map<String, String> OWO = new HashMap<>();
|
public static JSONObject OWO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 所有主题
|
* All of the themes
|
||||||
*/
|
*/
|
||||||
public static List<Theme> THEMES = new ArrayList<>();
|
public static List<Theme> THEMES = new ArrayList<>();
|
||||||
|
|
||||||
|
|
|
@ -5,9 +5,7 @@ import lombok.Data;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* Theme DTO
|
||||||
* 主题信息
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* @author : RYAN0UP
|
* @author : RYAN0UP
|
||||||
* @date : 2018/1/3
|
* @date : 2018/1/3
|
||||||
|
@ -18,17 +16,22 @@ public class Theme implements Serializable {
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 主题名称
|
* theme name
|
||||||
*/
|
*/
|
||||||
private String themeName;
|
private String themeName;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否支持设置
|
* is support setting options
|
||||||
*/
|
*/
|
||||||
private boolean hasOptions;
|
private boolean hasOptions;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否支持更新
|
* is support update
|
||||||
*/
|
*/
|
||||||
private boolean hasUpdate;
|
private boolean hasUpdate;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* is internal theme
|
||||||
|
*/
|
||||||
|
private boolean isInternal;
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package cc.ryanc.halo.repository;
|
||||||
import cc.ryanc.halo.model.entity.Option;
|
import cc.ryanc.halo.model.entity.Option;
|
||||||
import cc.ryanc.halo.repository.base.BaseRepository;
|
import cc.ryanc.halo.repository.base.BaseRepository;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Option repository.
|
* Option repository.
|
||||||
*
|
*
|
||||||
|
@ -10,4 +12,18 @@ import cc.ryanc.halo.repository.base.BaseRepository;
|
||||||
*/
|
*/
|
||||||
public interface OptionRepository extends BaseRepository<Option, Integer> {
|
public interface OptionRepository extends BaseRepository<Option, Integer> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query option by key
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @return Option
|
||||||
|
*/
|
||||||
|
Optional<Option> findByOptionKey(String key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete option by key
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
*/
|
||||||
|
void removeByOptionKey(String key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,8 @@ package cc.ryanc.halo.service;
|
||||||
import cc.ryanc.halo.model.entity.Option;
|
import cc.ryanc.halo.model.entity.Option;
|
||||||
import cc.ryanc.halo.service.base.CrudService;
|
import cc.ryanc.halo.service.base.CrudService;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Option service.
|
* Option service.
|
||||||
*
|
*
|
||||||
|
@ -10,4 +12,33 @@ import cc.ryanc.halo.service.base.CrudService;
|
||||||
*/
|
*/
|
||||||
public interface OptionService extends CrudService<Option, Integer> {
|
public interface OptionService extends CrudService<Option, Integer> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save one option
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @param value value
|
||||||
|
*/
|
||||||
|
void saveOption(String key, String value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save multiple options
|
||||||
|
*
|
||||||
|
* @param options options
|
||||||
|
*/
|
||||||
|
void saveOptions(Map<String, String> options);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all options
|
||||||
|
*
|
||||||
|
* @return Map
|
||||||
|
*/
|
||||||
|
Map<String, String> listOptions();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get option by key
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
String getByKey(String key);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,7 +4,12 @@ import cc.ryanc.halo.model.entity.Option;
|
||||||
import cc.ryanc.halo.repository.OptionRepository;
|
import cc.ryanc.halo.repository.OptionRepository;
|
||||||
import cc.ryanc.halo.service.OptionService;
|
import cc.ryanc.halo.service.OptionService;
|
||||||
import cc.ryanc.halo.service.base.AbstractCrudService;
|
import cc.ryanc.halo.service.base.AbstractCrudService;
|
||||||
|
import cc.ryanc.halo.utils.ServiceUtils;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.util.CollectionUtils;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* OptionService implementation class
|
* OptionService implementation class
|
||||||
|
@ -21,4 +26,65 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
|
||||||
super(optionRepository);
|
super(optionRepository);
|
||||||
this.optionRepository = optionRepository;
|
this.optionRepository = optionRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save one option
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @param value value
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void saveOption(String key, String value) {
|
||||||
|
if (StrUtil.equals(value, "")) {
|
||||||
|
optionRepository.removeByOptionKey(key);
|
||||||
|
} else if (StrUtil.isNotEmpty(key)) {
|
||||||
|
Option options = optionRepository.findByOptionKey(key).map(option -> {
|
||||||
|
// Exist
|
||||||
|
option.setOptionValue(value);
|
||||||
|
return option;
|
||||||
|
}).orElseGet(() -> {
|
||||||
|
// Not exist
|
||||||
|
Option option = new Option();
|
||||||
|
option.setOptionKey(key);
|
||||||
|
option.setOptionValue(value);
|
||||||
|
return option;
|
||||||
|
});
|
||||||
|
|
||||||
|
// Save or update the options
|
||||||
|
optionRepository.save(options);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save multiple options
|
||||||
|
*
|
||||||
|
* @param options options
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void saveOptions(Map<String, String> options) {
|
||||||
|
if (!CollectionUtils.isEmpty(options)) {
|
||||||
|
options.forEach(this::saveOption);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all options
|
||||||
|
*
|
||||||
|
* @return Map
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public Map<String, String> listOptions() {
|
||||||
|
return ServiceUtils.convertToMap(listAll(), Option::getOptionKey, Option::getOptionValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get option by key
|
||||||
|
*
|
||||||
|
* @param key key
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public String getByKey(String key) {
|
||||||
|
return optionRepository.findByOptionKey(key).map(Option::getOptionValue).orElse(null);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,5 @@
|
||||||
package cc.ryanc.halo.utils;
|
package cc.ryanc.halo.utils;
|
||||||
|
|
||||||
import cc.ryanc.halo.model.support.BackupDto;
|
|
||||||
import cc.ryanc.halo.model.support.Theme;
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.core.text.StrBuilder;
|
import cn.hutool.core.text.StrBuilder;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.qiniu.common.Zone;
|
import com.qiniu.common.Zone;
|
||||||
|
@ -10,7 +7,6 @@ import io.github.biezhi.ome.OhMyEmail;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
import org.springframework.util.Assert;
|
import org.springframework.util.Assert;
|
||||||
import org.springframework.util.ResourceUtils;
|
|
||||||
|
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
@ -25,7 +21,9 @@ import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.file.attribute.BasicFileAttributeView;
|
import java.nio.file.attribute.BasicFileAttributeView;
|
||||||
import java.nio.file.attribute.BasicFileAttributes;
|
import java.nio.file.attribute.BasicFileAttributes;
|
||||||
import java.util.*;
|
import java.util.Calendar;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Properties;
|
||||||
|
|
||||||
import static cc.ryanc.halo.model.support.HaloConst.OPTIONS;
|
import static cc.ryanc.halo.model.support.HaloConst.OPTIONS;
|
||||||
|
|
||||||
|
@ -207,113 +205,6 @@ public class HaloUtils {
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有主题
|
|
||||||
*
|
|
||||||
* @return List
|
|
||||||
*/
|
|
||||||
public static List<Theme> getThemes() {
|
|
||||||
final List<Theme> themes = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
// 获取项目根路径
|
|
||||||
final File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
|
|
||||||
// 获取主题路径
|
|
||||||
final File themesPath = new File(basePath.getAbsolutePath(), "templates/themes");
|
|
||||||
final File[] files = themesPath.listFiles();
|
|
||||||
if (null != files) {
|
|
||||||
Theme theme;
|
|
||||||
for (File file : files) {
|
|
||||||
if (file.isDirectory()) {
|
|
||||||
if (StrUtil.equals("__MACOSX", file.getName())) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
theme = new Theme();
|
|
||||||
theme.setThemeName(file.getName());
|
|
||||||
File optionsPath = new File(themesPath.getAbsolutePath(),
|
|
||||||
file.getName() + "/module/options.ftl");
|
|
||||||
if (optionsPath.exists()) {
|
|
||||||
theme.setHasOptions(true);
|
|
||||||
} else {
|
|
||||||
theme.setHasOptions(false);
|
|
||||||
}
|
|
||||||
File gitPath = new File(themesPath.getAbsolutePath(), file.getName() + "/.git");
|
|
||||||
if (gitPath.exists()) {
|
|
||||||
theme.setHasUpdate(true);
|
|
||||||
} else {
|
|
||||||
theme.setHasUpdate(false);
|
|
||||||
}
|
|
||||||
themes.add(theme);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Themes scan failed", e);
|
|
||||||
}
|
|
||||||
return themes;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取主题下的模板文件名
|
|
||||||
*
|
|
||||||
* @param theme theme
|
|
||||||
* @return List
|
|
||||||
*/
|
|
||||||
public static List<String> getTplName(String theme) {
|
|
||||||
final List<String> tpls = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
// 获取项目根路径
|
|
||||||
final File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
|
|
||||||
// 获取主题路径
|
|
||||||
final File themesPath = new File(basePath.getAbsolutePath(), "templates/themes/" + theme);
|
|
||||||
final File modulePath = new File(themesPath.getAbsolutePath(), "module");
|
|
||||||
final File[] baseFiles = themesPath.listFiles();
|
|
||||||
final File[] moduleFiles = modulePath.listFiles();
|
|
||||||
if (null != moduleFiles) {
|
|
||||||
for (File file : moduleFiles) {
|
|
||||||
if (file.isFile() && file.getName().endsWith(".ftl")) {
|
|
||||||
tpls.add("module/" + file.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (null != baseFiles) {
|
|
||||||
for (File file : baseFiles) {
|
|
||||||
if (file.isFile() && file.getName().endsWith(".ftl")) {
|
|
||||||
tpls.add(file.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("Failed to get theme template", e);
|
|
||||||
}
|
|
||||||
return tpls;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取定制模板 格式 page_xxx
|
|
||||||
*
|
|
||||||
* @return List
|
|
||||||
*/
|
|
||||||
public static List<String> getCustomTpl(String theme) {
|
|
||||||
final List<String> tpls = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
final File basePath = new File(ResourceUtils.getURL("classpath:").getPath());
|
|
||||||
// 获取主题路径
|
|
||||||
final File themePath = new File(basePath.getAbsolutePath(), "templates/themes/" + theme);
|
|
||||||
final File[] themeFiles = themePath.listFiles();
|
|
||||||
if (null != themeFiles && themeFiles.length > 0) {
|
|
||||||
for (File file : themeFiles) {
|
|
||||||
String[] split = StrUtil.removeSuffix(file.getName(), ".ftl").split("_");
|
|
||||||
if (split.length == 2 && "page".equals(split[0])) {
|
|
||||||
tpls.add(StrUtil.removeSuffix(file.getName(), ".ftl"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (FileNotFoundException e) {
|
|
||||||
log.error("File not found", e);
|
|
||||||
}
|
|
||||||
return tpls;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 导出为文件
|
* 导出为文件
|
||||||
*
|
*
|
||||||
|
|
|
@ -15,33 +15,35 @@ import java.util.Map;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* Markdown utils
|
||||||
|
*
|
||||||
* @author : RYAN0UP
|
* @author : RYAN0UP
|
||||||
* @date : 2018/11/14
|
* @date : 2018/11/14
|
||||||
*/
|
*/
|
||||||
public class MarkdownUtils {
|
public class MarkdownUtils {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Front-matter 插件
|
* Front-matter extension
|
||||||
*/
|
*/
|
||||||
private static final Set<Extension> EXTENSIONS_YAML = Collections.singleton(YamlFrontMatterExtension.create());
|
private static final Set<Extension> EXTENSIONS_YAML = Collections.singleton(YamlFrontMatterExtension.create());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Table 插件
|
* Table extension
|
||||||
*/
|
*/
|
||||||
private static final Set<Extension> EXTENSIONS_TABLE = Collections.singleton(TablesExtension.create());
|
private static final Set<Extension> EXTENSIONS_TABLE = Collections.singleton(TablesExtension.create());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 解析 Markdown 文档
|
* Parse Markdown content
|
||||||
*/
|
*/
|
||||||
private static final Parser PARSER = Parser.builder().extensions(EXTENSIONS_YAML).extensions(EXTENSIONS_TABLE).build();
|
private static final Parser PARSER = Parser.builder().extensions(EXTENSIONS_YAML).extensions(EXTENSIONS_TABLE).build();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染 HTML 文档
|
* Render HTML content
|
||||||
*/
|
*/
|
||||||
private static final HtmlRenderer RENDERER = HtmlRenderer.builder().extensions(EXTENSIONS_YAML).extensions(EXTENSIONS_TABLE).build();
|
private static final HtmlRenderer RENDERER = HtmlRenderer.builder().extensions(EXTENSIONS_YAML).extensions(EXTENSIONS_TABLE).build();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染 Markdown
|
* Render Markdown content
|
||||||
*
|
*
|
||||||
* @param content content
|
* @param content content
|
||||||
* @return String
|
* @return String
|
||||||
|
@ -66,7 +68,7 @@ public class MarkdownUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取元数据
|
* Get front-matter
|
||||||
*
|
*
|
||||||
* @param content content
|
* @param content content
|
||||||
* @return Map
|
* @return Map
|
||||||
|
|
|
@ -5,9 +5,7 @@ import lombok.extern.slf4j.Slf4j;
|
||||||
import static cc.ryanc.halo.model.support.HaloConst.OWO;
|
import static cc.ryanc.halo.model.support.HaloConst.OWO;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* Owo util
|
||||||
* OwO表情工具类
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* @author : RYAN0UP
|
* @author : RYAN0UP
|
||||||
* @date : 2017/12/22
|
* @date : 2017/12/22
|
||||||
|
@ -16,15 +14,15 @@ import static cc.ryanc.halo.model.support.HaloConst.OWO;
|
||||||
public class OwoUtil {
|
public class OwoUtil {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 将表情标志转化为图片地址
|
* Owo mark converted into a picture address
|
||||||
*
|
*
|
||||||
* @param mark 表情标志
|
* @param content content
|
||||||
* @return 表情图片地址
|
* @return picture address
|
||||||
*/
|
*/
|
||||||
public static String markToImg(String mark) {
|
public static String parseOwo(String content) {
|
||||||
for (String key : OWO.keySet()) {
|
for (String key : OWO.keySet()) {
|
||||||
mark = mark.replace(key, OWO.get(key));
|
content = content.replace(key, OWO.get(key).toString());
|
||||||
}
|
}
|
||||||
return mark;
|
return content;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,206 @@
|
||||||
|
package cc.ryanc.halo.utils;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.model.support.HaloConst;
|
||||||
|
import cc.ryanc.halo.model.support.Theme;
|
||||||
|
import cc.ryanc.halo.web.controller.content.base.BaseContentController;
|
||||||
|
import cn.hutool.core.text.StrBuilder;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.util.ResourceUtils;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Theme utils
|
||||||
|
*
|
||||||
|
* @author : RYAN0UP
|
||||||
|
* @date : 2019/3/16
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public class ThemeUtils {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan internal themes and user's themes
|
||||||
|
*
|
||||||
|
* @return List
|
||||||
|
*/
|
||||||
|
public static List<Theme> getThemes() {
|
||||||
|
final List<Theme> themes = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
themes.addAll(getThemesByPath(getInternalThemesPath(), true));
|
||||||
|
themes.addAll(getThemesByPath(getUsersThemesPath(), false));
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Themes scan failed", e);
|
||||||
|
}
|
||||||
|
return themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Scan themes by directory
|
||||||
|
*
|
||||||
|
* @param file file
|
||||||
|
* @return List<Theme>
|
||||||
|
*/
|
||||||
|
private static List<Theme> getThemesByPath(File themesPath, boolean isInternal) {
|
||||||
|
final List<Theme> themes = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
final File[] files = themesPath.listFiles();
|
||||||
|
if (null != files) {
|
||||||
|
Theme theme;
|
||||||
|
for (File file : files) {
|
||||||
|
if (file.isDirectory()) {
|
||||||
|
if (StrUtil.equals("__MACOSX", file.getName())) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
theme = new Theme();
|
||||||
|
theme.setThemeName(file.getName());
|
||||||
|
File optionsPath = new File(themesPath.getAbsolutePath(),
|
||||||
|
file.getName() + "/module/options.ftl");
|
||||||
|
if (optionsPath.exists()) {
|
||||||
|
theme.setHasOptions(true);
|
||||||
|
} else {
|
||||||
|
theme.setHasOptions(false);
|
||||||
|
}
|
||||||
|
File gitPath = new File(themesPath.getAbsolutePath(), file.getName() + "/.git");
|
||||||
|
if (gitPath.exists()) {
|
||||||
|
theme.setHasUpdate(true);
|
||||||
|
} else {
|
||||||
|
theme.setHasUpdate(false);
|
||||||
|
}
|
||||||
|
theme.setInternal(isInternal);
|
||||||
|
themes.add(theme);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Themes scan failed", e);
|
||||||
|
}
|
||||||
|
return themes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get internal themes path
|
||||||
|
*
|
||||||
|
* @return File
|
||||||
|
* @throws FileNotFoundException FileNotFoundException
|
||||||
|
*/
|
||||||
|
public static File getInternalThemesPath() throws FileNotFoundException {
|
||||||
|
return new File(ResourceUtils.getURL("classpath:").getPath(), "templates/themes");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get user's themes path
|
||||||
|
*
|
||||||
|
* @return File
|
||||||
|
*/
|
||||||
|
public static File getUsersThemesPath() {
|
||||||
|
return new File(System.getProperties().getProperty("user.home"), "halo/templates/themes");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get themes path by theme name
|
||||||
|
*
|
||||||
|
* @param themeName themeName
|
||||||
|
* @return File
|
||||||
|
*/
|
||||||
|
public static File getThemesPath(String themeName) throws FileNotFoundException {
|
||||||
|
if (isInternal(themeName)) {
|
||||||
|
return getInternalThemesPath();
|
||||||
|
} else {
|
||||||
|
return getUsersThemesPath();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get theme templates
|
||||||
|
*
|
||||||
|
* @param theme theme
|
||||||
|
* @return List<String>
|
||||||
|
*/
|
||||||
|
public static List<String> getTplName(String theme) {
|
||||||
|
final List<String> templates = new ArrayList<>();
|
||||||
|
try {
|
||||||
|
final File themesPath = new File(getThemesPath(theme), theme);
|
||||||
|
final File modulePath = new File(themesPath.getAbsolutePath(), "module");
|
||||||
|
final File[] baseFiles = themesPath.listFiles();
|
||||||
|
final File[] moduleFiles = modulePath.listFiles();
|
||||||
|
if (null != moduleFiles) {
|
||||||
|
for (File file : moduleFiles) {
|
||||||
|
if (file.isFile() && file.getName().endsWith(".ftl")) {
|
||||||
|
templates.add("module/" + file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (null != baseFiles) {
|
||||||
|
for (File file : baseFiles) {
|
||||||
|
if (file.isFile() && file.getName().endsWith(".ftl")) {
|
||||||
|
templates.add(file.getName());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Failed to get theme template", e);
|
||||||
|
}
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get custom template, such as page_xxx.ftl, and xxx will be template name
|
||||||
|
*
|
||||||
|
* @return List
|
||||||
|
*/
|
||||||
|
public static List<String> getCustomTpl(String theme) throws FileNotFoundException {
|
||||||
|
final List<String> templates = new ArrayList<>();
|
||||||
|
final File themePath = new File(getThemesPath(theme), theme);
|
||||||
|
final File[] themeFiles = themePath.listFiles();
|
||||||
|
if (null != themeFiles && themeFiles.length > 0) {
|
||||||
|
for (File file : themeFiles) {
|
||||||
|
String[] split = StrUtil.removeSuffix(file.getName(), ".ftl").split("_");
|
||||||
|
if (split.length == 2 && "page".equals(split[0])) {
|
||||||
|
templates.add(StrUtil.removeSuffix(file.getName(), ".ftl"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return templates;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judging whether template exists under the specified theme
|
||||||
|
*
|
||||||
|
* @param template template
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static boolean isTemplateExist(String template) throws FileNotFoundException {
|
||||||
|
boolean result = false;
|
||||||
|
StrBuilder templatePath = new StrBuilder(BaseContentController.THEME);
|
||||||
|
templatePath.append("/");
|
||||||
|
templatePath.append(template);
|
||||||
|
File file = new File(getThemesPath(BaseContentController.THEME), templatePath.toString());
|
||||||
|
if (file.exists()) {
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Judging whether the theme is a internal theme or not
|
||||||
|
*
|
||||||
|
* @param themeName themeName
|
||||||
|
* @return boolean
|
||||||
|
*/
|
||||||
|
public static boolean isInternal(String themeName) {
|
||||||
|
boolean result = false;
|
||||||
|
List<Theme> themes = HaloConst.THEMES;
|
||||||
|
for (Theme theme : themes) {
|
||||||
|
if (theme.getThemeName().equals(themeName) && theme.isInternal()) {
|
||||||
|
result = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,6 +1,8 @@
|
||||||
package cc.ryanc.halo.web.controller.admin;
|
package cc.ryanc.halo.web.controller.admin;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.service.CommentService;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,4 +14,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = "/admin/comments")
|
@RequestMapping(value = "/admin/comments")
|
||||||
public class CommentController {
|
public class CommentController {
|
||||||
|
|
||||||
|
private final CommentService commentService;
|
||||||
|
|
||||||
|
public CommentController(CommentService commentService) {
|
||||||
|
this.commentService = commentService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String comments(){
|
||||||
|
return "admin/admin_comment";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cc.ryanc.halo.web.controller.admin;
|
package cc.ryanc.halo.web.controller.admin;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.service.MenuService;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,4 +14,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = "/admin/menus")
|
@RequestMapping(value = "/admin/menus")
|
||||||
public class MenuController {
|
public class MenuController {
|
||||||
|
|
||||||
|
private final MenuService menuService;
|
||||||
|
|
||||||
|
public MenuController(MenuService menuService) {
|
||||||
|
this.menuService = menuService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String menus(){
|
||||||
|
return "admin/admin_menu";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cc.ryanc.halo.web.controller.admin;
|
package cc.ryanc.halo.web.controller.admin;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.service.OptionService;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,4 +14,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = "/admin/options")
|
@RequestMapping(value = "/admin/options")
|
||||||
public class OptionController {
|
public class OptionController {
|
||||||
|
|
||||||
|
private final OptionService optionService;
|
||||||
|
|
||||||
|
public OptionController(OptionService optionService) {
|
||||||
|
this.optionService = optionService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String options(){
|
||||||
|
return "admin/admin_option";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cc.ryanc.halo.web.controller.admin;
|
package cc.ryanc.halo.web.controller.admin;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.service.PostService;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,4 +14,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = "/admin/pages")
|
@RequestMapping(value = "/admin/pages")
|
||||||
public class PageController {
|
public class PageController {
|
||||||
|
|
||||||
|
private final PostService postService;
|
||||||
|
|
||||||
|
public PageController(PostService postService) {
|
||||||
|
this.postService = postService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String pages(){
|
||||||
|
return "admin/admin_page";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
package cc.ryanc.halo.web.controller.admin;
|
package cc.ryanc.halo.web.controller.admin;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.service.TagService;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -12,4 +14,15 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = "/admin/tags")
|
@RequestMapping(value = "/admin/tags")
|
||||||
public class TagController {
|
public class TagController {
|
||||||
|
|
||||||
|
private final TagService tagService;
|
||||||
|
|
||||||
|
public TagController(TagService tagService) {
|
||||||
|
this.tagService = tagService;
|
||||||
|
}
|
||||||
|
|
||||||
|
@GetMapping
|
||||||
|
public String tags(){
|
||||||
|
return "admin/admin_tag";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,32 @@
|
||||||
package cc.ryanc.halo.web.controller.admin;
|
package cc.ryanc.halo.web.controller.admin;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.logging.Logger;
|
||||||
|
import cc.ryanc.halo.model.support.JsonResult;
|
||||||
|
import cc.ryanc.halo.service.LogService;
|
||||||
|
import cc.ryanc.halo.service.OptionService;
|
||||||
|
import cc.ryanc.halo.utils.LocaleMessageUtil;
|
||||||
|
import cc.ryanc.halo.utils.ThemeUtils;
|
||||||
|
import cc.ryanc.halo.web.controller.admin.base.BaseController;
|
||||||
|
import cc.ryanc.halo.web.controller.content.base.BaseContentController;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
|
import cn.hutool.core.io.file.FileReader;
|
||||||
|
import cn.hutool.core.io.file.FileWriter;
|
||||||
|
import cn.hutool.core.text.StrBuilder;
|
||||||
|
import cn.hutool.core.util.RuntimeUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.core.util.ZipUtil;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import org.springframework.cache.annotation.CacheEvict;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.web.bind.annotation.RequestMapping;
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static cc.ryanc.halo.model.support.HaloConst.THEMES;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Themes controller
|
* Themes controller
|
||||||
|
@ -11,5 +36,253 @@ import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
*/
|
*/
|
||||||
@Controller
|
@Controller
|
||||||
@RequestMapping(value = "/admin/themes")
|
@RequestMapping(value = "/admin/themes")
|
||||||
public class ThemeController {
|
public class ThemeController extends BaseController {
|
||||||
|
|
||||||
|
private final Logger log = Logger.getLogger(getClass());
|
||||||
|
|
||||||
|
private LogService logsService;
|
||||||
|
|
||||||
|
public ThemeController(Configuration configuration,
|
||||||
|
OptionService optionService,
|
||||||
|
LocaleMessageUtil localeMessageUtil,
|
||||||
|
LogService logsService) {
|
||||||
|
super(configuration, optionService, localeMessageUtil);
|
||||||
|
this.logsService = logsService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render theme manage
|
||||||
|
*
|
||||||
|
* @param model model
|
||||||
|
* @return template path: admin/admin_theme.ftl
|
||||||
|
*/
|
||||||
|
@GetMapping
|
||||||
|
public String themes(Model model) {
|
||||||
|
model.addAttribute("activeTheme", BaseContentController.THEME);
|
||||||
|
model.addAttribute("themes", THEMES);
|
||||||
|
return "admin/admin_theme";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Active theme
|
||||||
|
*
|
||||||
|
* @param themeName theme name
|
||||||
|
* @param request request
|
||||||
|
* @return JsonResult
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/set")
|
||||||
|
@ResponseBody
|
||||||
|
@CacheEvict(value = "posts", allEntries = true, beforeInvocation = true)
|
||||||
|
public JsonResult activeTheme(@RequestParam("themeName") String themeName,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
optionService.saveOption("theme", themeName);
|
||||||
|
BaseContentController.THEME = themeName;
|
||||||
|
configuration.setSharedVariable("themeName", themeName);
|
||||||
|
log.info("Changed theme to {}", themeName);
|
||||||
|
return new JsonResult(1, localeMessage("code.admin.theme.change-success", new Object[]{themeName}));
|
||||||
|
} catch (Exception e) {
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.change-failed"));
|
||||||
|
} finally {
|
||||||
|
refreshCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Upload theme
|
||||||
|
*
|
||||||
|
* @param file file
|
||||||
|
* @return JsonResult
|
||||||
|
*/
|
||||||
|
@RequestMapping(value = "/upload", method = RequestMethod.POST)
|
||||||
|
@ResponseBody
|
||||||
|
public JsonResult uploadTheme(@RequestParam("file") MultipartFile file,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
if (!file.isEmpty()) {
|
||||||
|
final File themePath = new File(ThemeUtils.getUsersThemesPath().getAbsolutePath(), file.getOriginalFilename());
|
||||||
|
file.transferTo(themePath);
|
||||||
|
ZipUtil.unzip(themePath, ThemeUtils.getUsersThemesPath());
|
||||||
|
FileUtil.del(themePath);
|
||||||
|
log.info("Upload topic success, path is " + themePath.getAbsolutePath());
|
||||||
|
// logsService.save(LogsRecord.UPLOAD_THEME, file.getOriginalFilename(), request);
|
||||||
|
} else {
|
||||||
|
log.error("Upload theme failed, no file selected");
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.upload-no-file"));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Upload theme failed: {}", e.getMessage());
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.upload-failed"));
|
||||||
|
} finally {
|
||||||
|
refreshCache();
|
||||||
|
}
|
||||||
|
return new JsonResult(1, localeMessage("code.admin.theme.upload-success"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Delete theme
|
||||||
|
*
|
||||||
|
* @param themeName theme name
|
||||||
|
* @return redirect to admin/themes
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/remove")
|
||||||
|
public String removeTheme(@RequestParam("themeName") String themeName) {
|
||||||
|
try {
|
||||||
|
final File themePath = new File(ThemeUtils.getThemesPath(themeName), themeName);
|
||||||
|
FileUtil.del(themePath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Delete theme failed: {}", e.getMessage());
|
||||||
|
} finally {
|
||||||
|
refreshCache();
|
||||||
|
}
|
||||||
|
return "redirect:/admin/themes";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Install theme page
|
||||||
|
*
|
||||||
|
* @return template path: admin/widget/_theme-install.ftl
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/install")
|
||||||
|
public String install() {
|
||||||
|
return "admin/widget/_theme-install";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clone theme by git
|
||||||
|
*
|
||||||
|
* @param remoteAddr theme remote address
|
||||||
|
* @param themeName theme name
|
||||||
|
* @return JsonResult
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/clone")
|
||||||
|
@ResponseBody
|
||||||
|
public JsonResult cloneFromRemote(@RequestParam(value = "remoteAddr") String remoteAddr,
|
||||||
|
@RequestParam(value = "themeName") String themeName) {
|
||||||
|
if (StrUtil.isBlank(remoteAddr) || StrUtil.isBlank(themeName)) {
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.common.info-no-complete"));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final String cmdResult = RuntimeUtil.execForStr("git clone " + remoteAddr + " " + ThemeUtils.getUsersThemesPath().getAbsolutePath() + "/" + themeName);
|
||||||
|
if ("".equals(cmdResult)) {
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.no-git"));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Cloning theme failed: {}", e.getMessage());
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.clone-theme-failed"));
|
||||||
|
} finally {
|
||||||
|
refreshCache();
|
||||||
|
}
|
||||||
|
return new JsonResult(1, localeMessage("code.admin.common.install-success"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update theme
|
||||||
|
*
|
||||||
|
* @param themeName theme name
|
||||||
|
* @return JsonResult
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/pull")
|
||||||
|
@ResponseBody
|
||||||
|
public JsonResult pullFromRemote(@RequestParam(value = "themeName") String themeName) {
|
||||||
|
try {
|
||||||
|
final String cmdResult = RuntimeUtil.execForStr("cd " + ThemeUtils.getUsersThemesPath().getAbsolutePath() + "/" + themeName + " && git pull");
|
||||||
|
if ("".equals(cmdResult)) {
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.no-git"));
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Update theme failed: {}", e.getMessage());
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.update-theme-failed"));
|
||||||
|
} finally {
|
||||||
|
refreshCache();
|
||||||
|
}
|
||||||
|
return new JsonResult(1, localeMessage("code.admin.common.update-success"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Redirect to theme option page
|
||||||
|
*
|
||||||
|
* @param model model
|
||||||
|
* @param theme theme name
|
||||||
|
* @param hasUpdate hasUpdate
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/options")
|
||||||
|
public String setting(Model model,
|
||||||
|
@RequestParam("theme") String theme,
|
||||||
|
@RequestParam("hasUpdate") String hasUpdate) {
|
||||||
|
model.addAttribute("themeDir", theme);
|
||||||
|
if (StrUtil.equals(hasUpdate, "true")) {
|
||||||
|
model.addAttribute("hasUpdate", true);
|
||||||
|
} else {
|
||||||
|
model.addAttribute("hasUpdate", false);
|
||||||
|
}
|
||||||
|
return "themes/" + theme + "/module/options";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Edit theme template
|
||||||
|
*
|
||||||
|
* @param model model
|
||||||
|
* @return template path: admin/admin_theme-editor.ftl
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/editor")
|
||||||
|
public String editor(Model model) {
|
||||||
|
final List<String> templates = ThemeUtils.getTplName(BaseContentController.THEME);
|
||||||
|
model.addAttribute("tpls", templates);
|
||||||
|
return "admin/admin_theme-editor";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get template content
|
||||||
|
*
|
||||||
|
* @param tplName template name
|
||||||
|
* @return template content
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/getTpl", produces = "text/text;charset=UTF-8")
|
||||||
|
@ResponseBody
|
||||||
|
public String getTplContent(@RequestParam("tplName") String tplName) {
|
||||||
|
String tplContent = "";
|
||||||
|
try {
|
||||||
|
final StrBuilder themePath = new StrBuilder(ThemeUtils.getThemesPath(BaseContentController.THEME).getAbsolutePath());
|
||||||
|
themePath.append(BaseContentController.THEME);
|
||||||
|
themePath.append("/");
|
||||||
|
themePath.append(tplName);
|
||||||
|
final File themesPath = new File(themePath.toString());
|
||||||
|
final FileReader fileReader = new FileReader(themesPath);
|
||||||
|
tplContent = fileReader.readString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Get template file error: {}", e.getMessage());
|
||||||
|
}
|
||||||
|
return tplContent;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Save template file
|
||||||
|
*
|
||||||
|
* @param tplName template name
|
||||||
|
* @param tplContent template content
|
||||||
|
* @return JsonResult
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/editor/save")
|
||||||
|
@ResponseBody
|
||||||
|
public JsonResult saveTpl(@RequestParam("tplName") String tplName,
|
||||||
|
@RequestParam("tplContent") String tplContent) {
|
||||||
|
if (StrUtil.isBlank(tplContent)) {
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.theme.edit.no-content"));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
final StrBuilder themePath = new StrBuilder(ThemeUtils.getThemesPath(BaseContentController.THEME).getAbsolutePath());
|
||||||
|
themePath.append(BaseContentController.THEME);
|
||||||
|
themePath.append("/");
|
||||||
|
themePath.append(tplName);
|
||||||
|
final File tplPath = new File(themePath.toString());
|
||||||
|
final FileWriter fileWriter = new FileWriter(tplPath);
|
||||||
|
fileWriter.write(tplContent);
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("Template save failed: {}", e.getMessage());
|
||||||
|
return new JsonResult(0, localeMessage("code.admin.common.save-failed"));
|
||||||
|
}
|
||||||
|
return new JsonResult(1, localeMessage("code.admin.common.save-success"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,69 @@
|
||||||
|
package cc.ryanc.halo.web.controller.admin.base;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.service.OptionService;
|
||||||
|
import cc.ryanc.halo.utils.LocaleMessageUtil;
|
||||||
|
import cc.ryanc.halo.utils.ThemeUtils;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import freemarker.template.TemplateModelException;
|
||||||
|
|
||||||
|
import static cc.ryanc.halo.model.support.HaloConst.OPTIONS;
|
||||||
|
import static cc.ryanc.halo.model.support.HaloConst.THEMES;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Admin base Controller
|
||||||
|
*
|
||||||
|
* @author : RYAN0UP
|
||||||
|
* @date : 2019/3/16
|
||||||
|
*/
|
||||||
|
public abstract class BaseController {
|
||||||
|
|
||||||
|
public final Configuration configuration;
|
||||||
|
|
||||||
|
public final OptionService optionService;
|
||||||
|
|
||||||
|
public final LocaleMessageUtil localeMessageUtil;
|
||||||
|
|
||||||
|
public BaseController(Configuration configuration,
|
||||||
|
OptionService optionService,
|
||||||
|
LocaleMessageUtil localeMessageUtil) {
|
||||||
|
this.configuration = configuration;
|
||||||
|
this.optionService = optionService;
|
||||||
|
this.localeMessageUtil = localeMessageUtil;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Clear all caches
|
||||||
|
*/
|
||||||
|
public void refreshCache() {
|
||||||
|
try {
|
||||||
|
OPTIONS.clear();
|
||||||
|
THEMES.clear();
|
||||||
|
OPTIONS = optionService.listOptions();
|
||||||
|
THEMES = ThemeUtils.getThemes();
|
||||||
|
configuration.setSharedVariable("options", OPTIONS);
|
||||||
|
} catch (TemplateModelException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get message with code
|
||||||
|
*
|
||||||
|
* @param code code
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String localeMessage(String code) {
|
||||||
|
return localeMessageUtil.getMessage(code);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get message with code and params
|
||||||
|
*
|
||||||
|
* @param code code
|
||||||
|
* @param args args
|
||||||
|
* @return String
|
||||||
|
*/
|
||||||
|
public String localeMessage(String code, Object[] args) {
|
||||||
|
return localeMessageUtil.getMessage(code, args);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
package cc.ryanc.halo.web.controller.content;
|
||||||
|
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Blog index page controller
|
||||||
|
*
|
||||||
|
* @author : RYAN0UP
|
||||||
|
* @date : 2019-03-17
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping
|
||||||
|
public class IndexController {
|
||||||
|
}
|
|
@ -1,29 +1,28 @@
|
||||||
package cc.ryanc.halo.web.controller.core;
|
package cc.ryanc.halo.web.controller.content.base;
|
||||||
|
|
||||||
import cc.ryanc.halo.logging.Logger;
|
import cc.ryanc.halo.logging.Logger;
|
||||||
import cn.hutool.core.text.StrBuilder;
|
import cn.hutool.core.text.StrBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* Content base Controller
|
||||||
* Controller抽象类
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* @author : RYAN0UP
|
* @author : RYAN0UP
|
||||||
* @date : 2017/12/15
|
* @date : 2017/12/15
|
||||||
*/
|
*/
|
||||||
public abstract class BaseController {
|
public abstract class BaseContentController {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 定义默认主题
|
* Default theme
|
||||||
*/
|
*/
|
||||||
public static String THEME = "anatole";
|
public static String THEME = "anatole";
|
||||||
|
|
||||||
protected Logger log = Logger.getLogger(getClass());
|
protected Logger log = Logger.getLogger(getClass());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 根据模板名称渲染页面
|
* Render page by template name
|
||||||
*
|
*
|
||||||
* @param pageName pageName
|
* @param pageName pageName
|
||||||
* @return 返回拼接好的模板路径
|
* @return template path
|
||||||
*/
|
*/
|
||||||
public String render(String pageName) {
|
public String render(String pageName) {
|
||||||
final StrBuilder themeStr = new StrBuilder("themes/");
|
final StrBuilder themeStr = new StrBuilder("themes/");
|
||||||
|
@ -34,7 +33,7 @@ public abstract class BaseController {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染404页面
|
* Redirect to 404
|
||||||
*
|
*
|
||||||
* @return redirect:/404
|
* @return redirect:/404
|
||||||
*/
|
*/
|
|
@ -1,17 +1,22 @@
|
||||||
package cc.ryanc.halo.web.controller.core;
|
package cc.ryanc.halo.web.controller.core;
|
||||||
|
|
||||||
import cc.ryanc.halo.logging.Logger;
|
import cc.ryanc.halo.logging.Logger;
|
||||||
|
import cc.ryanc.halo.model.entity.User;
|
||||||
|
import cc.ryanc.halo.model.support.HaloConst;
|
||||||
|
import cc.ryanc.halo.utils.ThemeUtils;
|
||||||
|
import cc.ryanc.halo.web.controller.content.base.BaseContentController;
|
||||||
|
import cn.hutool.core.text.StrBuilder;
|
||||||
import org.springframework.boot.web.servlet.error.ErrorController;
|
import org.springframework.boot.web.servlet.error.ErrorController;
|
||||||
import org.springframework.stereotype.Controller;
|
import org.springframework.stereotype.Controller;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import javax.servlet.http.HttpSession;
|
||||||
|
import java.io.FileNotFoundException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <pre>
|
* Error page Controller
|
||||||
* 错误页面控制器
|
|
||||||
* </pre>
|
|
||||||
*
|
*
|
||||||
* @author : RYAN0UP
|
* @author : RYAN0UP
|
||||||
* @date : 2017/12/26
|
* @date : 2017/12/26
|
||||||
|
@ -20,18 +25,29 @@ import javax.servlet.http.HttpServletRequest;
|
||||||
public class CommonController implements ErrorController {
|
public class CommonController implements ErrorController {
|
||||||
|
|
||||||
private static final String ERROR_PATH = "/error";
|
private static final String ERROR_PATH = "/error";
|
||||||
|
|
||||||
|
private static final String NOT_FROUND_TEMPLATE = "404.ftl";
|
||||||
|
|
||||||
|
private static final String INTERNAL_ERROR_TEMPLATE = "500.ftl";
|
||||||
|
|
||||||
|
private static final String ADMIN_URL = "/admin";
|
||||||
|
|
||||||
private final Logger log = Logger.getLogger(getClass());
|
private final Logger log = Logger.getLogger(getClass());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染404,500
|
* Handle error
|
||||||
*
|
*
|
||||||
* @param request request
|
* @param request request
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = ERROR_PATH)
|
@GetMapping(value = ERROR_PATH)
|
||||||
public String handleError(HttpServletRequest request) {
|
public String handleError(HttpServletRequest request, HttpSession session) {
|
||||||
final Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
|
final Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
|
||||||
|
|
||||||
|
final String requestURI = request.getRequestURI();
|
||||||
|
|
||||||
|
final User user = (User) session.getAttribute(HaloConst.USER_SESSION_KEY);
|
||||||
|
|
||||||
log.error("Error path: [{}], status: [{}]", request.getRequestURI(), statusCode);
|
log.error("Error path: [{}], status: [{}]", request.getRequestURI(), statusCode);
|
||||||
|
|
||||||
// Get the exception
|
// Get the exception
|
||||||
|
@ -43,37 +59,70 @@ public class CommonController implements ErrorController {
|
||||||
if (StringUtils.startsWithIgnoreCase(throwable.getMessage(), "Could not resolve view with name '")) {
|
if (StringUtils.startsWithIgnoreCase(throwable.getMessage(), "Could not resolve view with name '")) {
|
||||||
// TODO May cause unreasoned problem
|
// TODO May cause unreasoned problem
|
||||||
// if Ftl was not found then redirect to /404
|
// if Ftl was not found then redirect to /404
|
||||||
return "redirect:/404";
|
if (requestURI.contains(ADMIN_URL) && null != user) {
|
||||||
|
return "redirect:/admin/404";
|
||||||
|
} else {
|
||||||
|
return "redirect:/404";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (requestURI.contains(ADMIN_URL) && null != user) {
|
||||||
// if (statusCode.equals(CommonParamsEnum.NOT_FOUND.getValue())) {
|
return "redirect:/admin/500";
|
||||||
// return "redirect:/404";
|
} else {
|
||||||
// } else {
|
return "redirect:/500";
|
||||||
// return "redirect:/500";
|
}
|
||||||
// }
|
|
||||||
// TODO Complete error handler
|
|
||||||
return "redirect:/500";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染404页面
|
* Render 404 error page
|
||||||
*
|
*
|
||||||
* @return String
|
* @return template path:
|
||||||
*/
|
*/
|
||||||
@GetMapping(value = "/404")
|
@GetMapping(value = "/admin/404")
|
||||||
public String fourZeroFour() {
|
public String adminNotFround() {
|
||||||
return "common/error/404";
|
return "common/error/404";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 渲染500页面
|
* Render 500 error page
|
||||||
|
*
|
||||||
|
* @return template path:
|
||||||
|
*/
|
||||||
|
@GetMapping(value = "/admin/500")
|
||||||
|
public String adminInternalError() {
|
||||||
|
return "common/error/500";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render 404 error page
|
||||||
*
|
*
|
||||||
* @return String
|
* @return String
|
||||||
*/
|
*/
|
||||||
|
@GetMapping(value = "/404")
|
||||||
|
public String contentNotFround() throws FileNotFoundException {
|
||||||
|
if (ThemeUtils.isTemplateExist(NOT_FROUND_TEMPLATE)) {
|
||||||
|
return "common/error/404";
|
||||||
|
}
|
||||||
|
StrBuilder path = new StrBuilder("themes/");
|
||||||
|
path.append(BaseContentController.THEME);
|
||||||
|
path.append("/404");
|
||||||
|
return path.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render 500 error page
|
||||||
|
*
|
||||||
|
* @return template path:
|
||||||
|
*/
|
||||||
@GetMapping(value = "/500")
|
@GetMapping(value = "/500")
|
||||||
public String fiveZeroZero() {
|
public String contentInternalError() throws FileNotFoundException {
|
||||||
return "common/error/500";
|
if (ThemeUtils.isTemplateExist(INTERNAL_ERROR_TEMPLATE)) {
|
||||||
|
return "common/error/404";
|
||||||
|
}
|
||||||
|
StrBuilder path = new StrBuilder("themes/");
|
||||||
|
path.append(BaseContentController.THEME);
|
||||||
|
path.append("/500");
|
||||||
|
return path.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -0,0 +1,194 @@
|
||||||
|
package cc.ryanc.halo.web.controller.core;
|
||||||
|
|
||||||
|
import cc.ryanc.halo.model.entity.*;
|
||||||
|
import cc.ryanc.halo.model.enums.CommentStatus;
|
||||||
|
import cc.ryanc.halo.model.enums.PostStatus;
|
||||||
|
import cc.ryanc.halo.model.support.JsonResult;
|
||||||
|
import cc.ryanc.halo.service.*;
|
||||||
|
import cc.ryanc.halo.utils.MarkdownUtils;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import freemarker.template.Configuration;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static cc.ryanc.halo.model.support.HaloConst.OPTIONS;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author : RYAN0UP
|
||||||
|
* @date : 2019-03-17
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/install")
|
||||||
|
public class InstallController {
|
||||||
|
|
||||||
|
private final UserService userService;
|
||||||
|
|
||||||
|
private final CategoryService categoryService;
|
||||||
|
|
||||||
|
private final PostService postService;
|
||||||
|
|
||||||
|
private final CommentService commentService;
|
||||||
|
|
||||||
|
private final OptionService optionService;
|
||||||
|
|
||||||
|
private final MenuService menuService;
|
||||||
|
|
||||||
|
private final Configuration configuration;
|
||||||
|
|
||||||
|
public InstallController(UserService userService,
|
||||||
|
CategoryService categoryService,
|
||||||
|
PostService postService,
|
||||||
|
CommentService commentService,
|
||||||
|
OptionService optionService,
|
||||||
|
MenuService menuService,
|
||||||
|
Configuration configuration) {
|
||||||
|
this.userService = userService;
|
||||||
|
this.categoryService = categoryService;
|
||||||
|
this.postService = postService;
|
||||||
|
this.commentService = commentService;
|
||||||
|
this.optionService = optionService;
|
||||||
|
this.menuService = menuService;
|
||||||
|
this.configuration = configuration;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render install page
|
||||||
|
*
|
||||||
|
* @param model model
|
||||||
|
* @return template path: common/install.ftl
|
||||||
|
*/
|
||||||
|
@GetMapping
|
||||||
|
public String install(Model model) {
|
||||||
|
try {
|
||||||
|
if (StrUtil.equals("true", OPTIONS.get("is_install"))) {
|
||||||
|
model.addAttribute("isInstall", true);
|
||||||
|
} else {
|
||||||
|
model.addAttribute("isInstall", false);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
}
|
||||||
|
return "common/install";
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Do install
|
||||||
|
*
|
||||||
|
* @param blogLocale language
|
||||||
|
* @param blogTitle blog title
|
||||||
|
* @param blogUrl blog url
|
||||||
|
* @param userName user name
|
||||||
|
* @param nickName nick name
|
||||||
|
* @param userEmail user email
|
||||||
|
* @param userPwd user password
|
||||||
|
* @param request request
|
||||||
|
* @return JsonResult
|
||||||
|
*/
|
||||||
|
@PostMapping(value = "/do")
|
||||||
|
@ResponseBody
|
||||||
|
public JsonResult doInstall(@RequestParam("blogLocale") String blogLocale,
|
||||||
|
@RequestParam("blogTitle") String blogTitle,
|
||||||
|
@RequestParam("blogUrl") String blogUrl,
|
||||||
|
@RequestParam("userName") String userName,
|
||||||
|
@RequestParam("userDisplayName") String nickName,
|
||||||
|
@RequestParam("userEmail") String userEmail,
|
||||||
|
@RequestParam("userPwd") String userPwd,
|
||||||
|
HttpServletRequest request) {
|
||||||
|
try {
|
||||||
|
if (StrUtil.equals("true", OPTIONS.get("is_install"))) {
|
||||||
|
return new JsonResult(0, "该博客已初始化,不能再次安装!");
|
||||||
|
}
|
||||||
|
// Create new user
|
||||||
|
final User user = new User();
|
||||||
|
user.setUsername(userName);
|
||||||
|
user.setNickname(StrUtil.isBlank(nickName) ? userName : nickName);
|
||||||
|
user.setEmail(userEmail);
|
||||||
|
user.setPassword(SecureUtil.md5(userPwd));
|
||||||
|
userService.create(user);
|
||||||
|
|
||||||
|
//默认分类
|
||||||
|
Category category = new Category();
|
||||||
|
category.setName("未分类");
|
||||||
|
category.setSnakeName("default");
|
||||||
|
category.setDescription("未分类");
|
||||||
|
category = categoryService.create(category);
|
||||||
|
|
||||||
|
//第一篇文章
|
||||||
|
final Post post = new Post();
|
||||||
|
final List<Category> categories = new ArrayList<>(1);
|
||||||
|
categories.add(category);
|
||||||
|
post.setTitle("Hello Halo!");
|
||||||
|
post.setOriginalContent("# Hello Halo!\n" +
|
||||||
|
"欢迎使用Halo进行创作,删除这篇文章后赶紧开始吧。");
|
||||||
|
post.setFormatContent(MarkdownUtils.renderMarkdown(post.getOriginalContent()));
|
||||||
|
post.setSummary("欢迎使用Halo进行创作,删除这篇文章后赶紧开始吧。");
|
||||||
|
post.setStatus(PostStatus.PUBLISHED);
|
||||||
|
post.setUrl("hello-halo");
|
||||||
|
post.setDisallowComment(true);
|
||||||
|
post.setThumbnail("/static/halo-frontend/images/thumbnail/thumbnail-" + RandomUtil.randomInt(1, 11) + ".jpg");
|
||||||
|
postService.create(post);
|
||||||
|
|
||||||
|
//第一个评论
|
||||||
|
final Comment comment = new Comment();
|
||||||
|
comment.setAuthor("ruibaby");
|
||||||
|
comment.setEmail("i@ryanc.cc");
|
||||||
|
comment.setAuthorUrl("https://ryanc.cc");
|
||||||
|
comment.setIpAddress("127.0.0.1");
|
||||||
|
comment.setGavatarMd5(SecureUtil.md5("i@ryanc.cc"));
|
||||||
|
comment.setContent("欢迎,欢迎!");
|
||||||
|
comment.setStatus(CommentStatus.PUBLISHED);
|
||||||
|
comment.setUserAgent("Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/65.0.3325.162 Safari/537.36");
|
||||||
|
comment.setIsAdmin(false);
|
||||||
|
commentService.create(comment);
|
||||||
|
|
||||||
|
final Map<String, String> options = new HashMap<>();
|
||||||
|
// options.put(BlogPropertiesEnum.IS_INSTALL.getProp(), TrueFalseEnum.TRUE.getDesc());
|
||||||
|
// options.put(BlogPropertiesEnum.BLOG_LOCALE.getProp(), blogLocale);
|
||||||
|
// options.put(BlogPropertiesEnum.BLOG_TITLE.getProp(), blogTitle);
|
||||||
|
// options.put(BlogPropertiesEnum.BLOG_URL.getProp(), blogUrl);
|
||||||
|
// options.put(BlogPropertiesEnum.THEME.getProp(), "anatole");
|
||||||
|
// options.put(BlogPropertiesEnum.BLOG_START.getProp(), DateUtil.format(DateUtil.date(), "yyyy-MM-dd"));
|
||||||
|
// options.put(BlogPropertiesEnum.SMTP_EMAIL_ENABLE.getProp(), TrueFalseEnum.FALSE.getDesc());
|
||||||
|
// options.put(BlogPropertiesEnum.NEW_COMMENT_NOTICE.getProp(), TrueFalseEnum.FALSE.getDesc());
|
||||||
|
// options.put(BlogPropertiesEnum.COMMENT_PASS_NOTICE.getProp(), TrueFalseEnum.FALSE.getDesc());
|
||||||
|
// options.put(BlogPropertiesEnum.COMMENT_REPLY_NOTICE.getProp(), TrueFalseEnum.FALSE.getDesc());
|
||||||
|
// options.put(BlogPropertiesEnum.ATTACH_LOC.getProp(), AttachLocationEnum.SERVER.getDesc());
|
||||||
|
optionService.saveOptions(options);
|
||||||
|
|
||||||
|
//更新日志
|
||||||
|
// logsService.save(LogsRecord.INSTALL, "安装成功,欢迎使用Halo。", request);
|
||||||
|
|
||||||
|
final Menu menuIndex = new Menu();
|
||||||
|
menuIndex.setName("首页");
|
||||||
|
menuIndex.setUrl("/");
|
||||||
|
menuIndex.setSort(1);
|
||||||
|
menuService.create(menuIndex);
|
||||||
|
|
||||||
|
final Menu menuArchive = new Menu();
|
||||||
|
menuArchive.setName("归档");
|
||||||
|
menuArchive.setUrl("/archives");
|
||||||
|
menuArchive.setSort(2);
|
||||||
|
menuService.create(menuArchive);
|
||||||
|
|
||||||
|
OPTIONS.clear();
|
||||||
|
OPTIONS = optionService.listOptions();
|
||||||
|
configuration.setSharedVariable("options", OPTIONS);
|
||||||
|
// configuration.setSharedVariable("user", userService.findUser());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error(e.getMessage());
|
||||||
|
return new JsonResult(0, e.getMessage());
|
||||||
|
}
|
||||||
|
return new JsonResult(1, "安装成功!");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,137 @@
|
||||||
|
{
|
||||||
|
"@[勉强]": "<img src='/static/halo-common/OwO/paopao/勉强.png' alt='勉强.png' style='vertical-align: middle;'>",
|
||||||
|
"@[乖]": "<img src='/static/halo-common/OwO/paopao/乖.png' alt='乖.png' style='vertical-align: middle;'>",
|
||||||
|
"@[黑线]": "<img src='/static/halo-common/OwO/paopao/黑线.png' alt='黑线.png' style='vertical-align: middle;'>",
|
||||||
|
"@(献花)": "<img src='/static/halo-common/OwO/alu/献花.png' alt='献花.png' style='vertical-align: middle;'>",
|
||||||
|
"@(想一想)": "<img src='/static/halo-common/OwO/alu/想一想.png' alt='想一想.png' style='vertical-align: middle;'>",
|
||||||
|
"@(蜡烛)": "<img src='/static/halo-common/OwO/alu/蜡烛.png' alt='蜡烛.png' style='vertical-align: middle;'>",
|
||||||
|
"@[滑稽]": "<img src='/static/halo-common/OwO/paopao/滑稽.png' alt='滑稽.png' style='vertical-align: middle;'>",
|
||||||
|
"@(黑线)": "<img src='/static/halo-common/OwO/alu/黑线.png' alt='黑线.png' style='vertical-align: middle;'>",
|
||||||
|
"@[小乖]": "<img src='/static/halo-common/OwO/paopao/小乖.png' alt='小乖.png' style='vertical-align: middle;'>",
|
||||||
|
"@(中枪)": "<img src='/static/halo-common/OwO/alu/中枪.png' alt='中枪.png' style='vertical-align: middle;'>",
|
||||||
|
"@(长草)": "<img src='/static/halo-common/OwO/alu/长草.png' alt='长草.png' style='vertical-align: middle;'>",
|
||||||
|
"@[捂嘴笑]": "<img src='/static/halo-common/OwO/paopao/捂嘴笑.png' alt='捂嘴笑.png' style='vertical-align: middle;'>",
|
||||||
|
"@[酷]": "<img src='/static/halo-common/OwO/paopao/酷.png' alt='酷.png' style='vertical-align: middle;'>",
|
||||||
|
"@(喷血)": "<img src='/static/halo-common/OwO/alu/喷血.png' alt='喷血.png' style='vertical-align: middle;'>",
|
||||||
|
"@[彩虹]": "<img src='/static/halo-common/OwO/paopao/彩虹.png' alt='彩虹.png' style='vertical-align: middle;'>",
|
||||||
|
"@[钱]": "<img src='/static/halo-common/OwO/paopao/钱.png' alt='钱.png' style='vertical-align: middle;'>",
|
||||||
|
"@(呲牙)": "<img src='/static/halo-common/OwO/alu/呲牙.png' alt='呲牙.png' style='vertical-align: middle;'>",
|
||||||
|
"@[手纸]": "<img src='/static/halo-common/OwO/paopao/手纸.png' alt='手纸.png' style='vertical-align: middle;'>",
|
||||||
|
"@[钱币]": "<img src='/static/halo-common/OwO/paopao/钱币.png' alt='钱币.png' style='vertical-align: middle;'>",
|
||||||
|
"@[太开心]": "<img src='/static/halo-common/OwO/paopao/太开心.png' alt='太开心.png' style='vertical-align: middle;'>",
|
||||||
|
"@(抠鼻)": "<img src='/static/halo-common/OwO/alu/抠鼻.png' alt='抠鼻.png' style='vertical-align: middle;'>",
|
||||||
|
"@[你懂的]": "<img src='/static/halo-common/OwO/paopao/你懂的.png' alt='你懂的.png' style='vertical-align: middle;'>",
|
||||||
|
"@[吐舌]": "<img src='/static/halo-common/OwO/paopao/吐舌.png' alt='吐舌.png' style='vertical-align: middle;'>",
|
||||||
|
"@[茶杯]": "<img src='/static/halo-common/OwO/paopao/茶杯.png' alt='茶杯.png' style='vertical-align: middle;'>",
|
||||||
|
"@[泪]": "<img src='/static/halo-common/OwO/paopao/泪.png' alt='泪.png' style='vertical-align: middle;'>",
|
||||||
|
"@(吐)": "<img src='/static/halo-common/OwO/alu/吐.png' alt='吐.png' style='vertical-align: middle;'>",
|
||||||
|
"@(吐舌)": "<img src='/static/halo-common/OwO/alu/吐舌.png' alt='吐舌.png' style='vertical-align: middle;'>",
|
||||||
|
"@[太阳]": "<img src='/static/halo-common/OwO/paopao/太阳.png' alt='太阳.png' style='vertical-align: middle;'>",
|
||||||
|
"@(不出所料)": "<img src='/static/halo-common/OwO/alu/不出所料.png' alt='不出所料.png' style='vertical-align: middle;'>",
|
||||||
|
"@[挖鼻]": "<img src='/static/halo-common/OwO/paopao/挖鼻.png' alt='挖鼻.png' style='vertical-align: middle;'>",
|
||||||
|
"@(观察)": "<img src='/static/halo-common/OwO/alu/观察.png' alt='观察.png' style='vertical-align: middle;'>",
|
||||||
|
"@(内伤)": "<img src='/static/halo-common/OwO/alu/内伤.png' alt='内伤.png' style='vertical-align: middle;'>",
|
||||||
|
"@[灯泡]": "<img src='/static/halo-common/OwO/paopao/灯泡.png' alt='灯泡.png' style='vertical-align: middle;'>",
|
||||||
|
"@[呵呵]": "<img src='/static/halo-common/OwO/paopao/呵呵.png' alt='呵呵.png' style='vertical-align: middle;'>",
|
||||||
|
"@(尴尬)": "<img src='/static/halo-common/OwO/alu/尴尬.png' alt='尴尬.png' style='vertical-align: middle;'>",
|
||||||
|
"@(深思)": "<img src='/static/halo-common/OwO/alu/深思.png' alt='深思.png' style='vertical-align: middle;'>",
|
||||||
|
"@(小怒)": "<img src='/static/halo-common/OwO/alu/小怒.png' alt='小怒.png' style='vertical-align: middle;'>",
|
||||||
|
"@[狂汗]": "<img src='/static/halo-common/OwO/paopao/狂汗.png' alt='狂汗.png' style='vertical-align: middle;'>",
|
||||||
|
"@[what]": "<img src='/static/halo-common/OwO/paopao/what.png' alt='what.png' style='vertical-align: middle;'>",
|
||||||
|
"@(口水)": "<img src='/static/halo-common/OwO/alu/口水.png' alt='口水.png' style='vertical-align: middle;'>",
|
||||||
|
"@(大囧)": "<img src='/static/halo-common/OwO/alu/大囧.png' alt='大囧.png' style='vertical-align: middle;'>",
|
||||||
|
"@[懒得理]": "<img src='/static/halo-common/OwO/paopao/懒得理.png' alt='懒得理.png' style='vertical-align: middle;'>",
|
||||||
|
"@[真棒]": "<img src='/static/halo-common/OwO/paopao/真棒.png' alt='真棒.png' style='vertical-align: middle;'>",
|
||||||
|
"@[三道杠]": "<img src='/static/halo-common/OwO/paopao/三道杠.png' alt='三道杠.png' style='vertical-align: middle;'>",
|
||||||
|
"@[睡觉]": "<img src='/static/halo-common/OwO/paopao/睡觉.png' alt='睡觉.png' style='vertical-align: middle;'>",
|
||||||
|
"@[沙发]": "<img src='/static/halo-common/OwO/paopao/沙发.png' alt='沙发.png' style='vertical-align: middle;'>",
|
||||||
|
"@(暗地观察)": "<img src='/static/halo-common/OwO/alu/暗地观察.png' alt='暗地观察.png' style='vertical-align: middle;'>",
|
||||||
|
"@[笑尿]": "<img src='/static/halo-common/OwO/paopao/笑尿.png' alt='笑尿.png' style='vertical-align: middle;'>",
|
||||||
|
"@[生气]": "<img src='/static/halo-common/OwO/paopao/生气.png' alt='生气.png' style='vertical-align: middle;'>",
|
||||||
|
"@(肿包)": "<img src='/static/halo-common/OwO/alu/肿包.png' alt='肿包.png' style='vertical-align: middle;'>",
|
||||||
|
"@(狂汗)": "<img src='/static/halo-common/OwO/alu/狂汗.png' alt='狂汗.png' style='vertical-align: middle;'>",
|
||||||
|
"@(喷水)": "<img src='/static/halo-common/OwO/alu/喷水.png' alt='喷水.png' style='vertical-align: middle;'>",
|
||||||
|
"@(惊喜)": "<img src='/static/halo-common/OwO/alu/惊喜.png' alt='惊喜.png' style='vertical-align: middle;'>",
|
||||||
|
"@[便便]": "<img src='/static/halo-common/OwO/paopao/便便.png' alt='便便.png' style='vertical-align: middle;'>",
|
||||||
|
"@(阴暗)": "<img src='/static/halo-common/OwO/alu/阴暗.png' alt='阴暗.png' style='vertical-align: middle;'>",
|
||||||
|
"@[汗]": "<img src='/static/halo-common/OwO/paopao/汗.png' alt='汗.png' style='vertical-align: middle;'>",
|
||||||
|
"@(喜极而泣)": "<img src='/static/halo-common/OwO/alu/喜极而泣.png' alt='喜极而泣.png' style='vertical-align: middle;'>",
|
||||||
|
"@[香蕉]": "<img src='/static/halo-common/OwO/paopao/香蕉.png' alt='香蕉.png' style='vertical-align: middle;'>",
|
||||||
|
"@[大拇指]": "<img src='/static/halo-common/OwO/paopao/大拇指.png' alt='大拇指.png' style='vertical-align: middle;'>",
|
||||||
|
"@[蜡烛]": "<img src='/static/halo-common/OwO/paopao/蜡烛.png' alt='蜡烛.png' style='vertical-align: middle;'>",
|
||||||
|
"@(鼓掌)": "<img src='/static/halo-common/OwO/alu/鼓掌.png' alt='鼓掌.png' style='vertical-align: middle;'>",
|
||||||
|
"@(邪恶)": "<img src='/static/halo-common/OwO/alu/邪恶.png' alt='邪恶.png' style='vertical-align: middle;'>",
|
||||||
|
"@[惊恐]": "<img src='/static/halo-common/OwO/paopao/惊恐.png' alt='惊恐.png' style='vertical-align: middle;'>",
|
||||||
|
"@[惊哭]": "<img src='/static/halo-common/OwO/paopao/惊哭.png' alt='惊哭.png' style='vertical-align: middle;'>",
|
||||||
|
"@[嘚瑟]": "<img src='/static/halo-common/OwO/paopao/嘚瑟.png' alt='嘚瑟.png' style='vertical-align: middle;'>",
|
||||||
|
"@[药丸]": "<img src='/static/halo-common/OwO/paopao/药丸.png' alt='药丸.png' style='vertical-align: middle;'>",
|
||||||
|
"@[吐]": "<img src='/static/halo-common/OwO/paopao/吐.png' alt='吐.png' style='vertical-align: middle;'>",
|
||||||
|
"@[蛋糕]": "<img src='/static/halo-common/OwO/paopao/蛋糕.png' alt='蛋糕.png' style='vertical-align: middle;'>",
|
||||||
|
"@(愤怒)": "<img src='/static/halo-common/OwO/alu/愤怒.png' alt='愤怒.png' style='vertical-align: middle;'>",
|
||||||
|
"@(无所谓)": "<img src='/static/halo-common/OwO/alu/无所谓.png' alt='无所谓.png' style='vertical-align: middle;'>",
|
||||||
|
"@[啊]": "<img src='/static/halo-common/OwO/paopao/啊.png' alt='啊.png' style='vertical-align: middle;'>",
|
||||||
|
"@(坐等)": "<img src='/static/halo-common/OwO/alu/坐等.png' alt='坐等.png' style='vertical-align: middle;'>",
|
||||||
|
"@[nico]": "<img src='/static/halo-common/OwO/paopao/nico.png' alt='nico.png' style='vertical-align: middle;'>",
|
||||||
|
"@[弱]": "<img src='/static/halo-common/OwO/paopao/弱.png' alt='弱.png' style='vertical-align: middle;'>",
|
||||||
|
"@[小红脸]": "<img src='/static/halo-common/OwO/paopao/小红脸.png' alt='小红脸.png' style='vertical-align: middle;'>",
|
||||||
|
"@(哭泣)": "<img src='/static/halo-common/OwO/alu/哭泣.png' alt='哭泣.png' style='vertical-align: middle;'>",
|
||||||
|
"@[呼]": "<img src='/static/halo-common/OwO/paopao/呼.png' alt='呼.png' style='vertical-align: middle;'>",
|
||||||
|
"@[哈哈]": "<img src='/static/halo-common/OwO/paopao/哈哈.png' alt='哈哈.png' style='vertical-align: middle;'>",
|
||||||
|
"@[爱心]": "<img src='/static/halo-common/OwO/paopao/爱心.png' alt='爱心.png' style='vertical-align: middle;'>",
|
||||||
|
"@(不说话)": "<img src='/static/halo-common/OwO/alu/不说话.png' alt='不说话.png' style='vertical-align: middle;'>",
|
||||||
|
"@(脸红)": "<img src='/static/halo-common/OwO/alu/脸红.png' alt='脸红.png' style='vertical-align: middle;'>",
|
||||||
|
"@[惊讶]": "<img src='/static/halo-common/OwO/paopao/惊讶.png' alt='惊讶.png' style='vertical-align: middle;'>",
|
||||||
|
"@(傻笑)": "<img src='/static/halo-common/OwO/alu/傻笑.png' alt='傻笑.png' style='vertical-align: middle;'>",
|
||||||
|
"@(期待)": "<img src='/static/halo-common/OwO/alu/期待.png' alt='期待.png' style='vertical-align: middle;'>",
|
||||||
|
"@(击掌)": "<img src='/static/halo-common/OwO/alu/击掌.png' alt='击掌.png' style='vertical-align: middle;'>",
|
||||||
|
"@(抽烟)": "<img src='/static/halo-common/OwO/alu/抽烟.png' alt='抽烟.png' style='vertical-align: middle;'>",
|
||||||
|
"@[胜利]": "<img src='/static/halo-common/OwO/paopao/胜利.png' alt='胜利.png' style='vertical-align: middle;'>",
|
||||||
|
"@(害羞)": "<img src='/static/halo-common/OwO/alu/害羞.png' alt='害羞.png' style='vertical-align: middle;'>",
|
||||||
|
"@[吃翔]": "<img src='/static/halo-common/OwO/paopao/吃翔.png' alt='吃翔.png' style='vertical-align: middle;'>",
|
||||||
|
"@(便便)": "<img src='/static/halo-common/OwO/alu/便便.png' alt='便便.png' style='vertical-align: middle;'>",
|
||||||
|
"@(献黄瓜)": "<img src='/static/halo-common/OwO/alu/献黄瓜.png' alt='献黄瓜.png' style='vertical-align: middle;'>",
|
||||||
|
"@[不高兴]": "<img src='/static/halo-common/OwO/paopao/不高兴.png' alt='不高兴.png' style='vertical-align: middle;'>",
|
||||||
|
"@(皱眉)": "<img src='/static/halo-common/OwO/alu/皱眉.png' alt='皱眉.png' style='vertical-align: middle;'>",
|
||||||
|
"@(汗)": "<img src='/static/halo-common/OwO/alu/汗.png' alt='汗.png' style='vertical-align: middle;'>",
|
||||||
|
"@[吃瓜]": "<img src='/static/halo-common/OwO/paopao/吃瓜.png' alt='吃瓜.png' style='vertical-align: middle;'>",
|
||||||
|
"@[心碎]": "<img src='/static/halo-common/OwO/paopao/心碎.png' alt='心碎.png' style='vertical-align: middle;'>",
|
||||||
|
"@[玫瑰]": "<img src='/static/halo-common/OwO/paopao/玫瑰.png' alt='玫瑰.png' style='vertical-align: middle;'>",
|
||||||
|
"@(扇耳光)": "<img src='/static/halo-common/OwO/alu/扇耳光.png' alt='扇耳光.png' style='vertical-align: middle;'>",
|
||||||
|
"@[OK]": "<img src='/static/halo-common/OwO/paopao/OK.png' alt='OK.png' style='vertical-align: middle;'>",
|
||||||
|
"@[音乐]": "<img src='/static/halo-common/OwO/paopao/音乐.png' alt='音乐.png' style='vertical-align: middle;'>",
|
||||||
|
"@[阴险]": "<img src='/static/halo-common/OwO/paopao/阴险.png' alt='阴险.png' style='vertical-align: middle;'>",
|
||||||
|
"@(看热闹)": "<img src='/static/halo-common/OwO/alu/看热闹.png' alt='看热闹.png' style='vertical-align: middle;'>",
|
||||||
|
"@[星星月亮]": "<img src='/static/halo-common/OwO/paopao/星星月亮.png' alt='星星月亮.png' style='vertical-align: middle;'>",
|
||||||
|
"@[犀利]": "<img src='/static/halo-common/OwO/paopao/犀利.png' alt='犀利.png' style='vertical-align: middle;'>",
|
||||||
|
"@(高兴)": "<img src='/static/halo-common/OwO/alu/高兴.png' alt='高兴.png' style='vertical-align: middle;'>",
|
||||||
|
"@(亲亲)": "<img src='/static/halo-common/OwO/alu/亲亲.png' alt='亲亲.png' style='vertical-align: middle;'>",
|
||||||
|
"@[冷]": "<img src='/static/halo-common/OwO/paopao/冷.png' alt='冷.png' style='vertical-align: middle;'>",
|
||||||
|
"@[喷]": "<img src='/static/halo-common/OwO/paopao/喷.png' alt='喷.png' style='vertical-align: middle;'>",
|
||||||
|
"@(咽气)": "<img src='/static/halo-common/OwO/alu/咽气.png' alt='咽气.png' style='vertical-align: middle;'>",
|
||||||
|
"@[怒]": "<img src='/static/halo-common/OwO/paopao/怒.png' alt='怒.png' style='vertical-align: middle;'>",
|
||||||
|
"@(锁眉)": "<img src='/static/halo-common/OwO/alu/锁眉.png' alt='锁眉.png' style='vertical-align: middle;'>",
|
||||||
|
"@[红领巾]": "<img src='/static/halo-common/OwO/paopao/红领巾.png' alt='红领巾.png' style='vertical-align: middle;'>",
|
||||||
|
"@(中指)": "<img src='/static/halo-common/OwO/alu/中指.png' alt='中指.png' style='vertical-align: middle;'>",
|
||||||
|
"@[礼物]": "<img src='/static/halo-common/OwO/paopao/礼物.png' alt='礼物.png' style='vertical-align: middle;'>",
|
||||||
|
"@(赞一个)": "<img src='/static/halo-common/OwO/alu/赞一个.png' alt='赞一个.png' style='vertical-align: middle;'>",
|
||||||
|
"@(欢呼)": "<img src='/static/halo-common/OwO/alu/欢呼.png' alt='欢呼.png' style='vertical-align: middle;'>",
|
||||||
|
"@[花心]": "<img src='/static/halo-common/OwO/paopao/花心.png' alt='花心.png' style='vertical-align: middle;'>",
|
||||||
|
"@[鄙视]": "<img src='/static/halo-common/OwO/paopao/鄙视.png' alt='鄙视.png' style='vertical-align: middle;'>",
|
||||||
|
"@[呀咩爹]": "<img src='/static/halo-common/OwO/paopao/呀咩爹.png' alt='呀咩爹.png' style='vertical-align: middle;'>",
|
||||||
|
"@[开心]": "<img src='/static/halo-common/OwO/paopao/开心.png' alt='开心.png' style='vertical-align: middle;'>",
|
||||||
|
"@[酸爽]": "<img src='/static/halo-common/OwO/paopao/酸爽.png' alt='酸爽.png' style='vertical-align: middle;'>",
|
||||||
|
"@(得意)": "<img src='/static/halo-common/OwO/alu/得意.png' alt='得意.png' style='vertical-align: middle;'>",
|
||||||
|
"@(装大款)": "<img src='/static/halo-common/OwO/alu/装大款.png' alt='装大款.png' style='vertical-align: middle;'>",
|
||||||
|
"@[委屈]": "<img src='/static/halo-common/OwO/paopao/委屈.png' alt='委屈.png' style='vertical-align: middle;'>",
|
||||||
|
"@(中刀)": "<img src='/static/halo-common/OwO/alu/中刀.png' alt='中刀.png' style='vertical-align: middle;'>",
|
||||||
|
"@(看不见)": "<img src='/static/halo-common/OwO/alu/看不见.png' alt='看不见.png' style='vertical-align: middle;'>",
|
||||||
|
"@(小眼睛)": "<img src='/static/halo-common/OwO/alu/小眼睛.png' alt='小眼睛.png' style='vertical-align: middle;'>",
|
||||||
|
"@(无语)": "<img src='/static/halo-common/OwO/alu/无语.png' alt='无语.png' style='vertical-align: middle;'>",
|
||||||
|
"@(投降)": "<img src='/static/halo-common/OwO/alu/投降.png' alt='投降.png' style='vertical-align: middle;'>",
|
||||||
|
"@(无奈)": "<img src='/static/halo-common/OwO/alu/无奈.png' alt='无奈.png' style='vertical-align: middle;'>",
|
||||||
|
"@[咦]": "<img src='/static/halo-common/OwO/paopao/咦.png' alt='咦.png' style='vertical-align: middle;'>",
|
||||||
|
"@(不高兴)": "<img src='/static/halo-common/OwO/alu/不高兴.png' alt='不高兴.png' style='vertical-align: middle;'>",
|
||||||
|
"@[笑眼]": "<img src='/static/halo-common/OwO/paopao/笑眼.png' alt='笑眼.png' style='vertical-align: middle;'>",
|
||||||
|
"@(吐血倒地)": "<img src='/static/halo-common/OwO/alu/吐血倒地.png' alt='吐血倒地.png' style='vertical-align: middle;'>",
|
||||||
|
"@[疑问]": "<img src='/static/halo-common/OwO/paopao/疑问.png' alt='疑问.png' style='vertical-align: middle;'>"
|
||||||
|
}
|
|
@ -26,18 +26,18 @@
|
||||||
<ul class="menu">
|
<ul class="menu">
|
||||||
<#if newComments?size gt 0>
|
<#if newComments?size gt 0>
|
||||||
<#assign x=0>
|
<#assign x=0>
|
||||||
<#list newComments?sort_by("commentDate")?reverse as comment>
|
<#list newComments?sort_by("createTime")?reverse as comment>
|
||||||
<#assign x = x+1>
|
<#assign x = x+1>
|
||||||
<li>
|
<li>
|
||||||
<a data-pjax="true" href="/admin/comments?status=1">
|
<a data-pjax="true" href="/admin/comments?status=1">
|
||||||
<div class="pull-left">
|
<div class="pull-left">
|
||||||
<img src="//gravatar.loli.net/avatar/${comment.commentAuthorAvatarMd5?default("hash")}?s=256&d=${options.native_comment_avatar?default("mm")}" class="img-circle" alt="User Image">
|
<img src="//gravatar.loli.net/avatar/${comment.gavatarMd5!'hash'}?s=256&d=${options.native_comment_avatar!'mm'}" class="img-circle" alt="User Image">
|
||||||
</div>
|
</div>
|
||||||
<h4>
|
<h4>
|
||||||
${comment.commentAuthor}
|
${comment.author!}
|
||||||
<small> <@common.timeline datetime="${comment.commentDate}"?datetime /></small>
|
<small> <@common.timeline datetime="${comment.createTime}"?datetime /></small>
|
||||||
</h4>
|
</h4>
|
||||||
<object>${comment.commentContent}</object>
|
<object>${comment.content!}</object>
|
||||||
</a>
|
</a>
|
||||||
</li>
|
</li>
|
||||||
<#if x==10>
|
<#if x==10>
|
||||||
|
|
|
@ -1,52 +1 @@
|
||||||
<#compress>
|
404 Not Found
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
|
||||||
<meta name="renderer" content="webkit">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
|
||||||
<title>404 Not Found</title>
|
|
||||||
<link href="//cdnjs.loli.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
|
||||||
<link href="//cdnjs.loli.net/ajax/libs/animate.css/3.7.0/animate.min.css" rel="stylesheet">
|
|
||||||
<style type="text/css" rel="stylesheet">
|
|
||||||
body{margin:0}*{box-sizing:border-box}h1,h2{margin:0}a{color:#fff;text-decoration:none}body,html{font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.fullscreen{background-position:50% 50%;background-size:cover}.fullscreen,.fullscreen .backColor{position:absolute;top:0;left:0;width:100%;height:100%}.fullscreen .backColor{background-color:rgba(0,0,0,.1)}.infos{display:flex;text-align:center;align-items:center;justify-content:center}.infos,.main-content{position:absolute;top:0;left:0;width:100%;height:100%;color:#fff}.main-content{background: #833ab4;background: -webkit-linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);background: linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);}.errorPage{position:relative;width:100vw;height:100vh}.infos-h1{margin:0;font-size:5em;line-height:1}.infos-h1 h1{font-weight:200}.footer{position:absolute;right:1rem;bottom:1rem;left:1rem;z-index:9999;font-size:14px}.infos-h2{font-size:24px}.infos-h2 a:hover{color:#7a8d85}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="errorPage">
|
|
||||||
<div class="main-content ">
|
|
||||||
<div class="fullscreen">
|
|
||||||
<div class="backColor"></div>
|
|
||||||
</div>
|
|
||||||
<div class="infos">
|
|
||||||
<div class="infos-main">
|
|
||||||
<div class="infos-h1"><h1>404</h1></div>
|
|
||||||
<div class="infos-h2">
|
|
||||||
<a href="javascript:window.history.back()" title="返回上一页">
|
|
||||||
<i class="fa fa-chevron-left"></i>
|
|
||||||
</a>
|
|
||||||
<a href="/" title="返回到主页">
|
|
||||||
<i class="fa fa-home"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="footer">
|
|
||||||
<span>Copyright © 2018</span>
|
|
||||||
<a href="${options.blog_url!}">${options.blog_title!'Halo'}</a>
|
|
||||||
<span style="float: right">
|
|
||||||
Background image from <a href="https://cn.bing.com/" target="_blank">Bing</a>.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
<script src="//cdnjs.loli.net/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
|
||||||
<script>
|
|
||||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$.o(\'m://q.8.n/?1=4%y%z%B.5.9%d.e%f%g%h%i%j%k\',l(b){6 a=b.p[0].1;6 c=$(\'.r\');c.t("u-v","1(4://s.w.5.x"+a+")");c.2(\'3 A\');$(\'.7-C\').2(\'3 D\');$(\'.7-E\').2(\'3 F\')});',42,42,'|url|addClass|animated|http|bing|var|infos|afeld|com||||2FHPImageArchive|aspx|3Fformat|3Djs|26idx|3D0|26n|3D1|function|https|me|get|images|jsonp|fullscreen||css|background|image|cn|net|3A|2F|fadeIn|2Fcn|h1|shake|h2|fadeInDown'.split('|'),0,{}))
|
|
||||||
</script>
|
|
||||||
</html>
|
|
||||||
</#compress>
|
|
||||||
|
|
|
@ -1,52 +1 @@
|
||||||
<#compress>
|
500 Internal Error
|
||||||
<!DOCTYPE html>
|
|
||||||
<html lang="zh">
|
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8">
|
|
||||||
<meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
|
|
||||||
<meta name="renderer" content="webkit">
|
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
|
|
||||||
<title>500 Error Page</title>
|
|
||||||
<link href="//cdnjs.loli.net/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
|
|
||||||
<link href="//cdnjs.loli.net/ajax/libs/animate.css/3.7.0/animate.min.css" rel="stylesheet">
|
|
||||||
<style type="text/css" rel="stylesheet">
|
|
||||||
body{margin:0}*{box-sizing:border-box}h1,h2{margin:0}a{color:#fff;text-decoration:none}body,html{font-family:-apple-system,system-ui,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,sans-serif}.fullscreen{background-position:50% 50%;background-size:cover}.fullscreen,.fullscreen .backColor{position:absolute;top:0;left:0;width:100%;height:100%}.fullscreen .backColor{background-color:rgba(0,0,0,.1)}.infos{display:flex;text-align:center;align-items:center;justify-content:center}.infos,.main-content{position:absolute;top:0;left:0;width:100%;height:100%;color:#fff}.main-content{background: #833ab4;background: -webkit-linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);background: linear-gradient(to right, #833ab4, #fd1d1d, #fcb045);}.errorPage{position:relative;width:100vw;height:100vh}.infos-h1{margin:0;font-size:5em;line-height:1}.infos-h1 h1{font-weight:200}.footer{position:absolute;right:1rem;bottom:1rem;left:1rem;z-index:9999;font-size:14px}.infos-h2{font-size:24px}.infos-h2 a:hover{color:#7a8d85}
|
|
||||||
</style>
|
|
||||||
</head>
|
|
||||||
<body>
|
|
||||||
<div class="container">
|
|
||||||
<div class="errorPage">
|
|
||||||
<div class="main-content ">
|
|
||||||
<div class="fullscreen">
|
|
||||||
<div class="backColor"></div>
|
|
||||||
</div>
|
|
||||||
<div class="infos">
|
|
||||||
<div class="infos-main">
|
|
||||||
<div class="infos-h1"><h1>500</h1></div>
|
|
||||||
<div class="infos-h2">
|
|
||||||
<a href="javascript:window.history.back()" title="返回上一页">
|
|
||||||
<i class="fa fa-chevron-left"></i>
|
|
||||||
</a>
|
|
||||||
<a href="/" title="返回到主页">
|
|
||||||
<i class="fa fa-home"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="footer">
|
|
||||||
<span>Copyright © 2018</span>
|
|
||||||
<a href="${options.blog_title!}">${options.blog_title!'Halo'}</a>
|
|
||||||
<span style="float: right">
|
|
||||||
Background image from <a href="https://cn.bing.com/" target="_blank">Bing</a>.
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</body>
|
|
||||||
<script src="//cdnjs.loli.net/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
|
||||||
<script>
|
|
||||||
eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}('$.o(\'m://q.8.n/?1=4%y%z%B.5.9%d.e%f%g%h%i%j%k\',l(b){6 a=b.p[0].1;6 c=$(\'.r\');c.t("u-v","1(4://s.w.5.x"+a+")");c.2(\'3 A\');$(\'.7-C\').2(\'3 D\');$(\'.7-E\').2(\'3 F\')});',42,42,'|url|addClass|animated|http|bing|var|infos|afeld|com||||2FHPImageArchive|aspx|3Fformat|3Djs|26idx|3D0|26n|3D1|function|https|me|get|images|jsonp|fullscreen||css|background|image|cn|net|3A|2F|fadeIn|2Fcn|h1|shake|h2|fadeInDown'.split('|'),0,{}))
|
|
||||||
</script>
|
|
||||||
</html>
|
|
||||||
</#compress>
|
|
||||||
|
|
Loading…
Reference in New Issue