Merge pull request #195 from halo-dev/dev

Dev
pull/286/head
John Niang 2019-06-11 15:03:57 +08:00 committed by GitHub
commit c17448046e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 320 additions and 65 deletions

View File

@ -38,7 +38,7 @@ wget https://github.com/halo-dev/halo/releases/download/v1.0.1/halo-1.0.1.jar -O
### 启动 Halo
```bash
nohup java -jar halo-latest.jar &
nohup java -jar halo-latest.jar >/dev/null 2>&1&
```
详细文档请移步:<https://halo.run/docs>

View File

@ -1,7 +1,8 @@
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE'
id "io.freefair.lombok" version "3.1.4"
id "io.freefair.lombok" version "3.6.6"
id 'java'
id 'war'
}
apply plugin: 'io.spring.dependency-management'

View File

@ -2,6 +2,8 @@ package run.halo.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.servlet.support.SpringBootServletInitializer;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
import org.springframework.scheduling.annotation.EnableAsync;
@ -21,7 +23,7 @@ import run.halo.app.repository.base.BaseRepositoryImpl;
@EnableScheduling
@EnableAsync
@EnableJpaRepositories(basePackages = "run.halo.app.repository", repositoryBaseClass = BaseRepositoryImpl.class)
public class Application {
public class Application extends SpringBootServletInitializer {
public static void main(String[] args) {
// Customize the spring config location
@ -30,4 +32,10 @@ public class Application {
// Run application
SpringApplication.run(Application.class, args);
}
@Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
System.setProperty("spring.config.additional-location", "file:${user.home}/.halo/,file:${user.home}/halo-dev/");
return application.sources(Application.class);
}
}

View File

@ -29,6 +29,7 @@ import run.halo.app.security.resolver.AuthenticationArgumentResolver;
import java.io.IOException;
import java.util.List;
import java.util.Properties;
/**
* Mvc configuration.
@ -120,6 +121,11 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer {
configurer.setTemplateLoaderPaths(FILE_PROTOCOL + haloProperties.getWorkDir() + "templates/", "classpath:/templates/");
configurer.setDefaultEncoding("UTF-8");
Properties properties = new Properties();
properties.setProperty("auto_import","/common/macro/common_macro.ftl as common");
configurer.setFreemarkerSettings(properties);
// Predefine configuration
freemarker.template.Configuration configuration = configurer.createConfiguration();
if (haloProperties.isProductionEnv()) {

View File

@ -27,7 +27,7 @@ import java.util.Map;
*
* @author johnniang
*/
@RestControllerAdvice
@RestControllerAdvice({"run.halo.app.controller.admin.api", "run.halo.app.controller.content.api"})
@Slf4j
public class ControllerExceptionHandler {

View File

@ -66,7 +66,7 @@ public class ContentArchiveController {
* Render post archives page.
*
* @param model model
* @return template path : theme/{theme}/archives.ftl
* @return template path : themes/{theme}/archives.ftl
*/
@GetMapping
public String archives(Model model) {
@ -77,7 +77,7 @@ public class ContentArchiveController {
* Render post archives page.
*
* @param model model
* @return template path : theme/{theme}/archives.ftl
* @return template path : themes/{theme}/archives.ftl
*/
@GetMapping(value = "page/{page}")
public String archives(Model model,
@ -102,7 +102,7 @@ public class ContentArchiveController {
* @param url post slug url.
* @param cp comment page number
* @param model model
* @return template path: theme/{theme}/post.ftl
* @return template path: themes/{theme}/post.ftl
*/
@GetMapping("{url}")
public String post(@PathVariable("url") String url,

View File

@ -13,10 +13,8 @@ import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Post;
import run.halo.app.service.CategoryService;
import run.halo.app.service.OptionService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.ThemeService;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.service.*;
import static org.springframework.data.domain.Sort.Direction.DESC;
@ -34,25 +32,29 @@ public class ContentCategoryController {
private final PostCategoryService postCategoryService;
private final PostService postService;
private final OptionService optionService;
public ContentCategoryController(CategoryService categoryService,
ThemeService themeService,
PostCategoryService postCategoryService,
OptionService optionService) {
PostService postService, OptionService optionService) {
this.categoryService = categoryService;
this.themeService = themeService;
this.postCategoryService = postCategoryService;
this.postService = postService;
this.optionService = optionService;
}
/**
* Render category list page
*
* @return template path: theme/{theme}/categories.ftl
* @return template path: themes/{theme}/categories.ftl
*/
@GetMapping
public String categories() {
public String categories(Model model) {
model.addAttribute("is_categories", true);
return themeService.render("categories");
}
@ -61,7 +63,7 @@ public class ContentCategoryController {
*
* @param model model
* @param slugName slugName
* @return template path: theme/{theme}/category.ftl
* @return template path: themes/{theme}/category.ftl
*/
@GetMapping(value = "{slugName}")
public String categories(Model model,
@ -75,7 +77,7 @@ public class ContentCategoryController {
* @param model model
* @param slugName slugName
* @param page current page number
* @return template path: theme/{theme}/category.ftl
* @return template path: themes/{theme}/category.ftl
*/
@GetMapping("{slugName}/page/{page}")
public String categories(Model model,
@ -86,10 +88,11 @@ public class ContentCategoryController {
final Category category = categoryService.getBySlugName(slugName);
final Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), sort);
Page<Post> posts = postCategoryService.pagePostBy(category.getId(), pageable);
Page<Post> postPage = postCategoryService.pagePostBy(category.getId(), pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3);
model.addAttribute("is_categories", true);
model.addAttribute("is_category", true);
model.addAttribute("posts", posts);
model.addAttribute("rainbow", rainbow);
model.addAttribute("category", category);

View File

@ -51,7 +51,7 @@ public class ContentIndexController {
* Render blog index
*
* @param model model
* @return template path: /{theme}/post.ftl
* @return template path: themes/{theme}/index.ftl
*/
@GetMapping
public String index(Model model) {
@ -63,7 +63,7 @@ public class ContentIndexController {
*
* @param model model
* @param page current page number
* @return template path: /{theme}/post.ftl
* @return template path: themes/{theme}/index.ftl
*/
@GetMapping(value = "page/{page}")
public String index(Model model,

View File

@ -53,7 +53,7 @@ public class ContentJournalController {
* Render journal page.
*
* @param model model
* @return template path: theme/{theme}/journal.ftl
* @return template path: themes/{theme}/journals.ftl
*/
@GetMapping
public String journals(Model model) {
@ -66,7 +66,7 @@ public class ContentJournalController {
*
* @param model model
* @param page current page number
* @return template path: theme/{theme}/journal.ftl
* @return template path: themes/{theme}/journals.ftl
*/
@GetMapping(value = "page/{page}")
public String journals(Model model,

View File

@ -48,7 +48,7 @@ public class ContentSearchController {
*
* @param model model
* @param keyword keyword
* @return template path : themes/{theme}/search
* @return template path : themes/{theme}/search.ftl
*/
@GetMapping
public String search(Model model,
@ -61,7 +61,7 @@ public class ContentSearchController {
*
* @param model model
* @param keyword keyword
* @return template path :themes/{theme}/search
* @return template path :themes/{theme}/search.ftl
*/
@GetMapping(value = "page/{page}")
public String search(Model model,
@ -69,14 +69,14 @@ public class ContentSearchController {
@PathVariable(value = "page") Integer page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
final Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), sort);
final Page<Post> posts = postService.pageBy(keyword, pageable);
final Page<Post> postPage = postService.pageBy(keyword, pageable);
final Page<PostListVO> postPage = postService.convertToListVo(posts);
final Page<PostListVO> posts = postService.convertToListVo(postPage);
final int[] rainbow = PageUtil.rainbow(page, postPage.getTotalPages(), 3);
final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3);
model.addAttribute("is_search", true);
model.addAttribute("keyword", keyword);
model.addAttribute("posts", postPage);
model.addAttribute("posts", posts);
model.addAttribute("rainbow", rainbow);
return themeService.render("search");
}

View File

@ -4,7 +4,6 @@ import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestParam;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.support.HaloConst;
@ -34,7 +33,7 @@ public class ContentSheetController {
/**
* Render photo page
*
* @return template path: themes/{theme}/gallery.ftl
* @return template path: themes/{theme}/photos.ftl
*/
@GetMapping(value = "/photos")
public String photos() {
@ -60,7 +59,6 @@ public class ContentSheetController {
*/
@GetMapping(value = "/s/{url}")
public String sheet(@PathVariable(value = "url") String url,
@RequestParam(value = "cp", defaultValue = "1") Integer cp,
Model model) {
Sheet sheet = sheetService.getBy(PostStatus.PUBLISHED, url);

View File

@ -53,10 +53,11 @@ public class ContentTagController {
/**
* All of tags
*
* @return template path: themes/{theme}/tags
* @return template path: themes/{theme}/tags.ftl
*/
@GetMapping
public String tags() {
public String tags(Model model) {
model.addAttribute("is_tags", true);
return themeService.render("tags");
}
@ -65,7 +66,7 @@ public class ContentTagController {
*
* @param model model
* @param slugName slug name
* @return template path: themes/{theme}/tag
* @return template path: themes/{theme}/tag.ftl
*/
@GetMapping(value = "{slugName}")
public String tags(Model model,
@ -79,21 +80,22 @@ public class ContentTagController {
* @param model model
* @param slugName slug name
* @param page current page
* @return template path: themes/{theme}/tag
* @return template path: themes/{theme}/tag.ftl
*/
@GetMapping(value = "{slugName}/page/{page}")
public String tags(Model model,
@PathVariable("slugName") String slugName,
@PathVariable("page") Integer page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
Tag tag = tagService.getBySlugNameOfNonNull(slugName);
// Get tag by slug name
final Tag tag = tagService.getBySlugNameOfNonNull(slugName);
final Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), sort);
Page<Post> postPage = postTagService.pagePostsBy(tag.getId(), pageable);
Page<PostListVO> posts = postService.convertToListVo(postPage);
final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3);
model.addAttribute("is_tags", true);
model.addAttribute("is_tag", true);
model.addAttribute("posts", posts);
model.addAttribute("rainbow", rainbow);
model.addAttribute("tag", tag);

View File

@ -0,0 +1,66 @@
package run.halo.app.controller.content.api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.*;
import run.halo.app.model.dto.CategoryDTO;
import run.halo.app.model.dto.post.BasePostSimpleDTO;
import run.halo.app.model.entity.Category;
import run.halo.app.model.entity.Post;
import run.halo.app.service.CategoryService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.PostService;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
* Category portal controller.
*
* @author ryanwang
* @date 6/9/19
*/
@RestController("ApiContentCategoryController")
@RequestMapping("/api/content/categories")
public class CategoryController {
private final CategoryService categoryService;
private final PostCategoryService postCategoryService;
private final PostService postService;
public CategoryController(CategoryService categoryService,
PostCategoryService postCategoryService,
PostService postService) {
this.categoryService = categoryService;
this.postCategoryService = postCategoryService;
this.postService = postService;
}
@GetMapping
@ApiOperation("Lists categories")
public List<? extends CategoryDTO> listCategories(@SortDefault(sort = "updateTime", direction = DESC) Sort sort,
@RequestParam(name = "more", required = false, defaultValue = "false") Boolean more) {
if (more) {
return postCategoryService.listCategoryWithPostCountDto(sort);
}
return categoryService.convertTo(categoryService.listAll(sort));
}
@GetMapping("{slugName}/posts")
@ApiOperation("Lists posts by category slug name")
public Page<BasePostSimpleDTO> listPostsBy(@PathVariable("slugName") String slugName,
@PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable) {
// Get category by slug name
Category category = categoryService.getBySlugName(slugName);
Page<Post> postPage = postCategoryService.pagePostBy(category.getId(), pageable);
return postService.convertToSimple(postPage);
}
}

View File

@ -1,18 +1,24 @@
package run.halo.app.controller.content.api;
import io.swagger.annotations.ApiOperation;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import run.halo.app.model.dto.LinkDTO;
import run.halo.app.model.vo.LinkTeamVO;
import run.halo.app.service.LinkService;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
* Portal link controller.
*
* @author johnniang
* @author ryanwang
* @date 4/3/19
*/
@RestController("ApiContentLinkController")
@ -25,7 +31,14 @@ public class LinkController {
this.linkService = linkService;
}
@GetMapping
@ApiOperation("List all links")
public List<LinkDTO> listLinks(@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return linkService.listDtos(sort);
}
@GetMapping("team_view")
@ApiOperation("List all links with team view")
public List<LinkTeamVO> listTeamVos(Sort sort) {
return linkService.listTeamVos(sort);
}

View File

@ -7,6 +7,7 @@ import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import run.halo.app.model.dto.MenuDTO;
import run.halo.app.model.vo.MenuVO;
import run.halo.app.service.MenuService;
import java.util.List;
@ -17,6 +18,7 @@ import static org.springframework.data.domain.Sort.Direction.DESC;
* Portal menu controller.
*
* @author johnniang
* @author ryanwang
* @date 4/3/19
*/
@RestController("ApiContentMenuController")
@ -34,4 +36,10 @@ public class MenuController {
public List<MenuDTO> listAll(@SortDefault(sort = "priority", direction = DESC) Sort sort) {
return menuService.listDtos(sort);
}
@GetMapping(value = "tree_view")
@ApiOperation("Lists menus with tree view")
public List<MenuVO> listMenusTree(@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return menuService.listAsTree(sort);
}
}

View File

@ -59,6 +59,14 @@ public class PostController {
return postService.convertToSimple(postPage);
}
@PostMapping(value = "search")
@ApiOperation("Lists posts by keyword")
public Page<BasePostSimpleDTO> pageBy(@RequestParam(value = "keyword") String keyword,
@PageableDefault(sort = "createTime", direction = DESC) Pageable pageable) {
Page<Post> postPage = postService.pageBy(keyword, pageable);
return postService.convertToSimple(postPage);
}
@GetMapping("{postId:\\d+}")
@ApiOperation("Gets a post")
public BasePostDetailDTO getBy(@PathVariable("postId") Integer postId,

View File

@ -53,11 +53,11 @@ public class CommonController implements ErrorController {
if (StringUtils.startsWithIgnoreCase(throwable.getMessage(), "Could not resolve view with name '")) {
// TODO May cause unknown-reason problem
// if Ftl was not found then redirect to /404
return "redirect:/404";
return contentNotFround();
}
}
return statusCode == 500 ? "redirect:/500" : "redirect:/404";
return statusCode == 500 ? contentInternalError() : contentNotFround();
}
/**

View File

@ -12,6 +12,7 @@ import run.halo.app.event.options.OptionUpdatedEvent;
import run.halo.app.event.theme.ThemeActivatedEvent;
import run.halo.app.event.user.UserUpdatedEvent;
import run.halo.app.handler.theme.config.support.ThemeProperty;
import run.halo.app.model.support.HaloConst;
import run.halo.app.service.OptionService;
import run.halo.app.service.ThemeService;
import run.halo.app.service.ThemeSettingService;
@ -90,6 +91,7 @@ public class FreemarkerConfigAwareListener {
private void loadOptionsConfig() throws TemplateModelException {
configuration.setSharedVariable("options", optionService.listOptions());
configuration.setSharedVariable("context", optionService.getBlogBaseUrl());
configuration.setSharedVariable("version", HaloConst.HALO_VERSION);
log.debug("Loaded options");
}

View File

@ -1,6 +1,7 @@
package run.halo.app.model.dto;
import lombok.Data;
import run.halo.app.model.enums.Mode;
/**
* Theme controller.
@ -16,4 +17,6 @@ public class EnvironmentDTO {
private long startTime;
private String version;
private Mode mode;
}

View File

@ -0,0 +1,47 @@
package run.halo.app.model.enums;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.Nullable;
/**
* Halo runtime mode.
*
* @author johnniang
* @date 19-6-10
*/
public enum Mode {
PRODUCTION,
DEVELOPMENT,
TEST;
@JsonValue
String getValue() {
return this.name().toLowerCase();
}
/**
* Get mode from value.
*
* @param value mode value
* @return runtime mode or null if the value is mismatch
*/
@Nullable
@JsonCreator
public static Mode valueFrom(@Nullable String value) {
if (StringUtils.isBlank(value) || value.equalsIgnoreCase("prod")) {
return Mode.PRODUCTION;
}
if (value.equalsIgnoreCase("dev")) {
return Mode.DEVELOPMENT;
}
if (value.equalsIgnoreCase("test")) {
return Mode.TEST;
}
return null;
}
}

View File

@ -34,7 +34,7 @@ public class CommentTagDirective implements TemplateDirectiveModel {
switch (method) {
case "latest":
int top = Integer.parseInt(params.get("top").toString());
env.setVariable("categories", builder.build().wrap(postCommentService.pageLatest(top)));
env.setVariable("comments", builder.build().wrap(postCommentService.pageLatest(top)));
break;
case "count":
env.setVariable("count", builder.build().wrap(postCommentService.count()));

View File

@ -39,7 +39,7 @@ public class PhotoTagDirective implements TemplateDirectiveModel {
env.setVariable("photos", builder.build().wrap(photoService.listAll()));
break;
case "listTeams":
env.setVariable("teams", builder.build().wrap(photoService.listDtos(Sort.by(DESC, "createTime"))));
env.setVariable("teams", builder.build().wrap(photoService.listTeamVos(Sort.by(DESC, "createTime"))));
break;
case "listByTeam":
String team = params.get("team").toString();

View File

@ -2,6 +2,7 @@ package run.halo.app.model.params;
import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
/**
@ -14,6 +15,7 @@ import javax.validation.constraints.NotBlank;
public class MailParam {
@NotBlank(message = "收件人不能为空")
@Email(message = "邮箱格式错误")
private String to;
@NotBlank(message = "主题不能为空")

View File

@ -12,7 +12,9 @@ public enum OtherProperties implements PropertyEnum {
API_ACCESS_KEY("api_access_key", String.class, ""),
STATISTICS_CODE("statistics_code", String.class, ""),
CUSTOM_HEAD("blog_custom_head",String.class,""),
STATISTICS_CODE("blog_statistics_code", String.class, ""),
/**
*

View File

@ -23,7 +23,7 @@ public class HaloConst {
public final static String DEFAULT_THEME_ID = "caicai_anatole";
/**
* version constant
* Version constant. (Available in production environment)
*/
public static final String HALO_VERSION;

View File

@ -42,6 +42,7 @@ public interface CategoryService extends CrudService<Category, Integer> {
* @param name name
* @return Category
*/
@Nullable
Category getByName(@NonNull String name);
/**

View File

@ -2,6 +2,7 @@ package run.halo.app.service.impl;
import cn.hutool.core.lang.Validator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.lang.NonNull;
@ -14,6 +15,7 @@ import run.halo.app.model.dto.EnvironmentDTO;
import run.halo.app.model.dto.StatisticDTO;
import run.halo.app.model.entity.User;
import run.halo.app.model.enums.CommentStatus;
import run.halo.app.model.enums.Mode;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.params.LoginParam;
import run.halo.app.model.support.HaloConst;
@ -63,6 +65,8 @@ public class AdminServiceImpl implements AdminService {
private final String driverClassName;
private final String mode;
public AdminServiceImpl(PostService postService,
SheetService sheetService,
AttachmentService attachmentService,
@ -74,7 +78,8 @@ public class AdminServiceImpl implements AdminService {
LinkService linkService,
StringCacheStore cacheStore,
ApplicationEventPublisher eventPublisher,
@Value("${spring.datasource.driver-class-name}") String driverClassName) {
@Value("${spring.datasource.driver-class-name}") String driverClassName,
@Value("${spring.profiles.active:prod}") String mode) {
this.postService = postService;
this.sheetService = sheetService;
this.attachmentService = attachmentService;
@ -87,6 +92,7 @@ public class AdminServiceImpl implements AdminService {
this.cacheStore = cacheStore;
this.eventPublisher = eventPublisher;
this.driverClassName = driverClassName;
this.mode = mode;
}
@Override
@ -189,6 +195,8 @@ public class AdminServiceImpl implements AdminService {
environmentDTO.setVersion(HaloConst.HALO_VERSION);
environmentDTO.setMode(Mode.valueFrom(this.mode));
return environmentDTO;
}
@ -203,9 +211,8 @@ public class AdminServiceImpl implements AdminService {
User user = userService.getById(userId);
// Remove all token
cacheStore.getAny(SecurityUtils.buildAccessTokenKey(user), String.class).ifPresent(accessToken -> {
cacheStore.delete(SecurityUtils.buildTokenAccessKey(accessToken));
});
cacheStore.getAny(SecurityUtils.buildAccessTokenKey(user), String.class)
.ifPresent(accessToken -> cacheStore.delete(SecurityUtils.buildTokenAccessKey(accessToken)));
cacheStore.delete(SecurityUtils.buildTokenRefreshKey(refreshToken));
cacheStore.delete(SecurityUtils.buildAccessTokenKey(user));
cacheStore.delete(SecurityUtils.buildRefreshTokenKey(user));

View File

@ -8,6 +8,7 @@ import run.halo.app.service.BackupService;
import run.halo.app.service.PostService;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
/**
* Backup service implementation.
@ -28,7 +29,7 @@ public class BackupServiceImpl implements BackupService {
public BasePostDetailDTO importMarkdowns(MultipartFile file) throws IOException {
// Read markdown content.
String markdown = IoUtil.read(file.getInputStream(), "UTF-8");
String markdown = IoUtil.read(file.getInputStream(), StandardCharsets.UTF_8);
// TODO sheet import

View File

@ -29,10 +29,7 @@ import run.halo.app.model.vo.PostDetailVO;
import run.halo.app.model.vo.PostListVO;
import run.halo.app.repository.PostRepository;
import run.halo.app.service.*;
import run.halo.app.utils.DateUtils;
import run.halo.app.utils.MarkdownUtils;
import run.halo.app.utils.ServiceUtils;
import run.halo.app.utils.SlugUtils;
import run.halo.app.utils.*;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
@ -326,20 +323,24 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
if (null == tag) {
tag = new Tag();
tag.setName(ele);
tag.setSlugName(SlugUtils.slugify(ele));
String slugName = SlugUtils.slugify(ele);
tag.setSlugName(HaloUtils.initializeUrlIfBlank(slugName));
tag = tagService.create(tag);
}
tagIds.add(tag.getId());
break;
case "categories":
Category category = categoryService.getByName(ele);
if (null == category) {
category = new Category();
category.setName(ele);
category.setSlugName(SlugUtils.slugify(ele));
String slugName = SlugUtils.slugify(ele);
category.setSlugName(HaloUtils.initializeUrlIfBlank(slugName));
category.setDescription(ele);
category = categoryService.create(category);
}
categoryIds.add(category.getId());
break;
default:
break;
}

View File

@ -124,7 +124,7 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
User updatedUser = update(user);
// Log it
eventPublisher.publishEvent(new LogEvent(this, updatedUser.getId().toString(), LogType.PASSWORD_UPDATED, oldPassword));
eventPublisher.publishEvent(new LogEvent(this, updatedUser.getId().toString(), LogType.PASSWORD_UPDATED, HaloUtils.desensitize(oldPassword, 2, 1)));
return updatedUser;
}

View File

@ -21,6 +21,44 @@ import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
@Slf4j
public class HaloUtils {
/**
* Desensitizes the plain text.
*
* @param plainText plain text must not be null
* @param leftSize left size
* @param rightSize right size
* @return desensitization
*/
public static String desensitize(@NonNull String plainText, int leftSize, int rightSize) {
Assert.hasText(plainText, "Plain text must not be blank");
if (leftSize < 0) {
leftSize = 0;
}
if (leftSize > plainText.length()) {
leftSize = plainText.length();
}
if (rightSize < 0) {
rightSize = 0;
}
if (rightSize > plainText.length()) {
rightSize = plainText.length();
}
if (plainText.length() < leftSize + rightSize) {
rightSize = plainText.length() - leftSize;
}
int remainSize = plainText.length() - rightSize - leftSize;
String left = StringUtils.left(plainText, leftSize);
String right = StringUtils.right(plainText, rightSize);
return StringUtils.rightPad(left, remainSize + leftSize, '*') + right;
}
/**
* Changes file separator to url separator.
*

View File

@ -10,9 +10,15 @@
${options.blog_footer_info!}
</#macro>
<#macro custom_head>
${options.blog_custom_head!}
</#macro>
<#-- favicon -->
<#macro favicon>
<#if options.blog_favicon?? && options.blog_favicon!=''>
<link rel="shortcut icon" type="images/x-icon" href="${options.blog_favicon!}">
</#if>
</#macro>
<#-- 站点验证代码 -->
@ -46,11 +52,13 @@
</#macro>
<#macro globalHeader>
<@favicon />
<meta name="generator" content="Halo ${version!}" />
<@custom_head />
<@verification />
<@favicon />
</#macro>
<#macro globalFooter>
<@statistics />
<@footer_info />
<@statistics />
</#macro>

View File

@ -1,7 +1,7 @@
<#macro comment post,type>
<#if !post.disallowComment!false>
<script src="//cdn.jsdelivr.net/npm/vue@2.6.10/dist/vue.min.js"></script>
<script src="//cdn.jsdelivr.net/gh/halo-dev/halo-comment@1.0.0/dist/halo-comment.min.js"></script>
<script src="//cdn.jsdelivr.net/gh/halo-dev/halo-comment@1.0.2/dist/halo-comment.min.js"></script>
<halo-comment id="${post.id}" type="${type}"/>
</#if>
</#macro>

View File

@ -1,4 +1,4 @@
<#include "/common/macro/common_macro.ftl">
<#import "/common/macro/common_macro.ftl" as common>
<#macro head title,keywords,description>
<!DOCTYPE html>
<html>
@ -14,8 +14,7 @@
<meta name="author" content="${user.nickname!}" />
<meta name="keywords" content="${keywords!}"/>
<meta name="description" content="${description!}" />
<@verification />
<@favicon />
<@common.globalHeader />
<link href="${static!}/source/css/font-awesome.min.css" type="text/css" rel="stylesheet"/>
<link rel="stylesheet" href="${static!}/source/css/blog_basic.min.css?version=88107691fe">
<link href="${static!}/source/css/style.min.css" type="text/css" rel="stylesheet" />
@ -77,7 +76,7 @@
xhr.send();
</#if>
</script>
<@statistics />
<@common.statistics />
</body>
</html>
</#macro>

View File

@ -24,7 +24,7 @@
<a href="https://github.com/halo-dev/halo" target="_blank">Proudly published with Halo&#65281;</a>
</div>
<div class="footer_text">
<@footer_info></@footer_info>
<@common.footer_info />
</div>
</a>
</div>

View File

@ -1,5 +1,6 @@
package run.halo.app.utils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.junit.Test;
@ -14,6 +15,7 @@ import static org.junit.Assert.assertThat;
* @author johnniang
* @date 3/29/19
*/
@Slf4j
public class HaloUtilsTest {
@Test
@ -92,4 +94,33 @@ public class HaloUtilsTest {
public void pluralizeLabelExceptionTest() {
HaloUtils.pluralize(1, null, null);
}
@Test
public void desensitizeSuccessTest() {
String plainText = "12345678";
String desensitization = HaloUtils.desensitize(plainText, 1, 1);
assertThat(desensitization, equalTo("1******8"));
desensitization = HaloUtils.desensitize(plainText, 2, 3);
assertThat(desensitization, equalTo("12***678"));
desensitization = HaloUtils.desensitize(plainText, 2, 6);
assertThat(desensitization, equalTo("12345678"));
desensitization = HaloUtils.desensitize(plainText, 2, 7);
assertThat(desensitization, equalTo("12345678"));
desensitization = HaloUtils.desensitize(plainText, 0, 0);
assertThat(desensitization, equalTo("********"));
desensitization = HaloUtils.desensitize(plainText, -1, -1);
assertThat(desensitization, equalTo("********"));
}
@Test(expected = IllegalArgumentException.class)
public void desensitizeFailureTest() {
String plainText = " ";
HaloUtils.desensitize(plainText, 1, 1);
}
}