Dev
pull/286/head v1.0.2
Ryan Wang 2019-06-13 01:03:10 +08:00 committed by GitHub
commit 640fa13171
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
81 changed files with 483 additions and 321 deletions

View File

@ -1,15 +1,15 @@
plugins {
id 'org.springframework.boot' version '2.1.3.RELEASE'
id "io.freefair.lombok" version "3.6.6"
// id 'war'
id 'java'
id 'war'
}
apply plugin: 'io.spring.dependency-management'
group = 'run.halo.app'
archivesBaseName = 'halo'
version = '1.0.1'
version = '1.0.2'
sourceCompatibility = '1.8'
description = 'Halo, personal blog system developed in Java.'

View File

@ -31,6 +31,8 @@ import java.io.IOException;
import java.util.List;
import java.util.Properties;
import static run.halo.app.model.support.HaloConst.HALO_ADMIN_RELATIVE_PATH;
/**
* Mvc configuration.
*
@ -88,12 +90,10 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer {
.addResourceLocations("classpath:/admin/");
registry.addResourceHandler("/upload/**")
.addResourceLocations(workDir + "upload/");
registry.addResourceHandler("/favicon.ico")
.addResourceLocations("classpath:/static/halo-admin/images/favicon.ico");
registry.addResourceHandler("/backup/**")
.addResourceLocations(workDir + "backup/");
registry.addResourceHandler("/admin/**")
.addResourceLocations(workDir + "templates/admin/")
.addResourceLocations(workDir + HALO_ADMIN_RELATIVE_PATH)
.addResourceLocations("classpath:/admin/");
if (!haloProperties.isDocDisabled()) {
@ -122,7 +122,7 @@ public class WebMvcAutoConfiguration implements WebMvcConfigurer {
configurer.setDefaultEncoding("UTF-8");
Properties properties = new Properties();
properties.setProperty("auto_import","/common/macro/common_macro.ftl as common");
properties.setProperty("auto_import", "/common/macro/common_macro.ftl as common");
configurer.setFreemarkerSettings(properties);

View File

@ -67,4 +67,10 @@ public class AdminController {
return adminService.refreshToken(refreshToken);
}
@PutMapping("halo-admin")
@ApiOperation("Updates halo-admin manually")
public void updateAdmin() {
adminService.updateAdminAssets();
}
}

View File

@ -82,6 +82,20 @@ public class HaloConst {
*/
public static String USER_SESSION_KEY = "user_session";
/**
* Github Api url for halo-admin release.
*/
public final static String HALO_ADMIN_RELEASES_LATEST = "https://api.github.com/repos/halo-dev/halo-admin/releases/latest";
/**
* Halo admin version regex.
*/
public final static String HALO_ADMIN_VERSION_REGEX = "halo-admin-\\d+\\.\\d+(\\.\\d+)?(-\\S*)?\\.zip";
public final static String HALO_ADMIN_RELATIVE_PATH = "templates/admin/";
public final static String HALO_ADMIN_RELATIVE_BACKUP_PATH = "templates/admin-backup/";
static {
// Set version
HALO_VERSION = HaloConst.class.getPackage().getImplementationVersion();

View File

@ -64,4 +64,9 @@ public interface AdminService {
*/
@NonNull
AuthToken refreshToken(@NonNull String refreshToken);
/**
* Updates halo admin assets.
*/
void updateAdminAssets();
}

View File

@ -182,7 +182,6 @@ public interface BasePostService<POST extends BasePost> extends CrudService<POST
@Transactional
void increaseLike(@NonNull Integer postId);
/**
* Creates or updates by post.
*

View File

@ -2,15 +2,17 @@ package run.halo.app.service.impl;
import cn.hutool.core.lang.Validator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.http.ResponseEntity;
import org.springframework.lang.NonNull;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.web.client.RestTemplate;
import run.halo.app.cache.StringCacheStore;
import run.halo.app.config.properties.HaloProperties;
import run.halo.app.exception.BadRequestException;
import run.halo.app.exception.NotFoundException;
import run.halo.app.exception.ServiceException;
import run.halo.app.model.dto.EnvironmentDTO;
import run.halo.app.model.dto.StatisticDTO;
import run.halo.app.model.entity.User;
@ -24,11 +26,20 @@ import run.halo.app.security.context.SecurityContextHolder;
import run.halo.app.security.token.AuthToken;
import run.halo.app.security.util.SecurityUtils;
import run.halo.app.service.*;
import run.halo.app.utils.FileUtils;
import run.halo.app.utils.HaloUtils;
import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import static run.halo.app.model.support.HaloConst.*;
/**
* Admin service implementation.
@ -61,7 +72,9 @@ public class AdminServiceImpl implements AdminService {
private final StringCacheStore cacheStore;
private final ApplicationEventPublisher eventPublisher;
private final RestTemplate restTemplate;
private final HaloProperties haloProperties;
private final String driverClassName;
@ -77,7 +90,8 @@ public class AdminServiceImpl implements AdminService {
UserService userService,
LinkService linkService,
StringCacheStore cacheStore,
ApplicationEventPublisher eventPublisher,
RestTemplate restTemplate,
HaloProperties haloProperties,
@Value("${spring.datasource.driver-class-name}") String driverClassName,
@Value("${spring.profiles.active:prod}") String mode) {
this.postService = postService;
@ -90,7 +104,8 @@ public class AdminServiceImpl implements AdminService {
this.userService = userService;
this.linkService = linkService;
this.cacheStore = cacheStore;
this.eventPublisher = eventPublisher;
this.restTemplate = restTemplate;
this.haloProperties = haloProperties;
this.driverClassName = driverClassName;
this.mode = mode;
}
@ -220,6 +235,101 @@ public class AdminServiceImpl implements AdminService {
return buildAuthToken(user);
}
@Override
@SuppressWarnings("unchecked")
public void updateAdminAssets() {
// Request github api
ResponseEntity<Map> responseEntity = restTemplate.getForEntity(HaloConst.HALO_ADMIN_RELEASES_LATEST, Map.class);
if (responseEntity == null ||
responseEntity.getStatusCode().isError() ||
responseEntity.getBody() == null) {
log.debug("Failed to request remote url: [{}]", HALO_ADMIN_RELEASES_LATEST);
throw new ServiceException("系统无法访问到 Github 的 API").setErrorData(HALO_ADMIN_RELEASES_LATEST);
}
Object assetsObject = responseEntity.getBody().get("assets");
if (assetsObject instanceof List) {
try {
List assets = (List) assetsObject;
Map assetMap = (Map) assets.stream()
.filter(assetPredicate())
.findFirst()
.orElseThrow(() -> new ServiceException("Halo admin 最新版暂无资源文件,请稍后再试"));
Object browserDownloadUrl = assetMap.getOrDefault("browser_download_url", "");
// Download the assets
ResponseEntity<byte[]> downloadResponseEntity = restTemplate.getForEntity(browserDownloadUrl.toString(), byte[].class);
if (downloadResponseEntity == null ||
downloadResponseEntity.getStatusCode().isError() ||
downloadResponseEntity.getBody() == null) {
throw new ServiceException("Failed to request remote url: " + browserDownloadUrl.toString()).setErrorData(browserDownloadUrl.toString());
}
String adminTargetName = haloProperties.getWorkDir() + HALO_ADMIN_RELATIVE_PATH;
Path adminPath = Paths.get(adminTargetName);
Path adminBackupPath = Paths.get(haloProperties.getWorkDir(), HALO_ADMIN_RELATIVE_BACKUP_PATH);
backupAndClearAdminAssetsIfPresent(adminPath, adminBackupPath);
// Create temp folder
Path assetTempPath = FileUtils.createTempDirectory()
.resolve(assetMap.getOrDefault("name", "halo-admin-latest.zip").toString());
// Unzip
FileUtils.unzip(downloadResponseEntity.getBody(), assetTempPath);
// Copy it to template/admin folder
FileUtils.copyFolder(FileUtils.tryToSkipZipParentFolder(assetTempPath), adminPath);
} catch (Throwable t) {
log.error("Failed to update halo admin", t);
throw new ServiceException("更新 Halo admin 失败");
}
} else {
throw new ServiceException("Github API 返回内容有误").setErrorData(assetsObject);
}
}
@NonNull
@SuppressWarnings("unchecked")
private Predicate<Object> assetPredicate() {
return asset -> {
if (!(asset instanceof Map)) {
return false;
}
Map aAssetMap = (Map) asset;
// Get content-type
String contentType = aAssetMap.getOrDefault("content_type", "").toString();
Object name = aAssetMap.getOrDefault("name", "");
return name.toString().matches(HALO_ADMIN_VERSION_REGEX) && contentType.equalsIgnoreCase("application/zip");
};
}
private void backupAndClearAdminAssetsIfPresent(@NonNull Path sourcePath, @NonNull Path backupPath) throws IOException {
Assert.notNull(sourcePath, "Source path must not be null");
Assert.notNull(backupPath, "Backup path must not be null");
if (!FileUtils.isEmpty(sourcePath)) {
// Clone this assets
Path adminPathBackup = Paths.get(haloProperties.getWorkDir(), HALO_ADMIN_RELATIVE_BACKUP_PATH);
// Delete backup
FileUtils.deleteFolder(backupPath);
// Copy older assets into backup
FileUtils.copyFolder(sourcePath, backupPath);
// Delete older assets
FileUtils.deleteFolder(sourcePath);
} else {
FileUtils.createIfAbsent(sourcePath);
}
}
/**
* Builds authentication token.
*

View File

@ -5,7 +5,6 @@ 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;
@ -34,10 +33,9 @@ import run.halo.app.service.OptionService;
import run.halo.app.service.ThemeService;
import run.halo.app.utils.FileUtils;
import run.halo.app.utils.FilenameUtils;
import run.halo.app.utils.GitUtils;
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;
@ -46,6 +44,7 @@ import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipInputStream;
import static run.halo.app.model.support.HaloConst.DEFAULT_THEME_ID;
@ -127,15 +126,17 @@ public class ThemeServiceImpl implements ThemeService {
Optional<ThemeProperty[]> themePropertiesOptional = cacheStore.getAny(THEMES_CACHE_KEY, ThemeProperty[].class);
try {
if (themePropertiesOptional.isPresent()) {
// Convert to theme properties
ThemeProperty[] themeProperties = themePropertiesOptional.get();
return new HashSet<>(Arrays.asList(themeProperties));
}
if (themePropertiesOptional.isPresent()) {
// Convert to theme properties
ThemeProperty[] themeProperties = themePropertiesOptional.get();
return new HashSet<>(Arrays.asList(themeProperties));
}
try (Stream<Path> pathStream = Files.list(getBasePath())) {
// List and filter sub folders
List<Path> themePaths = Files.list(getBasePath()).filter(path -> Files.isDirectory(path)).collect(Collectors.toList());
List<Path> themePaths = pathStream.filter(path -> Files.isDirectory(path))
.collect(Collectors.toList());
if (CollectionUtils.isEmpty(themePaths)) {
return Collections.emptySet();
@ -172,9 +173,8 @@ public class ThemeServiceImpl implements ThemeService {
// Get the theme path
Path themePath = Paths.get(getThemeOfNonNullBy(themeId).getThemePath());
try {
return Files.list(themePath)
.filter(path -> StringUtils.startsWithIgnoreCase(path.getFileName().toString(), CUSTOM_SHEET_PREFIX))
try (Stream<Path> pathStream = Files.list(themePath)) {
return pathStream.filter(path -> StringUtils.startsWithIgnoreCase(path.getFileName().toString(), CUSTOM_SHEET_PREFIX))
.map(path -> {
// Remove prefix
String customTemplate = StringUtils.removeStartIgnoreCase(path.getFileName().toString(), CUSTOM_SHEET_PREFIX);
@ -253,8 +253,7 @@ public class ThemeServiceImpl implements ThemeService {
try {
// Delete the folder
FileUtils.del(Paths.get(themeProperty.getThemePath()));
FileUtils.deleteFolder(Paths.get(themeProperty.getThemePath()));
// Delete theme cache
eventPublisher.publishEvent(new ThemeUpdatedEvent(this));
} catch (Exception e) {
@ -377,7 +376,7 @@ public class ThemeServiceImpl implements ThemeService {
try {
// Create temp directory
tempPath = createTempPath();
tempPath = FileUtils.createTempDirectory();
String basename = FilenameUtils.getBasename(file.getOriginalFilename());
Path themeTempPath = tempPath.resolve(basename);
@ -391,7 +390,7 @@ public class ThemeServiceImpl implements ThemeService {
FileUtils.unzip(zis, themeTempPath);
// Go to the base folder and add the theme into system
return add(FileUtils.skipZipParentFolder(themeTempPath));
return add(FileUtils.tryToSkipZipParentFolder(themeTempPath));
} catch (IOException e) {
throw new ServiceException("上传主题失败: " + file.getOriginalFilename(), e);
} finally {
@ -408,7 +407,10 @@ public class ThemeServiceImpl implements ThemeService {
Assert.isTrue(Files.isDirectory(themeTmpPath), "Theme temporary path must be a directory");
log.debug("Children path of [{}]:", themeTmpPath);
Files.list(themeTmpPath).forEach(path -> log.debug(path.toString()));
try (Stream<Path> pathStream = Files.list(themeTmpPath)) {
pathStream.forEach(path -> log.debug(path.toString()));
}
// Check property config
ThemeProperty tmpThemeProperty = getProperty(themeTmpPath);
@ -443,7 +445,7 @@ public class ThemeServiceImpl implements ThemeService {
try {
// Create temp path
tmpPath = createTempPath();
tmpPath = FileUtils.createTempDirectory();
// Create temp path
Path themeTmpPath = tmpPath.resolve(HaloUtils.randomUUIDWithoutDash());
@ -451,7 +453,8 @@ public class ThemeServiceImpl implements ThemeService {
downloadZipAndUnzip(uri, themeTmpPath);
} else {
uri = StringUtils.appendIfMissingIgnoreCase(uri, ".git", ".git");
cloneFromGit(uri, themeTmpPath);
// Clone from git
GitUtils.cloneFromGit(uri, themeTmpPath);
}
return add(themeTmpPath);
@ -491,83 +494,56 @@ public class ThemeServiceImpl implements ThemeService {
String branch = StringUtils.isBlank(themeProperty.getBranch()) ?
DEFAULT_REMOTE_BRANCH : themeProperty.getBranch();
File themeFolder = Paths.get(themeProperty.getThemePath()).toFile();
// Open the theme path
Git git;
Git git = null;
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)
git = GitUtils.openOrInit(Paths.get(themeProperty.getThemePath()));
// 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("拉取失败!您与主题作者可能同时更改了同一个文件");
}
} finally {
GitUtils.closeQuietly(git);
}
// 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 when clone error
*/
private void cloneFromGit(@NonNull String gitUrl, @NonNull Path targetPath) throws GitAPIException {
Assert.hasText(gitUrl, "Git url must not be blank");
Assert.notNull(targetPath, "Target path must not be null");
log.debug("Cloning git repo [{}] to [{}]", gitUrl, targetPath);
// Clone it
Git.cloneRepository()
.setURI(gitUrl)
.setDirectory(targetPath.toFile())
.call();
log.debug("Cloned git repo [{}]", gitUrl);
}
/**
@ -592,22 +568,8 @@ public class ThemeServiceImpl implements ThemeService {
log.debug("Downloaded [{}]", zipUrl);
// New zip input stream
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(downloadResponse.getBody()));
// Unzip it
FileUtils.unzip(zis, targetPath);
}
/**
* Creates temporary path.
*
* @return temporary path
* @throws IOException if an I/O error occurs or the temporary-file directory does not exist
*/
@NonNull
private Path createTempPath() throws IOException {
return Files.createTempDirectory("halo");
FileUtils.unzip(downloadResponse.getBody(), targetPath);
}
/**
@ -625,10 +587,10 @@ public class ThemeServiceImpl implements ThemeService {
return null;
}
try {
try (Stream<Path> pathStream = Files.list(topPath)) {
List<ThemeFile> themeFiles = new LinkedList<>();
Files.list(topPath).forEach(path -> {
pathStream.forEach(path -> {
// Build theme file
ThemeFile themeFile = new ThemeFile();
themeFile.setName(path.getFileName().toString());
@ -787,12 +749,13 @@ public class ThemeServiceImpl implements ThemeService {
private Optional<String> getScreenshotsFileName(@NonNull Path themePath) throws IOException {
Assert.notNull(themePath, "Theme path must not be null");
return Files.list(themePath)
.filter(path -> Files.isRegularFile(path)
&& Files.isReadable(path)
&& FilenameUtils.getBasename(path.toString()).equalsIgnoreCase(THEME_SCREENSHOTS_NAME))
.findFirst()
.map(path -> path.getFileName().toString());
try (Stream<Path> pathStream = Files.list(themePath)) {
return pathStream.filter(path -> Files.isRegularFile(path)
&& Files.isReadable(path)
&& FilenameUtils.getBasename(path.toString()).equalsIgnoreCase(THEME_SCREENSHOTS_NAME))
.findFirst()
.map(path -> path.getFileName().toString());
}
}
/**

View File

@ -1,20 +1,19 @@
package run.halo.app.utils;
import cn.hutool.core.io.IORuntimeException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.lang.NonNull;
import org.springframework.lang.Nullable;
import org.springframework.util.Assert;
import run.halo.app.exception.ForbiddenException;
import java.io.File;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
@ -67,18 +66,30 @@ public class FileUtils {
public static void deleteFolder(@NonNull Path deletingPath) throws IOException {
Assert.notNull(deletingPath, "Deleting path must not be null");
log.debug("Deleting [{}]", deletingPath);
log.info("Deleting [{}]", deletingPath);
Files.walk(deletingPath)
.sorted(Comparator.reverseOrder())
.map(Path::toFile)
.forEach(File::delete);
// Delete folder recursively
org.eclipse.jgit.util.FileUtils.delete(deletingPath.toFile(),
org.eclipse.jgit.util.FileUtils.RECURSIVE | org.eclipse.jgit.util.FileUtils.RETRY);
log.debug("Deleted [{}] successfully", deletingPath);
// try (Stream<Path> pathStream = Files.walk(deletingPath)) {
// pathStream.sorted(Comparator.reverseOrder())
// .peek(path -> log.debug("Try to delete [{}]", path.toString()))
// .forEach(path -> {
// try {
// Files.delete(path);
// log.debug("Deleted [{}] successfully", path.toString());
// } catch (IOException e) {
// throw new ServiceException("Failed to delete " + path.toString(), e).setErrorData(deletingPath.toString());
// }
// });
// }
log.info("Deleted [{}] successfully", deletingPath);
}
/**
* Unzip content to the target path.
* Unzips content to the target path.
*
* @param zis zip input stream must not be null
* @param targetPath target path must not be null and not empty
@ -115,23 +126,40 @@ public class FileUtils {
}
}
/**
* Skips zip parent folder. (Go into base folder)
* Unzips content to the target path.
*
* @param bytes zip bytes array must not be null
* @param targetPath target path must not be null and not empty
* @throws IOException
*/
public static void unzip(@NonNull byte[] bytes, @NonNull Path targetPath) throws IOException {
Assert.notNull(bytes, "Zip bytes must not be null");
ZipInputStream zis = new ZipInputStream(new ByteArrayInputStream(bytes));
unzip(zis, targetPath);
}
/**
* Try to skip zip parent folder. (Go into base folder)
*
* @param unzippedPath unzipped path must not be null
* @return path containing base files
* @throws IOException
*/
public static Path skipZipParentFolder(@NonNull Path unzippedPath) throws IOException {
public static Path tryToSkipZipParentFolder(@NonNull Path unzippedPath) throws IOException {
Assert.notNull(unzippedPath, "Unzipped folder must not be null");
List<Path> childrenPath = Files.list(unzippedPath).collect(Collectors.toList());
// TODO May cause a latent problem.
try (Stream<Path> pathStream = Files.list(unzippedPath)) {
List<Path> childrenPath = pathStream.collect(Collectors.toList());
if (childrenPath.size() == 1 && Files.isDirectory(childrenPath.get(0))) {
return childrenPath.get(0);
if (childrenPath.size() == 1 && Files.isDirectory(childrenPath.get(0))) {
return childrenPath.get(0);
}
return unzippedPath;
}
return unzippedPath;
}
/**
@ -161,7 +189,13 @@ public class FileUtils {
public static boolean isEmpty(@NonNull Path path) throws IOException {
Assert.notNull(path, "Path must not be null");
return Files.list(path).count() == 0;
if (!Files.isDirectory(path) || Files.notExists(path)) {
return true;
}
try (Stream<Path> pathStream = Files.list(path)) {
return pathStream.count() == 0;
}
}
/**
@ -261,43 +295,15 @@ public class FileUtils {
}
}
/**
*
* Creates temp directory.
*
* @param path path
* @return boolean
* @throws IORuntimeException IORuntimeException
* @return temp directory path
* @throws IOException if an I/O error occurs or the temporary-file directory does not exist
*/
public static boolean del(Path path) throws IORuntimeException {
if (Files.notExists(path)) {
return true;
}
try {
if (Files.isDirectory(path)) {
Files.walkFileTree(path, new SimpleFileVisitor<Path>() {
@Override
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
Files.delete(file);
return FileVisitResult.CONTINUE;
}
@Override
public FileVisitResult postVisitDirectory(Path dir, IOException e) throws IOException {
if (e == null) {
Files.delete(dir);
return FileVisitResult.CONTINUE;
} else {
throw e;
}
}
});
} else {
Files.delete(path);
}
} catch (IOException e) {
throw new IORuntimeException(e);
}
return true;
@NonNull
public static Path createTempDirectory() throws IOException {
return Files.createTempDirectory("halo");
}
}

View File

@ -0,0 +1,69 @@
package run.halo.app.utils;
import lombok.extern.slf4j.Slf4j;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.errors.RepositoryNotFoundException;
import org.eclipse.jgit.storage.file.WindowCacheConfig;
import org.springframework.lang.NonNull;
import org.springframework.util.Assert;
import java.io.IOException;
import java.nio.file.Path;
/**
* Git utilities.
*
* @author johnniang
* @date 19-6-12
*/
@Slf4j
public class GitUtils {
private GitUtils() {
// Config packed git MMAP
WindowCacheConfig config = new WindowCacheConfig();
config.setPackedGitMMAP(false);
config.install();
}
public static void cloneFromGit(@NonNull String repoUrl, @NonNull Path targetPath) throws GitAPIException {
Assert.hasText(repoUrl, "Repository remote url must not be blank");
Assert.notNull(targetPath, "Target path must not be null");
log.debug("Trying to clone git repo [{}] to [{}]", repoUrl, targetPath);
// Use try-with-resource-statement
Git git = null;
try {
git = Git.cloneRepository()
.setURI(repoUrl)
.setDirectory(targetPath.toFile())
.call();
log.debug("Cloned git repo [{}] successfully", repoUrl);
} finally {
closeQuietly(git);
}
}
public static Git openOrInit(Path repoPath) throws IOException, GitAPIException {
Git git;
try {
git = Git.open(repoPath.toFile());
} catch (RepositoryNotFoundException e) {
log.warn("Git repository may not exist, we will try to initialize an empty repository", e);
git = Git.init().setDirectory(repoPath.toFile()).call();
}
return git;
}
public static void closeQuietly(Git git) {
if (git != null) {
git.getRepository().close();
git.close();
}
}
}

View File

@ -8,6 +8,7 @@ import org.springframework.util.Assert;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.nio.file.Path;
import java.util.UUID;
import static run.halo.app.model.support.HaloConst.FILE_SEPARATOR;

View File

@ -1 +0,0 @@
.attach-detail-img img{width:100%}.ant-divider-horizontal[data-v-b694bf52]{margin:24px 0 12px 0}.search-box[data-v-b694bf52]{padding-bottom:12px}.attach-thumb[data-v-b694bf52]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.attach-thumb img[data-v-b694bf52]{width:100%;height:100%;position:absolute;top:0;left:0}.ant-card-meta[data-v-b694bf52]{padding:.8rem}.attach-detail-img img[data-v-b694bf52]{width:100%}.table-operator[data-v-b694bf52]{margin-bottom:0}

View File

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

View File

@ -0,0 +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}@-webkit-keyframes scaleDraw-data-v-0ce6900e{0%{-webkit-transform:scale(1);transform:scale(1)}25%{-webkit-transform:scale(1.3);transform:scale(1.3)}50%{-webkit-transform:scale(1);transform:scale(1)}75%{-webkit-transform:scale(1.3);transform:scale(1.3)}}@keyframes scaleDraw-data-v-0ce6900e{0%{-webkit-transform:scale(1);transform:scale(1)}25%{-webkit-transform:scale(1.3);transform:scale(1.3)}50%{-webkit-transform:scale(1);transform:scale(1)}75%{-webkit-transform:scale(1.3);transform:scale(1.3)}}.upload-button[data-v-0ce6900e]{-webkit-animation:scaleDraw-data-v-0ce6900e 4s ease-in-out infinite;position:fixed;bottom:30px;right:30px}.theme-thumb[data-v-0ce6900e]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.theme-thumb img[data-v-0ce6900e]{width:100%;height:100%;position:absolute;top:0;left:0}

View File

@ -0,0 +1 @@
.height-100[data-v-1ac0b863]{height:100vh}.install-action[data-v-1ac0b863]{margin-top:1rem}.previus-button[data-v-1ac0b863]{margin-right:1rem}.install-card[data-v-1ac0b863]{-webkit-box-shadow:0 10px 20px 0 hsla(0,0%,92.5%,.86);box-shadow:0 10px 20px 0 hsla(0,0%,92.5%,.86)}

View File

@ -0,0 +1 @@
.environment-info ul,ul{margin:0;padding:0;list-style:none}.environment-info a{margin-right:10px}

View File

@ -1 +0,0 @@
ul{margin:0;padding:0;list-style:none}

View File

@ -1 +0,0 @@
.height-100[data-v-f2997e68]{height:100vh}.install-action[data-v-f2997e68]{margin-top:1rem}.previus-button[data-v-f2997e68]{margin-right:1rem}.install-card[data-v-f2997e68]{-webkit-box-shadow:0 10px 20px 0 hsla(0,0%,92.5%,.86);box-shadow:0 10px 20px 0 hsla(0,0%,92.5%,.86)}

View File

@ -0,0 +1 @@
.v-note-wrapper[data-v-6778754a]{z-index:1000;min-height:580px}.sheet-thum .img[data-v-6778754a]{width:100%;cursor:pointer;border-radius:4px}.sheet-thum .sheet-thum-remove[data-v-6778754a]{margin-top:16px}

View File

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

View File

@ -1 +0,0 @@
.v-note-wrapper[data-v-5a42b07f]{z-index:1000;min-height:580px}.sheet-thum .img[data-v-5a42b07f]{width:100%;cursor:pointer;border-radius:4px}.sheet-thum .sheet-thum-remove[data-v-5a42b07f]{margin-top:16px}

View File

@ -0,0 +1 @@
.attach-detail-img img{width:100%}.ant-divider-horizontal[data-v-18d41aa9]{margin:24px 0 12px 0}.search-box[data-v-18d41aa9]{padding-bottom:12px}.attach-thumb[data-v-18d41aa9]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.attach-thumb img[data-v-18d41aa9]{width:100%;height:100%;position:absolute;top:0;left:0}.ant-card-meta[data-v-18d41aa9]{padding:.8rem}.attach-detail-img img[data-v-18d41aa9]{width:100%}.table-operator[data-v-18d41aa9]{margin-bottom:0}

View File

@ -0,0 +1 @@
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}.ant-divider-horizontal[data-v-4bf43659]{margin:24px 0 12px 0}.search-box[data-v-4bf43659]{padding-bottom:12px}.photo-thumb[data-v-4bf43659]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.photo-thumb img[data-v-4bf43659]{width:100%;height:100%;position:absolute;top:0;left:0}.ant-card-meta[data-v-4bf43659]{padding:.8rem}.photo-detail-img img[data-v-4bf43659]{width:100%}.table-operator[data-v-4bf43659]{margin-bottom:0}

