🍎 新增备份功能(资源文件,数据库,文章)

pull/18/head
ruibaby 2018-06-04 22:49:24 +08:00
parent 2bd40d3ec8
commit 18a60f07f1
19 changed files with 666 additions and 69 deletions

6
.gitignore vendored
View File

@ -31,5 +31,7 @@ nbdist/
*/.DS_Store
### VS Code ###
.project
.factorypath
*.project
*.factorypath
~/

View File

@ -38,6 +38,7 @@ public class MvcConfig implements WebMvcConfigurer {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loginInterceptor)
.addPathPatterns("/admin/**")
.addPathPatterns("/backup/**")
.excludePathPatterns("/admin/login")
.excludePathPatterns("/admin/getLogin")
.excludePathPatterns("/static/**");
@ -63,5 +64,7 @@ public class MvcConfig implements WebMvcConfigurer {
.addResourceLocations("classpath:/upload/");
registry.addResourceHandler("/favicon.ico")
.addResourceLocations("classpath:/static/images/favicon.ico");
registry.addResourceHandler("/backup/**")
.addResourceLocations("file:///"+System.getProperties().getProperty("user.home")+"/halo/backup/");
}
}

View File

@ -61,7 +61,7 @@ public class User implements Serializable {
/**
*
*/
private String loginEnable;
private String loginEnable = "true";
/**
*
@ -71,5 +71,5 @@ public class User implements Serializable {
/**
*
*/
private Integer loginError;
private Integer loginError = 0;
}

View File

@ -0,0 +1,39 @@
package cc.ryanc.halo.model.dto;
import lombok.Data;
import java.util.Date;
/**
* @author : RYAN0UP
* @version : 1.0
* @date : 2018/6/4
*/
@Data
public class BackupDto {
/**
*
*/
private String fileName;
/**
*
*/
private Date createAt;
/**
*
*/
private String fileSize;
/**
*
*/
private String fileType;
/**
*
*/
private String backupType;
}

View File

@ -27,4 +27,15 @@ public interface MailService {
* @param templateName
*/
void sendTemplateMail(String to, String subject, Map<String, Object> content, String templateName);
/**
*
*
* @param to
* @param subject
* @param content
* @param templateName
* @param attachSrc
*/
void sendAttachMail(String to, String subject, Map<String, Object> content, String templateName, String attachSrc);
}

View File

@ -10,6 +10,7 @@ import org.springframework.stereotype.Service;
import org.springframework.ui.freemarker.FreeMarkerTemplateUtils;
import org.springframework.web.servlet.view.freemarker.FreeMarkerConfigurer;
import java.io.File;
import java.util.Map;
/**
@ -76,4 +77,36 @@ public class MailServiceImpl implements MailService {
e.printStackTrace();
}
}
/**
*
*
* @param to
* @param subject
* @param content
* @param templateName
* @param attachSrc
*/
@Override
public void sendAttachMail(String to, String subject, Map<String, Object> content, String templateName, String attachSrc) {
//配置邮件服务器
HaloUtils.configMail(
HaloConst.OPTIONS.get("mail_smtp_host"),
HaloConst.OPTIONS.get("mail_smtp_username"),
HaloConst.OPTIONS.get("mail_smtp_password"));
File file = new File(attachSrc);
String text = "";
try{
Template template = freeMarker.getConfiguration().getTemplate(templateName);
text = FreeMarkerTemplateUtils.processTemplateIntoString(template,content);
OhMyEmail.subject(subject)
.from(HaloConst.OPTIONS.get("mail_from_name"))
.to(to)
.html(text)
.attach(file,file.getName())
.send();
}catch (Exception e){
e.printStackTrace();
}
}
}

View File

