From bda261a767b2967cad26cfb72ff9d826cf8969e2 Mon Sep 17 00:00:00 2001 From: "xiaoqi.cxq" Date: Fri, 25 Nov 2022 20:12:51 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BC=98=E5=8C=96pdf=E5=AF=BC=E5=87=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- docs/大文档导出PDF方式.md | 10 ++ package-lock.json | 88 +++-------------- package.json | 2 - server/conf.js | 4 - server/index.js | 5 - server/pandoc.js | 2 +- server/user.js | 116 ----------------------- src/components/modals/PdfExportModal.vue | 2 +- src/styles/base.scss | 2 +- 9 files changed, 28 insertions(+), 203 deletions(-) create mode 100644 docs/大文档导出PDF方式.md delete mode 100644 server/user.js diff --git a/docs/大文档导出PDF方式.md b/docs/大文档导出PDF方式.md new file mode 100644 index 00000000..097271b5 --- /dev/null +++ b/docs/大文档导出PDF方式.md @@ -0,0 +1,10 @@ +# 大文档导出PDF方式说明 +> 由于大文档导出PDF,需要消费非常多的服务器资源,而且很容易导致导出超时,故导出PDF的MD文档过大时,可以使用 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 工具导出。 + +# 操作步骤 +- 先在 **[StackEdit中文版](https://stackedit.cn/app)** 中使用 `导出为HTML` 功能导出MD文档,导出后可以得到一个HTML文档。 +- 到 **[wkhtmltopdf](https://wkhtmltopdf.org/downloads.html)** 官网下载安装程序。 +- 使用 wkhtmltopdf 的导出PDF的命令 `wkhtmltopdf [GLOBAL OPTION]... [OBJECT]... ` 把HTML导出为PDF,如简单的导出命令:`wkhtmltopdf test.html test.pdf`,具体的 `GLOBAL OPTION` 参数说明可以通过 `wkhtmltopdf -H` 查看帮助文档。 + + + diff --git a/package-lock.json b/package-lock.json index db07cd69..a4f86cce 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1278,38 +1278,6 @@ "postcss-value-parser": "^3.2.3" } }, - "aws-sdk": { - "version": "2.317.0", - "resolved": "https://registry.npmjs.org/aws-sdk/-/aws-sdk-2.317.0.tgz", - "integrity": "sha512-X2Cd1Gb9Cf9WVgGOiBSW4TK6q5Mb6AYiGmEA9XikCgur4H8E4TgmgWbBWJnTzxssugclVLVoWQfw3RshNKJksg==", - "requires": { - "buffer": "4.9.1", - "events": "1.1.1", - "ieee754": "1.1.8", - "jmespath": "0.15.0", - "querystring": "0.2.0", - "sax": "1.2.1", - "url": "0.10.3", - "uuid": "3.1.0", - "xml2js": "0.4.19" - }, - "dependencies": { - "xml2js": { - "version": "0.4.19", - "resolved": "https://registry.npmjs.org/xml2js/-/xml2js-0.4.19.tgz", - "integrity": "sha512-esZnJZJOiJR9wWKMyuvSE1y6Dq5LCuJanqhxslH2bxM6duahNZ+HMpCLhBQGZkbX6xRf8x1Y2eJlgt2q3qo49Q==", - "requires": { - "sax": ">=0.6.0", - "xmlbuilder": "~9.0.1" - } - }, - "xmlbuilder": { - "version": "9.0.7", - "resolved": "https://registry.npmjs.org/xmlbuilder/-/xmlbuilder-9.0.7.tgz", - "integrity": "sha1-Ey7mPS7FVlxVfiD0wi35rKaGsQ0=" - } - } - }, "aws-sign2": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", @@ -2351,7 +2319,8 @@ "base64-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.2.1.tgz", - "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==" + "integrity": "sha512-dwVUVIXsBZXwTuwnXI9RK8sBmgq09NDHzyR9SAph9eqk76gKK2JSQmZARC2zRC81JC2QTtxD0ARU5qTS25gIGw==", + "dev": true }, "bcrypt-pbkdf": { "version": "1.0.2", @@ -2599,6 +2568,7 @@ "version": "4.9.1", "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz", "integrity": "sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg=", + "dev": true, "requires": { "base64-js": "^1.0.2", "ieee754": "^1.1.4", @@ -5392,7 +5362,8 @@ "events": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/events/-/events-1.1.1.tgz", - "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=" + "integrity": "sha1-nr23Y1rQmccNzEwqH1AEKI6L2SQ=", + "dev": true }, "eventsource-polyfill": { "version": "0.9.6", @@ -8665,16 +8636,6 @@ "delegate": "^3.1.2" } }, - "google-id-token-verifier": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/google-id-token-verifier/-/google-id-token-verifier-0.2.3.tgz", - "integrity": "sha1-nmt41FieLQUNqBYT+4kK26MKTqg=", - "requires": { - "request": "^2.65.0", - "rsa-pem-from-mod-exp": "^0.8.4", - "underscore": "^1.8.3" - } - }, "graceful-fs": { "version": "4.1.11", "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz", @@ -9663,7 +9624,8 @@ "ieee754": { "version": "1.1.8", "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.8.tgz", - "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=" + "integrity": "sha1-vjPUCsEO8ZJnAfbwii2G+/0a0+Q=", + "dev": true }, "iferr": { "version": "0.1.5", @@ -11262,11 +11224,6 @@ "url-regex": "^3.0.0" } }, - "jmespath": { - "version": "0.15.0", - "resolved": "https://registry.npmjs.org/jmespath/-/jmespath-0.15.0.tgz", - "integrity": "sha1-o/Iiqarp+Wb10nx5ZRDigJF2Qhc=" - }, "jpeg-js": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/jpeg-js/-/jpeg-js-0.2.0.tgz", @@ -15312,7 +15269,8 @@ "punycode": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", - "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true }, "q": { "version": "1.5.1", @@ -15338,7 +15296,8 @@ "querystring": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", - "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true }, "querystring-es3": { "version": "0.2.1", @@ -16458,11 +16417,6 @@ "inherits": "^2.0.1" } }, - "rsa-pem-from-mod-exp": { - "version": "0.8.4", - "resolved": "https://registry.npmjs.org/rsa-pem-from-mod-exp/-/rsa-pem-from-mod-exp-0.8.4.tgz", - "integrity": "sha1-NipCxtMEBW1JOz8SvOq7LGV2ptQ=" - }, "rsvp": { "version": "3.6.2", "resolved": "https://registry.npmjs.org/rsvp/-/rsvp-3.6.2.tgz", @@ -17753,7 +17707,8 @@ "sax": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.1.tgz", - "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=" + "integrity": "sha1-e45lYZCyKOgaZq6nSEgNgozS03o=", + "dev": true }, "schema-utils": { "version": "0.3.0", @@ -20610,7 +20565,8 @@ "underscore": { "version": "1.8.3", "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.8.3.tgz", - "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=" + "integrity": "sha1-Tz+1OxBuYJf8+ctBCfKl6b36UCI=", + "dev": true }, "undertaker": { "version": "1.3.0", @@ -20885,15 +20841,6 @@ "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", "dev": true }, - "url": { - "version": "0.10.3", - "resolved": "https://registry.npmjs.org/url/-/url-0.10.3.tgz", - "integrity": "sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=", - "requires": { - "punycode": "1.3.2", - "querystring": "0.2.0" - } - }, "url-loader": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/url-loader/-/url-loader-1.1.1.tgz", @@ -21018,11 +20965,6 @@ "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", "dev": true }, - "uuid": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz", - "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g==" - }, "v8flags": { "version": "3.2.0", "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.2.0.tgz", diff --git a/package.json b/package.json index f981af78..ffac49ba 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,6 @@ "dependencies": { "@vue/test-utils": "^1.0.0-beta.16", "abcjs": "^5.2.0", - "aws-sdk": "^2.317.0", "babel-runtime": "^6.26.0", "bezier-easing": "^1.1.0", "body-parser": "^1.18.2", @@ -35,7 +34,6 @@ "compression": "^1.7.0", "diff-match-patch": "^1.0.0", "file-saver": "^1.3.8", - "google-id-token-verifier": "^0.2.3", "handlebars": "^4.0.10", "indexeddbshim": "^3.6.2", "js-yaml": "^3.11.0", diff --git a/server/conf.js b/server/conf.js index 748621d3..2c02071a 100644 --- a/server/conf.js +++ b/server/conf.js @@ -1,7 +1,5 @@ const pandocPath = process.env.PANDOC_PATH || 'pandoc'; const wkhtmltopdfPath = process.env.WKHTMLTOPDF_PATH || 'wkhtmltopdf'; -const userBucketName = process.env.USER_BUCKET_NAME || 'stackedit-users'; -const paypalUri = process.env.PAYPAL_URI || 'https://www.paypal.com/cgi-bin/webscr'; const paypalReceiverEmail = process.env.PAYPAL_RECEIVER_EMAIL; const dropboxAppKey = process.env.DROPBOX_APP_KEY; @@ -20,8 +18,6 @@ const giteaUrl = process.env.GITEA_URL; exports.values = { pandocPath, wkhtmltopdfPath, - userBucketName, - paypalUri, paypalReceiverEmail, dropboxAppKey, dropboxAppKeyFull, diff --git a/server/index.js b/server/index.js index 821f78a8..33f0cc3f 100644 --- a/server/index.js +++ b/server/index.js @@ -2,7 +2,6 @@ const compression = require('compression'); const serveStatic = require('serve-static'); const bodyParser = require('body-parser'); const path = require('path'); -const user = require('./user'); const github = require('./github'); const gitee = require('./gitee'); const gitea = require('./gitea'); @@ -30,12 +29,8 @@ module.exports = (app) => { app.get('/oauth2/giteeToken', gitee.giteeToken); app.get('/oauth2/giteaToken', gitea.giteaToken); app.get('/conf', (req, res) => res.send(conf.publicValues)); - app.get('/userInfo', user.userInfo); app.post('/pdfExport', pdf.generate); app.post('/pandocExport', pandoc.generate); - app.post('/paypalIpn', bodyParser.urlencoded({ - extended: false, - }), user.paypalIpn); app.get('/giteeClientId', (req, res) => { const giteeClientIds = conf.values.giteeClientId.split(','); // 仅一个 则直接返回 diff --git a/server/pandoc.js b/server/pandoc.js index cf93ac51..f5fca770 100644 --- a/server/pandoc.js +++ b/server/pandoc.js @@ -59,7 +59,7 @@ exports.generate = (req, res) => { const metadata = readJson(req.query.metadata); const params = []; - params.push('--pdf-engine=xelatex'); + 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'); diff --git a/server/user.js b/server/user.js deleted file mode 100644 index 335296c8..00000000 --- a/server/user.js +++ /dev/null @@ -1,116 +0,0 @@ -const request = require('request'); -const AWS = require('aws-sdk'); -const verifier = require('google-id-token-verifier'); -const conf = require('./conf'); - -const s3Client = new AWS.S3(); - -const cb = (resolve, reject) => (err, res) => { - if (err) { - reject(err); - } else { - resolve(res); - } -}; - -exports.getUser = id => new Promise((resolve, reject) => { - s3Client.getObject({ - Bucket: conf.values.userBucketName, - Key: id, - }, cb(resolve, reject)); -}) - .then( - res => JSON.parse(`${res.Body}`), - (err) => { - if (err.code !== 'NoSuchKey') { - throw err; - } - }, - ); - -exports.putUser = (id, user) => new Promise((resolve, reject) => { - s3Client.putObject({ - Bucket: conf.values.userBucketName, - Key: id, - Body: JSON.stringify(user), - }, cb(resolve, reject)); -}); - -exports.removeUser = id => new Promise((resolve, reject) => { - s3Client.deleteObject({ - Bucket: conf.values.userBucketName, - Key: id, - }, cb(resolve, reject)); -}); - -exports.getUserFromToken = idToken => new Promise((resolve, reject) => verifier - .verify(idToken, conf.values.googleClientId, cb(resolve, reject))) - .then(tokenInfo => exports.getUser(tokenInfo.sub)); - -exports.userInfo = (req, res) => exports.getUserFromToken(req.query.idToken) - .then( - user => res.send(Object.assign({ - sponsorUntil: 0, - }, user)), - err => res - .status(400) - .send(err ? err.message || err.toString() : 'invalid_token'), - ); - -exports.paypalIpn = (req, res, next) => Promise.resolve() - .then(() => { - const userId = req.body.custom; - const paypalEmail = req.body.payer_email; - const gross = parseFloat(req.body.mc_gross); - let sponsorUntil; - if (gross === 5) { - sponsorUntil = Date.now() + (3 * 31 * 24 * 60 * 60 * 1000); // 3 months - } else if (gross === 15) { - sponsorUntil = Date.now() + (366 * 24 * 60 * 60 * 1000); // 1 year - } else if (gross === 25) { - sponsorUntil = Date.now() + (2 * 366 * 24 * 60 * 60 * 1000); // 2 years - } else if (gross === 50) { - sponsorUntil = Date.now() + (5 * 366 * 24 * 60 * 60 * 1000); // 5 years - } - if ( - req.body.receiver_email !== conf.values.paypalReceiverEmail || - req.body.payment_status !== 'Completed' || - req.body.mc_currency !== 'USD' || - (req.body.txn_type !== 'web_accept' && req.body.txn_type !== 'subscr_payment') || - !userId || !sponsorUntil - ) { - // Ignoring PayPal IPN - return res.end(); - } - // Processing PayPal IPN - req.body.cmd = '_notify-validate'; - return new Promise((resolve, reject) => request.post({ - uri: conf.values.paypalUri, - form: req.body, - }, (err, response, body) => { - if (err) { - reject(err); - } else if (body !== 'VERIFIED') { - reject(new Error('PayPal IPN unverified')); - } else { - resolve(); - } - })) - .then(() => exports.putUser(userId, { - paypalEmail, - sponsorUntil, - })) - .then(() => res.end()); - }) - .catch(next); - -exports.checkSponsor = (idToken) => { - if (!conf.publicValues.allowSponsorship) { - return Promise.resolve(true); - } - if (!idToken) { - return Promise.resolve(false); - } - return exports.getUserFromToken(idToken) - .then(userInfo => userInfo && userInfo.sponsorUntil > Date.now(), () => false); -}; diff --git a/src/components/modals/PdfExportModal.vue b/src/components/modals/PdfExportModal.vue index bc6ab0b2..bfd03e9f 100644 --- a/src/components/modals/PdfExportModal.vue +++ b/src/components/modals/PdfExportModal.vue @@ -1,7 +1,7 @@