View File

@ -1 +0,0 @@
.attach-detail-img img{width:100%}.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}.upload-button[data-v-40d5a5ae]{position:fixed;bottom:30px;right:30px}.theme-thumb[data-v-40d5a5ae]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.theme-thumb img[data-v-40d5a5ae]{width:100%;height:100%;position:absolute;top:0;left:0}

View File

@ -1 +0,0 @@
.analysis-card-container[data-v-4cadd8f2]{position:relative;overflow:hidden;width:100%}.analysis-card-container .meta[data-v-4cadd8f2]{position:relative;overflow:hidden;width:100%;color:rgba(0,0,0,.45);font-size:14px;line-height:22px}.analysis-card-container .meta .analysis-card-action[data-v-4cadd8f2]{cursor:pointer;position:absolute;top:0;right:0}.number[data-v-4cadd8f2]{overflow:hidden;text-overflow:ellipsis;word-break:break-all;white-space:nowrap;color:#000;margin-top:4px;margin-bottom:0;font-size:32px;line-height:38px;height:38px}

View File

@ -1 +0,0 @@
.v-note-wrapper[data-v-669770a4]{z-index:1000;min-height:580px}.post-thum .img[data-v-669770a4]{width:100%;cursor:pointer;border-radius:4px}.post-thum .post-thum-remove[data-v-669770a4]{margin-top:16px}

View File

@ -0,0 +1 @@
.analysis-card-container[data-v-698a5e37]{position:relative;overflow:hidden;width:100%}.analysis-card-container .meta[data-v-698a5e37]{position:relative;overflow:hidden;width:100%;color:rgba(0,0,0,.45);font-size:14px;line-height:22px}.analysis-card-container .meta .analysis-card-action[data-v-698a5e37]{cursor:pointer;position:absolute;top:0;right:0}.number[data-v-698a5e37]{overflow:hidden;text-overflow:ellipsis;word-break:break-all;white-space:nowrap;color:#000;margin-top:4px;margin-bottom:0;font-size:32px;line-height:38px;height:38px}

View File

@ -1 +0,0 @@
.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}.ant-divider-horizontal[data-v-2a97a053]{margin:24px 0 12px 0}.search-box[data-v-2a97a053]{padding-bottom:12px}.photo-thumb[data-v-2a97a053]{width:100%;margin:0 auto;position:relative;padding-bottom:56%;overflow:hidden}.photo-thumb img[data-v-2a97a053]{width:100%;height:100%;position:absolute;top:0;left:0}.ant-card-meta[data-v-2a97a053]{padding:.8rem}.photo-detail-img img[data-v-2a97a053]{width:100%}.table-operator[data-v-2a97a053]{margin-bottom:0}

View File

@ -1 +1 @@
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}.page-header-wrapper-grid-content-main[data-v-0c60a972]{width:100%;height:100%;min-height:100%;-webkit-transition:.3s;transition:.3s}.page-header-wrapper-grid-content-main .profile-center-avatarHolder[data-v-0c60a972]{text-align:center;margin-bottom:24px}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar[data-v-0c60a972]{margin:0 auto;width:104px;height:104px;margin-bottom:20px;border-radius:50%;overflow:hidden;cursor:pointer}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar img[data-v-0c60a972]{height:100%;width:100%}.page-header-wrapper-grid-content-main .profile-center-avatarHolder .username[data-v-0c60a972]{color:rgba(0,0,0,.85);font-size:20px;line-height:28px;font-weight:500;margin-bottom:4px}.page-header-wrapper-grid-content-main .profile-center-detail p[data-v-0c60a972]{margin-bottom:8px;padding-left:26px;position:relative}.page-header-wrapper-grid-content-main .profile-center-detail i[data-v-0c60a972]{position:absolute;height:14px;width:14px;left:0;top:4px}
.attach-item{width:50%;margin:0 auto;position:relative;padding-bottom:28%;overflow:hidden;float:left;cursor:pointer}.attach-item img{width:100%;height:100%;position:absolute;top:0;left:0}.page-header-wrapper-grid-content-main[data-v-69ef61d6]{width:100%;height:100%;min-height:100%;-webkit-transition:.3s;transition:.3s}.page-header-wrapper-grid-content-main .profile-center-avatarHolder[data-v-69ef61d6]{text-align:center;margin-bottom:24px}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar[data-v-69ef61d6]{margin:0 auto;width:104px;height:104px;margin-bottom:20px;border-radius:50%;overflow:hidden;cursor:pointer}.page-header-wrapper-grid-content-main .profile-center-avatarHolder>.avatar img[data-v-69ef61d6]{height:100%;width:100%}.page-header-wrapper-grid-content-main .profile-center-avatarHolder .username[data-v-69ef61d6]{color:rgba(0,0,0,.85);font-size:20px;line-height:28px;font-weight:500;margin-bottom:4px}.page-header-wrapper-grid-content-main .profile-center-detail p[data-v-69ef61d6]{margin-bottom:8px;padding-left:26px;position:relative}.page-header-wrapper-grid-content-main .profile-center-detail i[data-v-69ef61d6]{position:absolute;height:14px;width:14px;left:0;top:4px}

