express.js multiple file upload callback - javascript

I'm new to node.js & express.js, so... I want to upload multiple files, and later work with them.
But i need to send a response (ok or error status) after all my files have been saved on disk, or if one failed - then send an error callback.
Now I have such code:
var express = require('express');
var router = express.Router();
var multipart = require('connect-multiparty');
var multipartMiddleware = multipart();
var fs = require('fs');
router.post('/upload', multipartMiddleware, function(req, res) {
var reqBody = req.body;
var reqFiles = req.files;
saveFile(reqFiles, 'main.xlsx', function(err) {
if (err) {
res.status(404).send('');
return;
}
res.send('Multi-File File uploaded');
}
});
function saveFile(file, name, callback) {
fs.writeFile('./uploads/' + name, file, callback);
}
but how can i change my code to parse this:
router.post('/upload', multipartMiddleware, function(req, res) {
var reqBody = req.body;
var reqFiles = req.files;
saveFile(reqFiles['files'][0], 'main.xlsx', function(err) {
if (err) {
res.status(404).send('');
return;
}
}
saveFile(reqFiles['files'][1], 'second.xlsx', function(err) {
if (err) {
res.status(404).send('');
return;
}
}
res.send(''); // only after first two fileUploaders have finished
});
function saveFile(file, name, callback) {
fs.writeFile('./uploads/' + name, file, callback);
}

You need to iterate through req.files. You can use async library.
For example:
async.each(req.files, function(file, callback) {
saveFile(file, file.name, callback)
}, function(err) {
res.send('')
})

The module recommends not using this. Use the multiparty module directly.
When you have the list of files they will also have file names. you can loop through those and save each file asynchronously. Then respond. Take a peek here

Related

Passing a pdf file to a function when it requires a path or link

I am working on a web application for an online library. I want to extract metadata from the PDF's that will be uploaded and for that I am using the nodejs library pdf.js-extract and multer-gridfs-storage for the upload. The problem is that I am receiving a PDF file (req.file) and the function requires a path or link to the PDF file and therefore shows the error
"TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type object"
I would like to know if there is a way to pass a file as a link, save the file locally temporarily or find another library that fits my needs.
This is my current code.
const PDFExtract = require('pdf.js-extract').PDFExtract;
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
pdfExtract.extract(req.file, options, (err, data) => {
if (err){
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
});
(Edit for clarification) I am using multer with gridFS to upload a file to mongoose.
const multer = require('multer');
const GridFsStorage = require('multer-gridfs-storage');
// Create storage engine
const storage = new GridFsStorage({
url: mongoURI,
file: (req, file) => {
return new Promise((resolve, reject) => {
crypto.randomBytes(16, (err, buf) => {
if (err) {
return reject(err);
}
const filename = buf.toString('hex') + path.extname(file.originalname);
const fileInfo = {
filename: filename,
bucketName: 'uploads'
};
resolve(fileInfo);
});
});
}
});
const upload = multer({ storage });
Solution inspired by Oliver Nybo
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
var readableStream = gfs.createReadStream({ filename : req.file.filename });
var buff;
var bufferArray = [];
readableStream.on('data',function(chunk){
bufferArray.push(chunk);
});
readableStream.on('end',function(){
var buffer = Buffer.concat(bufferArray);
buff=buffer;
pdfExtract.extractBuffer(buff, options, (err, data) => {
if (err) {
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
})
});
According to multer's api documentation, you can use req.file.path to get the full path of the uploaded file.
const PDFExtract = require('pdf.js-extract').PDFExtract;
app.post('/upload', upload.single('file'), (req, res) => {
const pdfExtract = new PDFExtract();
const options = {};
pdfExtract.extract(req.file.path, options, (err, data) => {
if (err){
res.status(404).send({ message: err });
}
res.status(200).send({ message: data });
});
});
Edit: I just read the multer options and there is an option called preservePath.
preservePath - Keep the full path of files instead of just the base name
Edit 2: I think you need to extract the file from the database with gridfs-stream, then convert it into a buffer (like in this thread), and then use PDFExtract's extractBuffer function.

My code is deleting the file and removing it from the database records, however, I get an error in the console

I'm trying to add a delete image functionality to my website and even though my code deletes the file from the images folder and removes the image record from my database, I get an error in the console and I don't get redirected to my home page. The error is :
DeprecationWarning: Calling an asynchronous function without callback is deprecated.
And my code:
var express = require('express');
var router = express.Router();
var db = require('../helpers/db');
var fs = require('fs');
router.post('/', function(req, res, next) {
if (req.method == 'POST') {
var id = req.body.id;
var path = req.body.path;
var author = req.body.author;
var completePath = 'public/images/uploads/' + path;
db.query('DELETE FROM image WHERE id = ?', [id], function(error, results, fields) {
if (error) throw error;
if (fs.unlink(completePath)) {
console.log('Successful');
res.redirect('/');
} else {
console.log('Unsuccessful');
}
})
}
});
module.exports = router;
My console logs Unsuccessful and it doesn't redirect me to res.redirect('/');
fs.unlink is an asynchronous function that takes a callback on success. You should use it like this:
db.query('DELETE FROM image WHERE id = ?', [id], function(error, results, fields) {
if (error) throw error;
fs.unlink(completePath,function(err) {
if(err) {
console.log('unsuccessful');
return;
}
console.log('successful');
res.redirect('/');
});
})

How to get filename from multiple directories using fs in nodejs?

I want to get file information from all the directories once i have that i have further implementation of code, but i am stuck here and getting error that is pasted in question any idea what is implemented wrong in below code ?
cron.js
var fs = require('fs');
var path = require('path');
var async = require('async');
var directories = ['./logs/dit', './logs/st','./logs/uat']
function cronJob() {
directories.forEach(function(dir){
var files = fs.readdir(dir);
async.eachSeries(files, function(file,callback) {
var filePath = path.join(dirPath, file);
var fileInfo = {};
fs.stat(filePath, function(err, stats) {
if (err) {
console.info("File doesn't");
} else {
fileInfo.fileDate = stats.birthtime;
fileInfo.filename = file;
console.log(fileInfo);
// compareDates(fileInfo,filePath);
// callback();
}
});
});
})
}
cronJob();
Error
s\Ulog-0\ulog\app\serverfiles\logs\dit'
at Error (native)
at Object.fs.readdirSync (fs.js:808:18)
at C:\Users\WebstormProjects\Ulog-0\ulog\app\serverfiles\cronJob
20
at Array.forEach (native)
at cronJob (C:\Users\WebstormProjects\Ulog-0\ulog\app\serverfile
obs.js:7:13)
at Object.<anonymous> (C:\Users\\WebstormProjects\Ulog-0\ulog\app
readdir is asynchronous so you need to wait for its callback to execute further operations.
It's hard to know what exactly is the problem, so I have included log statements.
Edit
var fs = require('fs');
var path = require('path');
var async = require('async');
var directories = ['/../../logs/dit', '/../../logs/st', '/../../logs/uat'];
// loop through each directory
async.eachSeries(directories, function (dir, cb1) {
var dir = __dirname + dir;
console.log('reading', dir);
// get files for the directory
fs.readdir(dir, function (err, files) {
if (err) return cb1(err);
// loop through each file
async.eachSeries(files, function (file, cb2) {
var filePath = path.resolve(dir + '/' + file);
// get info for the file
fs.stat(filePath, function (err, stats) {
if (err) return cb2(err);
var fileInfo = { fileDate: stats.birthtime, filename: file };
console.log('fileInfo', fileInfo);
compareDates(fileInfo, filePath);
cb2(null, fileInfo);
});
}, cb1);
});
}, function (err, fileInfos) {
if (err) {
console.info('error', err);
return;
}
// when you're done reading all the files, do something...
});

Promisify an upload with multer

I have some troubles using multer and promises (bluebird).
I try to upload a pdf file in a folder then extract the text inside this pdf with the plugin (textract)
Both of the functions I created works, but I have some trouble in the execution and the promisification of the upload function. here's my code :
pdf-rest.js :
var bodyParser = require('body-parser');
var request = require('request');
var jsonParser = bodyParser.json();
var fs = require('fs');
var Promise = require('bluebird');
var multer = require('multer');
var textract = require('textract');
module.exports = function(app) {
var destination = "uploads";
var filename = "" + Date.now() + ".pdf";
var filePath = "C:\\wamp64\\www\\ebook-stage\\backend\\rest\\uploads\\" + filename;
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, destination);
},
filename: function (req, file, cb) {
cb(null, filename);
}
});
app.post('/rest/create_pdf', function (req, res) {
var upload = multer({storage: storage}).single('file');
function uploadFile() {
var uploadFilePromise = new Promise(function (resolve, reject) {
upload(req, res, function (err) {
if (err) {
reject(err);
res.end('error uploading file')
}
else {
res.end('file uploaded');
console.log('fileupload')
}
});
resolve(upload);
});
console.log(uploadFilePromise);
return uploadFilePromise;
}
function textractPdf(path) {
textract.fromFileWithPath(path, function (error, text) {
console.log('textract');
if (text) {
console.log(text);
return text;
}
else {
console.log(error);
return error;
}
});
}
uploadFile().then(textractPdf(filePath));
});
server.js :
var express = require('express');
var app = express();
require('./pdf-rest.js')(app);
app.listen(8080);
I use a button to execute this script in a HTML page, the upload of the pdf in the folder work the first time I click on the button but the textract doesn't.
I know I do something wrong, the execution of the function textractPdf(Path) is done first. I think I didn't promisify correctly my upload function.

Cannot read "path" property of undefined Nodejs

Here is my jade file
form(method="post", action="/upload", enctype="multipart/form-data")
input(type="file", name="logName")
button(type="submit") Upload
And my index.js file
/* GET home page. */
router.get('/', function (req, res) {
res.render('fileUpload', { title: 'Building a Log File Viewer' });
});
var formidable = require('formidable'),
fs = require('fs'),
util = require('util');
/* POST the file upload */
router.post('/upload', function (req, res) {
var form = new formidable.IncomingForm();
form.parse(req, function (err, fields, files) {
fs.readFileSync(files.upload.path, function (err, data) {
if (err) throw err;
console.log("Test");
})
});
});
I keep getting the TypeError property that property "path" is undefined; however, when I sumbit the code under a http.createServer, instead of a router.post, it works fine. I have also tried the asychronous file reading, and it gave me the same error. Any ideas?
please try
fs.readFileSync(files.logName.path, function (err, data){ ... });
instead of
fs.readFileSync(files.upload.path, function (err, data) { ... });

Categories