From f0612d112088ab295cb85a9f79de2709d652adb3 Mon Sep 17 00:00:00 2001 From: "xiaoqi.cxq" Date: Sat, 4 Jun 2022 03:07:10 +0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BB=E7=A9=BA=E9=97=B4=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E4=B8=BAgitee?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 +- chrome-app/manifest.json | 2 +- server/pandoc.js | 196 +++++++------- server/pdf.js | 249 +++++++++-------- src/components/Modal.vue | 8 +- src/components/SideBar.vue | 4 +- src/components/StatusBar.vue | 13 +- src/components/Tour.vue | 4 +- src/components/menus/HistoryMenu.vue | 6 +- src/components/menus/ImportExportMenu.vue | 8 +- src/components/menus/MainMenu.vue | 18 +- src/components/menus/WorkspaceBackupMenu.vue | 4 +- src/components/menus/WorkspacesMenu.vue | 16 +- src/components/modals/PandocExportModal.vue | 13 +- src/components/modals/PdfExportModal.vue | 26 +- src/components/modals/SyncManagementModal.vue | 10 +- .../modals/WorkspaceManagementModal.vue | 16 +- .../providers/CouchdbWorkspaceModal.vue | 4 +- .../modals/providers/GiteaWorkspaceModal.vue | 2 +- .../modals/providers/GiteeWorkspaceModal.vue | 2 +- .../modals/providers/GithubWorkspaceModal.vue | 2 +- .../modals/providers/GitlabWorkspaceModal.vue | 2 +- .../providers/GoogleDriveWorkspaceModal.vue | 4 +- src/data/defaults/defaultWorkspaces.js | 2 +- src/data/faq.md | 4 +- src/data/features.js | 60 ++-- src/data/simpleModals.js | 82 +++--- src/data/welcomeFile.md | 14 +- src/icons/Provider.vue | 2 +- .../providers/giteeAppDataProvider.js | 256 ++++++++++++++++++ .../providers/giteeWorkspaceProvider.js | 2 +- src/services/providers/helpers/giteeHelper.js | 28 ++ src/services/syncSvc.js | 6 +- src/store/discussion.js | 4 +- src/store/workspace.js | 17 +- static/landing/index.html | 2 +- 36 files changed, 668 insertions(+), 424 deletions(-) create mode 100644 src/services/providers/giteeAppDataProvider.js diff --git a/README.md b/README.md index 4e255340..854fac87 100644 --- a/README.md +++ b/README.md @@ -14,7 +14,7 @@ StackEdit的作者可能因为什么原因,已经很久不维护了,Github ### TODO: 关于后续的一些想法 - 支持**Gitea**、**Gogs**两个轻量级且适于自建的Git仓库(毕竟Gitlab对机器配置要求较高)。想支持这两个主要也是考虑到其实很多公司已经禁用了Github或Gitee仓库,在公司都没法连上自己的Git仓库。 - 汉化,毕竟大家最熟悉的还是母语,并且该编辑器功能页面也不多,汉化工作量并不会很大。 -- 替换主工作区为Gitee(原版本主工作区是Google Drive,国内只有fan墙才可以用) +- 替换主文档空间为Gitee(原版本主文档空间是Google Drive,国内只有fan墙才可以用) - 引入mdnice,右边预览增加mdnice预览选项,主要含选主题(含mdnice常用20多个主题)、支持自定义主题、复制到公众号、复制到知乎、复制到稀土掘金等基本功能,便于喜欢写公众号、博客的同学可以更好更快的排版。 - ... 另外,朋友们有好的想法也可以在Issue或者加我微信 qicoding 提给我。 @@ -27,7 +27,7 @@ StackEdit的作者可能因为什么原因,已经很久不维护了,Github **已汉化主要功能部分(2022-06-01)** -**接下来修改主工作区为Gitee** +**接下来修改主文档空间为Gitee** diff --git a/chrome-app/manifest.json b/chrome-app/manifest.json index d13a5f37..a5013794 100644 --- a/chrome-app/manifest.json +++ b/chrome-app/manifest.json @@ -1,6 +1,6 @@ { "name": "StackEdit中文版", - "description": "浏览器内 Markdown 编辑器", + "description": "支持Gitee仓库的浏览器内 Markdown 编辑器", "version": "1.0.13", "manifest_version": 2, "container" : "GOOGLE_DRIVE", diff --git a/server/pandoc.js b/server/pandoc.js index 8ac0f3d3..cf93ac51 100644 --- a/server/pandoc.js +++ b/server/pandoc.js @@ -2,7 +2,6 @@ const { spawn } = require('child_process'); const fs = require('fs'); const tmp = require('tmp'); -const user = require('./user'); const conf = require('./conf'); const outputFormats = { @@ -42,108 +41,101 @@ exports.generate = (req, res) => { const outputFormat = Object.prototype.hasOwnProperty.call(outputFormats, req.query.format) ? req.query.format : 'pdf'; - user.checkSponsor(req.query.idToken) - .then((isSponsor) => { - if (!isSponsor) { - throw new Error('unauthorized'); - } - - return new Promise((resolve, reject) => { - tmp.file({ - postfix: `.${outputFormat}`, - }, (err, filePath, fd, cleanupCallback) => { - if (err) { - reject(err); - } else { - resolve({ - filePath, - cleanupCallback, - }); - } - }); - }); - }) - .then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => { - const options = readJson(req.query.options); - const metadata = readJson(req.query.metadata); - const params = []; - - params.push('--latex-engine=xelatex'); - params.push('--webtex=http://chart.apis.google.com/chart?cht=tx&chf=bg,s,FFFFFF00&chco=000000&chl='); - if (options.toc) { - params.push('--toc'); - } - options.tocDepth = parseInt(options.tocDepth, 10); - if (!Number.isNaN(options.tocDepth)) { - params.push('--toc-depth', options.tocDepth); - } - options.highlightStyle = highlightStyles.includes(options.highlightStyle) ? options.highlightStyle : 'kate'; - params.push('--highlight-style', options.highlightStyle); - Object.keys(metadata).forEach((key) => { - params.push('-M', `${key}=${metadata[key]}`); - }); - - let finished = false; - - function onError(error) { - finished = true; - cleanupCallback(); - reject(error); - } - - const format = outputFormat === 'pdf' ? 'latex' : outputFormat; - params.push('-f', 'json', '-t', format, '-o', filePath); - const pandoc = spawn(conf.values.pandocPath, params, { - stdio: [ - 'pipe', - 'ignore', - 'pipe', - ], - }); - let timeoutId = setTimeout(() => { - timeoutId = null; - pandoc.kill(); - }, 50000); - pandoc.on('error', onError); - pandoc.stdin.on('error', onError); - pandoc.stderr.on('data', (data) => { - pandocError += `${data}`; - }); - pandoc.on('close', (code) => { - if (!finished) { - clearTimeout(timeoutId); - if (!timeoutId) { - res.statusCode = 408; - cleanupCallback(); - reject(new Error('timeout')); - } else if (code) { - cleanupCallback(); - reject(); - } else { - res.set('Content-Type', outputFormats[outputFormat]); - const readStream = fs.createReadStream(filePath); - readStream.on('open', () => readStream.pipe(res)); - readStream.on('close', () => cleanupCallback()); - readStream.on('error', () => { - cleanupCallback(); - reject(); - }); - } - } - }); - req.pipe(pandoc.stdin); - })) - .catch((err) => { - const message = err && err.message; - if (message === 'unauthorized') { - res.statusCode = 401; - res.end('Unauthorized.'); - } else if (message === 'timeout') { - res.statusCode = 408; - res.end('Request timeout.'); + new Promise((resolve, reject) => { + tmp.file({ + postfix: `.${outputFormat}`, + }, (err, filePath, fd, cleanupCallback) => { + if (err) { + reject(err); } else { - res.statusCode = 400; - res.end(pandocError || 'Unknown error.'); + resolve({ + filePath, + cleanupCallback, + }); } }); + }).then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => { + const options = readJson(req.query.options); + const metadata = readJson(req.query.metadata); + const params = []; + + params.push('--pdf-engine=xelatex'); + params.push('--webtex=http://chart.apis.google.com/chart?cht=tx&chf=bg,s,FFFFFF00&chco=000000&chl='); + if (options.toc) { + params.push('--toc'); + } + options.tocDepth = parseInt(options.tocDepth, 10); + if (!Number.isNaN(options.tocDepth)) { + params.push('--toc-depth', options.tocDepth); + } + options.highlightStyle = highlightStyles.includes(options.highlightStyle) ? options.highlightStyle : 'kate'; + params.push('--highlight-style', options.highlightStyle); + Object.keys(metadata).forEach((key) => { + params.push('-M', `${key}=${metadata[key]}`); + }); + + let finished = false; + + function onError(error) { + finished = true; + cleanupCallback(); + reject(error); + } + + const format = outputFormat === 'pdf' ? 'latex' : outputFormat; + params.push('-f', 'json', '-t', format, '-o', filePath); + const pandoc = spawn(conf.values.pandocPath, params, { + stdio: [ + 'pipe', + 'ignore', + 'pipe', + ], + }); + let timeoutId = setTimeout(() => { + timeoutId = null; + pandoc.kill(); + }, 50000); + pandoc.on('error', onError); + pandoc.stdin.on('error', onError); + pandoc.stderr.on('data', (data) => { + pandocError += `${data}`; + }); + pandoc.on('close', (code) => { + if (!finished) { + clearTimeout(timeoutId); + if (!timeoutId) { + res.statusCode = 408; + cleanupCallback(); + reject(new Error('timeout')); + } else if (code) { + cleanupCallback(); + reject(); + } else { + res.set('Content-Type', outputFormats[outputFormat]); + const readStream = fs.createReadStream(filePath); + readStream.on('open', () => readStream.pipe(res)); + readStream.on('close', () => cleanupCallback()); + readStream.on('error', () => { + cleanupCallback(); + reject(); + }); + } + } + }); + req.pipe(pandoc.stdin); + })) + .catch((err) => { + console.error(err); + const message = err && err.message; + if (message === 'unauthorized') { + res.statusCode = 401; + res.end('Unauthorized.'); + } else if (message === 'timeout') { + res.statusCode = 408; + res.end('Request timeout.'); + } else { + res.statusCode = 400; + res.end(pandocError || 'Unknown error.'); + } + }); }; diff --git a/server/pdf.js b/server/pdf.js index 0fe4337a..f898b8a0 100644 --- a/server/pdf.js +++ b/server/pdf.js @@ -2,7 +2,6 @@ const { spawn } = require('child_process'); const fs = require('fs'); const tmp = require('tmp'); -const user = require('./user'); const conf = require('./conf'); /* eslint-disable no-var, prefer-arrow-callback, func-names */ @@ -51,135 +50,129 @@ const readJson = (str) => { exports.generate = (req, res) => { let wkhtmltopdfError = ''; - user.checkSponsor(req.query.idToken) - .then((isSponsor) => { - if (!isSponsor) { - throw new Error('unauthorized'); - } - return new Promise((resolve, reject) => { - tmp.file((err, filePath, fd, cleanupCallback) => { - if (err) { - reject(err); - } else { - resolve({ - filePath, - cleanupCallback, - }); - } - }); - }); - }) - .then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => { - let finished = false; - - function onError(err) { - finished = true; - cleanupCallback(); + new Promise((resolve, reject) => { + tmp.file((err, filePath, fd, cleanupCallback) => { + if (err) { reject(err); - } - const options = readJson(req.query.options); - const params = []; - - // Margins - const marginTop = parseInt(`${options.marginTop}`, 10); - params.push('-T', Number.isNaN(marginTop) ? 25 : marginTop); - const marginRight = parseInt(`${options.marginRight}`, 10); - params.push('-R', Number.isNaN(marginRight) ? 25 : marginRight); - const marginBottom = parseInt(`${options.marginBottom}`, 10); - params.push('-B', Number.isNaN(marginBottom) ? 25 : marginBottom); - const marginLeft = parseInt(`${options.marginLeft}`, 10); - params.push('-L', Number.isNaN(marginLeft) ? 25 : marginLeft); - - // Header - if (options.headerCenter) { - params.push('--header-center', `${options.headerCenter}`); - } - if (options.headerLeft) { - params.push('--header-left', `${options.headerLeft}`); - } - if (options.headerRight) { - params.push('--header-right', `${options.headerRight}`); - } - if (options.headerFontName) { - params.push('--header-font-name', `${options.headerFontName}`); - } - if (options.headerFontSize) { - params.push('--header-font-size', `${options.headerFontSize}`); - } - - // Footer - if (options.footerCenter) { - params.push('--footer-center', `${options.footerCenter}`); - } - if (options.footerLeft) { - params.push('--footer-left', `${options.footerLeft}`); - } - if (options.footerRight) { - params.push('--footer-right', `${options.footerRight}`); - } - if (options.footerFontName) { - params.push('--footer-font-name', `${options.footerFontName}`); - } - if (options.footerFontSize) { - params.push('--footer-font-size', `${options.footerFontSize}`); - } - - // Page size - params.push('--page-size', !authorizedPageSizes.includes(options.pageSize) ? 'A4' : options.pageSize); - - // Use a temp file as wkhtmltopdf can't access /dev/stdout on Amazon EC2 for some reason - params.push('--run-script', `${waitForJavaScript.toString()}waitForJavaScript()`); - params.push('--window-status', 'done'); - const wkhtmltopdf = spawn(conf.values.wkhtmltopdfPath, params.concat('-', filePath), { - stdio: [ - 'pipe', - 'ignore', - 'pipe', - ], - }); - let timeoutId = setTimeout(function () { - timeoutId = null; - wkhtmltopdf.kill(); - }, 50000); - wkhtmltopdf.on('error', onError); - wkhtmltopdf.stdin.on('error', onError); - wkhtmltopdf.stderr.on('data', (data) => { - wkhtmltopdfError += `${data}`; - }); - wkhtmltopdf.on('close', (code) => { - if (!finished) { - clearTimeout(timeoutId); - if (!timeoutId) { - cleanupCallback(); - reject(new Error('timeout')); - } else if (code) { - cleanupCallback(); - reject(); - } else { - res.set('Content-Type', 'application/pdf'); - const readStream = fs.createReadStream(filePath); - readStream.on('open', () => readStream.pipe(res)); - readStream.on('close', () => cleanupCallback()); - readStream.on('error', () => { - cleanupCallback(); - reject(); - }); - } - } - }); - req.pipe(wkhtmltopdf.stdin); - })) - .catch((err) => { - const message = err && err.message; - if (message === 'unauthorized') { - res.statusCode = 401; - res.end('Unauthorized.'); - } else if (message === 'timeout') { - res.statusCode = 408; - res.end('Request timeout.'); } else { - res.statusCode = 400; - res.end(wkhtmltopdfError || 'Unknown error.'); + resolve({ + filePath, + cleanupCallback, + }); } }); + }).then(({ filePath, cleanupCallback }) => new Promise((resolve, reject) => { + let finished = false; + + function onError(err) { + finished = true; + cleanupCallback(); + reject(err); + } + const options = readJson(req.query.options); + const params = []; + + // Margins + const marginTop = parseInt(`${options.marginTop}`, 10); + params.push('-T', Number.isNaN(marginTop) ? 25 : marginTop); + const marginRight = parseInt(`${options.marginRight}`, 10); + params.push('-R', Number.isNaN(marginRight) ? 25 : marginRight); + const marginBottom = parseInt(`${options.marginBottom}`, 10); + params.push('-B', Number.isNaN(marginBottom) ? 25 : marginBottom); + const marginLeft = parseInt(`${options.marginLeft}`, 10); + params.push('-L', Number.isNaN(marginLeft) ? 25 : marginLeft); + + // Header + if (options.headerCenter) { + params.push('--header-center', `${options.headerCenter}`); + } + if (options.headerLeft) { + params.push('--header-left', `${options.headerLeft}`); + } + if (options.headerRight) { + params.push('--header-right', `${options.headerRight}`); + } + if (options.headerFontName) { + params.push('--header-font-name', `${options.headerFontName}`); + } + if (options.headerFontSize) { + params.push('--header-font-size', `${options.headerFontSize}`); + } + + // Footer + if (options.footerCenter) { + params.push('--footer-center', `${options.footerCenter}`); + } + if (options.footerLeft) { + params.push('--footer-left', `${options.footerLeft}`); + } + if (options.footerRight) { + params.push('--footer-right', `${options.footerRight}`); + } + if (options.footerFontName) { + params.push('--footer-font-name', `${options.footerFontName}`); + } + if (options.footerFontSize) { + params.push('--footer-font-size', `${options.footerFontSize}`); + } + + // Page size + params.push('--page-size', !authorizedPageSizes.includes(options.pageSize) ? 'A4' : options.pageSize); + + // Use a temp file as wkhtmltopdf can't access /dev/stdout on Amazon EC2 for some reason + params.push('--run-script', `${waitForJavaScript.toString()}waitForJavaScript()`); + params.push('--window-status', 'done'); + const wkhtmltopdf = spawn(conf.values.wkhtmltopdfPath, params.concat('-', filePath), { + stdio: [ + 'pipe', + 'ignore', + 'pipe', + ], + }); + let timeoutId = setTimeout(function () { + timeoutId = null; + wkhtmltopdf.kill(); + }, 50000); + wkhtmltopdf.on('error', onError); + wkhtmltopdf.stdin.on('error', onError); + wkhtmltopdf.stderr.on('data', (data) => { + wkhtmltopdfError += `${data}`; + }); + wkhtmltopdf.on('close', (code) => { + if (!finished) { + clearTimeout(timeoutId); + if (!timeoutId) { + cleanupCallback(); + reject(new Error('timeout')); + } else if (code) { + cleanupCallback(); + reject(); + } else { + res.set('Content-Type', 'application/pdf'); + const readStream = fs.createReadStream(filePath); + readStream.on('open', () => readStream.pipe(res)); + readStream.on('close', () => cleanupCallback()); + readStream.on('error', () => { + cleanupCallback(); + reject(); + }); + } + } + }); + req.pipe(wkhtmltopdf.stdin); + })) + .catch((err) => { + console.error(err); + const message = err && err.message; + if (message === 'unauthorized') { + res.statusCode = 401; + res.end('Unauthorized.'); + } else if (message === 'timeout') { + res.statusCode = 408; + res.end('Request timeout.'); + } else { + res.statusCode = 400; + res.end(wkhtmltopdfError || 'Unknown error.'); + } + }); }; diff --git a/src/components/Modal.vue b/src/components/Modal.vue index b37f1a0c..05fae4f7 100644 --- a/src/components/Modal.vue +++ b/src/components/Modal.vue @@ -1,9 +1,9 @@ diff --git a/src/components/menus/MainMenu.vue b/src/components/menus/MainMenu.vue index 34fc013d..4ac6c1a1 100644 --- a/src/components/menus/MainMenu.vue +++ b/src/components/menus/MainMenu.vue @@ -11,8 +11,8 @@
- - {{currentWorkspace.name}} 与您的 Google Drive 应用数据文件夹同步。 + + {{currentWorkspace.name}} 与您的 Gitee 默认文档空间仓库同步。 {{currentWorkspace.name}}Google Drive 文件夹同步。 @@ -42,13 +42,13 @@ -
使用 Google 登录
- 同步您的主工作区并解锁功能。 +
使用 Gitee 登录
+ 同步您的主文档空间并解锁功能。
-
工作区
- 切换到另一个工作区。 +
文档空间
+ 切换到另一个文档空间。