View File

@ -0,0 +1 @@
.v-note-wrapper[data-v-348cd59e]{z-index:1000;min-height:580px}.post-thum .img[data-v-348cd59e]{width:100%;cursor:pointer;border-radius:4px}.post-thum .post-thum-remove[data-v-348cd59e]{margin-top:16px}

View File

@ -0,0 +1 @@
.exception[data-v-230942b4]{min-height:500px;height:80%;-webkit-box-align:center;-ms-flex-align:center;align-items:center;text-align:center;margin-top:150px}.exception .img[data-v-230942b4]{display:inline-block;padding-right:52px;zoom:1}.exception .img img[data-v-230942b4]{height:360px;max-width:430px}.exception .content[data-v-230942b4]{display:inline-block;-webkit-box-flex:1;-ms-flex:auto;flex:auto}.exception .content h1[data-v-230942b4]{color:#434e59;font-size:72px;font-weight:600;line-height:72px;margin-bottom:24px}.exception .content .desc[data-v-230942b4]{color:rgba(0,0,0,.45);font-size:20px;line-height:28px;margin-bottom:16px}.mobile .exception[data-v-230942b4]{margin-top:30px}.mobile .exception .img[data-v-230942b4]{padding-right:unset}.mobile .exception .img img[data-v-230942b4]{height:40%;max-width:80%}

View File

@ -1 +0,0 @@
.exception[data-v-729a8fea]{min-height:500px;height:80%;-webkit-box-align:center;-ms-flex-align:center;align-items:center;text-align:center;margin-top:150px}.exception .img[data-v-729a8fea]{display:inline-block;padding-right:52px;zoom:1}.exception .img img[data-v-729a8fea]{height:360px;max-width:430px}.exception .content[data-v-729a8fea]{display:inline-block;-webkit-box-flex:1;-ms-flex:auto;flex:auto}.exception .content h1[data-v-729a8fea]{color:#434e59;font-size:72px;font-weight:600;line-height:72px;margin-bottom:24px}.exception .content .desc[data-v-729a8fea]{color:rgba(0,0,0,.45);font-size:20px;line-height:28px;margin-bottom:16px}.mobile .exception[data-v-729a8fea]{margin-top:30px}.mobile .exception .img[data-v-729a8fea]{padding-right:unset}.mobile .exception .img img[data-v-729a8fea]{height:40%;max-width:80%}

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-009936c1.f3153164.css rel=prefetch><link href=/css/chunk-0aa79c38.26a33a1b.css rel=prefetch><link href=/css/chunk-1be69b35.b6783003.css rel=prefetch><link href=/css/chunk-2ca3170e.61a5a976.css rel=prefetch><link href=/css/chunk-37d95348.909d3d1b.css rel=prefetch><link href=/css/chunk-436563a2.cb1e7f15.css rel=prefetch><link href=/css/chunk-46d7532c.94c6eb30.css rel=prefetch><link href=/css/chunk-4851a43a.210847fe.css rel=prefetch><link href=/css/chunk-6e38bcf5.2ee2b33a.css rel=prefetch><link href=/css/chunk-70b33d4d.701a4459.css rel=prefetch><link href=/css/chunk-75c7eed4.7cf84e9e.css rel=prefetch><link href=/css/chunk-9449c032.dafef2de.css rel=prefetch><link href=/css/chunk-9cb97d52.046bf41d.css rel=prefetch><link href=/css/chunk-bb4f0d4a.c1990d7c.css rel=prefetch><link href=/css/fail.e9c3e2d8.css rel=prefetch><link href=/js/chunk-009936c1.cde57fa8.js rel=prefetch><link href=/js/chunk-0aa79c38.2659df6e.js rel=prefetch><link href=/js/chunk-0ba750a2.02c8e842.js rel=prefetch><link href=/js/chunk-142c8832.8aceee71.js rel=prefetch><link href=/js/chunk-1be69b35.4a496da5.js rel=prefetch><link href=/js/chunk-2ca3170e.258d6e52.js rel=prefetch><link href=/js/chunk-2d0b64bf.25665dba.js rel=prefetch><link href=/js/chunk-2d0d65a2.1c8f2476.js rel=prefetch><link href=/js/chunk-2d21a35c.2fc10284.js rel=prefetch><link href=/js/chunk-2d228d13.dd7018e7.js rel=prefetch><link href=/js/chunk-37d95348.9ac04f40.js rel=prefetch><link href=/js/chunk-436563a2.89c8f183.js rel=prefetch><link href=/js/chunk-46d7532c.7500e276.js rel=prefetch><link href=/js/chunk-4851a43a.e3ce92c4.js rel=prefetch><link href=/js/chunk-5bf599cc.fc6c7d8c.js rel=prefetch><link href=/js/chunk-6e38bcf5.7b552106.js rel=prefetch><link href=/js/chunk-70b33d4d.f5bbad6f.js rel=prefetch><link href=/js/chunk-75c7eed4.cee58ce6.js rel=prefetch><link href=/js/chunk-87e2df70.f4b6bdc6.js rel=prefetch><link href=/js/chunk-9449c032.0036f54b.js rel=prefetch><link href=/js/chunk-9cb97d52.abfd8c14.js rel=prefetch><link href=/js/chunk-bb4f0d4a.3b7dfaaa.js rel=prefetch><link href=/js/fail.8a6d08f5.js rel=prefetch><link href=/css/app.d748d7bc.css rel=preload as=style><link href=/css/chunk-vendors.278be955.css rel=preload as=style><link href=/js/app.1842d5e6.js rel=preload as=script><link href=/js/chunk-vendors.811663b9.js rel=preload as=script><link href=/css/chunk-vendors.278be955.css rel=stylesheet><link href=/css/app.d748d7bc.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.811663b9.js></script><script src=/js/app.1842d5e6.js></script></body></html>
<!DOCTYPE html><html lang=zh-cmn-Hans><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no"><meta name=robots content=noindex,nofllow><meta name=generator content=Halo><link rel=icon href=/logo.png><title>Halo Dashboard</title><link href=/css/chunk-0337f7a6.4c6b622f.css rel=prefetch><link href=/css/chunk-1079f749.94b473ad.css rel=prefetch><link href=/css/chunk-14e0b302.32f796a8.css rel=prefetch><link href=/css/chunk-161dc990.5ac5144c.css rel=prefetch><link href=/css/chunk-1be69b35.43c1fc12.css rel=prefetch><link href=/css/chunk-31c8ea42.4a090118.css rel=prefetch><link href=/css/chunk-5000e55c.7fb9bc61.css rel=prefetch><link href=/css/chunk-6d8b31f6.ad8d17b2.css rel=prefetch><link href=/css/chunk-81d936d8.05888d95.css rel=prefetch><link href=/css/chunk-b2d0b040.389eca76.css rel=prefetch><link href=/css/chunk-bb4f0d4a.c1990d7c.css rel=prefetch><link href=/css/chunk-bfd5bbcc.6a83ae7d.css rel=prefetch><link href=/css/chunk-c0a1d3c4.09186be6.css rel=prefetch><link href=/css/chunk-cec31564.6f053d75.css rel=prefetch><link href=/css/fail.809a6bc5.css rel=prefetch><link href=/js/chunk-0337f7a6.11326d77.js rel=prefetch><link href=/js/chunk-0ba750a2.b786c9db.js rel=prefetch><link href=/js/chunk-1079f749.ec67c7db.js rel=prefetch><link href=/js/chunk-142c8832.0f8270b3.js rel=prefetch><link href=/js/chunk-14e0b302.a86d1254.js rel=prefetch><link href=/js/chunk-161dc990.5de9313f.js rel=prefetch><link href=/js/chunk-1be69b35.81559bfc.js rel=prefetch><link href=/js/chunk-2d0b64bf.61d5d7c3.js rel=prefetch><link href=/js/chunk-2d0d65a2.2249765a.js rel=prefetch><link href=/js/chunk-2d21a35c.eda7a11a.js rel=prefetch><link href=/js/chunk-2d228d13.85b46532.js rel=prefetch><link href=/js/chunk-31c8ea42.0b2feab9.js rel=prefetch><link href=/js/chunk-5000e55c.3bd9ce3a.js rel=prefetch><link href=/js/chunk-5bf599cc.ac9398f3.js rel=prefetch><link href=/js/chunk-6d8b31f6.b64e5366.js rel=prefetch><link href=/js/chunk-81d936d8.5c1d2539.js rel=prefetch><link href=/js/chunk-87e2df70.0ada7d4e.js rel=prefetch><link href=/js/chunk-b2d0b040.b0d70d07.js rel=prefetch><link href=/js/chunk-bb4f0d4a.048dc3a4.js rel=prefetch><link href=/js/chunk-bfd5bbcc.d2ca1e80.js rel=prefetch><link href=/js/chunk-c0a1d3c4.41d0d3f8.js rel=prefetch><link href=/js/chunk-cec31564.cfe3fd85.js rel=prefetch><link href=/js/fail.61f30b0f.js rel=prefetch><link href=/css/app.f8b02c30.css rel=preload as=style><link href=/css/chunk-vendors.ee4e8dbf.css rel=preload as=style><link href=/js/app.845922f6.js rel=preload as=script><link href=/js/chunk-vendors.2f7bce79.js rel=preload as=script><link href=/css/chunk-vendors.ee4e8dbf.css rel=stylesheet><link href=/css/app.f8b02c30.css rel=stylesheet></head><body><noscript><strong>We're sorry but vue-antd-pro doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.2f7bce79.js></script><script src=/js/app.845922f6.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

View File

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1be69b35"],{"031c":function(t,a,e){},2967: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",[e("a-col",{attrs:{span:24}},[e("a-card",{attrs:{bordered:!1}},[e("a-list",{attrs:{itemLayout:"horizontal"}},[e("a-list-item",[e("a-list-item-meta",[e("h3",{attrs:{slot:"title"},slot:"title"},[t._v("\n 环境信息\n ")]),e("template",{slot:"description"},[e("ul",[e("li",[t._v("版本:"+t._s(t.environments.version))]),e("li",[t._v("数据库:"+t._s(t.environments.database))]),e("li",[t._v("启动时间:"+t._s(t._f("moment")(t.environments.startTime)))])]),e("a",{attrs:{href:"https://github.com/halo-dev",target:"_blank"}},[t._v("开源地址\n "),e("a-icon",{attrs:{type:"link"}})],1),t._v(" \n "),e("a",{attrs:{href:"https://halo.run/docs",target:"_blank"}},[t._v("用户文档\n "),e("a-icon",{attrs:{type:"link"}})],1),t._v(" \n "),e("a",{attrs:{href:"https://bbs.halo.run",target:"_blank"}},[t._v("在线社区\n "),e("a-icon",{attrs:{type:"link"}})],1),t._v(" \n ")])],2)],1),e("a-list-item",[e("a-list-item-meta",[e("h3",{attrs:{slot:"title"},slot:"title"},[t._v("\n 开发者\n ")]),e("template",{slot:"description"},t._l(t.developers,function(t,a){return e("a-tooltip",{key:a,attrs:{placement:"top",title:t.name}},[e("a-avatar",{style:{marginRight:"10px"},attrs:{size:"large",src:t.avatar}})],1)}),1)],2)],1),e("a-list-item",[e("a-list-item-meta",[e("h3",{attrs:{slot:"title"},slot:"title"},[t._v("\n 时间轴\n ")]),e("template",{slot:"description"},[e("a-timeline",[e("a-timeline-item",[t._v("...")]),t._l(t.steps,function(a,n){return e("a-timeline-item",{key:n},[t._v(t._s(a.date)+" "+t._s(a.content))])})],2)],1)],2)],1)],1)],1)],1)],1)],1)},i=[],s=e("50fc"),r={data:function(){return{environments:{},developers:[{name:"Ryan Wang",avatar:"//cn.gravatar.com/avatar/7cc7f29278071bd4dce995612d428834?s=256&d=mm",website:"https://ryanc.cc",github:"https://github.com/ruibaby"},{name:"John Niang",avatar:"//cn.gravatar.com/avatar/1dcf60ef27363dae539385d5bae9b2bd?s=256&d=mm",website:"https://johnniang.me",github:"https://github.com/johnniang"},{name:"Aquan",avatar:"//cn.gravatar.com/avatar/3958035fa354403fa9ca3fca36b08068?s=256&d=mm",website:"https://blog.eunji.cn",github:"https://github.com/aquanlerou"},{name:"appdev",avatar:"//cn.gravatar.com/avatar/08cf681fb7c6ad1b4fe70a8269c2103c?s=256&d=mm",website:"https://www.apkdv.com",github:"https://github.com/appdev"}],steps:[{date:"2019-06-01",content:"1.0 正式版发布"},{date:"2019-05-03",content:"Star 数达到 3300"},{date:"2019-01-30",content:"John Niang 加入开发"},{date:"2018-10-18",content:"构建镜像到 Docker hub"},{date:"2018-09-22",content:"Star 数达到 800"},{date:"2018-05-02",content:"第一条 Issue"},{date:"2018-05-01",content:"Star 数达到 100"},{date:"2018-04-29",content:"第一个 Pull request"},{date:"2018-04-28",content:"正式开源"},{date:"2018-03-21",content:"确定命名为 Halo并上传到 Github"}]}},created:function(){this.getEnvironments()},methods:{getEnvironments:function(){var t=this;s["a"].environments().then(function(a){t.environments=a.data.data})}}},o=r,c=(e("5ea2"),e("17cc")),l=Object(c["a"])(o,n,i,!1,null,null,null);a["default"]=l.exports},"5ea2":function(t,a,e){"use strict";var n=e("031c"),i=e.n(n);i.a}}]);

