Merge pull request #172 from halo-dev/dev

Dev
pull/1449/head
Ryan Wang 2019-06-01 01:12:42 +08:00 committed by GitHub
commit d6bfa0748c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
106 changed files with 936 additions and 7970 deletions

View File

@ -5,7 +5,8 @@
**我确定我已经查看了** (标注`[ ]`为`[x]`)
- [ ] [Halo 使用文档](https://docs.halo.run/)
- [ ] [Halo 使用文档](https://halo.run/docs)
- [ ] [Halo 论坛](https://bbs.halo.run)
- [ ] [Github Wiki 常见问题](https://github.com/halo-dev/halo/wiki/4.-%E5%B8%B8%E8%A7%81%E9%97%AE%E9%A2%98)
- [ ] [其他 Issues](https://github.com/halo-dev/halo/issues)

View File

@ -35,9 +35,10 @@
## 周边
- 后台管理源码:<[https://github.com/halo-dev/halo-admin](https://github.com/halo-dev/halo-admin)>
- 后台管理halo-admin<[https://github.com/halo-dev/halo-admin](https://github.com/halo-dev/halo-admin)>
- 独立评论模块halo-comment<[https://github.com/halo-dev/halo-comment](https://github.com/halo-dev/halo-comment)>
- 管理 APPhalo-app<[https://github.com/halo-dev/halo-app](https://github.com/halo-dev/halo-app)>
- 主题仓库:<[https://halo.run/theme](https://halo.run/theme)>
- 管理 APP<[https://github.com/halo-dev/halo-app](https://github.com/halo-dev/halo-app)>
## 许可证

View File

@ -8,7 +8,7 @@ apply plugin: 'io.spring.dependency-management'
group = 'run.halo.app'
archivesBaseName = 'halo'
version = '1.0.0-beta.7'
version = '1.0.0-beta.8'
sourceCompatibility = '1.8'
description = 'Halo, personal blog system developed in Java.'
@ -56,6 +56,10 @@ dependencies {
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'

View File

@ -113,7 +113,8 @@ public class HaloConfiguration {
ApiAuthenticationFilter apiFilter = new ApiAuthenticationFilter(haloProperties, optionService);
apiFilter.addExcludeUrlPatterns(
"/api/content/*/comments",
"/api/content/**/comments/**"
"/api/content/**/comments/**",
"/api/content/options/comment"
);
DefaultAuthenticationFailureHandler failureHandler = new DefaultAuthenticationFailureHandler();

View File

@ -1,9 +1,18 @@
package run.halo.app.controller.admin.api;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestPart;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import run.halo.app.service.BackupService;
import java.io.IOException;
import java.util.LinkedList;
import java.util.List;
/**
* Backup controller
*
@ -19,4 +28,15 @@ public class BackupController {
public BackupController(BackupService backupService) {
this.backupService = backupService;
}
@PostMapping("import/markdowns")
@ApiOperation("Import markdowns")
public List<BasePostDetailDTO> backupMarkdowns(@RequestPart("files") MultipartFile[] files) throws IOException {
List<BasePostDetailDTO> result = new LinkedList<>();
for (MultipartFile file : files) {
BasePostDetailDTO post = backupService.importMarkdowns(file);
result.add(post);
}
return result;
}
}

View File

@ -50,7 +50,7 @@ public class JournalController {
}
@GetMapping
@ApiOperation("Gets latest journals")
@ApiOperation("Lists journals")
public Page<JournalWithCmtCountDTO> pageBy(@PageableDefault(sort = "updateTime", direction = DESC) Pageable pageable,
JournalQuery journalQuery) {
Page<Journal> journalPage = journalService.pageBy(journalQuery, pageable);

View File

@ -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("You cannot migrate after blog installing");
throw new BadRequestException("不能在博客初始化完成之后迁移数据");
}
recoveryService.migrateFromV0_4_3(file);

View File

@ -5,6 +5,7 @@ import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.*;
import run.halo.app.model.dto.InternalSheetDTO;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.enums.PostStatus;
@ -13,6 +14,7 @@ import run.halo.app.model.vo.SheetListVO;
import run.halo.app.service.SheetService;
import javax.validation.Valid;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
@ -20,6 +22,7 @@ import static org.springframework.data.domain.Sort.Direction.DESC;
* Sheet controller.
*
* @author johnniang
* @author ryanwang
* @date 19-4-24
*/
@RestController
@ -46,6 +49,12 @@ public class SheetController {
return sheetService.convertToListVo(sheetPage);
}
@GetMapping("internal")
@ApiOperation("Lists internal sheets")
public List<InternalSheetDTO> internalSheets() {
return sheetService.listInternal();
}
@PostMapping
@ApiOperation("Creates a sheet")
public BasePostDetailDTO createBy(@RequestBody @Valid SheetParam sheetParam,

View File

@ -117,6 +117,13 @@ public class ThemeController {
themeSettingService.save(settings, themeId);
}
@PutMapping("{themeId}")
public ThemeProperty updateTheme(@PathVariable("themeId") String themeId,
@RequestPart(name = "file", required = false) MultipartFile file) {
return themeService.update(themeId);
}
@DeleteMapping("{themeId}")
@ApiOperation("Deletes a theme")
public void deleteBy(@PathVariable("themeId") String themeId) {
@ -145,4 +152,5 @@ public class ThemeController {
public BaseResponse exists(@RequestParam(value = "template") String template) {
return BaseResponse.ok(themeService.templateExists(template));
}
}

View File

@ -5,6 +5,7 @@ import run.halo.app.model.dto.UserDTO;
import run.halo.app.model.entity.User;
import run.halo.app.model.params.PasswordParam;
import run.halo.app.model.params.UserParam;
import run.halo.app.model.support.BaseResponse;
import run.halo.app.model.support.UpdateCheck;
import run.halo.app.service.UserService;
import run.halo.app.utils.ValidationUtils;
@ -45,7 +46,8 @@ public class UserController {
}
@PutMapping("profiles/password")
public void updatePassword(@RequestBody @Valid PasswordParam passwordParam, User user) {
public BaseResponse updatePassword(@RequestBody @Valid PasswordParam passwordParam, User user) {
userService.updatePassword(passwordParam.getOldPassword(), passwordParam.getNewPassword(), user.getId());
return BaseResponse.ok("密码修改成功");
}
}

View File

@ -8,13 +8,18 @@ import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.*;
import run.halo.app.cache.lock.CacheLock;
import run.halo.app.model.dto.BaseCommentDTO;
import run.halo.app.model.entity.JournalComment;
import run.halo.app.model.enums.CommentStatus;
import run.halo.app.model.params.JournalCommentParam;
import run.halo.app.model.vo.BaseCommentVO;
import run.halo.app.model.vo.BaseCommentWithParentVO;
import run.halo.app.model.vo.CommentWithHasChildrenVO;
import run.halo.app.service.JournalCommentService;
import run.halo.app.service.JournalService;
import run.halo.app.service.OptionService;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
@ -39,12 +44,32 @@ public class JournalController {
this.optionService = optionService;
}
@GetMapping("{journalId:\\d+}/comments/top_view")
public Page<CommentWithHasChildrenVO> listTopComments(@PathVariable("journalId") Integer journalId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
Page<CommentWithHasChildrenVO> result = journalCommentService.pageTopCommentsBy(journalId, CommentStatus.PUBLISHED, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return journalCommentService.filterIpAddress(result);
}
@GetMapping("{journalId:\\d+}/comments/{commentParentId:\\d+}/children")
public List<BaseCommentDTO> listChildrenBy(@PathVariable("journalId") Integer journalId,
@PathVariable("commentParentId") Long commentParentId,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
// Find all children comments
List<JournalComment> postComments = journalCommentService.listChildrenBy(journalId, commentParentId, CommentStatus.PUBLISHED, sort);
// Convert to base comment dto
List<BaseCommentDTO> result = journalCommentService.convertTo(postComments);
return journalCommentService.filterIpAddress(result);
}
@GetMapping("{journalId:\\d+}/comments/tree_view")
@ApiOperation("Lists comments with tree view")
public Page<BaseCommentVO> listCommentsTree(@PathVariable("journalId") Integer journalId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return journalCommentService.pageVosBy(journalId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
Page<BaseCommentVO> result = journalCommentService.pageVosBy(journalId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return journalCommentService.filterIpAddress(result);
}
@GetMapping("{journalId:\\d+}/comments/list_view")
@ -52,7 +77,8 @@ public class JournalController {
public Page<BaseCommentWithParentVO> listComments(@PathVariable("journalId") Integer journalId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return journalCommentService.pageWithParentVoBy(journalId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
Page<BaseCommentWithParentVO> result = journalCommentService.pageWithParentVoBy(journalId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return journalCommentService.filterIpAddress(result);
}
@PostMapping("comments")

View File

@ -8,6 +8,7 @@ import run.halo.app.model.dto.OptionDTO;
import run.halo.app.model.support.BaseResponse;
import run.halo.app.service.OptionService;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@ -48,4 +49,14 @@ public class OptionController {
public BaseResponse<Object> getBy(@PathVariable("key") String key) {
return BaseResponse.ok(HttpStatus.OK.getReasonPhrase(), optionService.getByKey(key).orElse(null));
}
@GetMapping("comment")
@ApiOperation("Options for comment")
public Map<String, Object> comment() {
List<String> keys = new ArrayList<>();
keys.add("comment_gavatar_default");
keys.add("comment_content_placeholder");
return optionService.listOptions(keys);
}
}

View File

@ -83,7 +83,10 @@ public class PostController {
public Page<CommentWithHasChildrenVO> listTopComments(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return postCommentService.pageTopCommentsBy(postId, CommentStatus.PUBLISHED, PageRequest.of(page, optionService.getCommentPageSize(), sort));
Page<CommentWithHasChildrenVO> result = postCommentService.pageTopCommentsBy(postId, CommentStatus.PUBLISHED, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return postCommentService.filterIpAddress(result);
}
@ -94,7 +97,10 @@ public class PostController {
// Find all children comments
List<PostComment> postComments = postCommentService.listChildrenBy(postId, commentParentId, CommentStatus.PUBLISHED, sort);
// Convert to base comment dto
return postCommentService.convertTo(postComments);
List<BaseCommentDTO> result = postCommentService.convertTo(postComments);
return postCommentService.filterIpAddress(result);
}
@GetMapping("{postId:\\d+}/comments/tree_view")
@ -102,7 +108,8 @@ public class PostController {
public Page<BaseCommentVO> listCommentsTree(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return postCommentService.pageVosBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
Page<BaseCommentVO> result = postCommentService.pageVosBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return postCommentService.filterIpAddress(result);
}
@GetMapping("{postId:\\d+}/comments/list_view")
@ -110,7 +117,8 @@ public class PostController {
public Page<BaseCommentWithParentVO> listComments(@PathVariable("postId") Integer postId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return postCommentService.pageWithParentVoBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
Page<BaseCommentWithParentVO> result = postCommentService.pageWithParentVoBy(postId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return postCommentService.filterIpAddress(result);
}
@PostMapping("comments")

View File

@ -8,13 +8,18 @@ import org.springframework.data.web.SortDefault;
import org.springframework.web.bind.annotation.*;
import run.halo.app.cache.lock.CacheLock;
import run.halo.app.model.dto.BaseCommentDTO;
import run.halo.app.model.entity.SheetComment;
import run.halo.app.model.enums.CommentStatus;
import run.halo.app.model.params.SheetCommentParam;
import run.halo.app.model.vo.BaseCommentVO;
import run.halo.app.model.vo.BaseCommentWithParentVO;
import run.halo.app.model.vo.CommentWithHasChildrenVO;
import run.halo.app.service.OptionService;
import run.halo.app.service.SheetCommentService;
import run.halo.app.service.SheetService;
import java.util.List;
import static org.springframework.data.domain.Sort.Direction.DESC;
/**
@ -39,13 +44,33 @@ public class SheetController {
this.optionService = optionService;
}
@GetMapping("{sheetId:\\d+}/comments/top_view")
public Page<CommentWithHasChildrenVO> listTopComments(@PathVariable("sheetId") Integer sheetId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
Page<CommentWithHasChildrenVO> result = sheetCommentService.pageTopCommentsBy(sheetId, CommentStatus.PUBLISHED, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return sheetCommentService.filterIpAddress(result);
}
@GetMapping("{sheetId:\\d+}/comments/{commentParentId:\\d+}/children")
public List<BaseCommentDTO> listChildrenBy(@PathVariable("sheetId") Integer sheetId,
@PathVariable("commentParentId") Long commentParentId,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
// Find all children comments
List<SheetComment> sheetComments = sheetCommentService.listChildrenBy(sheetId, commentParentId, CommentStatus.PUBLISHED, sort);
// Convert to base comment dto
List<BaseCommentDTO> result = sheetCommentService.convertTo(sheetComments);
return sheetCommentService.filterIpAddress(result);
}
@GetMapping("{sheetId:\\d+}/comments/tree_view")
@ApiOperation("Lists comments with tree view")
public Page<BaseCommentVO> listCommentsTree(@PathVariable("sheetId") Integer sheetId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return sheetCommentService.pageVosBy(sheetId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
Page<BaseCommentVO> result = sheetCommentService.pageVosBy(sheetId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return sheetCommentService.filterIpAddress(result);
}
@GetMapping("{sheetId:\\d+}/comments/list_view")
@ -53,7 +78,8 @@ public class SheetController {
public Page<BaseCommentWithParentVO> listComments(@PathVariable("sheetId") Integer sheetId,
@RequestParam(name = "page", required = false, defaultValue = "0") int page,
@SortDefault(sort = "createTime", direction = DESC) Sort sort) {
return sheetCommentService.pageWithParentVoBy(sheetId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
Page<BaseCommentWithParentVO> result = sheetCommentService.pageWithParentVoBy(sheetId, PageRequest.of(page, optionService.getCommentPageSize(), sort));
return sheetCommentService.filterIpAddress(result);
}
@PostMapping("comments")

View File

@ -57,11 +57,7 @@ public class CommonController implements ErrorController {
}
}
if (statusCode == 500) {
return "redirect:/500";
} else {
return "redirect:/404";
}
return statusCode == 500 ? "redirect:/500" : "redirect:/404";
}
/**

View File

@ -0,0 +1,18 @@
package run.halo.app.exception;
/**
* Theme update exception.
*
* @author johnniang
* @date 19-5-30
*/
public class ThemeUpdateException extends ServiceException {
public ThemeUpdateException(String message) {
super(message);
}
public ThemeUpdateException(String message, Throwable cause) {
super(message, cause);
}
}

View File

@ -46,6 +46,7 @@ public class AliYunFileHandler implements FileHandler {
String ossAccessKey = optionService.getByPropertyOfNonNull(AliYunProperties.OSS_ACCESS_KEY).toString();
String ossAccessSecret = optionService.getByPropertyOfNonNull(AliYunProperties.OSS_ACCESS_SECRET).toString();
String ossBucketName = optionService.getByPropertyOfNonNull(AliYunProperties.OSS_BUCKET_NAME).toString();
String ossStyleRule = optionService.getByPropertyOfNonNull(AliYunProperties.OSS_STYLE_RULE).toString();
String ossSource = StringUtils.join("https://", ossBucketName, "." + ossEndPoint);
// Init OSS client
@ -61,7 +62,7 @@ public class AliYunFileHandler implements FileHandler {
// Upload
PutObjectResult putObjectResult = ossClient.putObject(ossBucketName, upFilePath, file.getInputStream());
if (putObjectResult == null) {
throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to AliYun " + upFilePath);
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到阿里云失败 ");
}
// Response result
@ -78,7 +79,7 @@ public class AliYunFileHandler implements FileHandler {
BufferedImage image = ImageIO.read(file.getInputStream());
uploadResult.setWidth(image.getWidth());
uploadResult.setHeight(image.getHeight());
uploadResult.setThumbPath(filePath);
uploadResult.setThumbPath(StringUtils.isBlank(ossStyleRule) ? filePath : filePath + ossStyleRule);
}
return uploadResult;
@ -113,7 +114,7 @@ public class AliYunFileHandler implements FileHandler {
try {
ossClient.deleteObject(new DeleteObjectsRequest(ossBucketName).withKey(key));
} catch (Exception e) {
throw new FileOperationException("Failed to delete file " + key + " from AliYun", e);
throw new FileOperationException("附件 " + key + " 从阿里云删除失败", e);
} finally {
ossClient.shutdown();
}

View File

@ -162,7 +162,7 @@ public class LocalFileHandler implements FileHandler {
return uploadResult;
} catch (IOException e) {
log.error("Failed to upload file to local: " + uploadPath, e);
throw new ServiceException("Failed to upload file to local").setErrorData(uploadPath);
throw new ServiceException("上传附件失败").setErrorData(uploadPath);
}
}
@ -177,7 +177,7 @@ public class LocalFileHandler implements FileHandler {
try {
Files.delete(path);
} catch (IOException e) {
throw new FileOperationException("Failed to delete " + key + " file", e);
throw new FileOperationException("附件 " + key + " 删除失败", e);
}
// Delete thumb if necessary
@ -197,7 +197,7 @@ public class LocalFileHandler implements FileHandler {
log.warn("Thumbnail: [{}] way not exist", thumbnailPath.toString());
}
} catch (IOException e) {
throw new FileOperationException("Failed to delete " + thumbnailName + " thumbnail", e);
throw new FileOperationException("附件缩略图 " + thumbnailName + " 删除失败", e);
}
}

View File

@ -53,11 +53,11 @@ public class QnYunFileHandler implements FileHandler {
// Get all config
Zone zone = optionService.getQnYunZone();
String accessKey = optionService.getByPropertyOfNonNull(QnYunProperties.ACCESS_KEY).toString();
String secretKey = optionService.getByPropertyOfNonNull(QnYunProperties.SECRET_KEY).toString();
String bucket = optionService.getByPropertyOfNonNull(QnYunProperties.BUCKET).toString();
String domain = optionService.getByPropertyOfNonNull(QnYunProperties.DOMAIN).toString();
String smallUrl = optionService.getByPropertyOrDefault(QnYunProperties.SMALL_URL, String.class, "");
String accessKey = optionService.getByPropertyOfNonNull(QnYunProperties.OSS_ACCESS_KEY).toString();
String secretKey = optionService.getByPropertyOfNonNull(QnYunProperties.OSS_SECRET_KEY).toString();
String bucket = optionService.getByPropertyOfNonNull(QnYunProperties.OSS_BUCKET).toString();
String domain = optionService.getByPropertyOfNonNull(QnYunProperties.OSS_DOMAIN).toString();
String styleRule = optionService.getByPropertyOrDefault(QnYunProperties.OSS_STYLE_RULE, String.class, "");
// Create configuration
Configuration configuration = new Configuration(zone);
@ -109,9 +109,10 @@ public class QnYunFileHandler implements FileHandler {
result.setWidth(putSet.getWidth());
result.setHeight(putSet.getHeight());
result.setMediaType(MediaType.valueOf(Objects.requireNonNull(file.getContentType())));
result.setSize(file.getSize());
if (isImageType(result.getMediaType())) {
result.setThumbPath(StringUtils.isBlank(smallUrl) ? filePath : filePath + smallUrl);
result.setThumbPath(StringUtils.isBlank(styleRule) ? filePath : filePath + styleRule);
}
return result;
@ -120,7 +121,7 @@ public class QnYunFileHandler implements FileHandler {
log.error("QnYun error response: [{}]", ((QiniuException) e).response);
}
throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to QnYun", e);
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到七牛云失败", e);
}
}
@ -130,9 +131,9 @@ public class QnYunFileHandler implements FileHandler {
// Get all config
Zone zone = optionService.getQnYunZone();
String accessKey = optionService.getByPropertyOfNonNull(QnYunProperties.ACCESS_KEY).toString();
String secretKey = optionService.getByPropertyOfNonNull(QnYunProperties.SECRET_KEY).toString();
String bucket = optionService.getByPropertyOfNonNull(QnYunProperties.BUCKET).toString();
String accessKey = optionService.getByPropertyOfNonNull(QnYunProperties.OSS_ACCESS_KEY).toString();
String secretKey = optionService.getByPropertyOfNonNull(QnYunProperties.OSS_SECRET_KEY).toString();
String bucket = optionService.getByPropertyOfNonNull(QnYunProperties.OSS_BUCKET).toString();
// Create configuration
Configuration configuration = new Configuration(zone);

View File

@ -50,7 +50,7 @@ public class SmmsFileHandler implements FileHandler {
if (!FileHandler.isImageType(file.getContentType())) {
log.error("Invalid extension: [{}]", file.getContentType());
throw new FileOperationException("Invalid extension for file " + file.getOriginalFilename() + ". Only \"jpeg, jpg, png, gif, bmp\" files are supported");
throw new FileOperationException("不支持的文件类型,仅支持 \"jpeg, jpg, png, gif, bmp\" 格式的图片");
}
HttpHeaders headers = new HttpHeaders();
@ -65,7 +65,7 @@ public class SmmsFileHandler implements FileHandler {
body.add("smfile", new HttpClientUtils.MultipartFileResource(file.getBytes(), file.getOriginalFilename()));
} catch (IOException e) {
log.error("Failed to get file input stream", e);
throw new FileOperationException("Failed to upload " + file.getOriginalFilename() + " file", e);
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到 SM.MS 失败", e);
}
body.add("ssl", false);
@ -79,7 +79,7 @@ public class SmmsFileHandler implements FileHandler {
// Check status
if (mapResponseEntity.getStatusCode().isError()) {
log.error("Server response detail: [{}]", mapResponseEntity.toString());
throw new FileOperationException("Smms server response error. status: " + mapResponseEntity.getStatusCodeValue());
throw new FileOperationException("SM.MS 服务状态异常,状态码: " + mapResponseEntity.getStatusCodeValue());
}
// Get smms response
@ -88,7 +88,7 @@ public class SmmsFileHandler implements FileHandler {
// Check error
if (!isResponseSuccessfully(smmsResponse)) {
log.error("Smms response detail: [{}]", smmsResponse);
throw new FileOperationException(smmsResponse == null ? "Smms response is null" : smmsResponse.getMsg()).setErrorData(smmsResponse);
throw new FileOperationException(smmsResponse == null ? "SM.MS 服务返回内容为空" : smmsResponse.getMsg()).setErrorData(smmsResponse);
}
// Get response data
@ -128,7 +128,7 @@ public class SmmsFileHandler implements FileHandler {
if (responseEntity.getStatusCode().isError()) {
log.debug("Smms server response error: [{}]", responseEntity.toString());
throw new FileOperationException("Smms server response error");
throw new FileOperationException("SM.MS 服务状态异常");
}
log.debug("Smms response detail: [{}]", responseEntity.getBody());
@ -155,7 +155,7 @@ public class SmmsFileHandler implements FileHandler {
@Data
@ToString
@NoArgsConstructor
static class SmmsResponse {
private static class SmmsResponse {
private String code;
@ -168,7 +168,7 @@ public class SmmsFileHandler implements FileHandler {
@Data
@ToString(callSuper = true)
@NoArgsConstructor
static class SmmsResponseData {
private static class SmmsResponseData {
private String filename;

View File

@ -44,8 +44,8 @@ public class UpYunFileHandler implements FileHandler {
String ossBucket = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_BUCKET).toString();
String ossDomain = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_DOMAIN).toString();
String ossOperator = optionService.getByPropertyOfNonNull(UpYunProperties.OSS_OPERATOR).toString();
// small url can be null
String ossSmallUrl = optionService.getByPropertyOrDefault(UpYunProperties.OSS_SMALL_URL, String.class, "");
// style rule can be null
String ossStyleRule = optionService.getByPropertyOrDefault(UpYunProperties.OSS_STYLE_RULE, String.class, "");
// Create up yun
UpYun upYun = new UpYun(ossBucket, ossOperator, ossPassword);
@ -67,7 +67,7 @@ public class UpYunFileHandler implements FileHandler {
// Write file
boolean uploadSuccess = upYun.writeFile(upFilePath, file.getInputStream(), true, null);
if (!uploadSuccess) {
throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to UpYun " + upFilePath);
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到又拍云失败" + upFilePath);
}
String filePath = StringUtils.removeEnd(ossDomain, "/") + upFilePath;
@ -86,12 +86,12 @@ public class UpYunFileHandler implements FileHandler {
BufferedImage image = ImageIO.read(file.getInputStream());
uploadResult.setWidth(image.getWidth());
uploadResult.setHeight(image.getHeight());
uploadResult.setThumbPath(StringUtils.isBlank(ossSmallUrl) ? filePath : filePath + ossSmallUrl);
uploadResult.setThumbPath(StringUtils.isBlank(ossStyleRule) ? filePath : filePath + ossStyleRule);
}
return uploadResult;
} catch (Exception e) {
throw new FileOperationException("Failed to upload file " + file.getOriginalFilename() + " to UpYun", e);
throw new FileOperationException("上传附件 " + file.getOriginalFilename() + " 到又拍云失败", e);
}
}
@ -118,7 +118,7 @@ public class UpYunFileHandler implements FileHandler {
log.warn("Failed to delete file " + filePath + " from UpYun");
}
} catch (Exception e) {
throw new FileOperationException("Failed to delete file " + key + " from UpYun", e);
throw new FileOperationException("附件从又拍云删除失败", e);
}
}

View File

@ -1,6 +1,8 @@
package run.halo.app.handler.theme.config.impl;
import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.PropertyNamingStrategy;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
@ -18,7 +20,12 @@ import java.io.IOException;
@Service
public class YamlThemePropertyResolver implements ThemePropertyResolver {
private final ObjectMapper yamlMapper = new ObjectMapper(new YAMLFactory());
private final ObjectMapper yamlMapper;
public YamlThemePropertyResolver() {
yamlMapper = new ObjectMapper(new YAMLFactory());
yamlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
}
@Override
public ThemeProperty resolve(String content) throws IOException {

View File

@ -28,6 +28,16 @@ public class ThemeProperty {
*/
private String website;
/**
* Theme remote branch.(default is master)
*/
private String branch;
/**
* Theme repo url.
*/
private String repo;
/**
* Theme description.
*/
@ -49,7 +59,7 @@ public class ThemeProperty {
private Author author;
/**
* Theme path.
* Theme full path.
*/
private String themePath;

View File

@ -0,0 +1,23 @@
package run.halo.app.model.dto;
import lombok.Data;
import java.util.Date;
/**
* @author ryanwang
* @date 2019-05-25
*/
@Data
public class BackupDTO {
private String fileName;
private Date createTime;
private String fileSize;
private String fileType;
private String type;
}

View File

@ -0,0 +1,21 @@
package run.halo.app.model.dto;
import lombok.Data;
/**
* Theme controller.
*
* @author ryanwang
* @date : 2019/5/4
*/
@Data
public class InternalSheetDTO {
private Integer id;
private String title;
private String url;
private boolean status;
}

View File

@ -12,6 +12,7 @@ import run.halo.app.utils.HaloUtils;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;
import java.util.Date;
import java.util.Set;
/**
@ -50,6 +51,8 @@ public class PostParam implements InputConverter<Post> {
@Min(value = 0, message = "Post top priority must not be less than {value}")
private Integer topPriority = 0;
private Date createTime;
private PostCreateFrom createFrom = PostCreateFrom.ADMIN;
private Set<Integer> tagIds;

View File

@ -26,7 +26,12 @@ public enum AliYunProperties implements PropertyEnum {
/**
* Aliyun oss access secret.
*/
OSS_ACCESS_SECRET("oss_aliyun_access_secret", String.class, "");
OSS_ACCESS_SECRET("oss_aliyun_access_secret", String.class, ""),
/**
* Aliyun oss style rule
*/
OSS_STYLE_RULE("oss_aliyun_style_rule", String.class, "");
private final String value;

View File

@ -4,7 +4,8 @@ package run.halo.app.model.properties;
* Comment properties.
*
* @author johnniang
* @date 4/1/19
* @author ryanwang
* @date 2019-04-01
*/
public enum CommentProperties implements PropertyEnum {
@ -22,9 +23,7 @@ public enum CommentProperties implements PropertyEnum {
PAGE_SIZE("comment_page_size", Integer.class, "10"),
CONTENT_PLACEHOLDER("comment_content_placeholder", String.class, ""),
CUSTOM_STYLE("comment_custom_style", String.class, "");
CONTENT_PLACEHOLDER("comment_content_placeholder", String.class, "");
private final String value;

View File

@ -8,17 +8,17 @@ package run.halo.app.model.properties;
*/
public enum QnYunProperties implements PropertyEnum {
ZONE("oss_qiniu_zone", String.class, "auto"),
OSS_ZONE("oss_qiniu_zone", String.class, "auto"),
ACCESS_KEY("oss_qiniu_access_key", String.class, ""),
OSS_ACCESS_KEY("oss_qiniu_access_key", String.class, ""),
SECRET_KEY("oss_qiniu_secret_key", String.class, ""),
OSS_SECRET_KEY("oss_qiniu_secret_key", String.class, ""),
DOMAIN("oss_qiniu_domain", String.class, ""),
OSS_DOMAIN("oss_qiniu_domain", String.class, ""),
BUCKET("oss_qiniu_bucket", String.class, ""),
OSS_BUCKET("oss_qiniu_bucket", String.class, ""),
SMALL_URL("oss_qiniu_small_url", String.class, "");
OSS_STYLE_RULE("oss_qiniu_style_rule", String.class, "");
private final String value;

View File

@ -18,7 +18,7 @@ public enum UpYunProperties implements PropertyEnum {
OSS_OPERATOR("oss_upyun_operator", String.class, ""),
OSS_SMALL_URL("oss_upyun_small_url", String.class, "");
OSS_STYLE_RULE("oss_upyun_style_rule", String.class, "");
private final String defaultValue;
private String value;

View File

@ -36,4 +36,12 @@ public interface CategoryRepository extends BaseRepository<Category, Integer> {
* @return Optional of Category
*/
Optional<Category> getBySlugName(@NonNull String slugName);
/**
* Get category by name.
*
* @param name name
* @return Optional of Category
*/
Optional<Category> getByName(@NonNull String name);
}

View File

@ -1,8 +1,14 @@
package run.halo.app.repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.lang.NonNull;
import run.halo.app.model.entity.JournalComment;
import run.halo.app.model.projection.CommentChildrenCountProjection;
import run.halo.app.model.projection.CommentCountProjection;
import run.halo.app.repository.base.BaseCommentRepository;
import java.util.List;
/**
* Journal comment repository.
*
@ -11,8 +17,18 @@ import run.halo.app.repository.base.BaseCommentRepository;
*/
public interface JournalCommentRepository extends BaseCommentRepository<JournalComment> {
// @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from JournalComment comment where comment.postId in ?1 group by comment.postId")
// @NonNull
// @Override
// List<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
@Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) " +
"from JournalComment comment " +
"where comment.postId in ?1 group by comment.postId")
@NonNull
@Override
List<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
@Query("select new run.halo.app.model.projection.CommentChildrenCountProjection(count(comment.id), comment.parentId) " +
"from JournalComment comment " +
"where comment.parentId in ?1 " +
"group by comment.parentId")
@NonNull
@Override
List<CommentChildrenCountProjection> findDirectChildrenCount(@NonNull Iterable<Long> commentIds);
}

View File

@ -1,8 +1,14 @@
package run.halo.app.repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.lang.NonNull;
import run.halo.app.model.entity.PostComment;
import run.halo.app.model.projection.CommentChildrenCountProjection;
import run.halo.app.model.projection.CommentCountProjection;
import run.halo.app.repository.base.BaseCommentRepository;
import java.util.List;
/**
* PostComment repository.
*
@ -11,9 +17,17 @@ import run.halo.app.repository.base.BaseCommentRepository;
*/
public interface PostCommentRepository extends BaseCommentRepository<PostComment> {
// @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from PostComment comment where comment.postId in ?1 group by comment.postId")
// @NonNull
// @Override
// List<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
@Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) " +
"from PostComment comment " +
"where comment.postId in ?1 group by comment.postId")
@NonNull
@Override
List<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
@Query("select new run.halo.app.model.projection.CommentChildrenCountProjection(count(comment.id), comment.parentId) " +
"from PostComment comment " +
"where comment.parentId in ?1 " +
"group by comment.parentId")
@NonNull
List<CommentChildrenCountProjection> findDirectChildrenCount(@NonNull Iterable<Long> commentIds);
}

View File

@ -1,8 +1,14 @@
package run.halo.app.repository;
import org.springframework.data.jpa.repository.Query;
import org.springframework.lang.NonNull;
import run.halo.app.model.entity.SheetComment;
import run.halo.app.model.projection.CommentChildrenCountProjection;
import run.halo.app.model.projection.CommentCountProjection;
import run.halo.app.repository.base.BaseCommentRepository;
import java.util.List;
/**
* Sheet comment repository.
*
@ -10,9 +16,18 @@ import run.halo.app.repository.base.BaseCommentRepository;
* @date 19-4-24
*/
public interface SheetCommentRepository extends BaseCommentRepository<SheetComment> {
//
// @Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) from SheetComment comment where comment.postId in ?1 group by comment.postId")
// @NonNull
// @Override
// List<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
@Query("select new run.halo.app.model.projection.CommentCountProjection(count(comment.id), comment.postId) " +
"from SheetComment comment " +
"where comment.postId in ?1 group by comment.postId")
@NonNull
@Override
List<CommentCountProjection> countByPostIds(@NonNull Iterable<Integer> postIds);
@Query("select new run.halo.app.model.projection.CommentChildrenCountProjection(count(comment.id), comment.parentId) " +
"from SheetComment comment " +
"where comment.parentId in ?1 " +
"group by comment.parentId")
@NonNull
List<CommentChildrenCountProjection> findDirectChildrenCount(@NonNull Iterable<Long> commentIds);
}

View File

@ -29,4 +29,11 @@ public interface TagRepository extends BaseRepository<Tag, Integer> {
* @return Tag
*/
Optional<Tag> getBySlugName(@NonNull String slugName);
/**
* Get tag by name
* @param name name
* @return Tag
*/
Optional<Tag> getByName(@NonNull String name);
}

View File

@ -1,5 +1,10 @@
package run.halo.app.service;
import org.springframework.web.multipart.MultipartFile;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import java.io.IOException;
/**
* Backup service interface.
*
@ -7,4 +12,12 @@ package run.halo.app.service;
* @date 19-4-26
*/
public interface BackupService {
/**
* Backup posts and sheets
*
* @param file file
* @return post info
*/
BasePostDetailDTO importMarkdowns(MultipartFile file) throws IOException;
}

View File

@ -36,6 +36,14 @@ public interface CategoryService extends CrudService<Category, Integer> {
@NonNull
Category getBySlugName(@NonNull String slugName);
/**
* Get Category by name.
*
* @param name name
* @return Category
*/
Category getByName(@NonNull String name);
/**
* Removes category and post categories.
*

View File

@ -101,10 +101,11 @@ public interface PostService extends BasePostService<Post> {
* Import post from markdown document.
*
* @param markdown markdown document.
* @param filename filename
* @return imported post
*/
@NonNull
Post importMarkdown(@NonNull String markdown);
PostDetailVO importMarkdown(@NonNull String markdown, String filename);
/**
* Export post to markdown file by post id.

View File

@ -2,15 +2,19 @@ package run.halo.app.service;
import org.springframework.data.domain.Page;
import org.springframework.lang.NonNull;
import run.halo.app.model.dto.InternalSheetDTO;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.enums.PostStatus;
import run.halo.app.model.vo.SheetListVO;
import run.halo.app.service.base.BasePostService;
import java.util.List;
/**
* Sheet service interface.
*
* @author johnniang
* @author ryanwang
* @date 19-4-24
*/
public interface SheetService extends BasePostService<Sheet> {
@ -72,6 +76,14 @@ public interface SheetService extends BasePostService<Sheet> {
@NonNull
String exportMarkdown(@NonNull Sheet sheet);
/**
* List internal sheets.
*
* @return list of internal sheets
*/
@NonNull
List<InternalSheetDTO> listInternal();
/**
* Converts to list dto page.
*

View File

@ -25,6 +25,15 @@ public interface TagService extends CrudService<Tag, Integer> {
@NonNull
Tag getBySlugNameOfNonNull(@NonNull String slugName);
/**
* Get tag by tag name.
*
* @param name name
* @return Tag
*/
@Nullable
Tag getByName(@NonNull String name);
/**
* Converts to tag dto.
*

View File

@ -71,6 +71,16 @@ public interface ThemeService {
*/
String CUSTOM_SHEET_PREFIX = "sheet_";
/**
* Theme provider remote name.
*/
String THEME_PROVIDER_REMOTE_NAME = "theme-provider";
/**
* Default remote branch name.
*/
String DEFAULT_REMOTE_BRANCH = "master";
/**
* Get theme property by theme id.
*
@ -241,4 +251,13 @@ public interface ThemeService {
* Reloads themes
*/
void reload();
/**
* Updates theme by theme id.
*
* @param themeId theme id must not be blank
* @return theme property
*/
@NonNull
ThemeProperty update(@NonNull String themeId);
}

View File

@ -214,4 +214,26 @@ public interface BaseCommentService<COMMENT extends BaseComment> extends CrudSer
*/
@NonNull
List<COMMENT> listChildrenBy(@NonNull Integer targetId, @NonNull Long commentParentId, @NonNull CommentStatus status, @NonNull Sort sort);
/**
* Filters comment ip address.
*
* @param comment comment dto must not be null
*/
<T extends BaseCommentDTO> T filterIpAddress(@NonNull T comment);
/**
* Filters comment ip address.
*
* @param comments comment dto list
*/
<T extends BaseCommentDTO> List<T> filterIpAddress(@Nullable List<T> comments);
/**
* Filters comment ip address.
*
* @param commentPage comment page
*/
<T extends BaseCommentDTO> Page<T> filterIpAddress(@NonNull Page<T> commentPage);
}

View File

@ -3,6 +3,7 @@ package run.halo.app.service.impl;
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.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
@ -58,6 +59,8 @@ public class AdminServiceImpl implements AdminService {
private final StringCacheStore cacheStore;
private final ApplicationEventPublisher eventPublisher;
private final String driverClassName;
public AdminServiceImpl(PostService postService,
@ -70,6 +73,7 @@ public class AdminServiceImpl implements AdminService {
UserService userService,
LinkService linkService,
StringCacheStore cacheStore,
ApplicationEventPublisher eventPublisher,
@Value("${spring.datasource.driver-class-name}") String driverClassName) {
this.postService = postService;
this.sheetService = sheetService;
@ -81,6 +85,7 @@ public class AdminServiceImpl implements AdminService {
this.userService = userService;
this.linkService = linkService;
this.cacheStore = cacheStore;
this.eventPublisher = eventPublisher;
this.driverClassName = driverClassName;
}
@ -112,7 +117,7 @@ public class AdminServiceImpl implements AdminService {
if (SecurityContextHolder.getContext().isAuthenticated()) {
// If the user has been logged in
throw new BadRequestException("You have been logged in, do not log in repeatedly please");
throw new BadRequestException("您已登录,请不要重复登录");
}
// Generate new token
@ -125,7 +130,7 @@ public class AdminServiceImpl implements AdminService {
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
if (authentication == null) {
throw new BadRequestException("You haven't logged in yet, so you can't log out");
throw new BadRequestException("您尚未登录,因此无法注销");
}
// Get current user

View File

@ -188,7 +188,7 @@ public class AttachmentServiceImpl extends AbstractCrudService<Attachment, Integ
long pathCount = attachmentRepository.countByPath(attachment.getPath());
if (pathCount > 0) {
throw new AlreadyExistsException("The attachment with path " + attachment.getPath() + " exists already");
throw new AlreadyExistsException("附件路径为 " + attachment.getPath() + " 已经存在");
}
}

View File

@ -1,7 +1,13 @@
package run.halo.app.service.impl;
import cn.hutool.core.io.IoUtil;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;
import run.halo.app.model.dto.post.BasePostDetailDTO;
import run.halo.app.service.BackupService;
import run.halo.app.service.PostService;
import java.io.IOException;
/**
* Backup service implementation.
@ -12,4 +18,20 @@ import run.halo.app.service.BackupService;
@Service
public class BackupServiceImpl implements BackupService {
private final PostService postService;
public BackupServiceImpl(PostService postService) {
this.postService = postService;
}
@Override
public BasePostDetailDTO importMarkdowns(MultipartFile file) throws IOException {
// Read markdown content.
String markdown = IoUtil.read(file.getInputStream(), "UTF-8");
// TODO sheet import
return postService.importMarkdown(markdown, file.getOriginalFilename());
}
}

View File

@ -470,6 +470,53 @@ public abstract class BaseCommentServiceImpl<COMMENT extends BaseComment> extend
return childrenList;
}
@Override
public <T extends BaseCommentDTO> T filterIpAddress(@NonNull T comment) {
Assert.notNull(comment, "Base comment dto must not be null");
// Clear ip address
comment.setIpAddress("");
// Handle base comment vo
if (comment instanceof BaseCommentVO) {
BaseCommentVO baseCommentVO = (BaseCommentVO) comment;
Queue<BaseCommentVO> commentQueue = new LinkedList<>();
commentQueue.offer(baseCommentVO);
while (!commentQueue.isEmpty()) {
BaseCommentVO current = commentQueue.poll();
// Clear ip address
current.setIpAddress("");
if (!CollectionUtils.isEmpty(current.getChildren())) {
// Add children
commentQueue.addAll(current.getChildren());
}
}
}
return comment;
}
@Override
public <T extends BaseCommentDTO> List<T> filterIpAddress(List<T> comments) {
if (CollectionUtils.isEmpty(comments)) {
return Collections.emptyList();
}
comments.forEach(this::filterIpAddress);
return comments;
}
@Override
public <T extends BaseCommentDTO> Page<T> filterIpAddress(Page<T> commentPage) {
Assert.notNull(commentPage, "Comment page must not be null");
commentPage.forEach(this::filterIpAddress);
return commentPage;
}
/**
* Get children comments recursively.
*

View File

@ -342,7 +342,7 @@ public abstract class BasePostServiceImpl<POST extends BasePost> extends Abstrac
}
if (exist) {
throw new AlreadyExistsException("The post url " + post.getUrl() + " has been exist");
throw new AlreadyExistsException("文章路径 " + post.getUrl() + " 已存在");
}
}

View File

@ -16,6 +16,7 @@ import run.halo.app.repository.CategoryRepository;
import run.halo.app.service.CategoryService;
import run.halo.app.service.PostCategoryService;
import run.halo.app.service.base.AbstractCrudService;
import run.halo.app.utils.ServiceUtils;
import java.util.Collections;
import java.util.LinkedList;
@ -52,11 +53,11 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
if (count > 0) {
log.error("Category has exist already: [{}]", category);
throw new AlreadyExistsException("The category has exist already");
throw new AlreadyExistsException("该分类已存在");
}
// Check parent id
if (category.getParentId() > 0) {
if (!ServiceUtils.isEmptyId(category.getParentId())) {
count = categoryRepository.countById(category.getParentId());
if (count == 0) {
@ -154,6 +155,11 @@ public class CategoryServiceImpl extends AbstractCrudService<Category, Integer>
return categoryRepository.getBySlugName(slugName).orElseThrow(() -> new NotFoundException("The Category does not exist").setErrorData(slugName));
}
@Override
public Category getByName(String name) {
return categoryRepository.getByName(name).orElse(null);
}
@Override
public void removeCategoryAndPostCategoryBy(Integer categoryId) {
// Remove category

View File

@ -86,7 +86,7 @@ public class LinkServiceImpl extends AbstractCrudService<Link, Integer> implemen
boolean exist = existByName(linkParam.getName());
if (exist) {
throw new AlreadyExistsException("Link name " + linkParam.getName() + " has already existed").setErrorData(linkParam.getName());
throw new AlreadyExistsException("友情链接 " + linkParam.getName() + " 已存在").setErrorData(linkParam.getName());
}
return create(linkParam.convertTo());

View File

@ -171,7 +171,7 @@ public class MenuServiceImpl extends AbstractCrudService<Menu, Integer> implemen
}
if (exist) {
throw new AlreadyExistsException("The menu name " + menu.getName() + " already exists");
throw new AlreadyExistsException("菜单 " + menu.getName() + " 已存在");
}
}
}

View File

@ -312,7 +312,7 @@ public class OptionServiceImpl extends AbstractCrudService<Option, Integer> impl
@Override
public Zone getQnYunZone() {
return getByProperty(QnYunProperties.ZONE).map(qiniuZone -> {
return getByProperty(QnYunProperties.OSS_ZONE).map(qiniuZone -> {
Zone zone;
switch (qiniuZone.toString()) {

View File

@ -1,6 +1,9 @@
package run.halo.app.service.impl;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.text.StrBuilder;
import cn.hutool.core.util.RandomUtil;
import cn.hutool.core.util.StrUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.ApplicationEventPublisher;
@ -29,6 +32,7 @@ import run.halo.app.service.*;
import run.halo.app.utils.DateUtils;
import run.halo.app.utils.MarkdownUtils;
import run.halo.app.utils.ServiceUtils;
import run.halo.app.utils.SlugUtils;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
@ -275,7 +279,7 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
}
@Override
public Post importMarkdown(String markdown) {
public PostDetailVO importMarkdown(String markdown, String filename) {
Assert.notNull(markdown, "Markdown document must not be null");
// Render markdown to html document.
@ -284,7 +288,80 @@ public class PostServiceImpl extends BasePostServiceImpl<Post> implements PostSe
// Gets frontMatter
Map<String, List<String>> frontMatter = MarkdownUtils.getFrontMatter(markdown);
return null;
Post post = new Post();
List<String> elementValue;
Set<Integer> tagIds = new HashSet<>();
Set<Integer> categoryIds = new HashSet<>();
if (frontMatter.size() > 0) {
for (String key : frontMatter.keySet()) {
elementValue = frontMatter.get(key);
for (String ele : elementValue) {
switch (key) {
case "title":
post.setTitle(ele);
break;
case "date":
post.setCreateTime(DateUtil.parse(ele));
break;
case "updated":
post.setUpdateTime(DateUtil.parse(ele));
break;
case "permalink":
post.setUrl(ele);
break;
case "thumbnail":
post.setThumbnail(ele);
break;
case "status":
post.setStatus(PostStatus.valueOf(ele));
break;
case "comments":
post.setDisallowComment(Boolean.parseBoolean(ele));
break;
case "tags":
Tag tag = tagService.getByName(ele);
if (null == tag) {
tag = new Tag();
tag.setName(ele);
tag.setSlugName(SlugUtils.slugify(ele));
tag = tagService.create(tag);
}
tagIds.add(tag.getId());
case "categories":
Category category = categoryService.getByName(ele);
if (null == category) {
category = new Category();
category.setName(ele);
category.setSlugName(SlugUtils.slugify(ele));
category.setDescription(ele);
category = categoryService.create(category);
}
categoryIds.add(category.getId());
default:
break;
}
}
}
}
if (null == post.getStatus()) {
post.setStatus(PostStatus.PUBLISHED);
}
if (StrUtil.isEmpty(post.getTitle())) {
post.setTitle(filename);
}
if (StrUtil.isEmpty(post.getUrl())) {
post.setUrl(DateUtil.format(new Date(), "yyyyMMddHHmmss" + RandomUtil.randomNumbers(5)));
}
post.setOriginalContent(markdown);
return createBy(post, tagIds, categoryIds, false);
}
@Override

View File

@ -128,7 +128,7 @@ public class RecoveryServiceImpl implements RecoveryService {
log.debug("Migrated posts: [{}]", posts);
}
} catch (IOException e) {
throw new ServiceException("Failed to read multipart file " + file.getOriginalFilename(), e);
throw new ServiceException("备份文件 " + file.getOriginalFilename() + " 读取失败", e);
}
}

View File

@ -8,6 +8,7 @@ import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import run.halo.app.event.logger.LogEvent;
import run.halo.app.event.post.SheetVisitEvent;
import run.halo.app.model.dto.InternalSheetDTO;
import run.halo.app.model.entity.Sheet;
import run.halo.app.model.enums.LogType;
import run.halo.app.model.enums.PostStatus;
@ -16,9 +17,11 @@ import run.halo.app.repository.SheetRepository;
import run.halo.app.service.OptionService;
import run.halo.app.service.SheetCommentService;
import run.halo.app.service.SheetService;
import run.halo.app.service.ThemeService;
import run.halo.app.utils.MarkdownUtils;
import run.halo.app.utils.ServiceUtils;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -27,6 +30,7 @@ import java.util.Set;
* Sheet service implementation.
*
* @author johnniang
* @author ryanwang
* @date 19-4-24
*/
@Service
@ -38,14 +42,18 @@ public class SheetServiceImpl extends BasePostServiceImpl<Sheet> implements Shee
private final SheetCommentService sheetCommentService;
private final ThemeService themeService;
public SheetServiceImpl(SheetRepository sheetRepository,
ApplicationEventPublisher eventPublisher,
SheetCommentService sheetCommentService,
OptionService optionService) {
OptionService optionService,
ThemeService themeService) {
super(sheetRepository, optionService);
this.sheetRepository = sheetRepository;
this.eventPublisher = eventPublisher;
this.sheetCommentService = sheetCommentService;
this.themeService = themeService;
}
@Override
@ -136,6 +144,39 @@ public class SheetServiceImpl extends BasePostServiceImpl<Sheet> implements Shee
return content.toString();
}
@Override
public List<InternalSheetDTO> listInternal() {
List<InternalSheetDTO> internalSheetDTOS = new ArrayList<>();
// links sheet
InternalSheetDTO linkSheet = new InternalSheetDTO();
linkSheet.setId(1);
linkSheet.setTitle("友情链接");
linkSheet.setUrl("/links");
linkSheet.setStatus(themeService.templateExists("links.ftl"));
// photos sheet
InternalSheetDTO photoSheet = new InternalSheetDTO();
photoSheet.setId(2);
photoSheet.setTitle("图库页面");
photoSheet.setUrl("/photos");
photoSheet.setStatus(themeService.templateExists("photos.ftl"));
// journals sheet
InternalSheetDTO journalSheet = new InternalSheetDTO();
journalSheet.setId(3);
journalSheet.setTitle("日志页面");
journalSheet.setUrl("/journals");
journalSheet.setStatus(themeService.templateExists("journals.ftl"));
internalSheetDTOS.add(linkSheet);
internalSheetDTOS.add(photoSheet);
internalSheetDTOS.add(journalSheet);
return internalSheetDTOS;
}
@Override
public Sheet removeById(Integer id) {
Sheet sheet = super.removeById(id);

View File

@ -42,7 +42,7 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
if (count > 0) {
// If the tag has exist already
throw new AlreadyExistsException("The tag has already exist").setErrorData(tag);
throw new AlreadyExistsException("该标签已存在").setErrorData(tag);
}
// Get tag name
@ -60,6 +60,12 @@ public class TagServiceImpl extends AbstractCrudService<Tag, Integer> implements
return tagRepository.getBySlugName(slugName).orElseThrow(() -> new NotFoundException("The tag does not exist").setErrorData(slugName));
}
@Override
public Tag getByName(String name) {
return tagRepository.getByName(name).orElse(null);
}
@Override
public TagDTO convertTo(Tag tag) {
Assert.notNull(tag, "Tag must not be null");

View File

@ -3,7 +3,12 @@ package run.halo.app.service.impl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.PullResult;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.lib.Ref;
import org.eclipse.jgit.transport.RemoteConfig;
import org.eclipse.jgit.transport.URIish;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
@ -32,7 +37,9 @@ import run.halo.app.utils.FilenameUtils;
import run.halo.app.utils.HaloUtils;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
@ -241,7 +248,7 @@ public class ThemeServiceImpl implements ThemeService {
if (themeId.equals(getActivatedThemeId())) {
// Prevent to delete the activated theme
throw new BadRequestException("You can't delete the activated theme").setErrorData(themeId);
throw new BadRequestException("不能删除正在使用的主题").setErrorData(themeId);
}
try {
@ -251,7 +258,7 @@ public class ThemeServiceImpl implements ThemeService {
// Delete theme cache
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
} catch (Exception e) {
throw new ServiceException("Failed to delete theme folder", e).setErrorData(themeId);
throw new ServiceException("主题删除失败", e).setErrorData(themeId);
}
}
@ -288,7 +295,7 @@ public class ThemeServiceImpl implements ThemeService {
return Collections.emptyList();
} catch (IOException e) {
throw new ServiceException("Failed to read options file", e);
throw new ServiceException("读取主题配置文件失败", e);
}
}
@ -362,7 +369,7 @@ public class ThemeServiceImpl implements ThemeService {
Assert.notNull(file, "Multipart file must not be null");
if (!StringUtils.endsWithIgnoreCase(file.getOriginalFilename(), ".zip")) {
throw new UnsupportedMediaTypeException("Unsupported theme media type: " + file.getContentType()).setErrorData(file.getOriginalFilename());
throw new UnsupportedMediaTypeException("不支持的文件类型: " + file.getContentType()).setErrorData(file.getOriginalFilename());
}
ZipInputStream zis = null;
@ -386,7 +393,7 @@ public class ThemeServiceImpl implements ThemeService {
// Go to the base folder and add the theme into system
return add(FileUtils.skipZipParentFolder(themeTempPath));
} catch (IOException e) {
throw new ServiceException("Failed to upload theme file: " + file.getOriginalFilename(), e);
throw new ServiceException("上传主题失败: " + file.getOriginalFilename(), e);
} finally {
// Close zip input stream
FileUtils.closeQuietly(zis);
@ -440,15 +447,16 @@ public class ThemeServiceImpl implements ThemeService {
// Create temp path
Path themeTmpPath = tmpPath.resolve(HaloUtils.randomUUIDWithoutDash());
if (StringUtils.endsWithIgnoreCase(uri, ".git")) {
cloneFromGit(uri, themeTmpPath);
} else {
if (StringUtils.endsWithIgnoreCase(uri, ".zip")) {
downloadZipAndUnzip(uri, themeTmpPath);
} else {
uri = StringUtils.appendIfMissingIgnoreCase(uri, ".git", ".git");
cloneFromGit(uri, themeTmpPath);
}
return add(themeTmpPath);
} catch (IOException | GitAPIException e) {
throw new ServiceException("Failed to fetch theme from remote " + uri, e);
throw new ServiceException("主题拉取失败 " + uri, e);
} finally {
FileUtils.deleteFolderQuietly(tmpPath);
}
@ -459,12 +467,93 @@ public class ThemeServiceImpl implements ThemeService {
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
}
@Override
public ThemeProperty update(String themeId) {
Assert.hasText(themeId, "Theme id must not be blank");
ThemeProperty updatingTheme = getThemeOfNonNullBy(themeId);
try {
pullFromGit(updatingTheme);
} catch (Exception e) {
throw new ThemeUpdateException("主题更新失败!您与主题作者可能同时更改了同一个文件,您也可以尝试删除主题并重新拉取最新的主题", e).setErrorData(themeId);
}
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
return getThemeOfNonNullBy(themeId);
}
private void pullFromGit(@NonNull ThemeProperty themeProperty) throws IOException, GitAPIException, URISyntaxException {
Assert.notNull(themeProperty, "Theme property must not be null");
// Get branch
String branch = StringUtils.isBlank(themeProperty.getBranch()) ?
DEFAULT_REMOTE_BRANCH : themeProperty.getBranch();
File themeFolder = Paths.get(themeProperty.getThemePath()).toFile();
// Open the theme path
Git git;
try {
git = Git.open(themeFolder);
} catch (RepositoryNotFoundException e) {
// Repository is not initialized
git = Git.init().setDirectory(themeFolder).call();
}
// Force to set remote name
git.remoteRemove().setRemoteName(THEME_PROVIDER_REMOTE_NAME).call();
RemoteConfig remoteConfig = git.remoteAdd()
.setName(THEME_PROVIDER_REMOTE_NAME)
.setUri(new URIish(themeProperty.getRepo()))
.call();
// Add all changes
git.add()
.addFilepattern(".")
.call();
// Commit the changes
git.commit().setMessage("Commit by halo automatically").call();
// Check out to specified branch
if (!StringUtils.equalsIgnoreCase(branch, git.getRepository().getBranch())) {
boolean present = git.branchList()
.call()
.stream()
.map(Ref::getName)
.anyMatch(name -> StringUtils.equalsIgnoreCase(name, branch));
git.checkout()
.setCreateBranch(true)
.setForced(!present)
.setName(branch)
.call();
}
// Pull with rebasing
PullResult pullResult = git.pull()
.setRemote(remoteConfig.getName())
.setRemoteBranchName(branch)
.setRebase(true)
.call();
if (!pullResult.isSuccessful()) {
log.debug("Rebase result: [{}]", pullResult.getRebaseResult());
log.debug("Merge result: [{}]", pullResult.getMergeResult());
throw new ThemeUpdateException("拉取失败!您与主题作者可能同时更改了同一个文件");
}
// Close git
git.close();
}
/**
* Clones theme from git.
*
* @param gitUrl git url must not be blank
* @param targetPath target path must not be null
* @throws GitAPIException
* @throws GitAPIException throws when clone error
*/
private void cloneFromGit(@NonNull String gitUrl, @NonNull Path targetPath) throws GitAPIException {
Assert.hasText(gitUrl, "Git url must not be blank");
@ -486,7 +575,7 @@ public class ThemeServiceImpl implements ThemeService {
*
* @param zipUrl zip url must not be null
* @param targetPath target path must not be null
* @throws IOException
* @throws IOException throws when download zip or unzip error
*/
private void downloadZipAndUnzip(@NonNull String zipUrl, @NonNull Path targetPath) throws IOException {
Assert.hasText(zipUrl, "Zip url must not be blank");
@ -498,7 +587,7 @@ public class ThemeServiceImpl implements ThemeService {
log.debug("Download response: [{}]", downloadResponse.getStatusCode());
if (downloadResponse.getStatusCode().isError() || downloadResponse.getBody() == null) {
throw new ServiceException("Failed to download " + zipUrl + ", status: " + downloadResponse.getStatusCode());
throw new ServiceException("下载失败 " + zipUrl + ", 状态码: " + downloadResponse.getStatusCode());
}
log.debug("Downloaded [{}]", zipUrl);
@ -514,7 +603,7 @@ public class ThemeServiceImpl implements ThemeService {
* Creates temporary path.
*
* @return temporary path
* @throws IOException
* @throws IOException if an I/O error occurs or the temporary-file directory does not exist
*/
@NonNull
private Path createTempPath() throws IOException {

View File

@ -105,7 +105,7 @@ public class ThemeSettingServiceImpl extends AbstractCrudService<ThemeSetting, I
try {
configuration.setSharedVariable("settings", listAsMapBy(themeService.getActivatedThemeId()));
} catch (TemplateModelException e) {
throw new ServiceException("Save theme settings error", e);
throw new ServiceException("主题设置保存失败", e);
}
}

View File

@ -106,7 +106,7 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
Assert.notNull(userId, "User id must not be blank");
if (oldPassword.equals(newPassword)) {
throw new BadRequestException("There is nothing changed because new password is equal to old password");
throw new BadRequestException("新密码和旧密码不能相同");
}
// Get the user
@ -114,7 +114,7 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
// Check the user old password
if (!BCrypt.checkpw(oldPassword, user.getPassword())) {
throw new BadRequestException("Old password is mismatch").setErrorData(oldPassword);
throw new BadRequestException("旧密码错误").setErrorData(oldPassword);
}
// Set new password
@ -148,7 +148,7 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
if (user.getExpireTime() != null && user.getExpireTime().after(now)) {
long seconds = TimeUnit.MILLISECONDS.toSeconds(user.getExpireTime().getTime() - now.getTime());
// If expired
throw new ForbiddenException("You have been temporarily disabledplease try again " + HaloUtils.timeFormat(seconds) + " later").setErrorData(seconds);
throw new ForbiddenException("账号已被停用,请 " + HaloUtils.timeFormat(seconds) + " 后重试").setErrorData(seconds);
}
}
@ -164,7 +164,7 @@ public class UserServiceImpl extends AbstractCrudService<User, Integer> implemen
public User create(User user) {
// Check user
if (count() != 0) {
throw new BadRequestException("This blog already exists a blogger");
throw new BadRequestException("当前博客已有用户");
}
User createdUser = super.create(user);

View File

@ -64,7 +64,7 @@ public class FileUtils {
*
* @param deletingPath deleting path must not be null
*/
public static void deleteFolder(Path deletingPath) throws IOException {
public static void deleteFolder(@NonNull Path deletingPath) throws IOException {
Assert.notNull(deletingPath, "Deleting path must not be null");
log.debug("Deleting [{}]", deletingPath);
@ -249,9 +249,9 @@ public class FileUtils {
/**
* Deletes folder quietly.
*
* @param deletingPath deleting path must not be null
* @param deletingPath deleting path
*/
public static void deleteFolderQuietly(@NonNull Path deletingPath) {
public static void deleteFolderQuietly(@Nullable Path deletingPath) {
try {
if (deletingPath != null) {
FileUtils.deleteFolder(deletingPath);

View File

@ -1,31 +1,19 @@
package run.halo.app.utils;
import cn.hutool.core.text.StrBuilder;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.net.InetAddress;
import java.net.URL;
import java.net.URLConnection;
import java.net.UnknownHostException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Date;
import java.util.UUID;
import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;
/**
* <pre>
*
* </pre>
* Common utils
*
* @author ryanwang
* @date : 2017/12/22
@ -165,187 +153,4 @@ public class HaloUtils {
}
return machineAddress.getHostAddress();
}
// /**
// * 获取备份文件信息
// *
// * @param dir dir
// * @return List
// */
// public static List<BackupDto> getBackUps(String dir) {
// final StrBuilder srcPathStr = new StrBuilder(System.getProperties().getProperty("user.home"));
// srcPathStr.append("/halo/backup/");
// srcPathStr.append(dir);
// final File srcPath = new File(srcPathStr.toString());
// final File[] files = srcPath.listFiles();
// final List<BackupDto> backupDtos = new ArrayList<>();
// BackupDto backupDto;
// // 遍历文件
// if (null != files) {
// for (File file : files) {
// if (file.isFile()) {
// if (StrUtil.equals(file.getName(), ".DS_Store")) {
// continue;
// }
// backupDto = new BackupDto();
// backupDto.setFileName(file.getName());
// backupDto.setCreateAt(getCreateTime(file.getAbsolutePath()));
// backupDto.setFileType(FileUtil.getType(file));
// backupDto.setFileSize(parseSize(file.length()));
// backupDto.setBackupType(dir);
// backupDtos.add(backupDto);
// }
// }
// }
// return backupDtos;
// }
// /**
// * 转换文件大小
// *
// * @param size size
// * @return String
// */
// public static String parseSize(long size) {
// if (size < CommonParamsEnum.BYTE.getValue()) {
// return size + "B";
// } else {
// size = size / 1024;
// }
// if (size < CommonParamsEnum.BYTE.getValue()) {
// return size + "KB";
// } else {
// size = size / 1024;
// }
// if (size < CommonParamsEnum.BYTE.getValue()) {
// size = size * 100;
// return size / 100 + "." + size % 100 + "MB";
// } else {
// size = size * 100 / 1024;
// return size / 100 + "." + size % 100 + "GB";
// }
// }
/**
*
*
* @param srcPath
* @return
*/
public static Date getCreateTime(String srcPath) {
try {
BasicFileAttributes basicFileAttributes = Files.readAttributes(Paths.get(srcPath), BasicFileAttributes.class);
return new Date(basicFileAttributes.creationTime().toMillis());
} catch (IOException e) {
throw new RuntimeException("Failed to open the " + srcPath + " file", e);
}
}
/**
*
*
* @param file file
* @return String
*/
public static String getImageWh(File file) {
try {
final BufferedImage image = ImageIO.read(new FileInputStream(file));
return image.getWidth() + "x" + image.getHeight();
} catch (Exception e) {
throw new RuntimeException("Failed to get read image file", e);
}
}
/**
*
*
* @param data
* @param filePath
* @param fileName
*/
public static void postToFile(String data, String filePath, String fileName) throws IOException {
FileWriter fileWriter = null;
BufferedWriter bufferedWriter = null;
try {
final File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
}
fileWriter = new FileWriter(file.getAbsoluteFile() + "/" + fileName, true);
bufferedWriter = new BufferedWriter(fileWriter);
bufferedWriter.write(data);
} catch (Exception e) {
throw new RuntimeException("Failed to export file", e);
} finally {
if (null != bufferedWriter) {
bufferedWriter.close();
}
if (null != fileWriter) {
fileWriter.close();
}
}
}
/**
*
*
* @param blogUrl
* @param token token
* @param urls
* @return String
*/
public static String baiduPost(String blogUrl, String token, String urls) {
Assert.hasText(blogUrl, "blog url must not be blank");
Assert.hasText(token, "token must not be blank");
Assert.hasText(urls, "urls must not be blank");
final StrBuilder url = new StrBuilder("http://data.zz.baidu.com/urls?site=");
url.append(blogUrl);
url.append("&token=");
url.append(token);
final StrBuilder result = new StrBuilder();
PrintWriter out = null;
BufferedReader in = null;
try {
// 建立URL之间的连接
final URLConnection conn = new URL(url.toString()).openConnection();
// 设置通用的请求属性
conn.setRequestProperty("Host", "data.zz.baidu.com");
conn.setRequestProperty("User-Agent", "curl/7.12.1");
conn.setRequestProperty("Content-Length", "83");
conn.setRequestProperty("Content-Type", "text/plain");
// 发送POST请求必须设置如下两行
conn.setDoInput(true);
conn.setDoOutput(true);
// 获取conn对应的输出流
out = new PrintWriter(conn.getOutputStream());
out.print(urls.trim());
// 进行输出流的缓冲
out.flush();
// 通过BufferedReader输入流来读取Url的响应
in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = in.readLine()) != null) {
result.append(line);
}
} catch (Exception e) {
throw new RuntimeException("Failed to push posts to baidu", e);
} finally {
try {
if (null != out) {
out.close();
}
if (null != in) {
in.close();
}
} catch (IOException ex) {
// Ignore this exception
}
}
return result.toString();
}
}

View File

@ -2,9 +2,13 @@ package run.halo.app.utils;
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;
@ -26,30 +30,73 @@ import java.util.Set;
*/
public class MarkdownUtils {
/**
* Front-matter extension
*/
private static final Set<Extension> EXTENSIONS_YAML = Collections.singleton(YamlFrontMatterExtension.create());
/**
* Table extension
* commonmark-java extension for autolinking
*/
private static final Set<Extension> EXTENSIONS_TABLE = Collections.singleton(TablesExtension.create());
private static final Set<Extension> EXTENSIONS_AUTO_LINK = Collections.singleton(AutolinkExtension.create());
/**
* 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 &lt;ins&gt; (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_YAML).extensions(EXTENSIONS_TABLE).build();
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_YAML).extensions(EXTENSIONS_TABLE).build();
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_YAML).extensions(EXTENSIONS_TABLE).build();
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();
/**
* Render Markdown content
@ -59,20 +106,25 @@ public class MarkdownUtils {
* @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) {
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 bilibili video short url
if (content.contains(HaloConst.BILIBILI_VIDEO_PREFIX)) {
renderContent = content.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);
}
return renderContent;
}
@ -84,6 +136,7 @@ public class MarkdownUtils {
*/
@NonNull
public static String renderText(@Nullable String markdownContent) {
if (StringUtils.isBlank(markdownContent)) {
return "";
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
.category-tree[data-v-3d736771]{margin-top:1rem}

View File

@ -1 +0,0 @@
.category-tree[data-v-42549218]{margin-top:1rem}

View File

@ -1 +1 @@
.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}.upload-button[data-v-6d086f28]{position:fixed;bottom:30px;right:30px}.theme-thumb[data-v-6d086f28]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.theme-thumb img[data-v-6d086f28]{width:100%;height:100%;position:absolute;top:0;left: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}.upload-button[data-v-76b16ba4]{position:fixed;bottom:30px;right:30px}.theme-thumb[data-v-76b16ba4]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.theme-thumb img[data-v-76b16ba4]{width:100%;height:100%;position:absolute;top:0;left:0}

View File

@ -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-0aab7d1a.701a4459.css rel=prefetch><link href=/css/chunk-14e8932a.b6783003.css rel=prefetch><link href=/css/chunk-1c8b985a.c1990d7c.css rel=prefetch><link href=/css/chunk-31829c73.f3153164.css rel=prefetch><link href=/css/chunk-4d54295e.43661ea3.css rel=prefetch><link href=/css/chunk-4fb0639b.210847fe.css rel=prefetch><link href=/css/chunk-5d83fd61.7cf84e9e.css rel=prefetch><link href=/css/chunk-75751d79.7d0c0e85.css rel=prefetch><link href=/css/chunk-898a93f6.909d3d1b.css rel=prefetch><link href=/css/chunk-92a6af22.ca1bfaac.css rel=prefetch><link href=/css/chunk-9449c032.dafef2de.css rel=prefetch><link href=/css/chunk-b6cd2e50.0090ea54.css rel=prefetch><link href=/css/chunk-c5b09f02.5e377c2d.css rel=prefetch><link href=/css/chunk-cc47e7d0.bb8e6a18.css rel=prefetch><link href=/css/fail.e9c3e2d8.css rel=prefetch><link href=/js/chunk-0aab7d1a.dba028d3.js rel=prefetch><link href=/js/chunk-142c8832.ac1f84d9.js rel=prefetch><link href=/js/chunk-14e8932a.c6563b86.js rel=prefetch><link href=/js/chunk-1c8b985a.8f4810a0.js rel=prefetch><link href=/js/chunk-2d0b64bf.14e99e26.js rel=prefetch><link href=/js/chunk-2d0d65a2.f7c7af76.js rel=prefetch><link href=/js/chunk-2d21a35c.19f1174e.js rel=prefetch><link href=/js/chunk-31829c73.36a05806.js rel=prefetch><link href=/js/chunk-407d6578.b0b0e2da.js rel=prefetch><link href=/js/chunk-4d54295e.e29bba1d.js rel=prefetch><link href=/js/chunk-4fb0639b.1668db6b.js rel=prefetch><link href=/js/chunk-5bf599cc.b6b7c7ec.js rel=prefetch><link href=/js/chunk-5d83fd61.71621386.js rel=prefetch><link href=/js/chunk-71fa6d51.79e1ddb2.js rel=prefetch><link href=/js/chunk-75751d79.f0f603bc.js rel=prefetch><link href=/js/chunk-87e2df70.8d9028cf.js rel=prefetch><link href=/js/chunk-898a93f6.c0e9bb6c.js rel=prefetch><link href=/js/chunk-92a6af22.b84ae833.js rel=prefetch><link href=/js/chunk-9449c032.9e9ce69b.js rel=prefetch><link href=/js/chunk-b6cd2e50.d2c0d717.js rel=prefetch><link href=/js/chunk-c5b09f02.3952a273.js rel=prefetch><link href=/js/chunk-cc47e7d0.30a4457f.js rel=prefetch><link href=/js/fail.b90b115d.js rel=prefetch><link href=/css/app.d74a405f.css rel=preload as=style><link href=/css/chunk-vendors.6b95225a.css rel=preload as=style><link href=/js/app.25d2f925.js rel=preload as=script><link href=/js/chunk-vendors.fb9e7626.js rel=preload as=script><link href=/css/chunk-vendors.6b95225a.css rel=stylesheet><link href=/css/app.d74a405f.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.fb9e7626.js></script><script src=/js/app.25d2f925.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-02f1697e.7cf84e9e.css rel=prefetch><link href=/css/chunk-0aab7d1a.701a4459.css rel=prefetch><link href=/css/chunk-14e8932a.b6783003.css rel=prefetch><link href=/css/chunk-1c8b985a.c1990d7c.css rel=prefetch><link href=/css/chunk-1ea08528.db89d50a.css rel=prefetch><link href=/css/chunk-31829c73.f3153164.css rel=prefetch><link href=/css/chunk-4fb0639b.743bdcba.css rel=prefetch><link href=/css/chunk-75751d79.7d0c0e85.css rel=prefetch><link href=/css/chunk-898a93f6.909d3d1b.css rel=prefetch><link href=/css/chunk-9449c032.dafef2de.css rel=prefetch><link href=/css/chunk-b6cd2e50.0090ea54.css rel=prefetch><link href=/css/chunk-c5b09f02.5e377c2d.css rel=prefetch><link href=/css/chunk-edd856c6.ca1bfaac.css rel=prefetch><link href=/css/chunk-efde06fa.aaca0f75.css rel=prefetch><link href=/css/fail.e9c3e2d8.css rel=prefetch><link href=/js/chunk-02f1697e.fbb91c62.js rel=prefetch><link href=/js/chunk-0aab7d1a.dba028d3.js rel=prefetch><link href=/js/chunk-142c8832.0d298dce.js rel=prefetch><link href=/js/chunk-14e8932a.c6563b86.js rel=prefetch><link href=/js/chunk-1c8b985a.d1e58af8.js rel=prefetch><link href=/js/chunk-1ea08528.6dd705ab.js rel=prefetch><link href=/js/chunk-2d0b64bf.14e99e26.js rel=prefetch><link href=/js/chunk-2d0d65a2.d68d48c2.js rel=prefetch><link href=/js/chunk-2d21a35c.19f1174e.js rel=prefetch><link href=/js/chunk-31829c73.620e8a22.js rel=prefetch><link href=/js/chunk-407d6578.1ef8e454.js rel=prefetch><link href=/js/chunk-4fb0639b.1be7f2f2.js rel=prefetch><link href=/js/chunk-5bf599cc.b6b7c7ec.js rel=prefetch><link href=/js/chunk-71fa6d51.79e1ddb2.js rel=prefetch><link href=/js/chunk-75751d79.1b49b36e.js rel=prefetch><link href=/js/chunk-87e2df70.8d9028cf.js rel=prefetch><link href=/js/chunk-898a93f6.c0e9bb6c.js rel=prefetch><link href=/js/chunk-9449c032.9e9ce69b.js rel=prefetch><link href=/js/chunk-b6cd2e50.cc4cab63.js rel=prefetch><link href=/js/chunk-c5b09f02.3952a273.js rel=prefetch><link href=/js/chunk-edd856c6.20633ba8.js rel=prefetch><link href=/js/chunk-efde06fa.9e1e510c.js rel=prefetch><link href=/js/fail.b90b115d.js rel=prefetch><link href=/css/app.803dd628.css rel=preload as=style><link href=/css/chunk-vendors.80056587.css rel=preload as=style><link href=/js/app.63c77087.js rel=preload as=script><link href=/js/chunk-vendors.fb9e7626.js rel=preload as=script><link href=/css/chunk-vendors.80056587.css rel=stylesheet><link href=/css/app.803dd628.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.fb9e7626.js></script><script src=/js/app.63c77087.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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-407d6578"],{aa1e9:function(t,a,e){"use strict";e.r(a);var n=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"page-header-index-wide"},[e("a-row",{attrs:{gutter:12}},[e("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:10,lg:10,md:10,sm:24,xs:24}},[e("a-card",{attrs:{title:"添加标签"}},[e("a-form",{attrs:{layout:"horizontal"}},[e("a-form-item",{attrs:{label:"名称:",help:"* 页面上所显示的名称"}},[e("a-input",{model:{value:t.tagToCreate.name,callback:function(a){t.$set(t.tagToCreate,"name",a)},expression:"tagToCreate.name"}})],1),e("a-form-item",{attrs:{label:"别名",help:"* 一般为单个标签页面的标识,最好为英文"}},[e("a-input",{model:{value:t.tagToCreate.slugName,callback:function(a){t.$set(t.tagToCreate,"slugName",a)},expression:"tagToCreate.slugName"}})],1),e("a-form-item",[e("a-button",{attrs:{type:"primary"},on:{click:t.handleCreateTag}},[t._v("保存")])],1)],1)],1)],1),e("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:14,lg:14,md:14,sm:24,xs:24}},[e("a-card",{attrs:{title:"所有标签"}},t._l(t.tags,function(a){return e("a-tooltip",{key:a.id,attrs:{placement:"topLeft"}},[e("template",{slot:"title"},[e("span",[t._v(t._s(a.postCount)+" 篇文章")])]),e("a-tag",{attrs:{closable:"",color:"blue"},on:{close:function(e){return t.handleDeleteTag(a.id)}}},[t._v(t._s(a.name))])],2)}),1)],1)],1)],1)},o=[],l=e("d28db"),r={data:function(){return{tags:[],tagToCreate:{},tagToUpdate:{}}},created:function(){this.loadTags()},methods:{loadTags:function(){var t=this;l["a"].listAll(!0).then(function(a){t.tags=a.data.data})},handleCreateTag:function(){var t=this;l["a"].create(this.tagToCreate).then(function(a){t.loadTags()})},handleUpdateTag:function(t){var a=this;l["a"].update(t,this.tagToUpdate).then(function(t){a.loadTags()})},handleDeleteTag:function(t){var a=this;l["a"].delete(t).then(function(t){a.$message.success("删除成功!"),a.loadTags()})}}},s=r,c=e("17cc"),i=Object(c["a"])(s,n,o,!1,null,null,null);a["default"]=i.exports},d28db:function(t,a,e){"use strict";var n=e("9efd"),o="/api/admin/tags",l={listAll:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return Object(n["a"])({url:o,params:{more:t},method:"get"})},createWithName:function(t){return Object(n["a"])({url:o,data:{name:t},method:"post"})},create:function(t){return Object(n["a"])({url:o,data:t,method:"post"})},update:function(t,a){return Object(n["a"])({url:"".concat(o,"/").concat(t),data:a,method:"put"})},delete:function(t){return Object(n["a"])({url:"".concat(o,"/").concat(t),method:"delete"})}};a["a"]=l}}]);

View File

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-407d6578"],{aa1e9:function(t,a,e){"use strict";e.r(a);var n=function(){var t=this,a=t.$createElement,e=t._self._c||a;return e("div",{staticClass:"page-header-index-wide"},[e("a-row",{attrs:{gutter:12}},[e("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:10,lg:10,md:10,sm:24,xs:24}},[e("a-card",{attrs:{title:"添加标签"}},[e("a-form",{attrs:{layout:"horizontal"}},[e("a-form-item",{attrs:{label:"名称:",help:"* 页面上所显示的名称"}},[e("a-input",{model:{value:t.tagToCreate.name,callback:function(a){t.$set(t.tagToCreate,"name",a)},expression:"tagToCreate.name"}})],1),e("a-form-item",{attrs:{label:"路径名称:",help:"* 这是文章路径上显示的名称,最好为英文"}},[e("a-input",{model:{value:t.tagToCreate.slugName,callback:function(a){t.$set(t.tagToCreate,"slugName",a)},expression:"tagToCreate.slugName"}})],1),e("a-form-item",[e("a-button",{attrs:{type:"primary"},on:{click:t.handleCreateTag}},[t._v("保存")])],1)],1)],1)],1),e("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:14,lg:14,md:14,sm:24,xs:24}},[e("a-card",{attrs:{title:"所有标签"}},t._l(t.tags,function(a){return e("a-tooltip",{key:a.id,attrs:{placement:"topLeft"}},[e("template",{slot:"title"},[e("span",[t._v(t._s(a.postCount)+" 篇文章")])]),e("a-tag",{attrs:{closable:"",color:"blue"},on:{close:function(e){return t.handleDeleteTag(a.id)}}},[t._v(t._s(a.name))])],2)}),1)],1)],1)],1)},o=[],l=e("d28db"),r={data:function(){return{tags:[],tagToCreate:{},tagToUpdate:{}}},created:function(){this.loadTags()},methods:{loadTags:function(){var t=this;l["a"].listAll(!0).then(function(a){t.tags=a.data.data})},handleCreateTag:function(){var t=this;l["a"].create(this.tagToCreate).then(function(a){t.loadTags()})},handleUpdateTag:function(t){var a=this;l["a"].update(t,this.tagToUpdate).then(function(t){a.loadTags()})},handleDeleteTag:function(t){var a=this;l["a"].delete(t).then(function(t){a.$message.success("删除成功!"),a.loadTags()})}}},s=r,c=e("17cc"),i=Object(c["a"])(s,n,o,!1,null,null,null);a["default"]=i.exports},d28db:function(t,a,e){"use strict";var n=e("9efd"),o="/api/admin/tags",l={listAll:function(){var t=arguments.length>0&&void 0!==arguments[0]&&arguments[0];return Object(n["a"])({url:o,params:{more:t},method:"get"})},createWithName:function(t){return Object(n["a"])({url:o,data:{name:t},method:"post"})},create:function(t){return Object(n["a"])({url:o,data:t,method:"post"})},update:function(t,a){return Object(n["a"])({url:"".concat(o,"/").concat(t),data:a,method:"put"})},delete:function(t){return Object(n["a"])({url:"".concat(o,"/").concat(t),method:"delete"})}};a["a"]=l}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -13,23 +13,25 @@ server:
enabled: true
mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
output:
ansi:
enabled: always
datasource:
type: com.zaxxer.hikari.HikariDataSource
# H2database 配置
# H2 Database 配置
driver-class-name: org.h2.Driver
url: jdbc:h2:file:~/halo-dev/db/halo
username: admin
password: 123456
# MySql 配置
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
# MySQL 配置
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
h2:
console:
@ -44,8 +46,8 @@ spring:
open-in-view: false
servlet:
multipart:
max-file-size: 10MB
max-request-size: 10MB
max-file-size: 10240MB
max-request-size: 10240MB
cache:
type: none

View File

@ -13,23 +13,25 @@ server:
enabled: true
mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
output:
ansi:
enabled: always
datasource:
type: com.zaxxer.hikari.HikariDataSource
# H2database 配置
# H2 Database 配置
driver-class-name: org.h2.Driver
url: jdbc:h2:file:~/halo-test/db/halo
username: admin
password: 123456
# MySql 配置
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
# MySQL 配置
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
h2:
console:

View File

@ -4,19 +4,19 @@ spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# H2Database 配置,如果你需要使用 MySQL请注释掉该配置并取消注释 MySQL 的配置。
# H2 Database 配置,如果你需要使用 MySQL请注释掉该配置并取消注释 MySQL 的配置。
driver-class-name: org.h2.Driver
url: jdbc:h2:file:~/.halo/db/halo
username: admin
password: 123456
# MySql 配置,如果你需要使用 H2Database请注释掉该配置并取消注释上方 H2Database 的配置。
# MySQL 配置,如果你需要使用 H2 Database请注释掉该配置并取消注释上方 H2 Database 的配置。
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
# H2Database 的控制台相关配置,如果你使用的是 MySQL ,请注释掉下方内容。
# H2 Database 的控制台相关配置,如果你使用的是 MySQL ,请注释掉下方内容。
h2:
console:
settings:

View File

@ -13,6 +13,8 @@ server:
enabled: true
mime-types: application/javascript,text/css,application/json,application/xml,text/html,text/xml,text/plain
spring:
jackson:
date-format: yyyy-MM-dd HH:mm:ss
devtools:
add-properties: false
output:
@ -21,17 +23,17 @@ spring:
datasource:
type: com.zaxxer.hikari.HikariDataSource
# H2database 配置
# H2 Database 配置
driver-class-name: org.h2.Driver
url: jdbc:h2:file:~/.halo/db/halo
username: admin
password: 123456
# MySql 配置
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
# MySQL 配置
# driver-class-name: com.mysql.cj.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/halodb?characterEncoding=utf8&useSSL=false&serverTimezone=Asia/Shanghai
# username: root
# password: 123456
h2:
console:

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="alternate" type="application/rss+xml" title="atom 1.0" href="/atom.xml">
<title>Not Found</title>
<link href="${static!}/source/css/style.min.css" type="text/css" rel="stylesheet"/>
</head>
<div class="page_404">
<p>The page you are looking for is missing</p>
</div>
</html>

View File

@ -0,0 +1,12 @@
<!DOCTYPE html>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<link rel="alternate" type="application/rss+xml" title="atom 1.0" href="/atom.xml">
<title>Internal Error</title>
<link href="${static!}/source/css/style.min.css" type="text/css" rel="stylesheet"/>
</head>
<div class="page_404">
<p>The page you are looking for is error</p>
</div>
</html>

View File

@ -0,0 +1,18 @@
<h1><a href="https://github.com/halo-dev" target="_blank">halo-theme-anatole</a></h1>
## 说明
该主题的原作者为 [Caicai](https://www.caicai.me),非常感谢做出这么优秀的主题。
原主题地址:[https://github.com/hi-caicai/farbox-theme-Anatole](https://github.com/hi-caicai/farbox-theme-Anatole)
## 预览截图
![index](https://i.loli.net/2019/05/29/5ced6a1f70be890881.png)
![settings](https://i.loli.net/2019/05/29/5ced6a1fddb4562005.png)
## 使用方法
1. 克隆或者[下载](https://github.com/halo-dev/halo-theme-anatole/releases)。
2. 压缩为 zip 压缩包之后在后台的主题设置直接上传即可使用。

Some files were not shown because too many files have changed in this diff Show More