@ -1,8 +1,10 @@
package cc.ryanc.halo.utils;
import cc.ryanc.halo.model.domain.Post;
import cc.ryanc.halo.model.dto.BackupDto;
import cc.ryanc.halo.model.dto.HaloConst;
import cc.ryanc.halo.model.dto.Theme;
import cn.hutool.core.io.FileUtil;
import com.sun.syndication.feed.rss.Channel;
import com.sun.syndication.feed.rss.Content;
import com.sun.syndication.feed.rss.Item;
@ -17,13 +19,18 @@ import javax.imageio.ImageIO;
import javax.imageio.ImageReadParam;
import javax.imageio.ImageReader;
import javax.imageio.stream.ImageInputStream;
import javax.servlet.http.HttpServletRequest;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.LinkOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributeView;
import java.nio.file.attribute.BasicFileAttributes;
import java.text.SimpleDateFormat;
import java.time.Instant;
import java.time.ZoneId;
@ -104,6 +111,84 @@ public class HaloUtils {
return FILE_LIST;
}
/**
*
*
* @param dir dir
* @return List<BackupDto></>
*/
public static List<BackupDto> getBackUps(String dir) {
String srcPathStr = System.getProperties().getProperty("user.home") + "/halo/backup/" + dir;
File srcPath = new File(srcPathStr);
File[] files = srcPath.listFiles();
List<BackupDto> backupDtos = new ArrayList<>();
BackupDto backupDto = null;
//遍历文件
for (File file : files) {
if (file.isFile()) {
if (StringUtils.equals(file.getName(), ".DS_Store")) {
continue;
}
backupDto = new BackupDto();
backupDto.setFileName(file.getName());
backupDto.setCreateAt(getCreateTime(file.getAbsolutePath()));
backupDto.setFileType(FileUtil.getType(file));
backupDto.setFileSize(parseSize(file.length()));
backupDto.setBackupType(dir);
backupDtos.add(backupDto);
}
}
return backupDtos;
}
/**
*
*
* @param size size
* @return string
*/
public static String parseSize(long size) {
if (size < 1024) {
return String.valueOf(size) + "B";
} else {
size = size / 1024;
}
if (size < 1024) {
return String.valueOf(size) + "KB";
} else {
size = size / 1024;
}
if (size < 1024) {
size = size * 100;
return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "MB";
} else {
size = size * 100 / 1024;
return String.valueOf((size / 100)) + "." + String.valueOf((size % 100)) + "GB";
}
}
/**
*
*
* @param srcPath
* @return
*/
public static Date getCreateTime(String srcPath) {
Path path = Paths.get(srcPath);
BasicFileAttributeView basicview = Files.getFileAttributeView(path, BasicFileAttributeView.class, LinkOption.NOFOLLOW_LINKS);
BasicFileAttributes attr;
try {
attr = basicview.readAttributes();
Date createDate = new Date(attr.creationTime().toMillis());
return createDate;
} catch (Exception e) {
e.printStackTrace();
}
Calendar cal = Calendar.getInstance();
cal.set(1970, 0, 1, 0, 0, 0);
return cal.getTime();
}
/**
*
*
@ -215,26 +300,6 @@ public class HaloUtils {
return Instant.ofEpochSecond(unixTime).atZone(ZoneId.systemDefault()).format(DateTimeFormatter.ofPattern(format));
}
/**
* ip
*
* @param request request
* @return string
*/
public static String getIpAddr(HttpServletRequest request) {
String ip = request.getHeader("x-forwarded-for");
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getHeader("WL-Proxy-Client-IP");
}
if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
ip = request.getRemoteAddr();
}
return ip;
}
/**
*
*
@ -288,7 +353,14 @@ public class HaloUtils {
return false;
}
public static void dbToFile(String data,String filePath,String fileName){
/**
*
*
* @param data
* @param filePath
* @param fileName
*/
public static void postToFile(String data, String filePath, String fileName) {
try{
File file =new File(filePath);
if(!file.exists()){
@ -299,7 +371,6 @@ public class HaloUtils {
BufferedWriter bufferWritter = new BufferedWriter(fileWritter);
bufferWritter.write(data);
bufferWritter.close();
System.out.println("Done");
}catch (Exception e){
e.printStackTrace();
}

View File

@ -18,6 +18,7 @@ import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -126,9 +127,11 @@ public class AdminController extends BaseController {
//已注册账号,单用户,只有一个
User aUser = userService.findUser();
//首先判断是否已经被禁用已经是否已经过了10分钟
Date loginLast = aUser.getLoginLast();
Date loginLast = DateUtil.date();
if(null!=aUser.getLoginLast()){
loginLast = aUser.getLoginLast();
}
Long between = DateUtil.between(loginLast, DateUtil.date(), DateUnit.MINUTE);
log.info(between+"");
if (StringUtils.equals(aUser.getLoginEnable(), "false") && (between < 10)) {
return new JsonResult(0, "已禁止登录请10分钟后再试");
}
@ -145,7 +148,7 @@ public class AdminController extends BaseController {
session.setAttribute(HaloConst.USER_SESSION_KEY, aUser);
//重置用户的登录状态为正常
userService.updateUserNormal();
logsService.saveByLogs(new Logs(LogsRecord.LOGIN, LogsRecord.LOGIN_SUCCESS, HaloUtils.getIpAddr(request), DateUtil.date()));
logsService.saveByLogs(new Logs(LogsRecord.LOGIN, LogsRecord.LOGIN_SUCCESS, ServletUtil.getClientIP(request), DateUtil.date()));
return new JsonResult(1, "登录成功!");
} else {
//更新失败次数
@ -158,7 +161,7 @@ public class AdminController extends BaseController {
new Logs(
LogsRecord.LOGIN,
LogsRecord.LOGIN_ERROR + "[" + HtmlUtil.encode(loginName) + "," + HtmlUtil.encode(loginPwd) + "]",
HaloUtils.getIpAddr(request),
ServletUtil.getClientIP(request),
DateUtil.date()
)
);
@ -175,7 +178,7 @@ public class AdminController extends BaseController {
@GetMapping(value = "/logOut")
public String logOut(HttpSession session) {
User user = (User) session.getAttribute(HaloConst.USER_SESSION_KEY);
logsService.saveByLogs(new Logs(LogsRecord.LOGOUT, user.getUserName(), HaloUtils.getIpAddr(request), DateUtil.date()));
logsService.saveByLogs(new Logs(LogsRecord.LOGOUT, user.getUserName(), ServletUtil.getClientIP(request), DateUtil.date()));
session.invalidate();
log.info("用户[" + user.getUserName() + "]退出登录");
return "redirect:/admin/login";

View File

@ -9,6 +9,7 @@ import cc.ryanc.halo.service.AttachmentService;
import cc.ryanc.halo.service.LogsService;
import cc.ryanc.halo.utils.HaloUtils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -174,7 +175,7 @@ public class AttachmentController {
updateConst();
log.info("上传文件[" + fileName + "]到[" + mediaPath.getAbsolutePath() + "]成功");
logsService.saveByLogs(
new Logs(LogsRecord.UPLOAD_FILE, fileName, HaloUtils.getIpAddr(request), DateUtil.date())
new Logs(LogsRecord.UPLOAD_FILE, fileName, ServletUtil.getClientIP(request), DateUtil.date())
);
result.put("success", 1);
@ -246,7 +247,7 @@ public class AttachmentController {
updateConst();
log.info("删除文件[" + delFileName + "]成功!");
logsService.saveByLogs(
new Logs(LogsRecord.REMOVE_FILE, delFileName, HaloUtils.getIpAddr(request), DateUtil.date())
new Logs(LogsRecord.REMOVE_FILE, delFileName, ServletUtil.getClientIP(request), DateUtil.date())
);
} else {
log.error("删除附件[" + delFileName + "]失败!");

View File

@ -1,18 +1,31 @@
package cc.ryanc.halo.web.controller.admin;
import cc.ryanc.halo.model.domain.Post;
import cc.ryanc.halo.model.domain.User;
import cc.ryanc.halo.model.dto.BackupDto;
import cc.ryanc.halo.model.dto.HaloConst;
import cc.ryanc.halo.model.dto.JsonResult;
import cc.ryanc.halo.service.MailService;
import cc.ryanc.halo.service.PostService;
import cc.ryanc.halo.utils.HaloUtils;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.util.ResourceUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpSession;
import java.io.File;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author : RYAN0UP
@ -28,6 +41,10 @@ public class BackupController {
@Autowired
private PostService postService;
@Autowired
private MailService mailService;
/**
*
*
@ -35,55 +52,162 @@ public class BackupController {
* @return admin/admin_backup
*/
@GetMapping
public String backup() {
public String backup(Model model) {
List<BackupDto> resourcesBackup = HaloUtils.getBackUps("resources");
List<BackupDto> databasesBackup = HaloUtils.getBackUps("databases");
List<BackupDto> postsBackup = HaloUtils.getBackUps("posts");
model.addAttribute("resourcesBackup", resourcesBackup);
model.addAttribute("databasesBackup", databasesBackup);
model.addAttribute("postsBackup", postsBackup);
return "admin/admin_backup";
}
/**
*
*
* @param type
* @return JsonResult
*/
@GetMapping(value = "doBackup")
@ResponseBody
public JsonResult doBackup(@RequestParam("type") String type) {
if (StringUtils.equals("resources", type)) {
return this.backupResources();
} else if (StringUtils.equals("db", type)) {
return this.backupDatabase();
} else if (StringUtils.equals("posts", type)) {
return this.backupPosts();
} else {
return new JsonResult(0, "备份失败!");
}
}
/**
*
*
* @return /admin/backup
*/
@GetMapping(value = "/backupDb")
public String backupDatabase() {
String fileName = "db_backup_" + HaloUtils.getStringDate("yyyy_MM_dd_HH_mm_ss") + ".sql";
public JsonResult backupDatabase() {
try {
File path = new File(ResourceUtils.getURL("classpath:").getPath());
String savePath = path.getAbsolutePath() + "/backup/database";
HaloUtils.exportDatabase("localhost", "root", "123456", savePath, fileName, "testdb");
String srcPath = System.getProperties().getProperty("user.home") + "/halo";
String distName = "databases_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss");
ZipUtil.zip(srcPath + "/halo.mv.db", System.getProperties().getProperty("user.home") + "/halo/backup/databases/" + distName + ".zip");
return new JsonResult(1, "备份成功!");
} catch (Exception e) {
log.error("未知错误:{0}", e.getMessage());
log.error("未知错误:", e.getMessage());
return new JsonResult(0, "备份失败!");
}
return "redirect:/admin/backup";
}
/**
*
*
* @return return
* @return JsonResult
*/
@GetMapping(value = "/backupRe")
public String backupResources() {
return null;
public JsonResult backupResources() {
try {
File path = new File(ResourceUtils.getURL("classpath:").getPath());
String srcPath = path.getAbsolutePath();
String distName = "resources_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss");
//执行打包
ZipUtil.zip(srcPath, System.getProperties().getProperty("user.home") + "/halo/backup/resources/" + distName + ".zip");
return new JsonResult(1, "备份成功!");
} catch (Exception e) {
e.printStackTrace();
return new JsonResult(0, "备份失败!");
}
}
/**
* markdown
*
* @return /admin/backup
* @return JsonResult
*/
@GetMapping(value = "/backupPost")
public String backupPosts() {
public JsonResult backupPosts() {
List<Post> posts = postService.findAllPosts(HaloConst.POST_TYPE_POST);
posts.addAll(postService.findAllPosts(HaloConst.POST_TYPE_PAGE));
try {
File path = new File(ResourceUtils.getURL("classpath:").getPath());
String savePath = path.getAbsolutePath() + "/backup/posts/posts_backup_" + HaloUtils.getStringDate("yyyy_MM_dd_HH_mm_ss");
//打包好的文件名
String distName = "posts_backup_" + HaloUtils.getStringDate("yyyyMMddHHmmss");
String srcPath = System.getProperties().getProperty("user.home") + "/halo/backup/posts/" + distName;
for (Post post : posts) {
HaloUtils.dbToFile(post.getPostContentMd(), savePath, post.getPostTitle() + ".md");
HaloUtils.postToFile(post.getPostContentMd(), srcPath, post.getPostTitle() + ".md");
}
//打包导出好的文章
ZipUtil.zip(srcPath, System.getProperties().getProperty("user.home") + "/halo/backup/posts/" + distName + ".zip");
FileUtil.del(srcPath);
return new JsonResult(1, "备份成功!");
} catch (Exception e) {
e.printStackTrace();
}
return "redirect:/admin/backup";
return new JsonResult(0, "备份失败!");
}
}
/**
*
*
* @param fileName
* @param type
* @return JsonResult
*/
@GetMapping(value = "delBackup")
@ResponseBody
public JsonResult delBackup(@RequestParam("fileName") String fileName,
@RequestParam("type") String type) {
String srcPath = System.getProperties().getProperty("user.home") + "/halo/backup/" + type + "/" + fileName;
try {
FileUtil.del(srcPath);
return new JsonResult(1, "删除成功!");
} catch (Exception e) {
return new JsonResult(0, "删除失败!");
}
}
/**
*
*
* @param fileName
* @param type
* @return JsonResult
*/
@GetMapping(value = "sendToEmail")
@ResponseBody
public JsonResult sendToEmail(@RequestParam("fileName") String fileName,
@RequestParam("type") String type,
HttpSession session) {
String srcPath = System.getProperties().getProperty("user.home") + "/halo/backup/" + type + "/" + fileName;
User user = (User) session.getAttribute(HaloConst.USER_SESSION_KEY);
if (null == user.getUserEmail() || StringUtils.equals(user.getUserEmail(), "")) {
return new JsonResult(0, "博主邮箱没有配置!");
}
if (StringUtils.equals(HaloConst.OPTIONS.get("smtp_email_enable"), "false")) {
return new JsonResult(0, "发信邮箱没有配置!");
}
new EmailToAdmin(srcPath, user).start();
return new JsonResult(1, "邮件发送成功!");
}
class EmailToAdmin extends Thread {
private String srcPath;
private User user;
public EmailToAdmin(String srcPath, User user) {
this.srcPath = srcPath;
this.user = user;
}
@Override
public void run() {
File file = new File(srcPath);
Map<String, Object> content = new HashMap<>();
try {
content.put("fileName", file.getName());
content.put("createAt", HaloUtils.getCreateTime(srcPath));
content.put("size", HaloUtils.parseSize(file.length()));
mailService.sendAttachMail(user.getUserEmail(), "有新的备份!", content, "common/mail/mail_attach.ftl", srcPath);
} catch (Exception e) {
log.error("邮件服务器未配置:", e.getMessage());
}
}
}
}

View File

@ -13,6 +13,7 @@ import cc.ryanc.halo.web.controller.core.BaseController;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Validator;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -195,7 +196,7 @@ public class CommentController extends BaseController{
comment.setCommentAuthor(user.getUserDisplayName());
comment.setCommentAuthorEmail(user.getUserEmail());
comment.setCommentAuthorUrl(HaloConst.OPTIONS.get("blog_url"));
comment.setCommentAuthorIp(HaloUtils.getIpAddr(request));
comment.setCommentAuthorIp(ServletUtil.getClientIP(request));
comment.setCommentAuthorAvatarMd5(SecureUtil.md5(user.getUserEmail()));
comment.setCommentDate(DateUtil.date());
String lastContent = " //<a href='#comment-id-"+lastComment.getCommentId()+"'>@"+lastComment.getCommentAuthor()+"</a>:"+lastComment.getCommentContent();

View File

@ -10,6 +10,7 @@ import cc.ryanc.halo.service.LogsService;
import cc.ryanc.halo.service.PostService;
import cc.ryanc.halo.utils.HaloUtils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -232,7 +233,7 @@ public class PageController {
post.setPostUpdate(DateUtil.date());
}
postService.saveByPost(post);
logsService.saveByLogs(new Logs(LogsRecord.PUSH_PAGE, post.getPostTitle(), HaloUtils.getIpAddr(request), DateUtil.date()));
logsService.saveByLogs(new Logs(LogsRecord.PUSH_PAGE, post.getPostTitle(), ServletUtil.getClientIP(request), DateUtil.date()));
return new JsonResult(1,msg);
} catch (Exception e) {
log.error("未知错误:{0}", e.getMessage());

View File

@ -11,6 +11,7 @@ import cc.ryanc.halo.service.TagService;
import cc.ryanc.halo.utils.HaloUtils;
import cc.ryanc.halo.web.controller.core.BaseController;
import cn.hutool.core.date.DateUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -193,7 +194,7 @@ public class PostController extends BaseController{
}
post.setPostUrl(urlFilter(post.getPostUrl()));
postService.saveByPost(post);
logsService.saveByLogs(new Logs(LogsRecord.PUSH_POST,post.getPostTitle(),HaloUtils.getIpAddr(request),DateUtil.date()));
logsService.saveByLogs(new Logs(LogsRecord.PUSH_POST,post.getPostTitle(),ServletUtil.getClientIP(request),DateUtil.date()));
return new JsonResult(1,msg);
}catch (Exception e){
log.error("未知错误:", e.getMessage());
@ -298,7 +299,7 @@ public class PostController extends BaseController{
try{
Optional<Post> post = postService.findByPostId(postId);
postService.removeByPostId(postId);
logsService.saveByLogs(new Logs(LogsRecord.REMOVE_POST,post.get().getPostTitle(),HaloUtils.getIpAddr(request),DateUtil.date()));
logsService.saveByLogs(new Logs(LogsRecord.REMOVE_POST,post.get().getPostTitle(),ServletUtil.getClientIP(request),DateUtil.date()));
}catch (Exception e){
log.error("未知错误:{0}",e.getMessage());
}

View File

@ -11,6 +11,7 @@ import cc.ryanc.halo.web.controller.core.BaseController;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.extra.servlet.ServletUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
@ -78,7 +79,7 @@ public class ThemeController extends BaseController {
BaseController.THEME = siteTheme;
log.info("已将主题改变为:" + siteTheme);
logsService.saveByLogs(
new Logs(LogsRecord.CHANGE_THEME, "更换为" + siteTheme, HaloUtils.getIpAddr(request), DateUtil.date())
new Logs(LogsRecord.CHANGE_THEME, "更换为" + siteTheme, ServletUtil.getClientIP(request), DateUtil.date())
);
return new JsonResult(1,"主题已设置为"+siteTheme);
} catch (Exception e) {
@ -106,7 +107,7 @@ public class ThemeController extends BaseController {
file.transferTo(themePath);
log.info("上传主题成功,路径:" + themePath.getAbsolutePath());
logsService.saveByLogs(
new Logs(LogsRecord.UPLOAD_THEME, file.getOriginalFilename(), HaloUtils.getIpAddr(request), DateUtil.date())
new Logs(LogsRecord.UPLOAD_THEME, file.getOriginalFilename(), ServletUtil.getClientIP(request), DateUtil.date())
);
ZipUtil.unzip(themePath,new File(basePath.getAbsolutePath(), "templates/themes/"));
FileUtil.del(themePath);

View File

@ -7,6 +7,7 @@ import cc.ryanc.halo.service.*;
import cc.ryanc.halo.utils.HaloUtils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.crypto.SecureUtil;
import cn.hutool.extra.servlet.ServletUtil;
import freemarker.template.Configuration;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -177,7 +178,7 @@ public class InstallController {
new Logs(
LogsRecord.INSTALL,
"安装成功欢迎使用Halo。",
HaloUtils.getIpAddr(request),
ServletUtil.getClientIP(request),
DateUtil.date()
)
);

View File

@ -11,6 +11,7 @@ import cc.ryanc.halo.service.UserService;
import cc.ryanc.halo.utils.HaloUtils;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.servlet.ServletUtil;
import cn.hutool.http.HtmlUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
@ -103,7 +104,7 @@ public class FrontCommentController {
comment.setCommentAuthorEmail(HtmlUtil.encode(comment.getCommentAuthorEmail()).toLowerCase());
comment.setPost(post);
comment.setCommentDate(DateUtil.date());
comment.setCommentAuthorIp(HaloUtils.getIpAddr(request));
comment.setCommentAuthorIp(ServletUtil.getClientIP(request));
comment.setIsAdmin(0);
comment.setCommentAuthor(HtmlUtil.encode(comment.getCommentAuthor()));
if(comment.getCommentParent()>0){

View File

@ -7,21 +7,310 @@
<#include "module/_sidebar.ftl">
<div class="content-wrapper">
<section class="content-header">
<h1 style="display: inline-block;">正在开发中...</h1>
<h1 style="display: inline-block;">博客备份</h1>
<ol class="breadcrumb">
<li>
<a href="/admin"><i class="fa fa-dashboard"></i> 首页</a>
</li>
<li><a href="#">设置</a></li>
<li class="active">备份恢复</li>
<li class="active">博客备份</li>
</ol>
</section>
<!--
<section class="content container-fluid">
<a href="/admin/backup/backupDb">备份数据库</a>
<a href="/admin/backup/backupPost">备份文章</a>
<div class="row">
<div class="col-md-12">
<div class="nav-tabs-custom">
<ul class="nav nav-tabs">
<li class="active">
<a href="#resources" data-toggle="tab">资源目录备份</a>
</li>
<li>
<a href="#database" data-toggle="tab">数据库备份</a>
</li>
<li>
<a href="#post" data-toggle="tab">文章备份</a>
</li>
</ul>
<div class="tab-content">
<div class="tab-pane active" id="resources">
<form method="post" class="form-horizontal" id="resourcesBackup">
<div class="box-body table-responsive" style="padding: 10px 0;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>文件名称</th>
<th>备份时间</th>
<th>文件大小</th>
<th>文件类型</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<#if resourcesBackup?size gt 0>
<#list resourcesBackup as resource>
<tr>
<td>${resource.fileName}</td>
<td>${resource.createAt?string("yyyy-MM-dd HH:mm")}</td>
<td>${resource.fileSize}</td>
<td>${resource.fileType}</td>
<td>
<a href="/backup/resources/${resource.fileName}" class="btn btn-xs btn-primary" download="${resource.fileName}">下载</a>
<button type="button" class="btn btn-xs btn-info" onclick="sendToEmail('${resource.fileName}','${resource.backupType}')">发送到邮箱</button>
<button type="button" class="btn btn-xs btn-danger" onclick="delBackup('${resource.fileName}','${resource.backupType}')">删除</button>
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="5" style="text-align: center">暂无备份</td>
</tr>
</#if>
</tbody>
</table>
</div>
<div class="box-footer">
<button type="button" class="btn btn-primary btn-sm " onclick="btn_backup('resources')">备份</button>
</div>
</form>
</div>
<div class="tab-pane" id="database">
<form method="post" class="form-horizontal" id="databaseBackup">
<div class="box-body table-responsive" style="padding: 10px 0;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>文件名称</th>
<th>备份时间</th>
<th>文件大小</th>
<th>文件类型</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<#if databasesBackup?size gt 0>
<#list databasesBackup as database>
<tr>
<td>${database.fileName}</td>
<td>${database.createAt?string("yyyy-MM-dd HH:mm")}</td>
<td>${database.fileSize}</td>
<td>${database.fileType}</td>
<td>
<a href="/backup/databases/${database.fileName}" class="btn btn-xs btn-primary" download="${database.fileName}">下载</a>
<button type="button" class="btn btn-xs btn-info" onclick="sendToEmail('${database.fileName}','${database.backupType}')">发送到邮箱</button>
<button type="button" class="btn btn-xs btn-danger" onclick="delBackup('${database.fileName}','${database.backupType}')">删除</button>
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="5" style="text-align: center">暂无备份</td>
</tr>
</#if>
</tbody>
</table>
</div>
<div class="box-footer">
<button type="button" class="btn btn-primary btn-sm " onclick="btn_backup('db')">备份</button>
</div>
</form>
</div>
<div class="tab-pane" id="post">
<form method="post" class="form-horizontal" id="postBackup">
<div class="box-body table-responsive" style="padding: 10px 0;">
<table class="table table-bordered table-hover">
<thead>
<tr>
<th>文件名称</th>
<th>备份时间</th>
<th>文件大小</th>
<th>文件类型</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<#if postsBackup?size gt 0>
<#list postsBackup as post>
<tr>
<td>${post.fileName}</td>
<td>${post.createAt?string("yyyy-MM-dd HH:mm")}</td>
<td>${post.fileSize}</td>
<td>${post.fileType}</td>
<td>
<a href="/backup/posts/${post.fileName}" class="btn btn-xs btn-primary" download="${post.fileName}">下载</a>
<button type="button" class="btn btn-xs btn-info" onclick="sendToEmail('${post.fileName}','${post.backupType}')">发送到邮箱</button>
<button type="button" class="btn btn-xs btn-danger" onclick="delBackup('${post.fileName}','${post.backupType}')">删除</button>
</td>
</tr>
</#list>
<#else>
<tr>
<td colspan="5" style="text-align: center">暂无备份</td>
</tr>
</#if>
</tbody>
</table>
</div>
<div class="box-footer">
<button type="button" class="btn btn-primary btn-sm " onclick="btn_backup('posts')">备份</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
</section>
-->
<script>
/**
* 备份
*/
function btn_backup(type) {
$.ajax({
type: 'GET',
url: '/admin/backup/doBackup',
async: false,
data: {
'type' : type
},
success: function (data) {
if(data.code==1){
$.toast({
text: data.msg,
heading: '提示',
icon: 'success',
showHideTransition: 'fade',
allowToastClose: true,
hideAfter: 1000,
stack: 1,
position: 'top-center',
textAlign: 'left',
loader: true,
loaderBg: '#ffffff',
afterHidden: function () {
window.location.reload();
}
});
}else{
$.toast({
text: data.msg,
heading: '提示',
icon: 'error',
showHideTransition: 'fade',
allowToastClose: true,
hideAfter: 2000,
stack: 1,
position: 'top-center',
textAlign: 'left',
loader: true,
loaderBg: '#ffffff'
});
}
}
});
}
/**
* 发送备份到邮箱
*
* @param fileName
* @param type
*/
function sendToEmail(fileName,type) {
$.ajax({
type: 'GET',
url: '/admin/backup/sendToEmail',
async: false,
data: {
'type' : type,
'fileName' : fileName
},
success: function (data) {
if(data.code==1){
$.toast({
text: data.msg,
heading: '提示',
icon: 'success',
showHideTransition: 'fade',
allowToastClose: true,
hideAfter: 1000,
stack: 1,
position: 'top-center',
textAlign: 'left',
loader: true,
loaderBg: '#ffffff',
afterHidden: function () {
window.location.reload();
}
});
}else{
$.toast({
text: data.msg,
heading: '提示',
icon: 'error',
showHideTransition: 'fade',
allowToastClose: true,
hideAfter: 2000,
stack: 1,
position: 'top-center',
textAlign: 'left',
loader: true,
loaderBg: '#ffffff'
});
}
}
});
}
/**
* 删除备份
*/
function delBackup(fileName,type) {
$.ajax({
type: 'GET',
url: '/admin/backup/delBackup',
async: false,
data: {
'type' : type,
'fileName' : fileName
},
success: function (data) {
if(data.code==1){
$.toast({
text: data.msg,
heading: '提示',
icon: 'success',
showHideTransition: 'fade',
allowToastClose: true,
hideAfter: 1000,
stack: 1,
position: 'top-center',
textAlign: 'left',
loader: true,
loaderBg: '#ffffff',
afterHidden: function () {
window.location.reload();
}
});
}else{
$.toast({
text: data.msg,
heading: '提示',
icon: 'error',
showHideTransition: 'fade',
allowToastClose: true,
hideAfter: 2000,
stack: 1,
position: 'top-center',
textAlign: 'left',
loader: true,
loaderBg: '#ffffff'
});
}
}
});
}
</script>
</div>
<#include "module/_footer.ftl">
</div>

View File

@ -101,7 +101,7 @@
</a>
<ul class="treeview-menu">
<li><a data-pjax="true" href="/admin/option"><i class="fa fa-circle-o"></i>博客设置</a></li>
<li><a data-pjax="true" href="/admin/backup"><i class="fa fa-circle-o"></i>备份恢复</a></li>
<li><a data-pjax="true" href="/admin/backup"><i class="fa fa-circle-o"></i>博客备份</a></li>
</ul>
</li>
</ul>

View File

@ -0,0 +1,15 @@
<div class="emailpaged" style="background: #fff;">
<div class="emailcontent" style="width:100%;max-width:720px;text-align: left;margin: 0 auto;padding-top: 20px;padding-bottom: 80px">
<div class="emailtitle" style="border-radius: 5px;border:1px solid #eee;overflow: hidden;">
<h1 style="color:#fff;background: #3798e8;line-height:70px;font-size:24px;font-weight:normal;padding-left:40px;margin:0">
您有新的备份,请按需下载附件。
</h1>
<div class="emailtext" style="background:#fff;padding:20px 32px 40px;">
备份详情:<br />
文件名:${fileName}<br />
备份时间:${createAt?string("yyyy-MM-dd HH:mm")}<br />
文件大小:${size}
</div>
</div>
</div>
</div>