View File

@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-1be69b35"],{"031c":function(t,a,e){},2967: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",[e("a-col",{attrs:{span:24}},[e("a-card",{attrs:{bordered:!1}},[e("a-card",{staticClass:"environment-info",attrs:{title:"环境信息",bordered:!1}},[e("a-popconfirm",{attrs:{slot:"extra",placement:"left",okText:"确定",cancelText:"取消"},on:{confirm:t.confirmUpdate},slot:"extra"},[e("template",{slot:"title"},[e("p",[t._v("确定更新 "),e("b",[t._v("Halo admin")]),t._v(" 吗?")])]),e("a-icon",{attrs:{slot:"icon",type:"cloud-download"},slot:"icon"}),e("a-button",{attrs:{loading:t.updating,type:"dashed",shape:"circle",icon:"cloud-download"}})],2),e("ul",[e("li",[t._v("Server 版本:"+t._s(t.environments.version))]),e("li",[t._v("Admin 版本:"+t._s(t.adminVersion))]),e("li",[t._v("数据库:"+t._s(t.environments.database))]),e("li",[t._v("运行模式:"+t._s(t.environments.mode))]),e("li",[t._v("启动时间:"+t._s(t._f("moment")(t.environments.startTime)))])]),e("a",{attrs:{href:"https://github.com/halo-dev",target:"_blank"}},[t._v("开源地址\n "),e("a-icon",{attrs:{type:"link"}})],1),e("a",{attrs:{href:"https://halo.run/docs",target:"_blank"}},[t._v("用户文档\n "),e("a-icon",{attrs:{type:"link"}})],1),e("a",{attrs:{href:"https://bbs.halo.run",target:"_blank"}},[t._v("在线社区\n "),e("a-icon",{attrs:{type:"link"}})],1)],1),e("a-card",{attrs:{title:"开发者",bordered:!1}},t._l(t.developers,function(t,a){return e("a",{key:a,attrs:{href:t.github,target:"_blank"}},[e("a-tooltip",{attrs:{placement:"top",title:t.name}},[e("a-avatar",{style:{marginRight:"10px"},attrs:{size:"large",src:t.avatar}})],1)],1)}),0),e("a-card",{attrs:{title:"时间轴",bordered:!1}},[e("a-timeline",[e("a-timeline-item",[t._v("...")]),t._l(t.steps,function(a,n){return e("a-timeline-item",{key:n},[t._v(t._s(a.date)+" "+t._s(a.content))])})],2)],1)],1)],1)],1)],1)},i=[],r=e("50fc"),o={data:function(){return{adminVersion:this.VERSION,environments:{},developers:[{name:"Ryan Wang",avatar:"//cn.gravatar.com/avatar/7cc7f29278071bd4dce995612d428834?s=256&d=mm",website:"https://ryanc.cc",github:"https://github.com/ruibaby"},{name:"John Niang",avatar:"//cn.gravatar.com/avatar/1dcf60ef27363dae539385d5bae9b2bd?s=256&d=mm",website:"https://johnniang.me",github:"https://github.com/johnniang"},{name:"Aquan",avatar:"//cn.gravatar.com/avatar/3958035fa354403fa9ca3fca36b08068?s=256&d=mm",website:"https://blog.eunji.cn",github:"https://github.com/aquanlerou"},{name:"appdev",avatar:"//cn.gravatar.com/avatar/08cf681fb7c6ad1b4fe70a8269c2103c?s=256&d=mm",website:"https://www.apkdv.com",github:"https://github.com/appdev"}],steps:[{date:"2019-06-01",content:"1.0 正式版发布"},{date:"2019-05-03",content:"Star 数达到 3300"},{date:"2019-01-30",content:"John Niang 加入开发"},{date:"2018-10-18",content:"构建镜像到 Docker hub"},{date:"2018-09-22",content:"Star 数达到 800"},{date:"2018-05-02",content:"第一条 Issue"},{date:"2018-05-01",content:"Star 数达到 100"},{date:"2018-04-29",content:"第一个 Pull request"},{date:"2018-04-28",content:"正式开源"},{date:"2018-03-21",content:"确定命名为 Halo并上传到 Github"}],updating:!1}},created:function(){this.getEnvironments()},computed:{updateText:function(){return this.updating?"更新中...":"更新"}},methods:{getEnvironments:function(){var t=this;r["a"].environments().then(function(a){t.environments=a.data.data})},confirmUpdate:function(){var t=this;this.updating=!0,r["a"].updateAdminAssets().then(function(a){t.$notification.success({message:"更新成功",description:"请刷新后体验最新版本!"})}).finally(function(){t.updating=!1})}}},s=o,c=(e("5ea2"),e("17cc")),d=Object(c["a"])(s,n,i,!1,null,null,null);a["default"]=d.exports},"5ea2":function(t,a,e){"use strict";var n=e("031c"),i=e.n(n);i.a}}]);

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

@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d21a35c"],{bb17:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"page-header-index-wide"},[n("a-row",{attrs:{gutter:12}},[n("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:10,lg:10,md:10,sm:24,xs:24}},[n("a-card",{attrs:{title:t.title}},[n("a-form",{attrs:{layout:"horizontal"}},[n("a-form-item",{attrs:{label:"网站名称:"}},[n("a-input",{model:{value:t.link.name,callback:function(e){t.$set(t.link,"name",e)},expression:"link.name"}})],1),n("a-form-item",{attrs:{label:"网站地址:",help:"* 需要加上 http://"}},[n("a-input",{model:{value:t.link.url,callback:function(e){t.$set(t.link,"url",e)},expression:"link.url"}})],1),n("a-form-item",{attrs:{label:"Logo"}},[n("a-input",{model:{value:t.link.logo,callback:function(e){t.$set(t.link,"logo",e)},expression:"link.logo"}})],1),n("a-form-item",{attrs:{label:"分组:",help:"* 非必填"}},[n("a-input",{model:{value:t.link.team,callback:function(e){t.$set(t.link,"team",e)},expression:"link.team"}})],1),n("a-form-item",{attrs:{label:"描述:"}},[n("a-input",{attrs:{type:"textarea",autosize:{minRows:5}},model:{value:t.link.description,callback:function(e){t.$set(t.link,"description",e)},expression:"link.description"}})],1),n("a-form-item",["create"===t.formType?n("a-button",{attrs:{type:"primary"},on:{click:t.handleSaveClick}},[t._v("保存")]):n("a-button-group",[n("a-button",{attrs:{type:"primary"},on:{click:t.handleSaveClick}},[t._v("更新")]),"update"===t.formType?n("a-button",{attrs:{type:"dashed"},on:{click:t.handleAddLink}},[t._v("返回添加")]):t._e()],1)],1)],1)],1)],1),n("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:14,lg:14,md:14,sm:24,xs:24}},[n("a-card",{attrs:{title:"所有友情链接"}},[n("a-table",{attrs:{columns:t.columns,dataSource:t.links,loading:t.loading,rowKey:function(t){return t.id}},scopedSlots:t._u([{key:"url",fn:function(e){return[n("a",{attrs:{target:"_blank",href:e}},[t._v(t._s(e))])]}},{key:"name",fn:function(e){return n("ellipsis",{attrs:{length:15,tooltip:""}},[t._v(t._s(e))])}},{key:"action",fn:function(e,a){return n("span",{},[n("a",{attrs:{href:"javascript:;"},on:{click:function(e){return t.handleEditLink(a.id)}}},[t._v("编辑")]),n("a-divider",{attrs:{type:"vertical"}}),n("a-popconfirm",{attrs:{title:"你确定要删除【"+a.name+"】链接?",okText:"确定",cancelText:"取消"},on:{confirm:function(e){return t.handleDeleteLink(a.id)}}},[n("a",{attrs:{href:"javascript:;"}},[t._v("删除")])])],1)}}])})],1)],1)],1)],1)},i=[],l=(n("69a3"),n("9efd")),o="/api/admin/links",c={listAll:function(){return Object(l["a"])({url:"".concat(o),method:"get"})},create:function(t){return Object(l["a"])({url:o,data:t,method:"post"})},get:function(t){return Object(l["a"])({url:"".concat(o,"/").concat(t),method:"get"})},update:function(t,e){return Object(l["a"])({url:"".concat(o,"/").concat(t),data:e,method:"put"})},delete:function(t){return Object(l["a"])({url:"".concat(o,"/").concat(t),method:"delete"})}},r=c,s=[{title:"名称",dataIndex:"name",scopedSlots:{customRender:"name"}},{title:"网址",dataIndex:"url",scopedSlots:{customRender:"url"}},{title:"分组",dataIndex:"team"},{title:"操作",key:"action",scopedSlots:{customRender:"action"}}],d={data:function(){return{formType:"create",data:[],loading:!1,columns:s,links:[],link:{}}},computed:{title:function(){return this.link.id?"修改友情链接":"添加友情链接"}},created:function(){this.loadLinks()},methods:{loadLinks:function(){var t=this;this.loading=!0,r.listAll().then(function(e){t.links=e.data.data,t.loading=!1})},handleSaveClick:function(){this.createOrUpdateLink()},handleAddLink:function(){this.formType="create",this.link={}},handleEditLink:function(t){var e=this;r.get(t).then(function(t){e.link=t.data.data,e.formType="update"})},handleDeleteLink:function(t){var e=this;r.delete(t).then(function(t){e.$message.success("删除成功!"),e.loadLinks()})},createOrUpdateLink:function(){var t=this;this.link.id?r.update(this.link.id,this.link).then(function(e){t.$message.success("更新成功!"),t.loadLinks()}):r.create(this.link).then(function(e){t.$message.success("保存成功!"),t.loadLinks()}),this.handleAddLink()}}},u=d,m=n("17cc"),k=Object(m["a"])(u,a,i,!1,null,"243cf1cf",null);e["default"]=k.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d21a35c"],{bb17:function(t,e,n){"use strict";n.r(e);var a=function(){var t=this,e=t.$createElement,n=t._self._c||e;return n("div",{staticClass:"page-header-index-wide"},[n("a-row",{attrs:{gutter:12}},[n("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:10,lg:10,md:10,sm:24,xs:24}},[n("a-card",{attrs:{title:t.title}},[n("a-form",{attrs:{layout:"horizontal"}},[n("a-form-item",{attrs:{label:"网站名称:"}},[n("a-input",{model:{value:t.link.name,callback:function(e){t.$set(t.link,"name",e)},expression:"link.name"}})],1),n("a-form-item",{attrs:{label:"网站地址:",help:"* 需要加上 http://"}},[n("a-input",{model:{value:t.link.url,callback:function(e){t.$set(t.link,"url",e)},expression:"link.url"}})],1),n("a-form-item",{attrs:{label:"Logo"}},[n("a-input",{model:{value:t.link.logo,callback:function(e){t.$set(t.link,"logo",e)},expression:"link.logo"}})],1),n("a-form-item",{attrs:{label:"分组:",help:"* 非必填"}},[n("a-input",{model:{value:t.link.team,callback:function(e){t.$set(t.link,"team",e)},expression:"link.team"}})],1),n("a-form-item",{attrs:{label:"描述:"}},[n("a-input",{attrs:{type:"textarea",autosize:{minRows:5}},model:{value:t.link.description,callback:function(e){t.$set(t.link,"description",e)},expression:"link.description"}})],1),n("a-form-item",["create"===t.formType?n("a-button",{attrs:{type:"primary"},on:{click:t.handleSaveClick}},[t._v("保存")]):n("a-button-group",[n("a-button",{attrs:{type:"primary"},on:{click:t.handleSaveClick}},[t._v("更新")]),"update"===t.formType?n("a-button",{attrs:{type:"dashed"},on:{click:t.handleAddLink}},[t._v("返回添加")]):t._e()],1)],1)],1)],1)],1),n("a-col",{style:{"padding-bottom":"12px"},attrs:{xl:14,lg:14,md:14,sm:24,xs:24}},[n("a-card",{attrs:{title:"所有友情链接"}},[n("a-table",{attrs:{columns:t.columns,dataSource:t.links,loading:t.loading,rowKey:function(t){return t.id}},scopedSlots:t._u([{key:"url",fn:function(e){return[n("a",{attrs:{target:"_blank",href:e}},[t._v(t._s(e))])]}},{key:"name",fn:function(e){return n("ellipsis",{attrs:{length:15,tooltip:""}},[t._v(t._s(e))])}},{key:"action",fn:function(e,a){return n("span",{},[n("a",{attrs:{href:"javascript:;"},on:{click:function(e){return t.handleEditLink(a.id)}}},[t._v("编辑")]),n("a-divider",{attrs:{type:"vertical"}}),n("a-popconfirm",{attrs:{title:"你确定要删除【"+a.name+"】链接?",okText:"确定",cancelText:"取消"},on:{confirm:function(e){return t.handleDeleteLink(a.id)}}},[n("a",{attrs:{href:"javascript:;"}},[t._v("删除")])])],1)}}])})],1)],1)],1)],1)},i=[],l=(n("69a3"),n("9efd")),o="/api/admin/links",r={listAll:function(){return Object(l["a"])({url:"".concat(o),method:"get"})},create:function(t){return Object(l["a"])({url:o,data:t,method:"post"})},get:function(t){return Object(l["a"])({url:"".concat(o,"/").concat(t),method:"get"})},update:function(t,e){return Object(l["a"])({url:"".concat(o,"/").concat(t),data:e,method:"put"})},delete:function(t){return Object(l["a"])({url:"".concat(o,"/").concat(t),method:"delete"})}},c=r,s=[{title:"名称",dataIndex:"name",scopedSlots:{customRender:"name"}},{title:"网址",dataIndex:"url",scopedSlots:{customRender:"url"}},{title:"分组",dataIndex:"team"},{title:"操作",key:"action",scopedSlots:{customRender:"action"}}],d={data:function(){return{formType:"create",data:[],loading:!1,columns:s,links:[],link:{}}},computed:{title:function(){return this.link.id?"修改友情链接":"添加友情链接"}},created:function(){this.loadLinks()},methods:{loadLinks:function(){var t=this;this.loading=!0,c.listAll().then(function(e){t.links=e.data.data,t.loading=!1})},handleSaveClick:function(){this.createOrUpdateLink()},handleAddLink:function(){this.formType="create",this.link={}},handleEditLink:function(t){var e=this;c.get(t).then(function(t){e.link=t.data.data,e.formType="update"})},handleDeleteLink:function(t){var e=this;c.delete(t).then(function(t){e.$message.success("删除成功!"),e.loadLinks()})},createOrUpdateLink:function(){var t=this;this.link.id?c.update(this.link.id,this.link).then(function(e){t.$message.success("更新成功!"),t.loadLinks()}):c.create(this.link).then(function(e){t.$message.success("保存成功!"),t.loadLinks()}),this.handleAddLink()}}},u=d,m=n("17cc"),k=Object(m["a"])(u,a,i,!1,null,"56d4c6ed",null);e["default"]=k.exports}}]);

View File

@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d228d13"],{db98:function(a,t,o){"use strict";o.r(t);var e=function(){var a=this,t=a.$createElement,o=a._self._c||t;return o("div",{staticClass:"page-header-index-wide"},[o("div",{staticClass:"card-content"},[o("a-row",{attrs:{gutter:12}},[o("a-col",{attrs:{xl:6,lg:6,md:12,sm:24,xs:24}},[o("a-card",{attrs:{title:"Markdown 文章导入",bordered:!1,bodyStyle:{padding:"16px"}}},[o("p",[a._v("支持 Hexo/Jekyll 文章导入并解析元数据")]),o("a-button",{staticStyle:{float:"right"},attrs:{type:"primary"},on:{click:a.handleImportMarkdown}},[a._v("导入")])],1)],1)],1),o("a-modal",{attrs:{title:"Markdown 文章导入",footer:null},model:{value:a.markdownUpload,callback:function(t){a.markdownUpload=t},expression:"markdownUpload"}},[o("upload",{attrs:{name:"files",multiple:"",accept:"text/markdown",uploadHandler:a.uploadHandler},on:{change:a.handleChange}},[o("p",{staticClass:"ant-upload-drag-icon"},[o("a-icon",{attrs:{type:"inbox"}})],1),o("p",{staticClass:"ant-upload-text"},[a._v("拖拽或点击选择 Markdown 文件到此处")]),o("p",{staticClass:"ant-upload-hint"},[a._v("支持多个文件同时上传")])])],1)],1)])},n=[],d=(o("7364"),o("9efd")),r="/api/admin/backups",l={importMarkdown:function(a,t,o){return Object(d["a"])({url:"".concat(r,"/import/markdowns"),timeout:864e4,data:a,onUploadProgress:t,cancelToken:o,method:"post"})}},s=l,i={data:function(){return{markdownUpload:!1,uploadHandler:s.importMarkdown}},methods:{handleImportMarkdown:function(){this.markdownUpload=!0},handleChange:function(a){var t=a.file.status;"uploading"!==t&&console.log(a.file,a.fileList),"done"===t?this.$message.success("".concat(a.file.name," 导入成功!")):"error"===t&&this.$message.error("".concat(a.file.name," 导入失败!"))}}},c=i,p=o("17cc"),u=Object(p["a"])(c,e,n,!1,null,"5fc42ae9",null);t["default"]=u.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-2d228d13"],{db98:function(a,t,o){"use strict";o.r(t);var e=function(){var a=this,t=a.$createElement,o=a._self._c||t;return o("div",{staticClass:"page-header-index-wide"},[o("div",{staticClass:"card-content"},[o("a-row",{attrs:{gutter:12}},[o("a-col",{attrs:{xl:6,lg:6,md:12,sm:24,xs:24}},[o("a-card",{attrs:{title:"Markdown 文章导入",bordered:!1,bodyStyle:{padding:"16px"}}},[o("p",[a._v("支持 Hexo/Jekyll 文章导入并解析元数据")]),o("a-button",{staticStyle:{float:"right"},attrs:{type:"primary"},on:{click:a.handleImportMarkdown}},[a._v("导入")])],1)],1)],1),o("a-modal",{attrs:{title:"Markdown 文章导入",footer:null},model:{value:a.markdownUpload,callback:function(t){a.markdownUpload=t},expression:"markdownUpload"}},[o("upload",{attrs:{name:"files",multiple:"",accept:"text/markdown",uploadHandler:a.uploadHandler},on:{change:a.handleChange}},[o("p",{staticClass:"ant-upload-drag-icon"},[o("a-icon",{attrs:{type:"inbox"}})],1),o("p",{staticClass:"ant-upload-text"},[a._v("拖拽或点击选择 Markdown 文件到此处")]),o("p",{staticClass:"ant-upload-hint"},[a._v("支持多个文件同时上传")])])],1)],1)])},n=[],d=(o("7364"),o("9efd")),r="/api/admin/backups",l={importMarkdown:function(a,t,o){return Object(d["a"])({url:"".concat(r,"/import/markdowns"),timeout:864e4,data:a,onUploadProgress:t,cancelToken:o,method:"post"})}},s=l,i={data:function(){return{markdownUpload:!1,uploadHandler:s.importMarkdown}},methods:{handleImportMarkdown:function(){this.markdownUpload=!0},handleChange:function(a){var t=a.file.status;"uploading"!==t&&console.log(a.file,a.fileList),"done"===t?this.$message.success("".concat(a.file.name," 导入成功!")):"error"===t&&this.$message.error("".concat(a.file.name," 导入失败!"))}}},c=i,p=o("17cc"),u=Object(p["a"])(c,e,n,!1,null,"8dab78e6",null);t["default"]=u.exports}}]);

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["chunk-9449c032"],{9231:function(a,e,t){"use strict";var s=t("ea0a"),n=t.n(s);n.a},ac2a5:function(a,e,t){"use strict";t.r(e);var s=function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("div",{staticClass:"container"},[a._m(0),t("div",{staticClass:"loginBody animated"},[t("a-form",{attrs:{layout:"vertical"},nativeOn:{keyup:function(e){return!e.type.indexOf("key")&&a._k(e.keyCode,"enter",13,e.key,"Enter")?null:a.handleLogin(e)}}},[t("a-form-item",{staticClass:"animated fadeInUp",style:{"animation-delay":"0.1s"}},[t("a-input",{attrs:{placeholder:"用户名/邮箱"},model:{value:a.username,callback:function(e){a.username=e},expression:"username"}},[t("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),t("a-form-item",{staticClass:"animated fadeInUp",style:{"animation-delay":"0.2s"}},[t("a-input",{attrs:{type:"password",placeholder:"密码"},model:{value:a.password,callback:function(e){a.password=e},expression:"password"}},[t("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),t("a-row",[t("a-button",{staticClass:"animated fadeInUp",style:{"animation-delay":"0.3s"},attrs:{type:"primary",block:!0},on:{click:a.handleLogin}},[a._v("登录")])],1)],1)],1)])},n=[function(){var a=this,e=a.$createElement,t=a._self._c||e;return t("div",{staticClass:"loginLogo animated fadeInUp"},[t("span",[a._v("Halo")])])}],i=(t("34a3"),t("e20c")),r=t("591a"),o={data:function(){return{username:null,password:null}},methods:Object(i["a"])({},Object(r["b"])(["login","loadUser"]),{handleLogin:function(){var a=this;this.username?this.password?this.login({username:this.username,password:this.password}).then(function(e){a.loginSuccess()}):this.$message.warn("密码不能为空!"):this.$message.warn("用户名不能为空!")},loginSuccess:function(){this.loadUser(),this.$route.query.redirect?this.$router.replace(this.$route.query.redirect):this.$router.replace({name:"Dashboard"})}})},l=o,c=(t("9231"),t("17cc")),u=Object(c["a"])(l,s,n,!1,null,null,null);e["default"]=u.exports},ea0a:function(a,e,t){}}]);

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-cec31564"],{9231:function(e,a,t){"use strict";var s=t("ea0a"),n=t.n(s);n.a},ac2a:function(e,a,t){"use strict";t.r(a);var s=function(){var e=this,a=e.$createElement,t=e._self._c||a;return t("div",{staticClass:"container"},[e._m(0),t("div",{staticClass:"loginBody animated"},[t("a-form",{attrs:{layout:"vertical"},nativeOn:{keyup:function(a){return!a.type.indexOf("key")&&e._k(a.keyCode,"enter",13,a.key,"Enter")?null:e.handleLogin(a)}}},[t("a-form-item",{staticClass:"animated fadeInUp",style:{"animation-delay":"0.1s"}},[t("a-input",{attrs:{placeholder:"用户名/邮箱"},model:{value:e.username,callback:function(a){e.username=a},expression:"username"}},[t("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"user"},slot:"prefix"})],1)],1),t("a-form-item",{staticClass:"animated fadeInUp",style:{"animation-delay":"0.2s"}},[t("a-input",{attrs:{type:"password",placeholder:"密码"},model:{value:e.password,callback:function(a){e.password=a},expression:"password"}},[t("a-icon",{staticStyle:{color:"rgba(0,0,0,.25)"},attrs:{slot:"prefix",type:"lock"},slot:"prefix"})],1)],1),t("a-row",[t("a-button",{staticClass:"animated fadeInUp",style:{"animation-delay":"0.3s"},attrs:{type:"primary",block:!0},on:{click:e.handleLogin}},[e._v("登录")])],1)],1)],1)])},n=[function(){var e=this,a=e.$createElement,t=e._self._c||a;return t("div",{staticClass:"loginLogo animated fadeInUp"},[t("span",[e._v("Halo")])])}],i=(t("34a3"),t("e20c")),r=t("591a"),o={data:function(){return{username:null,password:null}},methods:Object(i["a"])({},Object(r["b"])(["login","loadUser"]),{handleLogin:function(){var e=this;this.username?this.password?this.login({username:this.username,password:this.password}).then(function(a){e.loginSuccess()}):this.$message.warn("密码不能为空!"):this.$message.warn("用户名不能为空!")},loginSuccess:function(){this.loadUser(),this.$route.query.redirect?this.$router.replace(this.$route.query.redirect):this.$router.replace({name:"Dashboard"})}})},l=o,c=(t("9231"),t("17cc")),u=Object(c["a"])(l,s,n,!1,null,null,null);a["default"]=u.exports},ea0a:function(e,a,t){}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["fail"],{5517:function(t,e,s){"use strict";var c=s("92530"),n=s.n(c);n.a},92530:function(t,e,s){},cc89:function(t,e,s){"use strict";s.r(e);var c=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("exception-page",{attrs:{type:"404"}})},n=[],a=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"exception"},[s("div",{staticClass:"img"},[s("img",{attrs:{src:t.config[t.type].img}})]),s("div",{staticClass:"content"},[s("h1",[t._v(t._s(t.config[t.type].title))]),s("div",{staticClass:"desc"},[t._v(t._s(t.config[t.type].desc))]),s("div",{staticClass:"action"},[s("a-button",{attrs:{type:"primary"},on:{click:t.handleToHome}},[t._v("返回首页")])],1)])])},i=[],o={404:{img:"https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg",title:"404",desc:"抱歉,你访问的页面不存在"},500:{img:"https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg",title:"500",desc:"抱歉,服务器出错了"}},p=o,r={name:"Exception",props:{type:{type:String,default:"404"}},data:function(){return{config:p}},methods:{handleToHome:function(){this.$router.push({name:"Dashboard"})}}},l=r,u=(s("5517"),s("17cc")),d=Object(u["a"])(l,a,i,!1,null,"729a8fea",null),f=d.exports,m={components:{ExceptionPage:f}},g=m,v=Object(u["a"])(g,c,n,!1,null,"388fe08d",null);e["default"]=v.exports}}]);
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["fail"],{"01a4":function(t,e,s){},2254:function(t,e,s){"use strict";var a=s("01a4"),c=s.n(a);c.a},cc89:function(t,e,s){"use strict";s.r(e);var a=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("exception-page",{attrs:{type:"404"}})},c=[],n=function(){var t=this,e=t.$createElement,s=t._self._c||e;return s("div",{staticClass:"exception"},[s("div",{staticClass:"img"},[s("img",{attrs:{src:t.config[t.type].img}})]),s("div",{staticClass:"content"},[s("h1",[t._v(t._s(t.config[t.type].title))]),s("div",{staticClass:"desc"},[t._v(t._s(t.config[t.type].desc))]),s("div",{staticClass:"action"},[s("a-button",{attrs:{type:"primary"},on:{click:t.handleToHome}},[t._v("返回首页")])],1)])])},i=[],o={404:{img:"https://gw.alipayobjects.com/zos/rmsportal/KpnpchXsobRgLElEozzI.svg",title:"404",desc:"抱歉,你访问的页面不存在"},500:{img:"https://gw.alipayobjects.com/zos/rmsportal/RVRUAYdCGeYNBWoKiIwB.svg",title:"500",desc:"抱歉,服务器出错了"}},p=o,r={name:"Exception",props:{type:{type:String,default:"404"}},data:function(){return{config:p}},methods:{handleToHome:function(){this.$router.push({name:"Dashboard"})}}},l=r,u=(s("2254"),s("17cc")),d=Object(u["a"])(l,n,i,!1,null,"230942b4",null),m=d.exports,g={components:{ExceptionPage:m}},f=g,v=Object(u["a"])(f,a,c,!1,null,"e319b3a6",null);e["default"]=v.exports}}]);

