diff --git a/README.md b/README.md index f3926da5a..b6e860a3b 100755 --- a/README.md +++ b/README.md @@ -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& ``` 详细文档请移步: diff --git a/build.gradle b/build.gradle index 4ece1a6f8..708910710 100644 --- a/build.gradle +++ b/build.gradle @@ -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' diff --git a/src/main/java/run/halo/app/Application.java b/src/main/java/run/halo/app/Application.java index b4e6fb4f9..28ec81d22 100755 --- a/src/main/java/run/halo/app/Application.java +++ b/src/main/java/run/halo/app/Application.java @@ -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); + } } diff --git a/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java b/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java index d46577754..6f26bcd2e 100644 --- a/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java +++ b/src/main/java/run/halo/app/config/WebMvcAutoConfiguration.java @@ -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()) { diff --git a/src/main/java/run/halo/app/controller/base/ControllerExceptionHandler.java b/src/main/java/run/halo/app/controller/base/ControllerExceptionHandler.java index bd756d1d4..5bd8474cd 100644 --- a/src/main/java/run/halo/app/controller/base/ControllerExceptionHandler.java +++ b/src/main/java/run/halo/app/controller/base/ControllerExceptionHandler.java @@ -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 { diff --git a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java index 3af73e910..acb363232 100644 --- a/src/main/java/run/halo/app/controller/content/ContentArchiveController.java +++ b/src/main/java/run/halo/app/controller/content/ContentArchiveController.java @@ -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, diff --git a/src/main/java/run/halo/app/controller/content/ContentCategoryController.java b/src/main/java/run/halo/app/controller/content/ContentCategoryController.java index 582da8b7d..e85fb98be 100644 --- a/src/main/java/run/halo/app/controller/content/ContentCategoryController.java +++ b/src/main/java/run/halo/app/controller/content/ContentCategoryController.java @@ -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 posts = postCategoryService.pagePostBy(category.getId(), pageable); + Page postPage = postCategoryService.pagePostBy(category.getId(), pageable); + Page 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); diff --git a/src/main/java/run/halo/app/controller/content/ContentIndexController.java b/src/main/java/run/halo/app/controller/content/ContentIndexController.java index ba19b65c1..c3ce7449a 100644 --- a/src/main/java/run/halo/app/controller/content/ContentIndexController.java +++ b/src/main/java/run/halo/app/controller/content/ContentIndexController.java @@ -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, diff --git a/src/main/java/run/halo/app/controller/content/ContentJournalController.java b/src/main/java/run/halo/app/controller/content/ContentJournalController.java index 513cb5999..925542cfc 100644 --- a/src/main/java/run/halo/app/controller/content/ContentJournalController.java +++ b/src/main/java/run/halo/app/controller/content/ContentJournalController.java @@ -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, diff --git a/src/main/java/run/halo/app/controller/content/ContentSearchController.java b/src/main/java/run/halo/app/controller/content/ContentSearchController.java index 70c2c7610..93bf732b3 100644 --- a/src/main/java/run/halo/app/controller/content/ContentSearchController.java +++ b/src/main/java/run/halo/app/controller/content/ContentSearchController.java @@ -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 posts = postService.pageBy(keyword, pageable); + final Page postPage = postService.pageBy(keyword, pageable); - final Page postPage = postService.convertToListVo(posts); + final Page 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"); } diff --git a/src/main/java/run/halo/app/controller/content/ContentSheetController.java b/src/main/java/run/halo/app/controller/content/ContentSheetController.java index 38c7fb358..2b1ae4c61 100644 --- a/src/main/java/run/halo/app/controller/content/ContentSheetController.java +++ b/src/main/java/run/halo/app/controller/content/ContentSheetController.java @@ -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); diff --git a/src/main/java/run/halo/app/controller/content/ContentTagController.java b/src/main/java/run/halo/app/controller/content/ContentTagController.java index b506e5a20..eae71c455 100644 --- a/src/main/java/run/halo/app/controller/content/ContentTagController.java +++ b/src/main/java/run/halo/app/controller/content/ContentTagController.java @@ -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 postPage = postTagService.pagePostsBy(tag.getId(), pageable); Page 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); diff --git a/src/main/java/run/halo/app/controller/content/api/CategoryController.java b/src/main/java/run/halo/app/controller/content/api/CategoryController.java new file mode 100644 index 000000000..1be79ec43 --- /dev/null +++ b/src/main/java/run/halo/app/controller/content/api/CategoryController.java @@ -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 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 listPostsBy(@PathVariable("slugName") String slugName, + @PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable) { + // Get category by slug name + Category category = categoryService.getBySlugName(slugName); + + Page postPage = postCategoryService.pagePostBy(category.getId(), pageable); + return postService.convertToSimple(postPage); + } +} diff --git a/src/main/java/run/halo/app/controller/content/api/LinkController.java b/src/main/java/run/halo/app/controller/content/api/LinkController.java index dea1585b6..20b51b35f 100644 --- a/src/main/java/run/halo/app/controller/content/api/LinkController.java +++ b/src/main/java/run/halo/app/controller/content/api/LinkController.java @@ -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 listLinks(@SortDefault(sort = "createTime", direction = DESC) Sort sort) { + return linkService.listDtos(sort); + } + @GetMapping("team_view") + @ApiOperation("List all links with team view") public List listTeamVos(Sort sort) { return linkService.listTeamVos(sort); } diff --git a/src/main/java/run/halo/app/controller/content/api/MenuController.java b/src/main/java/run/halo/app/controller/content/api/MenuController.java index 45cc954f6..866cb5894 100644 --- a/src/main/java/run/halo/app/controller/content/api/MenuController.java +++ b/src/main/java/run/halo/app/controller/content/api/MenuController.java @@ -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 listAll(@SortDefault(sort = "priority", direction = DESC) Sort sort) { return menuService.listDtos(sort); } + + @GetMapping(value = "tree_view") + @ApiOperation("Lists menus with tree view") + public List listMenusTree(@SortDefault(sort = "createTime", direction = DESC) Sort sort) { + return menuService.listAsTree(sort); + } } diff --git a/src/main/java/run/halo/app/controller/content/api/PostController.java b/src/main/java/run/halo/app/controller/content/api/PostController.java index ae8fbff0f..6ec1514c5 100644 --- a/src/main/java/run/halo/app/controller/content/api/PostController.java +++ b/src/main/java/run/halo/app/controller/content/api/PostController.java @@ -59,6 +59,14 @@ public class PostController { return postService.convertToSimple(postPage); } + @PostMapping(value = "search") + @ApiOperation("Lists posts by keyword") + public Page pageBy(@RequestParam(value = "keyword") String keyword, + @PageableDefault(sort = "createTime", direction = DESC) Pageable pageable) { + Page postPage = postService.pageBy(keyword, pageable); + return postService.convertToSimple(postPage); + } + @GetMapping("{postId:\\d+}") @ApiOperation("Gets a post") public BasePostDetailDTO getBy(@PathVariable("postId") Integer postId, diff --git a/src/main/java/run/halo/app/controller/core/CommonController.java b/src/main/java/run/halo/app/controller/core/CommonController.java index c56710cbd..06f28a76b 100644 --- a/src/main/java/run/halo/app/controller/core/CommonController.java +++ b/src/main/java/run/halo/app/controller/core/CommonController.java @@ -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(); } /** diff --git a/src/main/java/run/halo/app/event/freemarker/FreemarkerConfigAwareListener.java b/src/main/java/run/halo/app/event/freemarker/FreemarkerConfigAwareListener.java index f1b8bbe5d..003ddf25c 100644 --- a/src/main/java/run/halo/app/event/freemarker/FreemarkerConfigAwareListener.java +++ b/src/main/java/run/halo/app/event/freemarker/FreemarkerConfigAwareListener.java @@ -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"); } diff --git a/src/main/java/run/halo/app/model/dto/EnvironmentDTO.java b/src/main/java/run/halo/app/model/dto/EnvironmentDTO.java index 644da2bee..b2fddafa4 100644 --- a/src/main/java/run/halo/app/model/dto/EnvironmentDTO.java +++ b/src/main/java/run/halo/app/model/dto/EnvironmentDTO.java @@ -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; } diff --git a/src/main/java/run/halo/app/model/enums/Mode.java b/src/main/java/run/halo/app/model/enums/Mode.java new file mode 100644 index 000000000..1dd4a7374 --- /dev/null +++ b/src/main/java/run/halo/app/model/enums/Mode.java @@ -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; + } +} diff --git a/src/main/java/run/halo/app/model/freemarker/tag/CommentTagDirective.java b/src/main/java/run/halo/app/model/freemarker/tag/CommentTagDirective.java index 8c6b15d01..9b01c571b 100644 --- a/src/main/java/run/halo/app/model/freemarker/tag/CommentTagDirective.java +++ b/src/main/java/run/halo/app/model/freemarker/tag/CommentTagDirective.java @@ -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())); diff --git a/src/main/java/run/halo/app/model/freemarker/tag/PhotoTagDirective.java b/src/main/java/run/halo/app/model/freemarker/tag/PhotoTagDirective.java index fc5ad3c14..16e55b374 100644 --- a/src/main/java/run/halo/app/model/freemarker/tag/PhotoTagDirective.java +++ b/src/main/java/run/halo/app/model/freemarker/tag/PhotoTagDirective.java @@ -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(); diff --git a/src/main/java/run/halo/app/model/params/MailParam.java b/src/main/java/run/halo/app/model/params/MailParam.java index d106a8ad1..70dae944e 100644 --- a/src/main/java/run/halo/app/model/params/MailParam.java +++ b/src/main/java/run/halo/app/model/params/MailParam.java @@ -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 = "主题不能为空") diff --git a/src/main/java/run/halo/app/model/properties/OtherProperties.java b/src/main/java/run/halo/app/model/properties/OtherProperties.java index e2be5d420..e3b370925 100644 --- a/src/main/java/run/halo/app/model/properties/OtherProperties.java +++ b/src/main/java/run/halo/app/model/properties/OtherProperties.java @@ -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, ""), /** * 是否禁止爬虫 diff --git a/src/main/java/run/halo/app/model/support/HaloConst.java b/src/main/java/run/halo/app/model/support/HaloConst.java index 49be00fa6..6455ea3aa 100644 --- a/src/main/java/run/halo/app/model/support/HaloConst.java +++ b/src/main/java/run/halo/app/model/support/HaloConst.java @@ -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; diff --git a/src/main/java/run/halo/app/service/CategoryService.java b/src/main/java/run/halo/app/service/CategoryService.java index e73e74d2e..7de4e678f 100755 --- a/src/main/java/run/halo/app/service/CategoryService.java +++ b/src/main/java/run/halo/app/service/CategoryService.java @@ -42,6 +42,7 @@ public interface CategoryService extends CrudService { * @param name name * @return Category */ + @Nullable Category getByName(@NonNull String name); /** diff --git a/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java b/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java index 9a6e2ca32..51b989f9b 100644 --- a/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/AdminServiceImpl.java @@ -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)); diff --git a/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java b/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java index 88df39af0..483b6308a 100644 --- a/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/BackupServiceImpl.java @@ -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 diff --git a/src/main/java/run/halo/app/service/impl/PostServiceImpl.java b/src/main/java/run/halo/app/service/impl/PostServiceImpl.java index 96666b825..d1130ea96 100644 --- a/src/main/java/run/halo/app/service/impl/PostServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/PostServiceImpl.java @@ -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 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; } diff --git a/src/main/java/run/halo/app/service/impl/UserServiceImpl.java b/src/main/java/run/halo/app/service/impl/UserServiceImpl.java index 091cd22eb..96b49b401 100644 --- a/src/main/java/run/halo/app/service/impl/UserServiceImpl.java +++ b/src/main/java/run/halo/app/service/impl/UserServiceImpl.java @@ -124,7 +124,7 @@ public class UserServiceImpl extends AbstractCrudService 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; } diff --git a/src/main/java/run/halo/app/utils/HaloUtils.java b/src/main/java/run/halo/app/utils/HaloUtils.java index 93125eb49..37354f7c6 100755 --- a/src/main/java/run/halo/app/utils/HaloUtils.java +++ b/src/main/java/run/halo/app/utils/HaloUtils.java @@ -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. * diff --git a/src/main/resources/templates/common/macro/common_macro.ftl b/src/main/resources/templates/common/macro/common_macro.ftl index 1df74279b..e78fcae64 100644 --- a/src/main/resources/templates/common/macro/common_macro.ftl +++ b/src/main/resources/templates/common/macro/common_macro.ftl @@ -10,9 +10,15 @@ ${options.blog_footer_info!} +<#macro custom_head> + ${options.blog_custom_head!} + + <#-- favicon --> <#macro favicon> - + <#if options.blog_favicon?? && options.blog_favicon!=''> + + <#-- 站点验证代码 --> @@ -46,11 +52,13 @@ <#macro globalHeader> - <@favicon /> + + <@custom_head /> <@verification /> + <@favicon /> <#macro globalFooter> - <@statistics /> <@footer_info /> + <@statistics /> \ No newline at end of file diff --git a/src/main/resources/templates/themes/anatole/module/comment.ftl b/src/main/resources/templates/themes/anatole/module/comment.ftl index 70cbbde08..6d10c96ac 100644 --- a/src/main/resources/templates/themes/anatole/module/comment.ftl +++ b/src/main/resources/templates/themes/anatole/module/comment.ftl @@ -1,7 +1,7 @@ <#macro comment post,type> <#if !post.disallowComment!false> - + \ No newline at end of file diff --git a/src/main/resources/templates/themes/anatole/module/macro.ftl b/src/main/resources/templates/themes/anatole/module/macro.ftl index 6d864f8ec..d91175955 100644 --- a/src/main/resources/templates/themes/anatole/module/macro.ftl +++ b/src/main/resources/templates/themes/anatole/module/macro.ftl @@ -1,4 +1,4 @@ -<#include "/common/macro/common_macro.ftl"> +<#import "/common/macro/common_macro.ftl" as common> <#macro head title,keywords,description> @@ -14,8 +14,7 @@ - <@verification /> - <@favicon /> + <@common.globalHeader /> @@ -77,7 +76,7 @@ xhr.send(); -<@statistics /> +<@common.statistics /> diff --git a/src/main/resources/templates/themes/anatole/module/sidebar.ftl b/src/main/resources/templates/themes/anatole/module/sidebar.ftl index fbd5a799d..91362ce1b 100644 --- a/src/main/resources/templates/themes/anatole/module/sidebar.ftl +++ b/src/main/resources/templates/themes/anatole/module/sidebar.ftl @@ -24,7 +24,7 @@ Proudly published with Halo! diff --git a/src/main/resources/templates/themes/anatole/theme.yaml b/src/main/resources/templates/themes/anatole/theme.yaml index 53cf5f148..235adea7e 100644 --- a/src/main/resources/templates/themes/anatole/theme.yaml +++ b/src/main/resources/templates/themes/anatole/theme.yaml @@ -7,4 +7,4 @@ description: A other Halo theme logo: https://avatars1.githubusercontent.com/u/1811819?s=460&v=4 website: https://github.com/halo-dev/halo-theme-anatole repo: https://github.com/halo-dev/halo-theme-anatole -version: 1.0 \ No newline at end of file +version: 1.0 diff --git a/src/test/java/run/halo/app/utils/HaloUtilsTest.java b/src/test/java/run/halo/app/utils/HaloUtilsTest.java index 7d207211e..64fe55bee 100644 --- a/src/test/java/run/halo/app/utils/HaloUtilsTest.java +++ b/src/test/java/run/halo/app/utils/HaloUtilsTest.java @@ -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); + } }