pad.libre-service.eu-etherpad/src/node/handler/ExportHandler.js
muxator 6d36bb2c53 node8: we can safely use os.tmpdir()
Since we are requiring node >= 8, we can safely use native functionalities.
2019-02-19 22:01:12 +01:00

168 lines
5.4 KiB
JavaScript

/**
* Handles the export requests
*/
/*
* 2011 Peter 'Pita' Martischka (Primary Technology Ltd)
* 2014 John McLear (Etherpad Foundation / McLear Ltd)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS-IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
var ERR = require("async-stacktrace");
var exporthtml = require("../utils/ExportHtml");
var exporttxt = require("../utils/ExportTxt");
var exportEtherpad = require("../utils/ExportEtherpad");
var async = require("async");
var fs = require("fs");
var settings = require('../utils/Settings');
var os = require('os');
var hooks = require("ep_etherpad-lite/static/js/pluginfw/hooks");
var TidyHtml = require('../utils/TidyHtml');
var convertor = null;
// load abiword only if it is enabled
if (settings.abiword != null) {
convertor = require("../utils/Abiword");
}
// Use LibreOffice if an executable has been defined in the settings
if (settings.soffice != null) {
convertor = require("../utils/LibreOffice");
}
const tempDirectory = os.tmpdir();
/**
* do a requested export
*/
exports.doExport = function(req, res, padId, type)
{
var fileName = padId;
// allow fileName to be overwritten by a hook, the type type is kept static for security reasons
hooks.aCallFirst("exportFileName", padId,
function(err, hookFileName){
// if fileName is set then set it to the padId, note that fileName is returned as an array.
if (hookFileName.length) {
fileName = hookFileName;
}
// tell the browser that this is a downloadable file
res.attachment(fileName + "." + type);
// if this is a plain text export, we can do this directly
// We have to over engineer this because tabs are stored as attributes and not plain text
if (type == "etherpad") {
exportEtherpad.getPadRaw(padId, function(err, pad) {
if (!err) {
res.send(pad);
// return;
}
});
} else if (type == "txt") {
exporttxt.getPadTXTDocument(padId, req.params.rev, function(err, txt) {
if (!err) {
res.send(txt);
}
});
} else {
var html;
var randNum;
var srcFile, destFile;
async.series([
// render the html document
function(callback) {
exporthtml.getPadHTMLDocument(padId, req.params.rev, function(err, _html) {
if (ERR(err, callback)) return;
html = _html;
callback();
});
},
// decide what to do with the html export
function(callback) {
// if this is a html export, we can send this from here directly
if (type == "html") {
// do any final changes the plugin might want to make
hooks.aCallFirst("exportHTMLSend", html, function(err, newHTML) {
if (newHTML.length) html = newHTML;
res.send(html);
callback("stop");
});
} else {
// write the html export to a file
randNum = Math.floor(Math.random()*0xFFFFFFFF);
srcFile = tempDirectory + "/etherpad_export_" + randNum + ".html";
fs.writeFile(srcFile, html, callback);
}
},
// Tidy up the exported HTML
function(callback) {
// ensure html can be collected by the garbage collector
html = null;
TidyHtml.tidy(srcFile, callback);
},
// send the convert job to the convertor (abiword, libreoffice, ..)
function(callback) {
destFile = tempDirectory + "/etherpad_export_" + randNum + "." + type;
// Allow plugins to overwrite the convert in export process
hooks.aCallAll("exportConvert", { srcFile: srcFile, destFile: destFile, req: req, res: res }, function(err, result) {
if (!err && result.length > 0) {
// console.log("export handled by plugin", destFile);
handledByPlugin = true;
callback();
} else {
convertor.convertFile(srcFile, destFile, type, callback);
}
});
},
// send the file
function(callback) {
res.sendFile(destFile, null, callback);
},
// clean up temporary files
function(callback) {
async.parallel([
function(callback) {
fs.unlink(srcFile, callback);
},
function(callback) {
// 100ms delay to accommodate for slow windows fs
if (os.type().indexOf("Windows") > -1) {
setTimeout(function() {
fs.unlink(destFile, callback);
}, 100);
} else {
fs.unlink(destFile, callback);
}
}
], callback);
}
],
function(err) {
if (err && err != "stop") ERR(err);
})
}
}
);
};