Commit da595c87 authored by Liang Ding's avatar Liang Ding

新增 Markdown zip 导入方式 #128

parent 3e786b85
......@@ -519,7 +519,8 @@ public final class Server extends BaseServer {
get("/admin-preference.do", adminConsole::showAdminPreferenceFunction).
get("/console/export/sql", adminConsole::exportSQL).
get("/console/export/json", adminConsole::exportJSON).
get("/console/export/hexo", adminConsole::exportHexo);
get("/console/export/hexo", adminConsole::exportHexo).
post("/console/import/markdown-zip", adminConsole::importMarkdownZip);
adminConsoleGroup.router().get(new String[]{"/admin-article.do",
"/admin-article-list.do",
"/admin-comment-list.do",
......
......@@ -12,6 +12,7 @@
package org.b3log.solo.processor.console;
import jodd.io.ZipUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateFormatUtils;
......@@ -22,6 +23,8 @@ import org.b3log.latke.Keys;
import org.b3log.latke.Latkes;
import org.b3log.latke.event.Event;
import org.b3log.latke.event.EventManager;
import org.b3log.latke.http.FileUpload;
import org.b3log.latke.http.Request;
import org.b3log.latke.http.RequestContext;
import org.b3log.latke.http.Response;
import org.b3log.latke.http.renderer.AbstractFreeMarkerRenderer;
......@@ -31,14 +34,12 @@ import org.b3log.latke.model.Plugin;
import org.b3log.latke.model.User;
import org.b3log.latke.plugin.ViewLoadEventData;
import org.b3log.latke.service.LangPropsService;
import org.b3log.latke.util.Strings;
import org.b3log.solo.Server;
import org.b3log.solo.model.Common;
import org.b3log.solo.model.Option;
import org.b3log.solo.model.UserExt;
import org.b3log.solo.service.DataModelService;
import org.b3log.solo.service.ExportService;
import org.b3log.solo.service.OptionQueryService;
import org.b3log.solo.service.UserQueryService;
import org.b3log.solo.service.*;
import org.b3log.solo.util.Markdowns;
import org.b3log.solo.util.Solos;
import org.json.JSONObject;
......@@ -101,6 +102,12 @@ public class AdminConsole {
@Inject
private EventManager eventManager;
/**
* Import service.
*/
@Inject
private ImportService importService;
/**
* Shows administrator index with the specified context.
*
......@@ -220,6 +227,45 @@ public class AdminConsole {
fireFreeMarkerActionEvent(templateName, dataModel);
}
/**
* Imports markdown zip.
*
* @param context the specified context
*/
public void importMarkdownZip(final RequestContext context) {
final Request request = context.getRequest();
final FileUpload file = request.getFileUpload("file");
final String[] allowedSuffixArray = new String[]{"zip"};
final String fileName = file.getFilename();
String suffix = StringUtils.substringAfterLast(fileName, ".");
if (StringUtils.isBlank(suffix)) {
// TODO
return;
}
if (!Strings.containsIgnoreCase(suffix, allowedSuffixArray)) {
// TODO
return;
}
try {
final byte[] bytes = file.getData();
final String tmpDir = System.getProperty("java.io.tmpdir");
final String date = DateFormatUtils.format(new Date(), "yyyyMMddHHmmss");
final String zipPath = tmpDir + File.separator + "solo-import-" + date + ".zip";
final File zipFile = new File(zipPath);
FileUtils.writeByteArrayToFile(zipFile, bytes);
final String unzipPath = tmpDir + File.separator + "solo-import-" + date;
final File unzipDir = new File(unzipPath);
ZipUtil.unzip(zipFile, unzipDir);
importService.importMarkdownDir(unzipDir);
FileUtils.deleteQuietly(zipFile);
FileUtils.deleteQuietly(unzipDir);
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Imports markdown file failed", e);
return;
}
}
/**
* Exports data as SQL zip file.
*
......
......@@ -260,6 +260,10 @@ public class ExportService {
*/
public void exportGitHub() {
try {
if (Latkes.RuntimeMode.DEVELOPMENT == Latkes.getRuntimeMode()) {
return;
}
final JSONObject preference = optionQueryService.getPreference();
if (null == preference) {
return;
......
......@@ -35,7 +35,7 @@ import java.util.*;
* Import service.
*
* @author <a href="http://88250.b3log.org">Liang Ding</a>
* @version 1.0.1.6, Apr 23, 2020
* @version 1.0.1.7, May 21, 2020
* @since 2.2.0
*/
@Service
......@@ -64,8 +64,7 @@ public class ImportService {
private UserQueryService userQueryService;
/**
* Imports markdowns files as articles. See <a href="https://hacpai.com/article/1498490209748">Solo 支持 Hexo/Jekyll 数据导入</a> for
* more details.
* Imports markdown files as articles. See <a href="https://hacpai.com/article/1498490209748">Solo 支持 Hexo/Jekyll 数据导入</a> for more details.
*/
public void importMarkdowns() {
new Thread(() -> {
......@@ -80,65 +79,74 @@ public class ImportService {
}
final File markdownsPath = Latkes.getFile("/markdowns");
LOGGER.debug("Import directory [" + markdownsPath.getPath() + "]");
importMarkdownDir(markdownsPath);
}).start();
}
final JSONObject admin = userQueryService.getAdmin();
if (null == admin) { // Not init yet
return;
}
/**
* Imports markdown files under the specified markdown files dir.
*
* @param markdownsDir the specified markdown files dir
*/
public void importMarkdownDir(final File markdownsDir) {
LOGGER.debug("Import directory [" + markdownsDir.getPath() + "]");
final String adminId = admin.optString(Keys.OBJECT_ID);
final JSONObject admin = userQueryService.getAdmin();
if (null == admin) { // Not init yet
return;
}
int succCnt = 0, failCnt = 0;
final Set<String> failSet = new TreeSet<>();
final Collection<File> mds = FileUtils.listFiles(markdownsPath, new String[]{"md"}, true);
if (mds.isEmpty()) {
return;
}
final String adminId = admin.optString(Keys.OBJECT_ID);
for (final File md : mds) {
final String fileName = md.getName();
if (StringUtils.equalsIgnoreCase(fileName, "README.md")) {
continue;
}
int succCnt = 0, failCnt = 0;
final Set<String> failSet = new TreeSet<>();
final Collection<File> mds = FileUtils.listFiles(markdownsDir, new String[]{"md"}, true);
if (mds.isEmpty()) {
return;
}
for (final File md : mds) {
final String fileName = md.getName();
if (StringUtils.equalsIgnoreCase(fileName, "README.md")) {
continue;
}
try {
final String fileContent = FileUtils.readFileToString(md, "UTF-8");
final JSONObject article = parseArticle(fileName, fileContent);
article.put(Article.ARTICLE_AUTHOR_ID, adminId);
try {
final String fileContent = FileUtils.readFileToString(md, "UTF-8");
final JSONObject article = parseArticle(fileName, fileContent);
article.put(Article.ARTICLE_AUTHOR_ID, adminId);
final JSONObject request = new JSONObject();
request.put(Article.ARTICLE, article);
final JSONObject request = new JSONObject();
request.put(Article.ARTICLE, article);
final String id = articleMgmtService.addArticle(request);
FileUtils.moveFile(md, new File(md.getPath() + "." + id));
LOGGER.info("Imported article [" + article.optString(Article.ARTICLE_TITLE) + "]");
succCnt++;
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Import file [" + fileName + "] failed", e);
final String id = articleMgmtService.addArticle(request);
FileUtils.moveFile(md, new File(md.getPath() + "." + id));
LOGGER.info("Imported article [" + article.optString(Article.ARTICLE_TITLE) + "]");
succCnt++;
} catch (final Exception e) {
LOGGER.log(Level.ERROR, "Import file [" + fileName + "] failed", e);
failCnt++;
failSet.add(fileName);
}
failCnt++;
failSet.add(fileName);
}
}
if (0 == succCnt && 0 == failCnt) {
return;
}
if (0 == succCnt && 0 == failCnt) {
return;
}
final StringBuilder logBuilder = new StringBuilder();
logBuilder.append("[").append(succCnt).append("] imported, [").append(failCnt).append("] failed");
if (failCnt > 0) {
logBuilder.append(": ").append(Strings.LINE_SEPARATOR);
final StringBuilder logBuilder = new StringBuilder();
logBuilder.append("[").append(succCnt).append("] imported, [").append(failCnt).append("] failed");
if (failCnt > 0) {
logBuilder.append(": ").append(Strings.LINE_SEPARATOR);
for (final String fail : failSet) {
logBuilder.append(" ").append(fail).append(Strings.LINE_SEPARATOR);
}
} else {
logBuilder.append(" :p");
for (final String fail : failSet) {
logBuilder.append(" ").append(fail).append(Strings.LINE_SEPARATOR);
}
LOGGER.info(logBuilder.toString());
}).start();
} else {
logBuilder.append(" :p");
}
LOGGER.info(logBuilder.toString());
}
private JSONObject parseArticle(final String fileName, String fileContent) {
......
......@@ -23,6 +23,11 @@
<a href="#tools/others/data">${exportDataLabel}</a>
</div>
</li>
<li>
<div id="tabOthers_data">
<a href="#tools/others/import-data">${importDataLabel}</a>
</div>
</li>
<li>
<div id="tabOthers_log">
<a href="#tools/others/log">${viewLogLabel}</a>
......@@ -42,6 +47,10 @@
<button class="fn__margin12" onclick="admin.others.exportJSON();">${exportJSONLabel}</button>
<button class="fn__margin12" onclick="admin.others.exportHexo();">${exportHexoLabel}</button>
</div>
<div id="tabOthersPanel_import-data" class="fn__none">
TODO
<button class="fn__margin12" onclick="">${uploadMarkdownZipLabel}</button>
</div>
<div id="tabOthersPanel_log" class="fn__none form">
<textarea rows="32" readonly></textarea>
</div>
......
......@@ -18,6 +18,7 @@
# Author: Dongxu Wang
#
uploadMarkdownZipLabel=Upload Markdown Zip
editorModeSVLabel=Split View
editorModeIRLabel=Instant Rendering
editorModeWYSIWYGLabel=WYSIWYG
......@@ -55,6 +56,7 @@ getUploadTokenErrLabel=Get community file storage service upload token failed
startToUseLabel=Start
clearDataLabel=Clear data
exportDataLabel=Export data
importDataLabel=Import data
syncToCommunityLabel=Sync to community
cntLabel=
reply1Label=Reply
......
......@@ -18,6 +18,7 @@
# Author: Dongxu Wang
#
uploadMarkdownZipLabel=\u4E0A\u4F20 Markdown Zip \u5305
editorModeSVLabel=\u5206\u5C4F\u9884\u89C8
editorModeIRLabel=\u5373\u65F6\u6E32\u67D3
editorModeWYSIWYGLabel=\u6240\u89C1\u5373\u6240\u5F97
......@@ -55,6 +56,7 @@ getUploadTokenErrLabel=\u83B7\u53D6\u793E\u533A\u6587\u4EF6\u5B58\u50A8\u670D\u5
startToUseLabel=\u5F00\u59CB\u4F7F\u7528
clearDataLabel=\u6570\u636E\u6E05\u7406
exportDataLabel=\u6570\u636E\u5BFC\u51FA
importDataLabel=\u6570\u636E\u5BFC\u5165
syncToCommunityLabel=\u540C\u6B65\u5230\u793E\u533A
cntLabel=\u4E2A
reply1Label=\u56DE\u590D
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment