mirror of https://github.com/halo-dev/halo
release 1.0.3 (#235)
release 1.0.3 Co-authored-by: John Niang <johnniang@riseup.net>pull/286/head^2 v1.0.3
commit
117883fc8d
148
README-en_US.md
148
README-en_US.md
|
@ -1,148 +0,0 @@
|
|||

|
||||
|
||||
> Halo may be the best Java blog system.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://ryanc.cc"><img alt="Author" src="https://img.shields.io/badge/author-ruibaby-red.svg?style=flat-square"/></a>
|
||||
<a href="#"><img alt="JDK" src="https://img.shields.io/badge/JDK-1.8-yellow.svg?style=flat-square"/></a>
|
||||
<a href="https://github.com/ruibaby/halo/releases"><img alt="GitHub release" src="https://img.shields.io/github/release/ruibaby/halo.svg?style=flat-square"/></a>
|
||||
<a href="https://travis-ci.org/ruibaby/halo"><img alt="Travis CI" src="https://img.shields.io/travis/ruibaby/halo.svg?style=flat-square"/></a>
|
||||
<a href="https://hub.docker.com/r/ruibaby/halo/"><img alt="Docker Build Status" src="https://img.shields.io/docker/build/ruibaby/halo.svg?style=flat-square"/></a>
|
||||
</p>
|
||||
|
||||
------------------------------
|
||||
🇨🇳[简体中文](README.md) | 🇺🇸English
|
||||
|
||||
## Introduction
|
||||
|
||||
**Halo** [ˈheɪloʊ], Become the best blogging system using Java.
|
||||
|
||||
Fast, concise, and powerful blogging system developed in Java.
|
||||
|
||||
> QQ Group: 162747721,Telegram Group: [https://t.me/HaloBlog](https://t.me/HaloBlog) | Telegram Channel: [https://t.me/halo_dev](https://t.me/halo_dev) | [WeHalo 小程序](https://github.com/aquanlerou/WeHalo)。
|
||||
|
||||
## Demo
|
||||
|
||||
> Frontend: [https://demo.halo.run](https://demo.halo.run)
|
||||
> Backend: [https://demo.halo.run/admin](https://demo.halo.run/admin)
|
||||
> username: admin,password: 123456
|
||||
|
||||
## Quick start
|
||||
|
||||
Deploy with Docker:
|
||||
```bash
|
||||
# pull docker images
|
||||
$ docker pull ruibaby/halo
|
||||
|
||||
# create docker container and run it
|
||||
$ docker run -d --name halo -p 8090:8090 -v ~/halo:/root/halo ruibaby/halo
|
||||
|
||||
# Tips:DB_USER and DB_PASSWORD must be repaired and recorded
|
||||
```
|
||||
|
||||
Deploy with Docker compose:
|
||||
```bash
|
||||
# Download the nginx config file template
|
||||
$ curl https://raw.githubusercontent.com/jwilder/nginx-proxy/master/nginx.tmpl > /etc/nginx/nginx.tmpl
|
||||
|
||||
# Get the docker-compose.yaml
|
||||
$ yum install -y wget && wget -O docker-compose.yaml https://git.io/fpS8N
|
||||
|
||||
# Modify docker-compose.yaml
|
||||
# 1. modify VIRTUAL_HOST, LETSENCRYPT_HOST for your own domain name.
|
||||
# 2. modify LETSENCRYPT_EMAIL to your own mailbox.
|
||||
# 3. modify DB_USER .
|
||||
# 4. modify DB_PASSWORD .
|
||||
|
||||
# run
|
||||
$ docker-compose up -d
|
||||
```
|
||||
|
||||
Deploy with shell script:
|
||||
|
||||
```bash
|
||||
# install Halo
|
||||
$ yum install -y wget && wget -O halo-cli.sh https://git.io/fxHqp && bash halo-cli.sh -i
|
||||
|
||||
# upgrade Halo
|
||||
$ bash halo-cli.sh -u
|
||||
```
|
||||
|
||||
> Tips: If you use Idea, Eclipse and other IDEs to run, you need to install the Lombok plugin, In addition, JDK10 is not supported at the moment, and there are problems with themes scanning and uploading.
|
||||
> See the [Halo documentation](https://halo-doc.ryanc.cc/installation/) or [ Wiki](https://github.com/halo-dev/halo/wiki) for more details.
|
||||
|
||||
## Blogs with Halo
|
||||
|
||||
[Ryan0up'S Blog](https://ryanc.cc)
|
||||
|
||||
[SNAIL BLOG](https://slogc.cc)
|
||||
|
||||
[宋浩志博客](http://songhaozhi.com)
|
||||
|
||||
[KingYiFan'S Blog](https://blog.cnbuilder.cn)
|
||||
|
||||
[AquanBlog](https://blog.eunji.cn/)
|
||||
|
||||
## Themes
|
||||
|
||||
In addition to the built-in [Anatole](https://github.com/hi-caicai/farbox-theme-Anatole) and [Material](https://github.com/viosey/hexo-theme-material), there are the following The theme is not integrated in the project. If you need it, please download it and upload it through the background.
|
||||
|
||||
- [Vno](https://github.com/halo-dev/vno-halo) - From Jekyll,Author [Wei Wang](https://onevcat.com/).
|
||||
- [Hux](https://github.com/halo-dev/hux-halo) - From Jekyll,Author [Xuan Huang](https://huangxuan.me/).
|
||||
- [Story](https://github.com/halo-dev/story-halo) - From Typecho,Author [Trii Hsia](https://yumoe.com/).
|
||||
- [NexT](https://github.com/halo-dev/next-halo) - From Hexo,Author [iissnan](https://notes.iissnan.com/).
|
||||
- [Casper](https://github.com/halo-dev/casper-halo) - From Ghost,Author [Ghost](https://github.com/TryGhost).
|
||||
- [Pinghsu](https://github.com/halo-dev/pinghsu-halo) - From Typecho,Author [Chakhsu.Lau](https://github.com/chakhsu).
|
||||
|
||||
> Disclaimer: Do not accept any comments or suggestions on the functionality of the **Porting Theme**.
|
||||
|
||||
## License
|
||||
|
||||
[](https://github.com/halo-dev/halo/blob/master/LICENSE)
|
||||
|
||||
> Halo uses the GPL-v3.0 protocol to open source.
|
||||
|
||||
## Thanks
|
||||
|
||||
The birth of Halo is inseparable from the following projects:
|
||||
|
||||
- [Spring Boot](https://github.com/spring-projects/spring-boot): Spring's rapid development framework
|
||||
- [Freemarker](https://freemarker.apache.org/): Template engine to make pages static
|
||||
- [H2 Database](https://github.com/h2database/h2database): Embedded database, no need to install
|
||||
- [Spring-data-jpa](https://github.com/spring-projects/spring-data-jpa.git): a persistence layer framework that does not require writing sql statements
|
||||
- [Ehcache](http://www.ehcache.org/): Cache Framework
|
||||
- [Lombok](https://www.projectlombok.org/): Make the code simpler
|
||||
- [oh-my-email](https://github.com/biezhi/oh-my-email): Probably the smallest Java mailing library, support for CC, attachments, templates, etc.
|
||||
- [Hutool](https://github.com/looly/hutool): A Java Foundation Tools library
|
||||
- [Thumbnailator](https://github.com/coobird/thumbnailator): thumbnail generation library
|
||||
- [AdminLTE](https://github.com/almasaeed2010/AdminLTE): Bootstrap-based background template
|
||||
- [Bootstrap](https://github.com/twbs/bootstrap.git): The most widely used front-end ui framework
|
||||
- [Animate](https://github.com/daneden/animate.css.git): Very easy to use css effects library
|
||||
- [SimpleMDE - Markdown Editor](https://github.com/sparksuite/simplemde-markdown-editor): Simple, functional, and lightweight Markdown editor
|
||||
- [Bootstrap-FileInput](https://github.com/kartik-v/bootstrap-fileinput.git): Bootstrap-based file upload component
|
||||
- [Font-awesome](https://github.com/FortAwesome/Font-Awesome.git): the most widely used font icon library
|
||||
- [JQuery](https://github.com/jquery/jquery.git): The most widely used JavaScript framework
|
||||
- [Layer](https://github.com/sentsin/layer.git): Personally think that the most practical and best-looking pop-up layer component, no one
|
||||
- [JQuery-Toast](https://github.com/kamranahmedse/jquery-toast-plugin)
|
||||
: message prompt component
|
||||
- [Pjax](https://github.com/defunkt/jquery-pjax.git): pushState + ajax = pjax
|
||||
|
||||
## Donate
|
||||
|
||||
> If Halo is helpful to you, ask the author to have a ☕.
|
||||
|
||||
| AliPay/WeChat/QQ/PayPal |
|
||||
| :------------: |
|
||||
| <img src="https://i.loli.net/2018/12/23/5c1f68ce9b884.png" width="200"/> |
|
||||
|
||||
## Interface display
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
|
@ -26,13 +26,13 @@
|
|||
### 下载最新的 Halo 安装包
|
||||
|
||||
```bash
|
||||
curl -L https://github.com/halo-dev/halo/releases/download/v1.0.2/halo-1.0.2.jar --output halo-latest.jar
|
||||
curl -L https://github.com/halo-dev/halo/releases/download/v1.0.3/halo-1.0.3.jar --output halo-latest.jar
|
||||
```
|
||||
|
||||
或者
|
||||
|
||||
```bash
|
||||
wget https://github.com/halo-dev/halo/releases/download/v1.0.2/halo-1.0.2.jar -O halo-latest.jar
|
||||
wget https://github.com/halo-dev/halo/releases/download/v1.0.3/halo-1.0.3.jar -O halo-latest.jar
|
||||
```
|
||||
|
||||
### 启动 Halo
|
||||
|
|
23
build.gradle
23
build.gradle
|
@ -9,7 +9,7 @@ apply plugin: 'io.spring.dependency-management'
|
|||
|
||||
group = 'run.halo.app'
|
||||
archivesBaseName = 'halo'
|
||||
version = '1.0.2'
|
||||
version = '1.0.3'
|
||||
sourceCompatibility = '1.8'
|
||||
description = 'Halo, personal blog system developed in Java.'
|
||||
|
||||
|
@ -55,13 +55,6 @@ dependencies {
|
|||
implementation 'com.qiniu:qiniu-java-sdk:7.2.18'
|
||||
implementation 'com.aliyun.oss:aliyun-sdk-oss:3.4.2'
|
||||
implementation 'net.coobird:thumbnailator:0.4.8'
|
||||
implementation 'com.atlassian.commonmark:commonmark:0.12.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark-ext-gfm-tables:0.12.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark-ext-yaml-front-matter:0.12.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark-ext-autolink:0.12.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark-ext-gfm-strikethrough:0.12.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark-ext-heading-anchor:0.12.1'
|
||||
implementation 'com.atlassian.commonmark:commonmark-ext-ins:0.12.1'
|
||||
implementation 'io.springfox:springfox-swagger2:2.9.2'
|
||||
implementation 'io.springfox:springfox-swagger-ui:2.9.2'
|
||||
implementation 'org.apache.commons:commons-lang3:3.8.1'
|
||||
|
@ -69,6 +62,20 @@ dependencies {
|
|||
implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.9.2'
|
||||
implementation 'org.eclipse.jgit:org.eclipse.jgit:5.3.0.201903130848-r'
|
||||
|
||||
implementation 'com.vladsch.flexmark:flexmark:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-attributes:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-autolink:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-emoji:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-escaped-character:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-gfm-strikethrough:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-gfm-tasklist:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-ins:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-media-tags:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-tables:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-toc:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-ext-yaml-front-matter:0.42.12'
|
||||
implementation 'com.vladsch.flexmark:flexmark-html-parser:0.42.12'
|
||||
|
||||
runtimeOnly 'com.h2database:h2'
|
||||
runtimeOnly 'mysql:mysql-connector-java'
|
||||
|
||||
|
|
|
@ -147,18 +147,24 @@ public class SwaggerConfiguration {
|
|||
private List<SecurityContext> contentSecurityContext() {
|
||||
return Collections.singletonList(
|
||||
SecurityContext.builder()
|
||||
.securityReferences(defaultAuth())
|
||||
.securityReferences(contentApiAuth())
|
||||
.forPaths(PathSelectors.regex("/api/content/.*"))
|
||||
.build()
|
||||
);
|
||||
}
|
||||
|
||||
private List<SecurityReference> defaultAuth() {
|
||||
AuthorizationScope[] authorizationScopes = {new AuthorizationScope("global", "accessEverything")};
|
||||
AuthorizationScope[] authorizationScopes = {new AuthorizationScope("Admin api", "Access admin api")};
|
||||
return Arrays.asList(new SecurityReference("Token from header", authorizationScopes),
|
||||
new SecurityReference("Token from query", authorizationScopes));
|
||||
}
|
||||
|
||||
private List<SecurityReference> contentApiAuth() {
|
||||
AuthorizationScope[] authorizationScopes = {new AuthorizationScope("content api", "Access content api")};
|
||||
return Arrays.asList(new SecurityReference("Access key from header", authorizationScopes),
|
||||
new SecurityReference("Access key from query", authorizationScopes));
|
||||
}
|
||||
|
||||
private ApiInfo apiInfo() {
|
||||
return new ApiInfoBuilder()
|
||||
.title("Halo API Documentation")
|
||||
|
|
|
@ -81,13 +81,11 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer {
|
|||
@Override
|
||||
public void addResourceHandlers(ResourceHandlerRegistry registry) {
|
||||
String workDir = FILE_PROTOCOL + haloProperties.getWorkDir();
|
||||
registry.addResourceHandler("/static/**")
|
||||
.addResourceLocations("classpath:/static/")
|
||||
.addResourceLocations(workDir + "static/");
|
||||
registry.addResourceHandler("/**")
|
||||
.addResourceLocations(workDir + "templates/themes/")
|
||||
.addResourceLocations(workDir + "templates/admin/")
|
||||
.addResourceLocations("classpath:/admin/");
|
||||
.addResourceLocations("classpath:/admin/")
|
||||
.addResourceLocations(workDir + "static/");
|
||||
registry.addResourceHandler("/upload/**")
|
||||
.addResourceLocations(workDir + "upload/");
|
||||
registry.addResourceHandler("/backup/**")
|
||||
|
@ -122,7 +120,7 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer {
|
|||
configurer.setDefaultEncoding("UTF-8");
|
||||
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty("auto_import", "/common/macro/common_macro.ftl as common");
|
||||
properties.setProperty("auto_import", "/common/macro/common_macro.ftl as common,/common/macro/global_macro.ftl as global");
|
||||
|
||||
configurer.setFreemarkerSettings(properties);
|
||||
|
||||
|
|
|
@ -2,11 +2,13 @@ package run.halo.app.controller.admin.api;
|
|||
|
||||
import io.swagger.annotations.ApiOperation;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import run.halo.app.cache.lock.CacheLock;
|
||||
import run.halo.app.model.dto.EnvironmentDTO;
|
||||
import run.halo.app.model.dto.StatisticDTO;
|
||||
import run.halo.app.model.params.LoginParam;
|
||||
import run.halo.app.model.support.BaseResponse;
|
||||
import run.halo.app.security.token.AuthToken;
|
||||
import run.halo.app.service.AdminService;
|
||||
|
||||
|
@ -16,6 +18,7 @@ import javax.validation.Valid;
|
|||
* Admin controller.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 3/19/19
|
||||
*/
|
||||
@Slf4j
|
||||
|
@ -73,4 +76,9 @@ public class AdminController {
|
|||
adminService.updateAdminAssets();
|
||||
}
|
||||
|
||||
@GetMapping("spring/logs")
|
||||
@ApiOperation("Get application logs")
|
||||
public BaseResponse<String> getSpringLogs() {
|
||||
return BaseResponse.ok(HttpStatus.OK.getReasonPhrase(),adminService.getSpringLogs());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ public class RecoveryController {
|
|||
@ApiParam("This file content type should be json")
|
||||
@RequestPart("file") MultipartFile file) {
|
||||
if (optionService.getByPropertyOrDefault(PrimaryProperties.IS_INSTALLED, Boolean.class, false)) {
|
||||
throw new BadRequestException("不能在博客初始化完成之后迁移数据");
|
||||
throw new BadRequestException("无法在博客初始化完成之后迁移数据");
|
||||
}
|
||||
|
||||
recoveryService.migrateFromV0_4_3(file);
|
||||
|
|
|
@ -13,12 +13,15 @@ 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.model.enums.PostStatus;
|
||||
import run.halo.app.model.vo.PostListVO;
|
||||
import run.halo.app.service.*;
|
||||
|
||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||
|
||||
/**
|
||||
* Category controller.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019/3/20
|
||||
*/
|
||||
|
@ -85,10 +88,10 @@ public class ContentCategoryController {
|
|||
@PathVariable("page") Integer page,
|
||||
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
|
||||
// Get category by slug name
|
||||
final Category category = categoryService.getBySlugName(slugName);
|
||||
final Category category = categoryService.getBySlugNameOfNonNull(slugName);
|
||||
|
||||
final Pageable pageable = PageRequest.of(page - 1, optionService.getPostPageSize(), sort);
|
||||
Page<Post> postPage = postCategoryService.pagePostBy(category.getId(), pageable);
|
||||
Page<Post> postPage = postCategoryService.pagePostBy(category.getId(), PostStatus.PUBLISHED, pageable);
|
||||
Page<PostListVO> posts = postService.convertToListVo(postPage);
|
||||
final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3);
|
||||
|
||||
|
|
|
@ -22,7 +22,7 @@ import run.halo.app.service.ThemeService;
|
|||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||
|
||||
/**
|
||||
* Search Controller
|
||||
* Search controller.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-04-21
|
||||
|
|
|
@ -13,13 +13,14 @@ import org.springframework.web.bind.annotation.PathVariable;
|
|||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.entity.Tag;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.vo.PostListVO;
|
||||
import run.halo.app.service.*;
|
||||
|
||||
import static org.springframework.data.domain.Sort.Direction.DESC;
|
||||
|
||||
/**
|
||||
* Tag Controller
|
||||
* Tag controller.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-21
|
||||
|
@ -91,7 +92,7 @@ public class ContentTagController {
|
|||
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<Post> postPage = postTagService.pagePostsBy(tag.getId(), PostStatus.PUBLISHED, pageable);
|
||||
Page<PostListVO> posts = postService.convertToListVo(postPage);
|
||||
final int[] rainbow = PageUtil.rainbow(page, posts.getTotalPages(), 3);
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import javax.servlet.http.HttpServletResponse;
|
|||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* Admin page.
|
||||
* Main controller.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-04-23
|
||||
|
|
|
@ -11,6 +11,7 @@ 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.model.enums.PostStatus;
|
||||
import run.halo.app.service.CategoryService;
|
||||
import run.halo.app.service.PostCategoryService;
|
||||
import run.halo.app.service.PostService;
|
||||
|
@ -58,9 +59,9 @@ public class CategoryController {
|
|||
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);
|
||||
Category category = categoryService.getBySlugNameOfNonNull(slugName);
|
||||
|
||||
Page<Post> postPage = postCategoryService.pagePostBy(category.getId(), pageable);
|
||||
Page<Post> postPage = postCategoryService.pagePostBy(category.getId(), PostStatus.PUBLISHED, pageable);
|
||||
return postService.convertToSimple(postPage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ import run.halo.app.model.dto.TagDTO;
|
|||
import run.halo.app.model.dto.post.BasePostSimpleDTO;
|
||||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.entity.Tag;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.service.PostService;
|
||||
import run.halo.app.service.PostTagService;
|
||||
import run.halo.app.service.TagService;
|
||||
|
@ -24,6 +25,7 @@ import static org.springframework.data.domain.Sort.Direction.DESC;
|
|||
* Portal tag controller.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 4/2/19
|
||||
*/
|
||||
@RestController("ApiContentTagController")
|
||||
|
@ -63,7 +65,7 @@ public class TagController {
|
|||
Tag tag = tagService.getBySlugNameOfNonNull(slugName);
|
||||
|
||||
// Get posts, convert and return
|
||||
Page<Post> postPage = postTagService.pagePostsBy(tag.getId(), pageable);
|
||||
Page<Post> postPage = postTagService.pagePostsBy(tag.getId(), PostStatus.PUBLISHED, pageable);
|
||||
return postService.convertToSimple(postPage);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ import static run.halo.app.utils.BeanUtils.updateProperties;
|
|||
* <b>The implementation type must be equal to DTO type</b>
|
||||
*
|
||||
* @param <DTO> the implementation class type
|
||||
* @param <DOMAIN> doamin type
|
||||
* @param <DOMAIN> domain type
|
||||
* @author johnniang
|
||||
*/
|
||||
public interface OutputConverter<DTO extends OutputConverter<DTO, DOMAIN>, DOMAIN> {
|
||||
|
|
|
@ -5,7 +5,6 @@ import lombok.EqualsAndHashCode;
|
|||
import lombok.ToString;
|
||||
import run.halo.app.model.enums.PostCreateFrom;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.utils.MarkdownUtils;
|
||||
|
||||
import javax.persistence.*;
|
||||
import java.util.Date;
|
||||
|
@ -54,7 +53,7 @@ public class BasePost extends BaseEntity {
|
|||
/**
|
||||
* Rendered content.
|
||||
*
|
||||
* @see MarkdownUtils#renderMarkdown(String)
|
||||
* @see run.halo.app.utils.MarkdownUtils#renderHtml(String)
|
||||
*/
|
||||
@Column(name = "format_content", columnDefinition = "text not null")
|
||||
private String formatContent;
|
||||
|
|
|
@ -45,6 +45,7 @@ public class CategoryTagDirective implements TemplateDirectiveModel {
|
|||
case "listByPostId":
|
||||
Integer postId = Integer.parseInt(params.get("postId").toString());
|
||||
env.setVariable("categories", builder.build().wrap(postCategoryService.listCategoryBy(postId)));
|
||||
break;
|
||||
case "count":
|
||||
env.setVariable("count", builder.build().wrap(categoryService.count()));
|
||||
break;
|
||||
|
|
|
@ -3,6 +3,7 @@ package run.halo.app.model.freemarker.tag;
|
|||
import freemarker.core.Environment;
|
||||
import freemarker.template.*;
|
||||
import org.springframework.stereotype.Component;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.support.HaloConst;
|
||||
import run.halo.app.service.PostCategoryService;
|
||||
import run.halo.app.service.PostService;
|
||||
|
@ -57,11 +58,11 @@ public class PostTagDirective implements TemplateDirectiveModel {
|
|||
break;
|
||||
case "listByCategoryId":
|
||||
Integer categoryId = Integer.parseInt(params.get("categoryId").toString());
|
||||
env.setVariable("posts", builder.build().wrap(postCategoryService.listPostBy(categoryId)));
|
||||
env.setVariable("posts", builder.build().wrap(postCategoryService.listPostBy(categoryId, PostStatus.PUBLISHED)));
|
||||
break;
|
||||
case "listByTagId":
|
||||
Integer tagId = Integer.parseInt(params.get("tagId").toString());
|
||||
env.setVariable("posts", builder.build().wrap(postTagService.listPostsBy(tagId)));
|
||||
env.setVariable("posts", builder.build().wrap(postTagService.listPostsBy(tagId, PostStatus.PUBLISHED)));
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
package run.halo.app.model.properties;
|
||||
|
||||
/**
|
||||
* Api properties.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date 2019-06-25
|
||||
*/
|
||||
public enum ApiProperties implements PropertyEnum {
|
||||
|
||||
API_ENABLED("api_enabled", Boolean.class, "false"),
|
||||
|
||||
API_ACCESS_KEY("api_access_key", String.class, "");
|
||||
|
||||
private final String value;
|
||||
|
||||
private final Class<?> type;
|
||||
|
||||
private final String defaultValue;
|
||||
|
||||
ApiProperties(String value, Class<?> type, String defaultValue) {
|
||||
this.value = value;
|
||||
this.type = type;
|
||||
this.defaultValue = defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Class<?> getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String defaultValue() {
|
||||
return defaultValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
}
|
|
@ -4,22 +4,14 @@ package run.halo.app.model.properties;
|
|||
* Other properties.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 4/1/19
|
||||
*/
|
||||
public enum OtherProperties implements PropertyEnum {
|
||||
|
||||
API_ENABLED("api_enabled", Boolean.class, "false"),
|
||||
|
||||
API_ACCESS_KEY("api_access_key", String.class, ""),
|
||||
|
||||
CUSTOM_HEAD("blog_custom_head",String.class,""),
|
||||
|
||||
STATISTICS_CODE("blog_statistics_code", String.class, ""),
|
||||
|
||||
/**
|
||||
* 是否禁止爬虫
|
||||
*/
|
||||
SPIDER_DISABLED("spider_disabled", Boolean.class, "false");
|
||||
STATISTICS_CODE("blog_statistics_code", String.class, "");
|
||||
|
||||
private final String value;
|
||||
|
||||
|
|
|
@ -154,6 +154,7 @@ public interface PropertyEnum extends ValueEnum<String> {
|
|||
propertyEnumClasses.add(QnYunProperties.class);
|
||||
propertyEnumClasses.add(SeoProperties.class);
|
||||
propertyEnumClasses.add(UpYunProperties.class);
|
||||
propertyEnumClasses.add(ApiProperties.class);
|
||||
|
||||
Map<String, PropertyEnum> result = new HashMap<>();
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ package run.halo.app.model.properties;
|
|||
* SEO properties.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 4/1/19
|
||||
*/
|
||||
public enum SeoProperties implements PropertyEnum {
|
||||
|
@ -14,13 +15,10 @@ public enum SeoProperties implements PropertyEnum {
|
|||
|
||||
BAIDU_TOKEN("seo_baidu_token", String.class, ""),
|
||||
|
||||
VERIFICATION_BAIDU("seo_verification_baidu", String.class, ""),
|
||||
|
||||
VERIFICATION_GOOGLE("seo_verification_google", String.class, ""),
|
||||
|
||||
VERIFICATION_BING("seo_verification_bing", String.class, ""),
|
||||
|
||||
VERIFICATION_QIHU("seo_verification_qihu", String.class, "");
|
||||
/**
|
||||
* 是否禁止爬虫
|
||||
*/
|
||||
SPIDER_DISABLED("seo_spider_disabled", Boolean.class, "false");
|
||||
|
||||
private final String value;
|
||||
|
||||
|
|
|
@ -1,36 +0,0 @@
|
|||
package run.halo.app.model.support;
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* 日志常量
|
||||
* </pre>
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2018/1/19
|
||||
*/
|
||||
public interface LogsRecord {
|
||||
|
||||
String INSTALL = "初始化博客";
|
||||
|
||||
String LOGIN = "登录后台";
|
||||
|
||||
String LOGIN_SUCCESS = "登录成功";
|
||||
|
||||
String LOGIN_ERROR = "登录失败";
|
||||
|
||||
String LOGOUT = "退出登录";
|
||||
|
||||
String PUSH_POST = "发表文章";
|
||||
|
||||
String PUSH_PAGE = "发表页面";
|
||||
|
||||
String REMOVE_POST = "删除文章";
|
||||
|
||||
String CHANGE_THEME = "更换主题";
|
||||
|
||||
String UPLOAD_THEME = "上传主题";
|
||||
|
||||
String UPLOAD_FILE = "上传附件";
|
||||
|
||||
String REMOVE_FILE = "移除附件";
|
||||
}
|
|
@ -17,6 +17,7 @@ public class QiNiuPutSet {
|
|||
* 文件hash值
|
||||
*/
|
||||
public String hash;
|
||||
|
||||
/**
|
||||
* 文件名
|
||||
*/
|
||||
|
|
|
@ -3,6 +3,7 @@ package run.halo.app.repository;
|
|||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.lang.NonNull;
|
||||
import run.halo.app.model.entity.PostCategory;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.projection.CategoryPostCountProjection;
|
||||
import run.halo.app.repository.base.BaseRepository;
|
||||
|
||||
|
@ -14,6 +15,8 @@ import java.util.Set;
|
|||
* Post category repository.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 2019-03-19
|
||||
*/
|
||||
public interface PostCategoryRepository extends BaseRepository<PostCategory, Integer> {
|
||||
|
||||
|
@ -37,6 +40,17 @@ public interface PostCategoryRepository extends BaseRepository<PostCategory, Int
|
|||
@Query("select postCategory.postId from PostCategory postCategory where postCategory.categoryId = ?1")
|
||||
Set<Integer> findAllPostIdsByCategoryId(@NonNull Integer categoryId);
|
||||
|
||||
/**
|
||||
* Finds all post ids by category id and post status.
|
||||
*
|
||||
* @param categoryId category id must not be null
|
||||
* @param status post status must not be null
|
||||
* @return a set of post id
|
||||
*/
|
||||
@NonNull
|
||||
@Query("select postCategory.postId from PostCategory postCategory, Post post where postCategory.categoryId = ?1 and post.id = postCategory.postId and post.status = ?2")
|
||||
Set<Integer> findAllPostIdsByCategoryId(@NonNull Integer categoryId, @NonNull PostStatus status);
|
||||
|
||||
/**
|
||||
* Finds all post categories by post id in.
|
||||
*
|
||||
|
|
|
@ -3,6 +3,7 @@ package run.halo.app.repository;
|
|||
import org.springframework.data.jpa.repository.Query;
|
||||
import org.springframework.lang.NonNull;
|
||||
import run.halo.app.model.entity.PostTag;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.projection.TagPostPostCountProjection;
|
||||
import run.halo.app.repository.base.BaseRepository;
|
||||
|
||||
|
@ -14,6 +15,8 @@ import java.util.Set;
|
|||
* Post tag repository.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 2019-03-19
|
||||
*/
|
||||
public interface PostTagRepository extends BaseRepository<PostTag, Integer> {
|
||||
|
||||
|
@ -55,6 +58,17 @@ public interface PostTagRepository extends BaseRepository<PostTag, Integer> {
|
|||
@NonNull
|
||||
Set<Integer> findAllPostIdsByTagId(@NonNull Integer tagId);
|
||||
|
||||
/**
|
||||
* Finds all post id by tag id and post status.
|
||||
*
|
||||
* @param tagId tag id must not be null
|
||||
* @param status post status
|
||||
* @return a set of post id
|
||||
*/
|
||||
@Query("select postTag.postId from PostTag postTag,Post post where postTag.tagId = ?1 and post.id = postTag.postId and post.status = ?2")
|
||||
@NonNull
|
||||
Set<Integer> findAllPostIdsByTagId(@NonNull Integer tagId, @NonNull PostStatus status);
|
||||
|
||||
/**
|
||||
* Finds all tags by post id in.
|
||||
*
|
||||
|
|
|
@ -8,8 +8,8 @@ import org.springframework.util.Assert;
|
|||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.exception.AuthenticationException;
|
||||
import run.halo.app.exception.ForbiddenException;
|
||||
import run.halo.app.model.properties.ApiProperties;
|
||||
import run.halo.app.model.properties.CommentProperties;
|
||||
import run.halo.app.model.properties.OtherProperties;
|
||||
import run.halo.app.service.OptionService;
|
||||
|
||||
import javax.servlet.FilterChain;
|
||||
|
@ -48,7 +48,7 @@ public class ApiAuthenticationFilter extends AbstractAuthenticationFilter {
|
|||
}
|
||||
|
||||
// Get api_enable from option
|
||||
Boolean apiEnabled = optionService.getByPropertyOrDefault(OtherProperties.API_ENABLED, Boolean.class, false);
|
||||
Boolean apiEnabled = optionService.getByPropertyOrDefault(ApiProperties.API_ENABLED, Boolean.class, false);
|
||||
|
||||
if (!apiEnabled) {
|
||||
getFailureHandler().onFailure(request, response, new ForbiddenException("API has been disabled by blogger currently"));
|
||||
|
@ -65,7 +65,7 @@ public class ApiAuthenticationFilter extends AbstractAuthenticationFilter {
|
|||
}
|
||||
|
||||
// Get access key from option
|
||||
Optional<String> optionalAccessKey = optionService.getByProperty(OtherProperties.API_ACCESS_KEY, String.class);
|
||||
Optional<String> optionalAccessKey = optionService.getByProperty(ApiProperties.API_ACCESS_KEY, String.class);
|
||||
|
||||
if (!optionalAccessKey.isPresent()) {
|
||||
// If the access key is not set
|
||||
|
|
|
@ -7,11 +7,11 @@ import run.halo.app.model.params.LoginParam;
|
|||
import run.halo.app.security.token.AuthToken;
|
||||
|
||||
/**
|
||||
* Admin service.
|
||||
* Admin service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 19-4-29
|
||||
* @date 2019-04-29
|
||||
*/
|
||||
public interface AdminService {
|
||||
|
||||
|
@ -26,6 +26,8 @@ public interface AdminService {
|
|||
|
||||
String REFRESH_TOKEN_CACHE_PREFIX = "halo.admin.refresh_token.";
|
||||
|
||||
String LOGS_PATH = "logs/spring.log";
|
||||
|
||||
/**
|
||||
* Authenticates.
|
||||
*
|
||||
|
@ -69,4 +71,10 @@ public interface AdminService {
|
|||
* Updates halo admin assets.
|
||||
*/
|
||||
void updateAdminAssets();
|
||||
|
||||
/**
|
||||
* Get spring logs.
|
||||
* @return recently logs.
|
||||
*/
|
||||
String getSpringLogs();
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import java.util.List;
|
|||
* Attachment service.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date : 2019-03-14
|
||||
*/
|
||||
public interface AttachmentService extends CrudService<Attachment, Integer> {
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.io.IOException;
|
|||
* Backup service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-26
|
||||
* @date 2019-04-26
|
||||
*/
|
||||
public interface BackupService {
|
||||
|
||||
|
|
|
@ -15,7 +15,10 @@ import java.util.List;
|
|||
* Category service.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
*/
|
||||
@Transactional(readOnly = true)
|
||||
public interface CategoryService extends CrudService<Category, Integer> {
|
||||
|
||||
/**
|
||||
|
@ -36,6 +39,15 @@ public interface CategoryService extends CrudService<Category, Integer> {
|
|||
@NonNull
|
||||
Category getBySlugName(@NonNull String slugName);
|
||||
|
||||
/**
|
||||
* Get category by slug name
|
||||
*
|
||||
* @param slugName slug name
|
||||
* @return Category
|
||||
*/
|
||||
@NonNull
|
||||
Category getBySlugNameOfNonNull(String slugName);
|
||||
|
||||
/**
|
||||
* Get Category by name.
|
||||
*
|
||||
|
|
|
@ -13,7 +13,7 @@ import java.util.List;
|
|||
* Journal comment service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-25
|
||||
* @date 2019-04-25
|
||||
*/
|
||||
public interface JournalCommentService extends BaseCommentService<JournalComment> {
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ import java.util.List;
|
|||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 19-4-24
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
public interface JournalService extends CrudService<Journal, Integer> {
|
||||
|
||||
|
|
|
@ -11,9 +11,10 @@ import run.halo.app.service.base.CrudService;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Link service.
|
||||
* Link service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface LinkService extends CrudService<Link, Integer> {
|
||||
|
||||
|
|
|
@ -6,9 +6,10 @@ import run.halo.app.model.entity.Log;
|
|||
import run.halo.app.service.base.CrudService;
|
||||
|
||||
/**
|
||||
* Log service.
|
||||
* Log service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface LogService extends CrudService<Log, Long> {
|
||||
|
||||
|
|
|
@ -3,10 +3,10 @@ package run.halo.app.service;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Mail server
|
||||
* Mail service interface.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-17
|
||||
* @date 2019-03-17
|
||||
*/
|
||||
public interface MailService {
|
||||
|
||||
|
|
|
@ -11,10 +11,11 @@ import run.halo.app.service.base.CrudService;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Menu service.
|
||||
* Menu service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface MenuService extends CrudService<Menu, Integer> {
|
||||
|
||||
|
|
|
@ -18,9 +18,10 @@ import java.util.Map;
|
|||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Option service.
|
||||
* Option service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface OptionService extends CrudService<Option, Integer> {
|
||||
|
||||
|
|
|
@ -14,9 +14,10 @@ import run.halo.app.service.base.CrudService;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Photo service.
|
||||
* Photo service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface PhotoService extends CrudService<Photo, Integer> {
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import run.halo.app.model.dto.CategoryWithPostCountDTO;
|
|||
import run.halo.app.model.entity.Category;
|
||||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.entity.PostCategory;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.service.base.CrudService;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -21,7 +22,8 @@ import java.util.Set;
|
|||
* Post category service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 3/19/19
|
||||
* @author ryanwang
|
||||
* @date 2019-03-19
|
||||
*/
|
||||
public interface PostCategoryService extends CrudService<PostCategory, Integer> {
|
||||
|
||||
|
@ -52,6 +54,16 @@ public interface PostCategoryService extends CrudService<PostCategory, Integer>
|
|||
@NonNull
|
||||
List<Post> listPostBy(@NonNull Integer categoryId);
|
||||
|
||||
/**
|
||||
* Lists post by category id and post status.
|
||||
*
|
||||
* @param categoryId category id must not be null
|
||||
* @param status post status
|
||||
* @return a list of post
|
||||
*/
|
||||
@NonNull
|
||||
List<Post> listPostBy(@NonNull Integer categoryId, @NonNull PostStatus status);
|
||||
|
||||
/**
|
||||
* Pages post by category slug name.
|
||||
*
|
||||
|
@ -62,6 +74,17 @@ public interface PostCategoryService extends CrudService<PostCategory, Integer>
|
|||
@NonNull
|
||||
Page<Post> pagePostBy(@NonNull Integer categoryId, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Pages post by category slug name and post status.
|
||||
*
|
||||
* @param categoryId category id must not be null
|
||||
* @param status post status
|
||||
* @param pageable pageable
|
||||
* @return page of post
|
||||
*/
|
||||
@NonNull
|
||||
Page<Post> pagePostBy(@NonNull Integer categoryId, @NonNull PostStatus status, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Merges or creates post categories by post id and category id set if absent.
|
||||
*
|
||||
|
|
|
@ -12,9 +12,10 @@ import run.halo.app.service.base.BaseCommentService;
|
|||
import java.util.List;
|
||||
|
||||
/**
|
||||
* PostComment service.
|
||||
* Post comment service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface PostCommentService extends BaseCommentService<PostComment> {
|
||||
|
||||
|
|
|
@ -17,10 +17,11 @@ import java.util.List;
|
|||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Post service.
|
||||
* Post service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface PostService extends BasePostService<Post> {
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ import run.halo.app.model.dto.TagWithPostCountDTO;
|
|||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.entity.PostTag;
|
||||
import run.halo.app.model.entity.Tag;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.service.base.CrudService;
|
||||
|
||||
import java.util.Collection;
|
||||
|
@ -21,7 +22,8 @@ import java.util.Set;
|
|||
* Post tag service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 3/19/19
|
||||
* @author ryanwang
|
||||
* @date 2019-03-19
|
||||
*/
|
||||
public interface PostTagService extends CrudService<PostTag, Integer> {
|
||||
|
||||
|
@ -61,6 +63,16 @@ public interface PostTagService extends CrudService<PostTag, Integer> {
|
|||
@NonNull
|
||||
List<Post> listPostsBy(@NonNull Integer tagId);
|
||||
|
||||
/**
|
||||
* Lists posts by tag id and post status.
|
||||
*
|
||||
* @param tagId tag id must not be null
|
||||
* @param status post status
|
||||
* @return a list of post
|
||||
*/
|
||||
@NonNull
|
||||
List<Post> listPostsBy(@NonNull Integer tagId, @NonNull PostStatus status);
|
||||
|
||||
/**
|
||||
* Pages posts by tag id.
|
||||
*
|
||||
|
@ -70,6 +82,16 @@ public interface PostTagService extends CrudService<PostTag, Integer> {
|
|||
*/
|
||||
Page<Post> pagePostsBy(@NonNull Integer tagId, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Pages posts by tag id and post status.
|
||||
*
|
||||
* @param tagId must not be null
|
||||
* @param status post status
|
||||
* @param pageable must not be null
|
||||
* @return a page of post
|
||||
*/
|
||||
Page<Post> pagePostsBy(@NonNull Integer tagId, @NonNull PostStatus status, Pageable pageable);
|
||||
|
||||
/**
|
||||
* Merges or creates post tags by post id and tag id set if absent.
|
||||
*
|
||||
|
|
|
@ -7,7 +7,7 @@ import org.springframework.web.multipart.MultipartFile;
|
|||
* Recovery service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-26
|
||||
* @date 2019-04-26
|
||||
*/
|
||||
public interface RecoveryService {
|
||||
|
||||
|
|
|
@ -13,7 +13,7 @@ import java.util.List;
|
|||
* Sheet comment service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-24
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
public interface SheetCommentService extends BaseCommentService<SheetComment> {
|
||||
|
||||
|
|
|
@ -15,7 +15,7 @@ import java.util.List;
|
|||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 19-4-24
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
public interface SheetService extends BasePostService<Sheet> {
|
||||
|
||||
|
|
|
@ -8,11 +8,12 @@ import run.halo.app.service.base.CrudService;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
/**
|
||||
* Tag service.
|
||||
* Tag service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface TagService extends CrudService<Tag, Integer> {
|
||||
|
||||
|
@ -25,6 +26,15 @@ public interface TagService extends CrudService<Tag, Integer> {
|
|||
@NonNull
|
||||
Tag getBySlugNameOfNonNull(@NonNull String slugName);
|
||||
|
||||
/**
|
||||
* Get tag by slug name
|
||||
*
|
||||
* @param slugName slug name
|
||||
* @return tag
|
||||
*/
|
||||
@NonNull
|
||||
Tag getBySlugName(@NonNull String slugName);
|
||||
|
||||
/**
|
||||
* Get tag by tag name.
|
||||
*
|
||||
|
|
|
@ -14,8 +14,10 @@ import java.util.Optional;
|
|||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Theme service interface.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019/3/26
|
||||
* @date 2019-03-26
|
||||
*/
|
||||
public interface ThemeService {
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import java.util.Map;
|
|||
* Theme setting service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 4/8/19
|
||||
* @date 2019-04-08
|
||||
*/
|
||||
public interface ThemeSettingService {
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ import java.util.List;
|
|||
* Trace service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-6-18
|
||||
* @date 2019-06-18
|
||||
*/
|
||||
public interface TraceService {
|
||||
|
||||
|
|
|
@ -11,9 +11,10 @@ import run.halo.app.service.base.CrudService;
|
|||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* User service.
|
||||
* User service interface.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
public interface UserService extends CrudService<User, Integer> {
|
||||
|
||||
|
|
|
@ -1,8 +1,10 @@
|
|||
package run.halo.app.service.impl;
|
||||
|
||||
import cn.hutool.core.io.file.FileReader;
|
||||
import cn.hutool.core.lang.Validator;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.ApplicationEventPublisher;
|
||||
import org.springframework.http.ResponseEntity;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
@ -10,6 +12,7 @@ import org.springframework.util.Assert;
|
|||
import org.springframework.web.client.RestTemplate;
|
||||
import run.halo.app.cache.StringCacheStore;
|
||||
import run.halo.app.config.properties.HaloProperties;
|
||||
import run.halo.app.event.logger.LogEvent;
|
||||
import run.halo.app.exception.BadRequestException;
|
||||
import run.halo.app.exception.NotFoundException;
|
||||
import run.halo.app.exception.ServiceException;
|
||||
|
@ -17,6 +20,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.LogType;
|
||||
import run.halo.app.model.enums.Mode;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.params.LoginParam;
|
||||
|
@ -29,6 +33,7 @@ import run.halo.app.service.*;
|
|||
import run.halo.app.utils.FileUtils;
|
||||
import run.halo.app.utils.HaloUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.management.ManagementFactory;
|
||||
import java.lang.management.RuntimeMXBean;
|
||||
|
@ -46,7 +51,7 @@ import static run.halo.app.model.support.HaloConst.*;
|
|||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 19-4-29
|
||||
* @date 2019-04-29
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
@ -76,6 +81,8 @@ public class AdminServiceImpl implements AdminService {
|
|||
|
||||
private final HaloProperties haloProperties;
|
||||
|
||||
private final ApplicationEventPublisher eventPublisher;
|
||||
|
||||
private final String driverClassName;
|
||||
|
||||
private final String mode;
|
||||
|
@ -92,6 +99,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
StringCacheStore cacheStore,
|
||||
RestTemplate restTemplate,
|
||||
HaloProperties haloProperties,
|
||||
ApplicationEventPublisher eventPublisher,
|
||||
@Value("${spring.datasource.driver-class-name}") String driverClassName,
|
||||
@Value("${spring.profiles.active:prod}") String mode) {
|
||||
this.postService = postService;
|
||||
|
@ -106,6 +114,7 @@ public class AdminServiceImpl implements AdminService {
|
|||
this.cacheStore = cacheStore;
|
||||
this.restTemplate = restTemplate;
|
||||
this.haloProperties = haloProperties;
|
||||
this.eventPublisher = eventPublisher;
|
||||
this.driverClassName = driverClassName;
|
||||
this.mode = mode;
|
||||
}
|
||||
|
@ -126,6 +135,8 @@ public class AdminServiceImpl implements AdminService {
|
|||
userService.getByEmailOfNonNull(username) : userService.getByUsernameOfNonNull(username);
|
||||
} catch (NotFoundException e) {
|
||||
log.error("Failed to find user by name: " + username, e);
|
||||
eventPublisher.publishEvent(new LogEvent(this, loginParam.getUsername(), LogType.LOGIN_FAILED, loginParam.getUsername()));
|
||||
|
||||
throw new BadRequestException(mismatchTip);
|
||||
}
|
||||
|
||||
|
@ -133,6 +144,8 @@ public class AdminServiceImpl implements AdminService {
|
|||
|
||||
if (!userService.passwordMatch(user, loginParam.getPassword())) {
|
||||
// If the password is mismatch
|
||||
eventPublisher.publishEvent(new LogEvent(this, loginParam.getUsername(), LogType.LOGIN_FAILED, loginParam.getUsername()));
|
||||
|
||||
throw new BadRequestException(mismatchTip);
|
||||
}
|
||||
|
||||
|
@ -141,6 +154,9 @@ public class AdminServiceImpl implements AdminService {
|
|||
throw new BadRequestException("您已登录,请不要重复登录");
|
||||
}
|
||||
|
||||
// Log it then login successful
|
||||
eventPublisher.publishEvent(new LogEvent(this, user.getUsername(), LogType.LOGGED_IN, user.getNickname()));
|
||||
|
||||
// Generate new token
|
||||
return buildAuthToken(user);
|
||||
}
|
||||
|
@ -170,6 +186,8 @@ public class AdminServiceImpl implements AdminService {
|
|||
cacheStore.delete(SecurityUtils.buildRefreshTokenKey(user));
|
||||
});
|
||||
|
||||
eventPublisher.publishEvent(new LogEvent(this, user.getUsername(), LogType.LOGGED_OUT, user.getNickname()));
|
||||
|
||||
log.info("You have been logged out, looking forward to your next visit!");
|
||||
}
|
||||
|
||||
|
@ -357,4 +375,14 @@ public class AdminServiceImpl implements AdminService {
|
|||
|
||||
return token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSpringLogs() {
|
||||
File file = new File(haloProperties.getWorkDir(), LOGS_PATH);
|
||||
if (!file.exists()) {
|
||||
return "暂无日志";
|
||||
}
|
||||
FileReader reader = new FileReader(file);
|
||||
return reader.readString();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -32,6 +32,7 @@ import java.util.Objects;
|
|||
* AttachmentService implementation
|
||||
*
|
||||
* @author ryanwang
|
||||
* @author johnniang
|
||||
* @date : 2019-03-14
|
||||
*/
|
||||
@Slf4j
|
||||
|
|
|
@ -14,7 +14,7 @@ import java.nio.charset.StandardCharsets;
|
|||
* Backup service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-26
|
||||
* @date 2019-04-26
|
||||
*/
|
||||
@Service
|
||||
public class BackupServiceImpl implements BackupService {
|
||||
|
|
|
@ -51,7 +51,7 @@ import java.util.stream.Collectors;
|
|||
* Base comment service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-24
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extends AbstractCrudService<COMMENT, Long> implements BaseCommentService<COMMENT> {
|
||||
|
|
|
@ -7,7 +7,6 @@ import org.springframework.data.domain.PageRequest;
|
|||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import run.halo.app.exception.AlreadyExistsException;
|
||||
|
@ -24,6 +23,7 @@ import run.halo.app.service.OptionService;
|
|||
import run.halo.app.service.base.AbstractCrudService;
|
||||
import run.halo.app.service.base.BasePostService;
|
||||
import run.halo.app.utils.DateUtils;
|
||||
import run.halo.app.utils.HaloUtils;
|
||||
import run.halo.app.utils.MarkdownUtils;
|
||||
import run.halo.app.utils.ServiceUtils;
|
||||
|
||||
|
@ -40,7 +40,8 @@ import static org.springframework.data.domain.Sort.Direction.DESC;
|
|||
* Base post service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-24
|
||||
* @author ryanwang
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
@Slf4j
|
||||
public abstract class BasePostServiceImpl<POST extends BasePost> extends AbstractCrudService<POST, Integer> implements BasePostService<POST> {
|
||||
|
@ -212,7 +213,7 @@ public abstract class BasePostServiceImpl<POST extends BasePost> extends Abstrac
|
|||
Assert.notNull(post, "Post must not be null");
|
||||
|
||||
// Render content
|
||||
post.setFormatContent(MarkdownUtils.renderMarkdown(post.getOriginalContent()));
|
||||
post.setFormatContent(MarkdownUtils.renderHtml(post.getOriginalContent()));
|
||||
|
||||
// Create or update post
|
||||
if (ServiceUtils.isEmptyId(post.getId())) {
|
||||
|
@ -275,7 +276,7 @@ public abstract class BasePostServiceImpl<POST extends BasePost> extends Abstrac
|
|||
|
||||
// Set summary
|
||||
if (StringUtils.isBlank(basePostSimpleDTO.getSummary())) {
|
||||
basePostSimpleDTO.setSummary(convertToSummary(post.getOriginalContent()));
|
||||
basePostSimpleDTO.setSummary(generateSummary(post.getFormatContent()));
|
||||
}
|
||||
|
||||
return basePostSimpleDTO;
|
||||
|
@ -347,15 +348,14 @@ public abstract class BasePostServiceImpl<POST extends BasePost> extends Abstrac
|
|||
}
|
||||
|
||||
@NonNull
|
||||
protected String convertToSummary(@Nullable String markdownContent) {
|
||||
// Render text content
|
||||
String textContent = MarkdownUtils.renderText(markdownContent);
|
||||
protected String generateSummary(@NonNull String htmlContent) {
|
||||
Assert.notNull(htmlContent, "html content must not be null");
|
||||
|
||||
String text = HaloUtils.cleanHtmlTag(htmlContent);
|
||||
|
||||
// Get summary length
|
||||
Integer summaryLength = optionService.getByPropertyOrDefault(PostProperties.SUMMARY_LENGTH, Integer.class, 150);
|
||||
|
||||
// Set summary
|
||||
return StringUtils.substring(textContent, 0, summaryLength);
|
||||
return StringUtils.substring(text, 0, summaryLength);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -5,6 +5,7 @@ import lombok.extern.slf4j.Slf4j;
|
|||
import org.springframework.data.domain.Sort;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import run.halo.app.exception.AlreadyExistsException;
|
||||
|
@ -24,9 +25,10 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* CategoryService implementation class
|
||||
* CategoryService implementation class.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @author johnniang
|
||||
* @date : 2019-03-14
|
||||
*/
|
||||
@Slf4j
|
||||
|
@ -45,6 +47,7 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Category create(Category category) {
|
||||
Assert.notNull(category, "Category to create must not be null");
|
||||
|
||||
|
@ -144,15 +147,14 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
|||
return topCategory;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get category by slug name
|
||||
*
|
||||
* @param slugName slug name
|
||||
* @return Category
|
||||
*/
|
||||
@Override
|
||||
public Category getBySlugName(String slugName) {
|
||||
return categoryRepository.getBySlugName(slugName).orElseThrow(() -> new NotFoundException("该分类已存在").setErrorData(slugName));
|
||||
return categoryRepository.getBySlugName(slugName).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Category getBySlugNameOfNonNull(String slugName) {
|
||||
return categoryRepository.getBySlugName(slugName).orElseThrow(() -> new NotFoundException("该分类不存在").setErrorData(slugName));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -161,6 +163,7 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public void removeCategoryAndPostCategoryBy(Integer categoryId) {
|
||||
// Remove category
|
||||
removeById(categoryId);
|
||||
|
|
|
@ -28,7 +28,7 @@ import java.util.stream.Collectors;
|
|||
* Journal comment service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-25
|
||||
* @date 2019-04-25
|
||||
*/
|
||||
@Service
|
||||
public class JournalCommentServiceImpl extends BaseCommentServiceImpl<JournalComment> implements JournalCommentService {
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.stream.Collectors;
|
|||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 19-4-24
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
@Service
|
||||
public class JournalServiceImpl extends AbstractCrudService<Journal, Integer> implements JournalService {
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.stream.Collectors;
|
|||
* LinkService implementation class
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Service
|
||||
public class LinkServiceImpl extends AbstractCrudService<Link, Integer> implements LinkService {
|
||||
|
@ -36,12 +36,6 @@ public class LinkServiceImpl extends AbstractCrudService<Link, Integer> implemen
|
|||
this.linkRepository = linkRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* List link dtos.
|
||||
*
|
||||
* @param sort sort
|
||||
* @return all links
|
||||
*/
|
||||
@Override
|
||||
public List<LinkDTO> listDtos(Sort sort) {
|
||||
Assert.notNull(sort, "Sort info must not be null");
|
||||
|
|
|
@ -15,7 +15,7 @@ import run.halo.app.service.base.AbstractCrudService;
|
|||
* LogService implementation class
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Service
|
||||
public class LogServiceImpl extends AbstractCrudService<Log, Long> implements LogService {
|
||||
|
|
|
@ -20,7 +20,7 @@ import java.util.Properties;
|
|||
* Mail service implementation.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-17
|
||||
* @date 2019-03-17
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
@ -37,13 +37,6 @@ public class MailServiceImpl implements MailService {
|
|||
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a simple email
|
||||
*
|
||||
* @param to recipient
|
||||
* @param subject subject
|
||||
* @param content content
|
||||
*/
|
||||
@Override
|
||||
public void sendMail(String to, String subject, String content) {
|
||||
loadConfig();
|
||||
|
@ -63,14 +56,6 @@ public class MailServiceImpl implements MailService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends template mail
|
||||
*
|
||||
* @param to recipient
|
||||
* @param subject subject
|
||||
* @param content content
|
||||
* @param templateName template name
|
||||
*/
|
||||
@Override
|
||||
public void sendTemplateMail(String to, String subject, Map<String, Object> content, String templateName) {
|
||||
loadConfig();
|
||||
|
@ -93,15 +78,6 @@ public class MailServiceImpl implements MailService {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends mail with attachments
|
||||
*
|
||||
* @param to recipient
|
||||
* @param subject subject
|
||||
* @param content content
|
||||
* @param templateName template name
|
||||
* @param attachFilename attachment path
|
||||
*/
|
||||
@Override
|
||||
public void sendAttachMail(String to, String subject, Map<String, Object> content, String templateName, String attachFilename) {
|
||||
loadConfig();
|
||||
|
|
|
@ -21,10 +21,10 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* MenuService implementation class
|
||||
* MenuService implementation class.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Service
|
||||
public class MenuServiceImpl extends AbstractCrudService<Menu, Integer> implements MenuService {
|
||||
|
@ -51,12 +51,6 @@ public class MenuServiceImpl extends AbstractCrudService<Menu, Integer> implemen
|
|||
return create(menuParam.convertTo());
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists as menu tree.
|
||||
*
|
||||
* @param sort sort info must not be null
|
||||
* @return a menu tree
|
||||
*/
|
||||
@Override
|
||||
public List<MenuVO> listAsTree(Sort sort) {
|
||||
Assert.notNull(sort, "Sort info must not be null");
|
||||
|
|
|
@ -30,7 +30,7 @@ import java.util.*;
|
|||
* OptionService implementation class
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.stream.Collectors;
|
|||
* PhotoService implementation class
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Service
|
||||
public class PhotoServiceImpl extends AbstractCrudService<Photo, Integer> implements PhotoService {
|
||||
|
@ -41,12 +41,6 @@ public class PhotoServiceImpl extends AbstractCrudService<Photo, Integer> implem
|
|||
this.photoRepository = photoRepository;
|
||||
}
|
||||
|
||||
/**
|
||||
* List photo dtos.
|
||||
*
|
||||
* @param sort sort
|
||||
* @return all photos
|
||||
*/
|
||||
@Override
|
||||
public List<PhotoDTO> listDtos(Sort sort) {
|
||||
Assert.notNull(sort, "Sort info must not be null");
|
||||
|
@ -54,12 +48,6 @@ public class PhotoServiceImpl extends AbstractCrudService<Photo, Integer> implem
|
|||
return listAll(sort).stream().map(photo -> (PhotoDTO) new PhotoDTO().convertFrom(photo)).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
/**
|
||||
* Lists photo team vos.
|
||||
*
|
||||
* @param sort must not be null
|
||||
* @return a list of photo team vo
|
||||
*/
|
||||
@Override
|
||||
public List<PhotoTeamVO> listTeamVos(Sort sort) {
|
||||
Assert.notNull(sort, "Sort info must not be null");
|
||||
|
@ -88,13 +76,6 @@ public class PhotoServiceImpl extends AbstractCrudService<Photo, Integer> implem
|
|||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* List photos by team.
|
||||
*
|
||||
* @param team team
|
||||
* @param sort sort
|
||||
* @return list of photos
|
||||
*/
|
||||
@Override
|
||||
public List<PhotoDTO> listByTeam(String team, Sort sort) {
|
||||
List<Photo> photos = photoRepository.findByTeam(team, sort);
|
||||
|
|
|
@ -10,6 +10,7 @@ import run.halo.app.model.dto.CategoryWithPostCountDTO;
|
|||
import run.halo.app.model.entity.Category;
|
||||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.entity.PostCategory;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.projection.CategoryPostCountProjection;
|
||||
import run.halo.app.repository.CategoryRepository;
|
||||
import run.halo.app.repository.PostCategoryRepository;
|
||||
|
@ -25,7 +26,8 @@ import java.util.stream.Collectors;
|
|||
* Post category service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 3/19/19
|
||||
* @author ryanwang
|
||||
* @date 2019-03-19
|
||||
*/
|
||||
@Service
|
||||
public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, Integer> implements PostCategoryService {
|
||||
|
@ -93,6 +95,17 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
|||
return postRepository.findAllById(postIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Post> listPostBy(Integer categoryId, PostStatus status) {
|
||||
Assert.notNull(categoryId, "Category id must not be null");
|
||||
Assert.notNull(categoryId, "Post status must not be null");
|
||||
|
||||
// Find all post ids
|
||||
Set<Integer> postIds = postCategoryRepository.findAllPostIdsByCategoryId(categoryId, status);
|
||||
|
||||
return postRepository.findAllById(postIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Post> pagePostBy(Integer categoryId, Pageable pageable) {
|
||||
Assert.notNull(categoryId, "Category id must not be null");
|
||||
|
@ -104,6 +117,18 @@ public class PostCategoryServiceImpl extends AbstractCrudService<PostCategory, I
|
|||
return postRepository.findAllByIdIn(postIds, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Post> pagePostBy(Integer categoryId, PostStatus status, Pageable pageable) {
|
||||
Assert.notNull(categoryId, "Category id must not be null");
|
||||
Assert.notNull(categoryId, "Post status must not be null");
|
||||
Assert.notNull(pageable, "Page info must not be null");
|
||||
|
||||
// Find all post ids
|
||||
Set<Integer> postIds = postCategoryRepository.findAllPostIdsByCategoryId(categoryId, status);
|
||||
|
||||
return postRepository.findAllByIdIn(postIds, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PostCategory> mergeOrCreateByIfAbsent(Integer postId, Set<Integer> categoryIds) {
|
||||
Assert.notNull(postId, "Post id must not be null");
|
||||
|
|
|
@ -32,7 +32,8 @@ import java.util.stream.Collectors;
|
|||
* PostCommentService implementation class
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
|
|
@ -45,6 +45,7 @@ import static org.springframework.data.domain.Sort.Direction.DESC;
|
|||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
@ -280,7 +281,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
|||
Assert.notNull(markdown, "Markdown document must not be null");
|
||||
|
||||
// Render markdown to html document.
|
||||
String content = MarkdownUtils.renderMarkdown(markdown);
|
||||
String content = MarkdownUtils.renderHtml(markdown);
|
||||
|
||||
// Gets frontMatter
|
||||
Map<String, List<String>> frontMatter = MarkdownUtils.getFrontMatter(markdown);
|
||||
|
@ -462,8 +463,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
|
|||
PostListVO postListVO = new PostListVO().convertFrom(post);
|
||||
|
||||
if (StringUtils.isBlank(postListVO.getSummary())) {
|
||||
// Set summary
|
||||
postListVO.setSummary(convertToSummary(post.getOriginalContent()));
|
||||
postListVO.setSummary(generateSummary(post.getFormatContent()));
|
||||
}
|
||||
|
||||
Optional.ofNullable(tagListMap.get(post.getId())).orElseGet(LinkedList::new);
|
||||
|
|
|
@ -10,6 +10,7 @@ import run.halo.app.model.dto.TagWithPostCountDTO;
|
|||
import run.halo.app.model.entity.Post;
|
||||
import run.halo.app.model.entity.PostTag;
|
||||
import run.halo.app.model.entity.Tag;
|
||||
import run.halo.app.model.enums.PostStatus;
|
||||
import run.halo.app.model.projection.TagPostPostCountProjection;
|
||||
import run.halo.app.repository.PostRepository;
|
||||
import run.halo.app.repository.PostTagRepository;
|
||||
|
@ -25,7 +26,8 @@ import java.util.stream.Collectors;
|
|||
* Post tag service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 3/19/19
|
||||
* @author ryanwang
|
||||
* @date 2019-03-19
|
||||
*/
|
||||
@Service
|
||||
public class PostTagServiceImpl extends AbstractCrudService<PostTag, Integer> implements PostTagService {
|
||||
|
@ -113,6 +115,17 @@ public class PostTagServiceImpl extends AbstractCrudService<PostTag, Integer> im
|
|||
return postRepository.findAllById(postIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Post> listPostsBy(Integer tagId, PostStatus status) {
|
||||
Assert.notNull(tagId, "Tag id must not be null");
|
||||
Assert.notNull(tagId, "Post status must not be null");
|
||||
|
||||
// Find all post ids
|
||||
Set<Integer> postIds = postTagRepository.findAllPostIdsByTagId(tagId, status);
|
||||
|
||||
return postRepository.findAllById(postIds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Post> pagePostsBy(Integer tagId, Pageable pageable) {
|
||||
Assert.notNull(tagId, "Tag id must not be null");
|
||||
|
@ -124,6 +137,18 @@ public class PostTagServiceImpl extends AbstractCrudService<PostTag, Integer> im
|
|||
return postRepository.findAllByIdIn(postIds, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Page<Post> pagePostsBy(Integer tagId, PostStatus status, Pageable pageable) {
|
||||
Assert.notNull(tagId, "Tag id must not be null");
|
||||
Assert.notNull(tagId, "Post status must not be null");
|
||||
Assert.notNull(pageable, "Page info must not be null");
|
||||
|
||||
// Find all post ids
|
||||
Set<Integer> postIds = postTagRepository.findAllPostIdsByTagId(tagId, status);
|
||||
|
||||
return postRepository.findAllByIdIn(postIds, pageable);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<PostTag> mergeOrCreateByIfAbsent(Integer postId, Set<Integer> tagIds) {
|
||||
Assert.notNull(postId, "Post id must not be null");
|
||||
|
|
|
@ -33,7 +33,8 @@ import java.util.stream.Collectors;
|
|||
* Recovery service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-26
|
||||
* @author ryanwang
|
||||
* @date 2019-04-26
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
@ -64,6 +65,10 @@ public class RecoveryServiceImpl implements RecoveryService {
|
|||
|
||||
private final PhotoService photoService;
|
||||
|
||||
private final PostCategoryService postCategoryService;
|
||||
|
||||
private final PostTagService postTagService;
|
||||
|
||||
public RecoveryServiceImpl(AttachmentService attachmentService,
|
||||
PostService postService,
|
||||
LinkService linkService,
|
||||
|
@ -75,7 +80,9 @@ public class RecoveryServiceImpl implements RecoveryService {
|
|||
SheetCommentService sheetCommentService,
|
||||
SheetCommentRepository sheetCommentRepository,
|
||||
SheetService sheetService,
|
||||
PhotoService photoService) {
|
||||
PhotoService photoService,
|
||||
PostCategoryService postCategoryService,
|
||||
PostTagService postTagService) {
|
||||
this.attachmentService = attachmentService;
|
||||
this.postService = postService;
|
||||
this.linkService = linkService;
|
||||
|
@ -88,6 +95,8 @@ public class RecoveryServiceImpl implements RecoveryService {
|
|||
this.sheetCommentRepository = sheetCommentRepository;
|
||||
this.sheetService = sheetService;
|
||||
this.photoService = photoService;
|
||||
this.postCategoryService = postCategoryService;
|
||||
this.postTagService = postTagService;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -215,9 +224,21 @@ public class RecoveryServiceImpl implements RecoveryService {
|
|||
Post createdPost = postService.createOrUpdateBy(post);
|
||||
|
||||
Object commentsObject = postMap.get("comments");
|
||||
Object categoriesObject = postMap.get("categories");
|
||||
Object tagsObject = postMap.get("tags");
|
||||
// Handle comments
|
||||
List<BaseComment> baseComments = handleComment(commentsObject, createdPost.getId());
|
||||
|
||||
// Handle categories
|
||||
List<Category> categories = handleCategories(categoriesObject, createdPost.getId());
|
||||
|
||||
log.debug("Migrated categories of post [{}]: [{}]", categories, createdPost.getId());
|
||||
|
||||
// Handle tags
|
||||
List<Tag> tags = handleTags(tagsObject, createdPost.getId());
|
||||
|
||||
log.debug("Migrated tags of post [{}]: [{}]", tags, createdPost.getId());
|
||||
|
||||
List<PostComment> postComments = baseComments.stream()
|
||||
.map(baseComment -> BeanUtils.transformFrom(baseComment, PostComment.class))
|
||||
.collect(Collectors.toList());
|
||||
|
@ -372,6 +393,96 @@ public class RecoveryServiceImpl implements RecoveryService {
|
|||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Category> handleCategories(@Nullable Object categoriesObject, @NonNull Integer postId) {
|
||||
Assert.notNull(postId, "Post id must not be null");
|
||||
|
||||
if (!(categoriesObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> categoryObjectList = (List<Object>) categoriesObject;
|
||||
|
||||
List<Category> result = new LinkedList<>();
|
||||
|
||||
categoryObjectList.forEach(categoryObject -> {
|
||||
if (!(categoryObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> categoryMap = (Map<String, Object>) categoryObject;
|
||||
|
||||
String slugName = categoryMap.getOrDefault("cateUrl", "").toString();
|
||||
|
||||
Category category = categoryService.getBySlugName(slugName);
|
||||
|
||||
if (null == category) {
|
||||
category = new Category();
|
||||
category.setName(categoryMap.getOrDefault("cateName", "").toString());
|
||||
category.setSlugName(slugName);
|
||||
category.setDescription(categoryMap.getOrDefault("cateDesc", "").toString());
|
||||
category = categoryService.create(category);
|
||||
}
|
||||
|
||||
PostCategory postCategory = new PostCategory();
|
||||
postCategory.setCategoryId(category.getId());
|
||||
postCategory.setPostId(postId);
|
||||
postCategoryService.create(postCategory);
|
||||
|
||||
try {
|
||||
result.add(category);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to migrate a category", e);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Tag> handleTags(@Nullable Object tagsObject, @NonNull Integer postId) {
|
||||
Assert.notNull(postId, "Post id must not be null");
|
||||
|
||||
if (!(tagsObject instanceof List)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
List<Object> tagObjectList = (List<Object>) tagsObject;
|
||||
|
||||
List<Tag> result = new LinkedList<>();
|
||||
|
||||
tagObjectList.forEach(tagObject -> {
|
||||
if (!(tagObject instanceof Map)) {
|
||||
return;
|
||||
}
|
||||
|
||||
Map<String, Object> tagMap = (Map<String, Object>) tagObject;
|
||||
|
||||
String slugName = tagMap.getOrDefault("tagUrl", "").toString();
|
||||
|
||||
Tag tag = tagService.getBySlugName(slugName);
|
||||
|
||||
if (null == tag) {
|
||||
tag = new Tag();
|
||||
tag.setName(tagMap.getOrDefault("tagName", "").toString());
|
||||
tag.setSlugName(slugName);
|
||||
tag = tagService.create(tag);
|
||||
}
|
||||
|
||||
PostTag postTag = new PostTag();
|
||||
postTag.setTagId(tag.getId());
|
||||
postTag.setPostId(postId);
|
||||
postTagService.create(postTag);
|
||||
|
||||
try {
|
||||
result.add(tag);
|
||||
} catch (Exception e) {
|
||||
log.warn("Failed to migrate a tag", e);
|
||||
}
|
||||
});
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
private List<Menu> handleMenus(@Nullable Object menusObject) {
|
||||
|
|
|
@ -29,7 +29,7 @@ import java.util.stream.Collectors;
|
|||
* Sheet comment service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-4-24
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
@Service
|
||||
public class SheetCommentServiceImpl extends BaseCommentServiceImpl<SheetComment> implements SheetCommentService {
|
||||
|
|
|
@ -31,7 +31,7 @@ import java.util.Set;
|
|||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date 19-4-24
|
||||
* @date 2019-04-24
|
||||
*/
|
||||
@Service
|
||||
public class SheetServiceImpl extends BasePostServiceImpl<Sheet> implements SheetService {
|
||||
|
@ -85,13 +85,6 @@ public class SheetServiceImpl extends BasePostServiceImpl<Sheet> implements Shee
|
|||
return listAll(pageable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets sheet by post status and url.
|
||||
*
|
||||
* @param status post status must not be null
|
||||
* @param url sheet url must not be blank
|
||||
* @return sheet info
|
||||
*/
|
||||
@Override
|
||||
public Sheet getBy(PostStatus status, String url) {
|
||||
Sheet sheet = super.getBy(status, url);
|
||||
|
@ -109,11 +102,12 @@ public class SheetServiceImpl extends BasePostServiceImpl<Sheet> implements Shee
|
|||
Assert.notNull(markdown, "Markdown document must not be null");
|
||||
|
||||
// Render markdown to html document.
|
||||
String content = MarkdownUtils.renderMarkdown(markdown);
|
||||
String content = MarkdownUtils.renderHtml(markdown);
|
||||
|
||||
// Gets frontMatter
|
||||
Map<String, List<String>> frontMatter = MarkdownUtils.getFrontMatter(markdown);
|
||||
|
||||
// TODO
|
||||
return null;
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package run.halo.app.service.impl;
|
|||
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import run.halo.app.exception.AlreadyExistsException;
|
||||
|
@ -17,10 +18,11 @@ import java.util.List;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* TagService implementation class
|
||||
* TagService implementation class.
|
||||
*
|
||||
* @author johnniang
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
@ -34,6 +36,7 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
@Transactional
|
||||
public Tag create(Tag tag) {
|
||||
// Check if the tag is exist
|
||||
long count = tagRepository.countByNameOrSlugName(tag.getName(), tag.getSlugName());
|
||||
|
@ -49,17 +52,15 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
|
|||
return super.create(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tag by slug name
|
||||
*
|
||||
* @param slugName slug name
|
||||
* @return Tag
|
||||
*/
|
||||
@Override
|
||||
public Tag getBySlugNameOfNonNull(String slugName) {
|
||||
return tagRepository.getBySlugName(slugName).orElseThrow(() -> new NotFoundException("该标签已存在").setErrorData(slugName));
|
||||
return tagRepository.getBySlugName(slugName).orElseThrow(() -> new NotFoundException("该标签不存在").setErrorData(slugName));
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getBySlugName(String slugName) {
|
||||
return tagRepository.getBySlugName(slugName).orElse(null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tag getByName(String name) {
|
||||
|
|
|
@ -53,7 +53,7 @@ import static run.halo.app.model.support.HaloConst.DEFAULT_THEME_ID;
|
|||
* Theme service implementation.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019/3/26
|
||||
* @date 2019-03-26
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
|
|
@ -24,7 +24,7 @@ import java.util.*;
|
|||
* Theme setting service implementation.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 4/8/19
|
||||
* @date 2019-04-08
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
|
|
|
@ -2,18 +2,16 @@ package run.halo.app.service.impl;
|
|||
|
||||
import org.springframework.boot.actuate.trace.http.HttpTrace;
|
||||
import org.springframework.boot.actuate.trace.http.HttpTraceRepository;
|
||||
import org.springframework.data.domain.Page;
|
||||
import org.springframework.data.domain.PageImpl;
|
||||
import org.springframework.data.domain.Pageable;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.util.Assert;
|
||||
import run.halo.app.service.TraceService;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* TraceService implementation class.
|
||||
*
|
||||
* @author johnniang
|
||||
* @date 19-6-18
|
||||
* @date 2019-06-18
|
||||
*/
|
||||
@Service
|
||||
public class TraceServiceImpl implements TraceService {
|
||||
|
|
|
@ -31,10 +31,11 @@ import java.util.Optional;
|
|||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* UserService implementation class
|
||||
* UserService implementation class.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2019-03-14
|
||||
* @author johnniang
|
||||
* @date 2019-03-14
|
||||
*/
|
||||
@Service
|
||||
public class UserServiceImpl extends AbstractCrudService<User, Integer> implements UserService {
|
||||
|
@ -78,24 +79,11 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
|
|||
return getByUsername(username).orElseThrow(() -> new NotFoundException("The username dose not exist").setErrorData(username));
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets user by email.
|
||||
*
|
||||
* @param email email must not be blank
|
||||
* @return an optional user
|
||||
*/
|
||||
@Override
|
||||
public Optional<User> getByEmail(String email) {
|
||||
return userRepository.findByEmail(email);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets non null user by email.
|
||||
*
|
||||
* @param email email
|
||||
* @return user info
|
||||
* @throws NotFoundException throws when the username does not exist
|
||||
*/
|
||||
@Override
|
||||
public User getByEmailOfNonNull(String email) {
|
||||
return getByEmail(email).orElseThrow(() -> new NotFoundException("The email dose not exist").setErrorData(email));
|
||||
|
|
|
@ -8,7 +8,6 @@ import org.springframework.util.Assert;
|
|||
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.UUID;
|
||||
|
||||
import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
|
||||
|
@ -17,11 +16,14 @@ import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
|
|||
* Common utils
|
||||
*
|
||||
* @author ryanwang
|
||||
* @author johnniang
|
||||
* @date : 2017/12/22
|
||||
*/
|
||||
@Slf4j
|
||||
public class HaloUtils {
|
||||
|
||||
private static final String RE_HTML_MARK = "(<[^<]*?>)|(<[\\s]*?/[^<]*?>)|(<[^<]*?/[\\s]*?>)";
|
||||
|
||||
/**
|
||||
* Desensitizes the plain text.
|
||||
*
|
||||
|
@ -192,4 +194,14 @@ public class HaloUtils {
|
|||
}
|
||||
return machineAddress.getHostAddress();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clean all html tag
|
||||
*
|
||||
* @param content html document
|
||||
* @return text before cleaned
|
||||
*/
|
||||
public static String cleanHtmlTag(String content) {
|
||||
return content.replaceAll(RE_HTML_MARK, "");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,147 +1,107 @@
|
|||
package run.halo.app.utils;
|
||||
|
||||
import com.vladsch.flexmark.convert.html.FlexmarkHtmlParser;
|
||||
import com.vladsch.flexmark.ext.attributes.AttributesExtension;
|
||||
import com.vladsch.flexmark.ext.autolink.AutolinkExtension;
|
||||
import com.vladsch.flexmark.ext.emoji.EmojiExtension;
|
||||
import com.vladsch.flexmark.ext.emoji.EmojiImageType;
|
||||
import com.vladsch.flexmark.ext.emoji.EmojiShortcutType;
|
||||
import com.vladsch.flexmark.ext.escaped.character.EscapedCharacterExtension;
|
||||
import com.vladsch.flexmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||
import com.vladsch.flexmark.ext.gfm.tasklist.TaskListExtension;
|
||||
import com.vladsch.flexmark.ext.ins.InsExtension;
|
||||
import com.vladsch.flexmark.ext.media.tags.MediaTagsExtension;
|
||||
import com.vladsch.flexmark.ext.tables.TablesExtension;
|
||||
import com.vladsch.flexmark.ext.toc.TocExtension;
|
||||
import com.vladsch.flexmark.ext.yaml.front.matter.AbstractYamlFrontMatterVisitor;
|
||||
import com.vladsch.flexmark.ext.yaml.front.matter.YamlFrontMatterExtension;
|
||||
import com.vladsch.flexmark.html.HtmlRenderer;
|
||||
import com.vladsch.flexmark.parser.Parser;
|
||||
import com.vladsch.flexmark.util.ast.Node;
|
||||
import com.vladsch.flexmark.util.options.DataHolder;
|
||||
import com.vladsch.flexmark.util.options.MutableDataSet;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.commonmark.Extension;
|
||||
import org.commonmark.ext.autolink.AutolinkExtension;
|
||||
import org.commonmark.ext.front.matter.YamlFrontMatterExtension;
|
||||
import org.commonmark.ext.front.matter.YamlFrontMatterVisitor;
|
||||
import org.commonmark.ext.gfm.strikethrough.StrikethroughExtension;
|
||||
import org.commonmark.ext.gfm.tables.TablesExtension;
|
||||
import org.commonmark.ext.heading.anchor.HeadingAnchorExtension;
|
||||
import org.commonmark.ext.ins.InsExtension;
|
||||
import org.commonmark.node.Node;
|
||||
import org.commonmark.parser.Parser;
|
||||
import org.commonmark.renderer.html.HtmlRenderer;
|
||||
import org.commonmark.renderer.text.TextContentRenderer;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.lang.Nullable;
|
||||
import run.halo.app.model.support.HaloConst;
|
||||
|
||||
import java.util.Collections;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Markdown utils
|
||||
* Markdown utils.
|
||||
*
|
||||
* @author ryanwang
|
||||
* @date : 2018/11/14
|
||||
* @date : 2019/06/27
|
||||
*/
|
||||
public class MarkdownUtils {
|
||||
|
||||
private static final DataHolder OPTIONS = new MutableDataSet()
|
||||
.set(Parser.EXTENSIONS, Arrays.asList(
|
||||
AttributesExtension.create(),
|
||||
AutolinkExtension.create(),
|
||||
EmojiExtension.create(),
|
||||
EscapedCharacterExtension.create(),
|
||||
StrikethroughExtension.create(),
|
||||
TaskListExtension.create(),
|
||||
InsExtension.create(),
|
||||
MediaTagsExtension.create(),
|
||||
TablesExtension.create(),
|
||||
TocExtension.create(),
|
||||
YamlFrontMatterExtension.create())
|
||||
)
|
||||
.set(TablesExtension.WITH_CAPTION, false)
|
||||
.set(TablesExtension.COLUMN_SPANS, false)
|
||||
.set(TablesExtension.MIN_HEADER_ROWS, 1)
|
||||
.set(TablesExtension.MAX_HEADER_ROWS, 1)
|
||||
.set(TablesExtension.APPEND_MISSING_COLUMNS, true)
|
||||
.set(TablesExtension.DISCARD_EXTRA_COLUMNS, true)
|
||||
.set(TablesExtension.HEADER_SEPARATOR_COLUMN_MATCH, true)
|
||||
.set(EmojiExtension.USE_SHORTCUT_TYPE, EmojiShortcutType.GITHUB)
|
||||
.set(EmojiExtension.USE_IMAGE_TYPE, EmojiImageType.IMAGE_ONLY);
|
||||
|
||||
/**
|
||||
* commonmark-java extension for autolinking
|
||||
*/
|
||||
private static final Set<Extension> EXTENSIONS_AUTO_LINK = Collections.singleton(AutolinkExtension.create());
|
||||
private static final Parser PARSER = Parser.builder(OPTIONS).build();
|
||||
|
||||
/**
|
||||
* commonmark-java extension for strikethrough
|
||||
*/
|
||||
private static final Set<Extension> EXTENSIONS_STRIKETHROUGH = Collections.singleton(StrikethroughExtension.create());
|
||||
|
||||
/**
|
||||
* commonmark-java extension for tables
|
||||
*/
|
||||
private static final Set<Extension> EXTENSIONS_TABLES = Collections.singleton(TablesExtension.create());
|
||||
|
||||
/**
|
||||
* commonmark-java extension for adding id attributes to h tags
|
||||
*/
|
||||
private static final Set<Extension> EXTENSIONS_HEADING_ANCHOR = Collections.singleton(HeadingAnchorExtension.create());
|
||||
|
||||
/**
|
||||
* commonmark-java extension for <ins> (underline)
|
||||
*/
|
||||
private static final Set<Extension> EXTENSIONS_INS = Collections.singleton(InsExtension.create());
|
||||
|
||||
/**
|
||||
* commonmark-java extension for YAML front matter
|
||||
*/
|
||||
private static final Set<Extension> EXTENSIONS_YAML_FRONT_MATTER = Collections.singleton(YamlFrontMatterExtension.create());
|
||||
|
||||
|
||||
/**
|
||||
* Parse Markdown content
|
||||
*/
|
||||
private static final Parser PARSER = Parser.builder()
|
||||
.extensions(EXTENSIONS_AUTO_LINK)
|
||||
.extensions(EXTENSIONS_STRIKETHROUGH)
|
||||
.extensions(EXTENSIONS_TABLES)
|
||||
.extensions(EXTENSIONS_HEADING_ANCHOR)
|
||||
.extensions(EXTENSIONS_INS)
|
||||
.extensions(EXTENSIONS_YAML_FRONT_MATTER)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Render HTML content
|
||||
*/
|
||||
private static final HtmlRenderer RENDERER = HtmlRenderer.builder()
|
||||
.extensions(EXTENSIONS_AUTO_LINK)
|
||||
.extensions(EXTENSIONS_STRIKETHROUGH)
|
||||
.extensions(EXTENSIONS_TABLES)
|
||||
.extensions(EXTENSIONS_HEADING_ANCHOR)
|
||||
.extensions(EXTENSIONS_INS)
|
||||
.extensions(EXTENSIONS_YAML_FRONT_MATTER)
|
||||
.build();
|
||||
|
||||
/**
|
||||
* Render text content
|
||||
*/
|
||||
private static final TextContentRenderer TEXT_CONTENT_RENDERER = TextContentRenderer.builder()
|
||||
.extensions(EXTENSIONS_AUTO_LINK)
|
||||
.extensions(EXTENSIONS_STRIKETHROUGH)
|
||||
.extensions(EXTENSIONS_TABLES)
|
||||
.extensions(EXTENSIONS_HEADING_ANCHOR)
|
||||
.extensions(EXTENSIONS_INS)
|
||||
.extensions(EXTENSIONS_YAML_FRONT_MATTER)
|
||||
.build();
|
||||
private static final HtmlRenderer RENDERER = HtmlRenderer.builder(OPTIONS).build();
|
||||
|
||||
/**
|
||||
* Render Markdown content
|
||||
*
|
||||
* @param content content
|
||||
* @return String
|
||||
* @see <a href="https://github.com/otale/tale/blob/master/src/main/java/com/tale/utils/TaleUtils.java">TaleUtils.java</a>
|
||||
*/
|
||||
public static String renderMarkdown(String content) {
|
||||
public static String renderHtml(String markdown) {
|
||||
if (StringUtils.isBlank(markdown)) {
|
||||
return "";
|
||||
}
|
||||
Node document = PARSER.parse(markdown);
|
||||
String renderedContent = RENDERER.render(document);
|
||||
|
||||
final Node document = PARSER.parse(content);
|
||||
String renderContent = RENDERER.render(document);
|
||||
|
||||
// render netease music short url
|
||||
if (content.contains(HaloConst.NETEASE_MUSIC_PREFIX)) {
|
||||
renderContent = content.replaceAll(HaloConst.NETEASE_MUSIC_REG_PATTERN, HaloConst.NETEASE_MUSIC_IFRAME);
|
||||
// Render netease music short url.
|
||||
if (markdown.contains(HaloConst.NETEASE_MUSIC_PREFIX)) {
|
||||
renderedContent = markdown.replaceAll(HaloConst.NETEASE_MUSIC_REG_PATTERN, HaloConst.NETEASE_MUSIC_IFRAME);
|
||||
}
|
||||
|
||||
// render bilibili video short url
|
||||
if (content.contains(HaloConst.BILIBILI_VIDEO_PREFIX)) {
|
||||
renderContent = content.replaceAll(HaloConst.BILIBILI_VIDEO_REG_PATTERN, HaloConst.BILIBILI_VIDEO_IFRAME);
|
||||
// Render bilibili video short url.
|
||||
if (markdown.contains(HaloConst.BILIBILI_VIDEO_PREFIX)) {
|
||||
renderedContent = markdown.replaceAll(HaloConst.BILIBILI_VIDEO_REG_PATTERN, HaloConst.BILIBILI_VIDEO_IFRAME);
|
||||
}
|
||||
|
||||
// render youtube video short url
|
||||
if (content.contains(HaloConst.YOUTUBE_VIDEO_PREFIX)) {
|
||||
renderContent = content.replaceAll(HaloConst.YOUTUBE_VIDEO_REG_PATTERN, HaloConst.YOUTUBE_VIDEO_IFRAME);
|
||||
// Render youtube video short url.
|
||||
if (markdown.contains(HaloConst.YOUTUBE_VIDEO_PREFIX)) {
|
||||
renderedContent = markdown.replaceAll(HaloConst.YOUTUBE_VIDEO_REG_PATTERN, HaloConst.YOUTUBE_VIDEO_IFRAME);
|
||||
}
|
||||
|
||||
return renderContent;
|
||||
return renderedContent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Render text content.
|
||||
* Render html document to markdown document.
|
||||
*
|
||||
* @param markdownContent markdown content
|
||||
* @return text content or empty string if markdown content is blank
|
||||
* @param html html document
|
||||
* @return markdown document
|
||||
*/
|
||||
@NonNull
|
||||
public static String renderText(@Nullable String markdownContent) {
|
||||
|
||||
if (StringUtils.isBlank(markdownContent)) {
|
||||
return "";
|
||||
}
|
||||
|
||||
return TEXT_CONTENT_RENDERER.render(PARSER.parse(markdownContent));
|
||||
public static String renderMarkdown(String html) {
|
||||
return FlexmarkHtmlParser.parse(html);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -150,10 +110,10 @@ public class MarkdownUtils {
|
|||
* @param content content
|
||||
* @return Map
|
||||
*/
|
||||
public static Map<String, List<String>> getFrontMatter(String content) {
|
||||
final YamlFrontMatterVisitor visitor = new YamlFrontMatterVisitor();
|
||||
final Node document = PARSER.parse(content);
|
||||
document.accept(visitor);
|
||||
public static Map<String, List<String>> getFrontMatter(String markdown) {
|
||||
AbstractYamlFrontMatterVisitor visitor = new AbstractYamlFrontMatterVisitor();
|
||||
Node document = PARSER.parse(markdown);
|
||||
visitor.visit(document);
|
||||
return visitor.getData();
|
||||
}
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -0,0 +1 @@
|
|||
body{height:100%;background-color:#f5f5f5}.container{background:#f7f7f7;position:absolute;top:45%;left:50%;margin:-160px 0 0 -160px;width:320px;padding:16px 32px 32px 32px;-webkit-box-shadow:-4px 7px 46px 2px rgba(0,0,0,.1);box-shadow:-4px 7px 46px 2px rgba(0,0,0,.1)}.container .tip{cursor:pointer;margin-top:.5rem;float:right}.loginLogo{margin-bottom:20px;text-align:center}.loginLogo span{vertical-align:text-bottom;font-size:36px;display:inline-block;font-weight:600;color:#1790fe;background-image:-webkit-gradient(linear,37.219838% 34.532506%,36.425669% 93.178216%,from(#36c8f5),to(#1790fe),color-stop(.37,#1790fe));-webkit-text-fill-color:transparent;-webkit-background-clip:text}
|
|
@ -0,0 +1 @@
|
|||
a[data-v-4b6b2ba0]{text-decoration:none}.sheet-title[data-v-4b6b2ba0]{max-width:300px;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
@ -0,0 +1 @@
|
|||
.ant-upload-select-picture-card i{font-size:32px;color:#999}.ant-upload-select-picture-card .ant-upload-text{margin-top:8px;color:#666}.ant-upload-list-picture-card{float:none}.more-options-btn[data-v-7111bbfe]{margin-left:15px;text-decoration:none}.photo-card[data-v-7111bbfe]{width:104px;display:inline-block;margin-right:5px}
|
|
@ -1 +0,0 @@
|
|||
.attach-detail-img img{width:100%}.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}@-webkit-keyframes scaleDraw-data-v-0ce6900e{0%{-webkit-transform:scale(1);transform:scale(1)}25%{-webkit-transform:scale(1.3);transform:scale(1.3)}50%{-webkit-transform:scale(1);transform:scale(1)}75%{-webkit-transform:scale(1.3);transform:scale(1.3)}}@keyframes scaleDraw-data-v-0ce6900e{0%{-webkit-transform:scale(1);transform:scale(1)}25%{-webkit-transform:scale(1.3);transform:scale(1.3)}50%{-webkit-transform:scale(1);transform:scale(1)}75%{-webkit-transform:scale(1.3);transform:scale(1.3)}}.upload-button[data-v-0ce6900e]{-webkit-animation:scaleDraw-data-v-0ce6900e 4s ease-in-out infinite;position:fixed;bottom:30px;right:30px}.theme-thumb[data-v-0ce6900e]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.theme-thumb img[data-v-0ce6900e]{width:100%;height:100%;position:absolute;top:0;left:0}
|
|
@ -1 +1 @@
|
|||
.analysis-card-container[data-v-698a5e37]{position:relative;overflow:hidden;width:100%}.analysis-card-container .meta[data-v-698a5e37]{position:relative;overflow:hidden;width:100%;color:rgba(0,0,0,.45);font-size:14px;line-height:22px}.analysis-card-container .meta .analysis-card-action[data-v-698a5e37]{cursor:pointer;position:absolute;top:0;right:0}.number[data-v-698a5e37]{overflow:hidden;text-overflow:ellipsis;word-break:break-all;white-space:nowrap;color:#000;margin-top:4px;margin-bottom:0;font-size:32px;line-height:38px;height:38px}
|
||||
.analysis-card-container[data-v-698a5e37]{position:relative;overflow:hidden;width:100%}.analysis-card-container .meta[data-v-698a5e37]{position:relative;overflow:hidden;width:100%;color:rgba(0,0,0,.45);font-size:14px;line-height:22px}.analysis-card-container .meta .analysis-card-action[data-v-698a5e37]{cursor:pointer;position:absolute;top:0;right:0}.number[data-v-698a5e37]{overflow:hidden;text-overflow:ellipsis;word-break:break-all;white-space:nowrap;color:#000;margin-top:4px;margin-bottom:0;font-size:32px;line-height:38px;height:38px}.ant-upload-select-picture-card i{font-size:32px;color:#999}.ant-upload-select-picture-card .ant-upload-text{margin-top:8px;color:#666}.ant-upload-list-picture-card{float:none}.more-options-btn[data-v-77a18f66]{margin-left:15px;text-decoration:none}a[data-v-77a18f66]{text-decoration:none}
|
|
@ -0,0 +1 @@
|
|||
.ant-divider-horizontal[data-v-604cba98]{margin:24px 0 12px 0}.search-box[data-v-604cba98]{padding-bottom:12px}.attach-thumb[data-v-604cba98]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.attach-thumb img[data-v-604cba98],.attach-thumb span[data-v-604cba98]{width:100%;height:100%;position:absolute;top:0;left:0}.attach-thumb span[data-v-604cba98]{display:-webkit-box;display:-ms-flexbox;display:flex;font-size:12px;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;color:#9b9ea0}.ant-card-meta[data-v-604cba98]{padding:.8rem}.attach-detail-img img[data-v-604cba98]{width:100%}.table-operator[data-v-604cba98]{margin-bottom:0}
|
|
@ -0,0 +1 @@
|
|||
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}a[data-v-a379d92e]{text-decoration:none}.post-title[data-v-a379d92e]{max-width:150px;display:block;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}
|
|
@ -0,0 +1 @@
|
|||
.v-note-wrapper[data-v-6a7e5dfd]{z-index:1000;min-height:580px}
|
|
@ -0,0 +1 @@
|
|||
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}@font-face{font-family:fontello;src:url(../fonts/fontello.e73a0647.eot);src:url(../fonts/fontello.e73a0647.eot#iefix) format("embedded-opentype"),url(../fonts/fontello.8d4a4e6f.woff2) format("woff2"),url(../fonts/fontello.a782baa8.woff) format("woff"),url(../fonts/fontello.068ca2b3.ttf) format("truetype"),url(../assets/fontello.9354499c.svg#fontello) format("svg");font-weight:400;font-style:normal}[class*=" fa-mavon-"]:before,[class^=fa-mavon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-mavon-bold:before{content:"\E800"}.fa-mavon-italic:before{content:"\E801"}.fa-mavon-thumb-tack:before{content:"\E802"}.fa-mavon-link:before{content:"\E803"}.fa-mavon-picture-o:before{content:"\E804"}.fa-mavon-repeat:before{content:"\E805"}.fa-mavon-undo:before{content:"\E806"}.fa-mavon-trash-o:before{content:"\E807"}.fa-mavon-floppy-o:before{content:"\E808"}.fa-mavon-compress:before{content:"\E809"}.fa-mavon-eye:before{content:"\E80A"}.fa-mavon-eye-slash:before{content:"\E80B"}.fa-mavon-question-circle:before{content:"\E80C"}.fa-mavon-times:before{content:"\E80D"}.fa-mavon-align-left:before{content:"\E80F"}.fa-mavon-align-center:before{content:"\E810"}.fa-mavon-align-right:before{content:"\E811"}.fa-mavon-arrows-alt:before{content:"\F0B2"}.fa-mavon-bars:before{content:"\F0C9"}.fa-mavon-list-ul:before{content:"\F0CA"}.fa-mavon-list-ol:before{content:"\F0CB"}.fa-mavon-strikethrough:before{content:"\F0CC"}.fa-mavon-underline:before{content:"\F0CD"}.fa-mavon-table:before{content:"\F0CE"}.fa-mavon-columns:before{content:"\F0DB"}.fa-mavon-quote-left:before{content:"\F10D"}.fa-mavon-code:before{content:"\F121"}.fa-mavon-superscript:before{content:"\F12B"}.fa-mavon-subscript:before{content:"\F12C"}.fa-mavon-header:before{content:"\F1DC"}.fa-mavon-window-maximize:before{content:"\F2D0"}.markdown-body strong{font-weight:bolder}.markdown-body .hljs-center{text-align:center}.markdown-body .hljs-right{text-align:right}.markdown-body .hljs-left{text-align:left}
|
|
@ -1 +0,0 @@
|
|||
.attach-detail-img img{width:100%}.ant-divider-horizontal[data-v-18d41aa9]{margin:24px 0 12px 0}.search-box[data-v-18d41aa9]{padding-bottom:12px}.attach-thumb[data-v-18d41aa9]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.attach-thumb img[data-v-18d41aa9]{width:100%;height:100%;position:absolute;top:0;left:0}.ant-card-meta[data-v-18d41aa9]{padding:.8rem}.attach-detail-img img[data-v-18d41aa9]{width:100%}.table-operator[data-v-18d41aa9]{margin-bottom:0}
|
|
@ -0,0 +1 @@
|
|||
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}@-webkit-keyframes scaleDraw-data-v-290ad9ab{0%{-webkit-transform:scale(1);transform:scale(1)}25%{-webkit-transform:scale(1.3);transform:scale(1.3)}50%{-webkit-transform:scale(1);transform:scale(1)}75%{-webkit-transform:scale(1.3);transform:scale(1.3)}}@keyframes scaleDraw-data-v-290ad9ab{0%{-webkit-transform:scale(1);transform:scale(1)}25%{-webkit-transform:scale(1.3);transform:scale(1.3)}50%{-webkit-transform:scale(1);transform:scale(1)}75%{-webkit-transform:scale(1.3);transform:scale(1.3)}}.upload-button[data-v-290ad9ab]{-webkit-animation:scaleDraw-data-v-290ad9ab 4s ease-in-out infinite;position:fixed;bottom:30px;right:30px}.theme-thumb[data-v-290ad9ab]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.theme-thumb img[data-v-290ad9ab]{width:100%;height:100%;position:absolute;top:0;left:0}
|
|
@ -1 +1 @@
|
|||
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}.page-header-wrapper-grid-content-main[data-v-69ef61d6]{width:100%;height:100%;min-height:100%;-webkit-transition:.3s;transition:.3s}.page-header-wrapper-grid-content-main .profile-center-avatarHolder[data-v-69ef61d6]{text-align:center;margin-bottom:24px}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar[data-v-69ef61d6]{margin:0 auto;width:104px;height:104px;margin-bottom:20px;border-radius:50%;overflow:hidden;cursor:pointer}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar img[data-v-69ef61d6]{height:100%;width:100%}.page-header-wrapper-grid-content-main .profile-center-avatarHolder .username[data-v-69ef61d6]{color:rgba(0,0,0,.85);font-size:20px;line-height:28px;font-weight:500;margin-bottom:4px}.page-header-wrapper-grid-content-main .profile-center-detail p[data-v-69ef61d6]{margin-bottom:8px;padding-left:26px;position:relative}.page-header-wrapper-grid-content-main .profile-center-detail i[data-v-69ef61d6]{position:absolute;height:14px;width:14px;left:0;top:4px}
|
||||
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}.page-header-wrapper-grid-content-main[data-v-7e8f2146]{width:100%;height:100%;min-height:100%;-webkit-transition:.3s;transition:.3s}.page-header-wrapper-grid-content-main .profile-center-avatarHolder[data-v-7e8f2146]{text-align:center;margin-bottom:24px}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar[data-v-7e8f2146]{margin:0 auto;width:104px;height:104px;margin-bottom:20px;border-radius:50%;overflow:hidden;cursor:pointer}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar img[data-v-7e8f2146]{height:100%;width:100%}.page-header-wrapper-grid-content-main .profile-center-avatarHolder .username[data-v-7e8f2146]{color:rgba(0,0,0,.85);font-size:20px;line-height:28px;font-weight:500;margin-bottom:4px}.page-header-wrapper-grid-content-main .profile-center-detail p[data-v-7e8f2146]{margin-bottom:8px;padding-left:26px;position:relative}.page-header-wrapper-grid-content-main .profile-center-detail i[data-v-7e8f2146]{position:absolute;height:14px;width:14px;left:0;top:4px}
|
File diff suppressed because one or more lines are too long
|
@ -1 +0,0 @@
|
|||
.v-note-wrapper[data-v-348cd59e]{z-index:1000;min-height:580px}.post-thum .img[data-v-348cd59e]{width:100%;cursor:pointer;border-radius:4px}.post-thum .post-thum-remove[data-v-348cd59e]{margin-top:16px}
|
|
@ -1 +0,0 @@
|
|||
.attach-detail-img img{width:100%}.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}@font-face{font-family:fontello;src:url(../fonts/fontello.e73a0647.eot);src:url(../fonts/fontello.e73a0647.eot#iefix) format("embedded-opentype"),url(../fonts/fontello.8d4a4e6f.woff2) format("woff2"),url(../fonts/fontello.a782baa8.woff) format("woff"),url(../fonts/fontello.068ca2b3.ttf) format("truetype"),url(../assets/fontello.9354499c.svg#fontello) format("svg");font-weight:400;font-style:normal}[class*=" fa-mavon-"]:before,[class^=fa-mavon-]:before{font-family:fontello;font-style:normal;font-weight:400;speak:none;display:inline-block;text-decoration:inherit;width:1em;margin-right:.2em;text-align:center;font-variant:normal;text-transform:none;line-height:1em;margin-left:.2em;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.fa-mavon-bold:before{content:"\E800"}.fa-mavon-italic:before{content:"\E801"}.fa-mavon-thumb-tack:before{content:"\E802"}.fa-mavon-link:before{content:"\E803"}.fa-mavon-picture-o:before{content:"\E804"}.fa-mavon-repeat:before{content:"\E805"}.fa-mavon-undo:before{content:"\E806"}.fa-mavon-trash-o:before{content:"\E807"}.fa-mavon-floppy-o:before{content:"\E808"}.fa-mavon-compress:before{content:"\E809"}.fa-mavon-eye:before{content:"\E80A"}.fa-mavon-eye-slash:before{content:"\E80B"}.fa-mavon-question-circle:before{content:"\E80C"}.fa-mavon-times:before{content:"\E80D"}.fa-mavon-align-left:before{content:"\E80F"}.fa-mavon-align-center:before{content:"\E810"}.fa-mavon-align-right:before{content:"\E811"}.fa-mavon-arrows-alt:before{content:"\F0B2"}.fa-mavon-bars:before{content:"\F0C9"}.fa-mavon-list-ul:before{content:"\F0CA"}.fa-mavon-list-ol:before{content:"\F0CB"}.fa-mavon-strikethrough:before{content:"\F0CC"}.fa-mavon-underline:before{content:"\F0CD"}.fa-mavon-table:before{content:"\F0CE"}.fa-mavon-columns:before{content:"\F0DB"}.fa-mavon-quote-left:before{content:"\F10D"}.fa-mavon-code:before{content:"\F121"}.fa-mavon-superscript:before{content:"\F12B"}.fa-mavon-subscript:before{content:"\F12C"}.fa-mavon-header:before{content:"\F1DC"}.fa-mavon-window-maximize:before{content:"\F2D0"}.markdown-body strong{font-weight:bolder}.markdown-body .hljs-center{text-align:center}.markdown-body .hljs-right{text-align:right}.markdown-body .hljs-left{text-align:left}
|
|
@ -1 +0,0 @@
|
|||
body{height:100%;background-color:#f5f5f5}.container{background:#f7f7f7;position:absolute;top:45%;left:50%;margin:-160px 0 0 -160px;width:320px;padding:16px 32px 32px 32px;-webkit-box-shadow:-4px 7px 46px 2px rgba(0,0,0,.1);box-shadow:-4px 7px 46px 2px rgba(0,0,0,.1)}.loginLogo{margin-bottom:20px;text-align:center}.loginLogo span{vertical-align:text-bottom;font-size:36px;display:inline-block;font-weight:600;color:#1790fe;background-image:-webkit-gradient(linear,37.219838% 34.532506%,36.425669% 93.178216%,from(#36c8f5),to(#1790fe),color-stop(.37,#1790fe));-webkit-text-fill-color:transparent;-webkit-background-clip:text}
|
|
@ -1 +1 @@
|
|||
<!DOCTYPE html><html lang=zh-cmn-Hans><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><meta name=robots content=noindex,nofllow><meta name=generator content=Halo><link rel=icon href=/logo.png><title>Halo Dashboard</title><link href=/css/chunk-0337f7a6.4c6b622f.css rel=prefetch><link href=/css/chunk-1079f749.94b473ad.css rel=prefetch><link href=/css/chunk-14e0b302.32f796a8.css rel=prefetch><link href=/css/chunk-161dc990.5ac5144c.css rel=prefetch><link href=/css/chunk-1be69b35.43c1fc12.css rel=prefetch><link href=/css/chunk-31c8ea42.4a090118.css rel=prefetch><link href=/css/chunk-5000e55c.7fb9bc61.css rel=prefetch><link href=/css/chunk-6d8b31f6.ad8d17b2.css rel=prefetch><link href=/css/chunk-81d936d8.05888d95.css rel=prefetch><link href=/css/chunk-b2d0b040.389eca76.css rel=prefetch><link href=/css/chunk-bb4f0d4a.c1990d7c.css rel=prefetch><link href=/css/chunk-bfd5bbcc.6a83ae7d.css rel=prefetch><link href=/css/chunk-c0a1d3c4.09186be6.css rel=prefetch><link href=/css/chunk-cec31564.6f053d75.css rel=prefetch><link href=/css/fail.809a6bc5.css rel=prefetch><link href=/js/chunk-0337f7a6.11326d77.js rel=prefetch><link href=/js/chunk-0ba750a2.b786c9db.js rel=prefetch><link href=/js/chunk-1079f749.ec67c7db.js rel=prefetch><link href=/js/chunk-142c8832.0f8270b3.js rel=prefetch><link href=/js/chunk-14e0b302.a86d1254.js rel=prefetch><link href=/js/chunk-161dc990.5de9313f.js rel=prefetch><link href=/js/chunk-1be69b35.81559bfc.js rel=prefetch><link href=/js/chunk-2d0b64bf.61d5d7c3.js rel=prefetch><link href=/js/chunk-2d0d65a2.2249765a.js rel=prefetch><link href=/js/chunk-2d21a35c.eda7a11a.js rel=prefetch><link href=/js/chunk-2d228d13.85b46532.js rel=prefetch><link href=/js/chunk-31c8ea42.0b2feab9.js rel=prefetch><link href=/js/chunk-5000e55c.3bd9ce3a.js rel=prefetch><link href=/js/chunk-5bf599cc.6555f060.js rel=prefetch><link href=/js/chunk-6d8b31f6.b64e5366.js rel=prefetch><link href=/js/chunk-81d936d8.8bec77ac.js rel=prefetch><link href=/js/chunk-87e2df70.0ada7d4e.js rel=prefetch><link href=/js/chunk-b2d0b040.b0d70d07.js rel=prefetch><link href=/js/chunk-bb4f0d4a.ef7d1ded.js rel=prefetch><link href=/js/chunk-bfd5bbcc.d2ca1e80.js rel=prefetch><link href=/js/chunk-c0a1d3c4.41d0d3f8.js rel=prefetch><link href=/js/chunk-cec31564.cfe3fd85.js rel=prefetch><link href=/js/fail.61f30b0f.js rel=prefetch><link href=/css/app.852293da.css rel=preload as=style><link href=/css/chunk-vendors.ee4e8dbf.css rel=preload as=style><link href=/js/app.29b04043.js rel=preload as=script><link href=/js/chunk-vendors.2f7bce79.js rel=preload as=script><link href=/css/chunk-vendors.ee4e8dbf.css rel=stylesheet><link href=/css/app.852293da.css rel=stylesheet></head><body><noscript><strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.2f7bce79.js></script><script src=/js/app.29b04043.js></script></body></html>
|
||||
<!DOCTYPE html><html lang=zh-cmn-Hans><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><meta name=robots content=noindex,nofllow><meta name=generator content=Halo><link rel=icon href=/logo.png><title>Halo Dashboard</title><link href=/css/chunk-0337f7a6.4c6b622f.css rel=prefetch><link href=/css/chunk-0a078271.3df10fb3.css rel=prefetch><link href=/css/chunk-0d3fb064.5797d58a.css rel=prefetch><link href=/css/chunk-1021dac6.d511bd53.css rel=prefetch><link href=/css/chunk-14ae239d.e9de712a.css rel=prefetch><link href=/css/chunk-14e0b302.32f796a8.css rel=prefetch><link href=/css/chunk-1be69b35.43c1fc12.css rel=prefetch><link href=/css/chunk-2430dc8c.3592751a.css rel=prefetch><link href=/css/chunk-31c8ea42.4a090118.css rel=prefetch><link href=/css/chunk-3939e374.206f7b3f.css rel=prefetch><link href=/css/chunk-3b51c5ec.8e8c628e.css rel=prefetch><link href=/css/chunk-423b6722.dc42f304.css rel=prefetch><link href=/css/chunk-6d8b31f6.ad8d17b2.css rel=prefetch><link href=/css/chunk-71df32ec.5ac5144c.css rel=prefetch><link href=/css/chunk-7af5ef16.684c5100.css rel=prefetch><link href=/css/chunk-aa61da20.bb28474a.css rel=prefetch><link href=/css/chunk-b2e922b4.35a0ae16.css rel=prefetch><link href=/css/chunk-bb4f0d4a.c1990d7c.css rel=prefetch><link href=/css/fail.809a6bc5.css rel=prefetch><link href=/js/chunk-0337f7a6.363f14d6.js rel=prefetch><link href=/js/chunk-0a078271.82e60fe7.js rel=prefetch><link href=/js/chunk-0ba750a2.43dc1b14.js rel=prefetch><link href=/js/chunk-0d3fb064.5a2b4eaa.js rel=prefetch><link href=/js/chunk-1021dac6.8b7c9616.js rel=prefetch><link href=/js/chunk-14ae239d.d15f85b1.js rel=prefetch><link href=/js/chunk-14e0b302.f32c7cb3.js rel=prefetch><link href=/js/chunk-1be69b35.399a467a.js rel=prefetch><link href=/js/chunk-2430dc8c.9c9f8538.js rel=prefetch><link href=/js/chunk-2d0b64bf.ed671024.js rel=prefetch><link href=/js/chunk-2d0d65a2.2f8a16de.js rel=prefetch><link href=/js/chunk-2d21a35c.69287534.js rel=prefetch><link href=/js/chunk-2d228d13.75eca9d7.js rel=prefetch><link href=/js/chunk-31c8ea42.7133cb21.js rel=prefetch><link href=/js/chunk-3939e374.cb5da37a.js rel=prefetch><link href=/js/chunk-3b51c5ec.80a40c78.js rel=prefetch><link href=/js/chunk-423b6722.af6d6aaa.js rel=prefetch><link href=/js/chunk-6d8b31f6.db21019b.js rel=prefetch><link href=/js/chunk-71df32ec.a5429fe8.js rel=prefetch><link href=/js/chunk-7af5ef16.6ad0d11c.js rel=prefetch><link href=/js/chunk-aa61da20.c3df7494.js rel=prefetch><link href=/js/chunk-b2e922b4.32665c80.js rel=prefetch><link href=/js/chunk-bb4f0d4a.4e789394.js rel=prefetch><link href=/js/fail.e23b7151.js rel=prefetch><link href=/css/app.05b5cd85.css rel=preload as=style><link href=/css/chunk-vendors.ee4e8dbf.css rel=preload as=style><link href=/js/app.f0c2e6d9.js rel=preload as=script><link href=/js/chunk-vendors.2f7bce79.js rel=preload as=script><link href=/css/chunk-vendors.ee4e8dbf.css rel=stylesheet><link href=/css/app.05b5cd85.css rel=stylesheet></head><body><noscript><strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.2f7bce79.js></script><script src=/js/app.f0c2e6d9.js></script></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue