Commit 369051e9 authored by Alexandros Georgantas's avatar Alexandros Georgantas
Browse files

Merge branch 'support-export-scripts' into 'master'

Support export scripts

See merge request !1
parents 106e45d8 0622dd8a
......@@ -11,4 +11,6 @@ logs/*
tmp/
temp/
uploads/*
.env.*
\ No newline at end of file
.env.*
server/static/*
!config/static/.gitkeep
\ No newline at end of file
......@@ -2,6 +2,13 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
## [1.2.0](https://gitlab.coko.foundation/cokoapps/pagedjs/compare/v1.1.0...v1.2.0) (2021-05-31)
### Features
* **service:** support of export scripts added ([80ddb93](https://gitlab.coko.foundation/cokoapps/pagedjs/commit/80ddb9355ffb633aa1193f38482bcff9385d975e))
## 1.1.0 (2021-04-15)
......
......@@ -14,6 +14,7 @@ services:
- SERVER_PORT=${SERVER_PORT:-3000}
- SERVER_HOST=${SERVER_HOST:-server}
- SERVER_PROTOCOL=${SERVER_PROTOCOL:-http}
- EXTERNAL_URL=${EXTERNAL_URL:-null}
- POSTGRES_USER=${POSTGRES_USER:-pagedjs_user_dev}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-secretpassword}
- POSTGRES_HOST=db
......@@ -40,6 +41,8 @@ services:
'config',
'--ext',
'js,graphql',
'--ignore',
'/static/*',
]
volumes:
- ./server:/home/node/pagedjs/server
......@@ -47,12 +50,11 @@ services:
db:
image: postgres:12-alpine
ports:
- ${POSTGRES_PORT:-5432}:5432
# ports:
# - ${POSTGRES_PORT:-5432}:5432
environment:
- POSTGRES_USER
- POSTGRES_DB
- POSTGRES_PASSWORD
volumes:
- ./scripts/init-pgboss.sql:/docker-entrypoint-initdb.d/init-pgboss.sql
{
"name": "@coko/pagedjs",
"version": "1.1.0",
"version": "1.2.0",
"description": "Service that converts an HTML file into pdf, and pagedjs previewer",
"main": "server/index.js",
"scripts": {
......
......@@ -19,13 +19,15 @@ const storage = multer.diskStorage({
})
const fileFilter = (req, file, cb) => {
// Accept EPUBs only
// Accept zip only
if (!file.originalname.match(/\.(zip)$/)) {
req.fileValidationError = 'Only zip files are allowed!'
return cb(null, false)
}
return cb(null, true)
}
const uploadHandler = multer({ storage, fileFilter }).single('zip')
const removeFrameGuard = (req, res, next) => {
......@@ -48,6 +50,7 @@ const readFile = location =>
return resolve(data)
})
})
const downloadImage = (url, imagePath) =>
axios({
url,
......@@ -61,6 +64,7 @@ const downloadImage = (url, imagePath) =>
.on('error', e => reject(e))
}),
)
const objectKeyExtractor = url => {
const stage1 = url.split('?')
const stage2 = stage1[0].split('/')
......@@ -68,6 +72,7 @@ const objectKeyExtractor = url => {
return objectKey
}
const imageGatherer = book => {
const images = []
......@@ -98,6 +103,49 @@ const fixImagePaths = book => {
return $.html()
}
const indexHTMLPreparation = async (assetsLocation, pdf = false) => {
try {
let stylesheet
const scriptsToInject = []
fs.readdirSync(assetsLocation).forEach(file => {
const deconstruct = file.split('.')
if (deconstruct[1] === 'css') {
stylesheet = `./${file}`
}
if (deconstruct[1] === 'js') {
scriptsToInject.push(`./${file}`)
}
})
const indexContent = await readFile(`${assetsLocation}/index.html`)
const $ = cheerio.load(indexContent)
$('head').append(
`<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/KaTeX/0.13.0/katex.min.css" />`,
)
$('head').append(
`<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/default.min.css" />`,
)
$('head').append(`<link rel="stylesheet" href="${stylesheet}" />`)
if (!pdf) {
$('head').append(
`<script src="https://unpkg.com/pagedjs/dist/paged.polyfill.js"/>`,
)
for (let i = 0; i < scriptsToInject.length; i += 1) {
$('head').append(`<script src="${scriptsToInject[i]}"/>`)
}
}
await fs.remove(`${assetsLocation}/index.html`)
await writeFile(`${assetsLocation}/index.html`, $.html())
} catch (e) {
throw new Error(e)
}
}
module.exports = {
uploadHandler,
removeFrameGuard,
......@@ -106,4 +154,5 @@ module.exports = {
imageGatherer,
fixImagePaths,
writeFile,
indexHTMLPreparation,
}
......@@ -7,6 +7,7 @@ const crypto = require('crypto')
const config = require('config')
const { exec } = require('child_process')
const {
uploadHandler,
removeFrameGuard,
......@@ -15,6 +16,7 @@ const {
imageGatherer,
fixImagePaths,
writeFile,
indexHTMLPreparation,
} = require('./helpers')
const conversionHandler = async (req, res) => {
......@@ -22,9 +24,11 @@ const conversionHandler = async (req, res) => {
if (req.fileValidationError) {
return res.status(400).json({ msg: req.fileValidationError })
}
if (!req.file) {
return res.status(400).json({ msg: 'zip file is not included' })
}
const { path: filePath } = req.file
const id = crypto.randomBytes(16).toString('hex')
const outputFile = `temp/${id}/output.pdf`
......@@ -36,11 +40,14 @@ const conversionHandler = async (req, res) => {
if (error) {
return reject(error)
}
return resolve(stdout || stderr)
})
})
logger.info(`removing ${filePath}`)
await fs.remove(filePath)
logger.info(`creating pdf`)
const bookContent = await readFile(`temp/${id}/index.html`)
const bookImages = imageGatherer(bookContent)
......@@ -54,25 +61,51 @@ const conversionHandler = async (req, res) => {
const fixedContent = fixImagePaths(bookContent)
await fs.remove(`temp/${id}/index.html`)
await writeFile(`temp/${id}/index.html`, fixedContent)
await indexHTMLPreparation(`temp/${id}`, true)
let additionalScriptsParam = ''
fs.readdirSync(`temp/${id}`).forEach(file => {
const deconstruct = file.split('.')
if (deconstruct[1] === 'js') {
additionalScriptsParam += `--additional-script temp/${id}/${file} `
}
})
await new Promise((resolve, reject) => {
exec(
`/home/node/pagedjs/node_modules/.bin/pagedjs-cli -i temp/${id}/index.html -o ${outputFile}`,
(error, stdout, stderr) => {
if (error) {
return reject(error)
}
return resolve(stdout || stderr)
},
)
if (additionalScriptsParam.length > 0) {
exec(
`/home/node/pagedjs/node_modules/.bin/pagedjs-cli -i temp/${id}/index.html ${additionalScriptsParam.trim()} -o ${outputFile}`,
(error, stdout, stderr) => {
if (error) {
return reject(error)
}
return resolve(stdout || stderr)
},
)
} else {
exec(
`/home/node/pagedjs/node_modules/.bin/pagedjs-cli -i temp/${id}/index.html -o ${outputFile}`,
(error, stdout, stderr) => {
if (error) {
return reject(error)
}
return resolve(stdout || stderr)
},
)
}
})
if (!fs.existsSync(outputFile)) {
return res.status(500).json({ msg: 'Error, file was not created' })
}
res.writeHead(200, {
'Content-Type': 'application/octet-stream',
'Content-Disposition': `attachment; filename=output.pdf`,
})
res.on('finish', async () => {
logger.info(`removing folder temp/${id}`)
await fs.remove(`temp/${id}`)
......@@ -88,18 +121,22 @@ const previewerLinkHandler = async (req, res) => {
if (req.fileValidationError) {
return res.status(400).json({ msg: req.fileValidationError })
}
if (!req.file) {
return res.status(400).json({ msg: 'zip file is not included' })
}
const { path: filePath } = req.file
const id = new Date().getTime() // this is the current timestamp, this is due to cron clean up purposes
const { protocol, host, port, externalURL } = config.get('pubsweet-server')
let serverUrl
if (externalURL) {
serverUrl = externalURL
} else {
serverUrl = `${protocol}://${host}${port ? `:${port}` : ''}`
}
const out = `${path.join(__dirname, '..', 'static', `${id}`)}`
fs.ensureDir(out)
await new Promise((resolve, reject) => {
......@@ -109,22 +146,19 @@ const previewerLinkHandler = async (req, res) => {
if (error) {
return reject(error)
}
return resolve(stdout || stderr)
},
)
})
let cssFile
fs.readdirSync(`${path.join(__dirname, '..', 'static', `${id}`)}`).forEach(
file => {
const deconstruct = file.split('.')
if (deconstruct[1] === 'css') {
cssFile = file
}
},
// generation of index.html
await indexHTMLPreparation(
`${path.join(__dirname, '..', 'static', `${id}`)}`,
)
res.status(200).json({
link: `${serverUrl}/previewer/index.html?url=${id}/index.html&stylesheet=${id}/${cssFile}`,
link: `${serverUrl}/previewer/${id}/index.html`,
})
} catch (e) {
throw new Error(e)
......
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>Pagedjs Viewer</title>
<meta content="width=device-width, initial-scale=1" name="viewport">
<script src="https://unpkg.com/pagedjs/dist/paged.polyfill.js"></script>
<script>
let ready = new Promise(function(resolve, reject){
if (document.readyState === "interactive" || document.readyState === "complete") {
resolve(document.readyState);
return;
}
document.onreadystatechange = function ($) {
if (document.readyState === "interactive") {
resolve(document.readyState);
}
}
});
ready.then(async function () {
// Create a new Previewer
let previewer = new Paged.Previewer();
// Get the URL to load
let params = URLSearchParams && new URLSearchParams(document.location.search.substring(1));
let url = params && params.get("url") && decodeURIComponent(params.get("url"));
if (!url) {
console.error("No 'url' parameter given.");
return;
}
// Fetch and Parse Contents
let html = await fetch(url)
.then(response => response.text())
.then(str => (new DOMParser()).parseFromString(str, "text/html"))
// Gather all stylesheets from html document
let hrefs = previewer.removeStyles(html);
// Add a stylesheet url in params
let stylesheet = params && params.get("stylesheet") && decodeURIComponent(params.get("stylesheet"));
if (stylesheet) {
hrefs.push(stylesheet);
}
// Push all body elements to a document fragment
let content = html.querySelectorAll('body > *');
let fragment = document.createDocumentFragment();
for (let i = 0; i < content.length; i++) {
fragment.appendChild(content[i]);
}
// Run the Paged Preview
let done = await previewer.preview(fragment, hrefs, document.body);
});
</script>
<style>
@media screen {
body {
background-color: whitesmoke;
}
.pagedjs_page {
background-color: #fdfdfd;
margin: 10px auto;
flex: none;
box-shadow: 0 0 0 1px rgba(0, 0,0,0.2);
}
}
</style>
</head>
<body>
</body>
</html>
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