@@ -113,7 +113,7 @@
- 工作区备份 + 文档空间备份 @@ -131,7 +131,7 @@ import { mapGetters, mapActions } from 'vuex'; import MenuEntry from './common/MenuEntry'; import providerRegistry from '../../services/providers/common/providerRegistry'; import UserImage from '../UserImage'; -import googleHelper from '../../services/providers/helpers/googleHelper'; +import giteeHelper from '../../services/providers/helpers/giteeHelper'; import syncSvc from '../../services/syncSvc'; import userSvc from '../../services/userSvc'; import store from '../../store'; @@ -183,7 +183,7 @@ export default { }), async signin() { try { - await googleHelper.signin(); + await giteeHelper.signin(); syncSvc.requestSync(); } catch (e) { // Cancel diff --git a/src/components/menus/WorkspaceBackupMenu.vue b/src/components/menus/WorkspaceBackupMenu.vue index 50c0f6e0..ad2f5e9d 100644 --- a/src/components/menus/WorkspaceBackupMenu.vue +++ b/src/components/menus/WorkspaceBackupMenu.vue @@ -6,12 +6,12 @@
- 导入工作区备份 + 导入文档空间备份
- 导出工作区备份 + 导出文档空间备份 diff --git a/src/components/menus/WorkspacesMenu.vue b/src/components/menus/WorkspacesMenu.vue index 54184b03..c8ef2328 100644 --- a/src/components/menus/WorkspacesMenu.vue +++ b/src/components/menus/WorkspacesMenu.vue @@ -2,8 +2,8 @@