Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,6 @@ typings/
# next.js build output
.next

.DS_Store
.DS_Store

.idea
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
FROM node:8
FROM node:12

WORKDIR /tmp
RUN wget http://downloadarchive.documentfoundation.org/libreoffice/old/6.3.3.1/deb/x86_64/LibreOffice_6.3.3.1_Linux_x86-64_deb.tar.gz -O libo.tar.gz
RUN wget http://downloadarchive.documentfoundation.org/libreoffice/old/6.4.5.2/deb/x86_64/LibreOffice_6.4.5.2_Linux_x86-64_deb.tar.gz -O libo.tar.gz
RUN apt update \
&& apt install -y libxinerama1 libfontconfig1 libdbus-glib-1-2 libcairo2 libcups2 libglu1-mesa libsm6 unzip \
&& tar -zxvf libo.tar.gz
WORKDIR LibreOffice_6.3.3.1_Linux_x86-64_deb/DEBS
WORKDIR LibreOffice_6.4.5.2_Linux_x86-64_deb/DEBS
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Workdirs should not be used like this, I prefer this example:

FROM node:lts

WORKDIR /carbone-api

RUN apt update \
  && apt install -y libxinerama1 libfontconfig1 libdbus-glib-1-2 libcairo2 libcups2 libglu1-mesa libsm6 unzip

RUN wget http://downloadarchive.documentfoundation.org/libreoffice/old/6.4.5.2/deb/x86_64/LibreOffice_6.4.5.2_Linux_x86-64_deb.tar.gz -O libo.tar.gz \
    && tar -zxvf libo.tar.gz

RUN cd LibreOffice_6.4.5.2_Linux_x86-64_deb/DEBS && dpkg -i *.deb

COPY . /carbone-api

RUN yarn install --production

CMD node index

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I could agree just : what's the point but adding a slow COPY step ?

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

index.js has to be copied into container right?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry misread your proposal. Now I can say I disagree 😛

From dockerfile_best-practices :

For clarity and reliability, you should always use absolute paths for your WORKDIR.
Also, you should use WORKDIR instead of proliferating instructions like RUN cd … && do-something, which are hard to read, troubleshoot, and maintain.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok :DDD Agree anyway we can use that node:lts and rest 😄
Thank you!

RUN dpkg -i *.deb

RUN mkdir /tmp-reports
COPY . /carbone-api
WORKDIR /carbone-api
RUN yarn
RUN yarn install --production
CMD node index
18 changes: 11 additions & 7 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
const path = require(`path`);
const fs = require(`fs-extra`);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can replace fs extra and remove extra dependency in flavor of:

const fs = require(`fs`).promises;

const _ = require(`lodash`);
const util = require(`util`);
const carbone = require(`carbone`);
const telejson = require(`telejson`);
Expand All @@ -15,38 +14,43 @@ app.use(bodyParser.urlencoded({ extended: true }));

const render = util.promisify(carbone.render);

// Flagging default formatters to remove custom ones later
_.forEach(carbone.formatters, formatter => formatter.$isDefault = true);
const defaultFormatters = {...carbone.formatters};

app.get('/', (req, res) => {
res.sendFile(path.resolve(`./test.html`));
});

app.post('/render', upload.single(`template`), async (req, res) => {
const template = req.file;
if(!template) {
return res.status(400).send(`Template file required`);
}

const originalNameWOExt = template.originalname.split(`.`).slice(0, -1).join(`.`);
const originalFormat = template.originalname.split(`.`).reverse()[0];
let data = req.body.data;
let options = {};
let formatters = {};
try {
options = JSON.parse(req.body.options);
} catch (e) {}
} catch (e) {
return res.status(400).send(`Can't parse options JSON: ${e}`);
}
options.convertTo = options.convertTo || originalFormat;
options.outputName = options.outputName || `${originalNameWOExt}.${options.convertTo}`;
if (typeof data !== `object` || data === null) {
try {
data = JSON.parse(req.body.data);
} catch (e) {
data = {};
return res.status(400).send(`Can't parse data JSON: ${e}`);
}
}
try {
formatters = telejson.parse(req.body.formatters);
} catch (e) {}

// Removing previous custom formatters before adding new ones
carbone.formatters = _.filter(carbone.formatters, formatter => formatter.$isDefault === true);
carbone.formatters = {...defaultFormatters};

carbone.addFormatters(formatters);

Expand All @@ -56,7 +60,7 @@ app.post('/render', upload.single(`template`), async (req, res) => {
report = await render(template.path, data, options);
} catch (e) {
console.log(e);
return res.status(500).send(`Internal server error`);
return res.status(500).send(`Internal server error: ${e}`);
}

fs.remove(template.path);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is related to native fs dependency

await fs.unlink(template.path);

Expand Down
17 changes: 8 additions & 9 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
{
"name": "carbone-docker",
"version": "0.1.0",
"version": "0.2.0",
"description": "All what you need to build a standalone carbone.io Docker image",
"main": "index.js",
"author": "Florian Bezagu <florian@bezagu.com>",
"license": "MIT",
"dependencies": {
"body-parser": "^1.18.3",
"carbone": "^1.2.0",
"express": "^4.16.4",
"fs-extra": "^7.0.1",
"lodash": "^4.17.15",
"multer": "^1.4.1",
"telejson": "^3.0.3"
"body-parser": "^1.19.0",
"carbone": "^2.0.0",
"express": "^4.17.1",
"fs-extra": "^9.0.1",
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can remove this package

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why ? It's used in index.js

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry didn't see the other comment about the native promises

Copy link

@VeeeneX VeeeneX Jul 31, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes and can be replaced with native build in const fs = require('fs').promises; so we remove extra dependency and remove few kb 😄

"multer": "^1.4.2",
"telejson": "^4.0.0"
},
"devDependencies": {
"forever": "^1.0.0"
"forever": "^3.0.0"
}
}
62 changes: 43 additions & 19 deletions test.html
Original file line number Diff line number Diff line change
Expand Up @@ -3,33 +3,57 @@
<head>
<meta charset="UTF-8">
<title>Carbone Docker wrapper tester</title>
<style>
label { display: block; margin: 1em 0 0 0; max-width: 600px;}
label input { width: 100%; }
textarea { width: 100%; height: 200px; }
input:invalid, textarea:invalid { box-shadow: 0 0 0 2px #f88; }
button { margin-top: 1em; }
form:invalid button { opacity: 0.5; }
pre { margin: 0; font-size: 95%; color: grey; }
</style>
</head>
<body>
<form onsubmit="formatData()" action="/render" method="post" target="_blank" enctype="multipart/form-data">

<input type="file" name="template" id="template">
<input type="hidden" name="data" id="data">
<input type="hidden" name="format" value="pdf">
<input type="hidden" name="outputName" value="test.pdf">

<textarea name="_data" id="_data" cols="30" rows="10">{"firstname":"John"}</textarea>

<input type="submit" value="Générer">

<form action="/render" method="post" target="_blank" enctype="multipart/form-data">
<label>
Template:
<input type="file" name="template" id="template" required>
</label>
<label>
Data:
<textarea name="data" id="data">{
"firstname":"John"
}</textarea>
</label>
<pre>Datas to be inserted in the template represented by the {d.****}</pre>
<label>
Options:
<textarea name="options" id="options">{}</textarea>
</label>
<pre>"complement" : {} data which is represented by the {c.****}
"convertTo" : "pdf" || { "formatName", "formatOptions"} Convert the document in the format specified
"extension" : "odt" || undefined Specify the template extension
"variableStr" : "" pre-declared variables,
"lang" : overwrite default lang. Ex. "fr"
"translations" : overwrite all loaded translations {fr: {}, en: {}, es: {}}
"enum" : { ORDER_STATUS : ["open", "close", "sent"]
"currencySource" : currency of data, "EUR"
"currencyTarget" : default target currency when the formatter convCurr is used without target
"currencyRates" : rates, based on EUR { EUR : 1, USD : 1.14 }</pre>
<button type="submit">Generate</button>
</form>
<script>
function formatData() {
const _data = document.getElementById(`_data`).value;
let data = {};

function checkData(event) {
let element = event.target;
try {
data = JSON.parse(_data);
const data = JSON.parse(element.value);
element.setCustomValidity("");
} catch (e) {
console.error(`Cannot parse data : ${e}`);
element.setCustomValidity(e.toString());
}

document.getElementById(`data`).value = JSON.stringify(data);
}
document.getElementById('data').addEventListener('input', checkData);
document.getElementById('options').addEventListener('input', checkData);
</script>
</body>
</html>
Loading