View File

@ -8,6 +8,7 @@ import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import static org.hamcrest.Matchers.equalTo;
@ -27,26 +28,29 @@ public class FileUtilsTest {
// Create test folders
Files.createDirectories(testPath);
System.out.println("Walk path list");
List<Path> walkList = Files.walk(tempDirectory).collect(Collectors.toList());
walkList.forEach(System.out::println);
Assert.assertThat(walkList.size(), equalTo(4));
try (Stream<Path> pathStream = Files.walk(tempDirectory)) {
List<Path> walkList = pathStream.collect(Collectors.toList());
walkList.forEach(System.out::println);
Assert.assertThat(walkList.size(), equalTo(4));
}
try (Stream<Path> pathStream = Files.walk(tempDirectory, 1)) {
List<Path> walkList = pathStream.collect(Collectors.toList());
walkList.forEach(System.out::println);
Assert.assertThat(walkList.size(), equalTo(2));
}
System.out.println("Walk 1 deep path list");
List<Path> walk1DeepList = Files.walk(tempDirectory, 1).collect(Collectors.toList());
walk1DeepList.forEach(System.out::println);
Assert.assertThat(walk1DeepList.size(), equalTo(2));
try (Stream<Path> pathStream = Files.list(tempDirectory)) {
List<Path> walkList = pathStream.collect(Collectors.toList());
walkList.forEach(System.out::println);
Assert.assertThat(walkList.size(), equalTo(1));
}
System.out.println("List path list");
List<Path> listList = Files.list(tempDirectory).collect(Collectors.toList());
listList.forEach(System.out::println);
Assert.assertThat(listList.size(), equalTo(1));
System.out.println("List test path list");
List<Path> testPathList = Files.list(testPath).collect(Collectors.toList());
testPathList.forEach(System.out::println);
Assert.assertThat(testPathList.size(), equalTo(0));
try (Stream<Path> pathStream = Files.list(testPath)) {
List<Path> walkList = pathStream.collect(Collectors.toList());
walkList.forEach(System.out::println);
Assert.assertThat(walkList.size(), equalTo(0));
}
// Delete it
FileUtils.deleteFolder(tempDirectory);

View File

@ -41,9 +41,10 @@ public class GithubTest {
}
@Test
@SuppressWarnings("unchecked")
public void getLatestReleaseTest() throws Throwable {
ResponseEntity<Map> responseEntity = restTemplate.getForEntity(API_URL, Map.class);
System.out.println("Reponse: " + responseEntity);
System.out.println("Response: " + responseEntity);
Object assetsObject = responseEntity.getBody().get("assets");
System.out.println("Assets class: " + assetsObject.getClass());
System.out.println("Assets: " + assetsObject);

View File

@ -1,13 +1,12 @@
package run.halo.app.utils;
import com.sun.nio.zipfs.JarFileSystemProvider;
import org.junit.Test;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.file.*;
import java.util.Collections;
import java.nio.file.FileSystemNotFoundException;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* Path test.
@ -25,18 +24,4 @@ public class PathTest {
System.out.println("Path: " + path.toString());
}
// @Test
// public void getPathOfJarFileSuccessfully() throws URISyntaxException, IOException {
// String file = "jar:file:/path/to/jar/xxx.jar!/BOOT-INF/classes!/templates/themes";
// URI uri = new URI(file);
// FileSystem fileSystem = FileSystems.newFileSystem(uri, Collections.emptyMap());
// Path path = fileSystem.getPath("/BOOT-INF/classes/templates/themes");
//
// System.out.println("Path: " + path.toString());
//
// Files.walk(path, 1).forEach(p -> {
// System.out.println(p.toString());
// });
// }
}

View File

@ -1,6 +1,5 @@
package run.halo.app.utils;
import io.micrometer.core.annotation.TimedSet;
import org.junit.Test;
import java.nio.file.Path;