Nodejs Immediately delete generated file - node.js

I'm trying to delete a pdf immediately after is has been generated in node.js. The generated pdf is sent as an email attachment, uploaded to dropbox and then deleted from the local file system. But as i try to delete it , it does not delete it and it does not send the email either. The pdf is created using html-pdf. Here is my code :
if (result) {
var filename = user.number+ ".pdf";
var path = './public/files/'+filename ;
var options = { filename: path, format: 'Legal', orientation: 'portrait', directory: './public/files/',type: "pdf" };
html = result;
pdf.create(html, options).toFile(function(err, res) {
if (err) return console.log(err);
console.log(res);
});
var dbx = new dropbox({ accessToken: mytoken });
fs.readFile( path,function (err, contents) {
if (err) {
console.log('Error: ', err);
}
dbx.filesUpload({ path: "/"+filename ,contents: contents })
.then(function (response) {
console.log("done")
console.log(response);
})
.catch(function (err) {
console.log(err);
});
});
var mailOptions = {
from: 'xyz', // sender address
to: user.email, // list of receivers
subject: 'Confirmation received', // Subject line
attachments : [{
filename: filename,
path : path
}]
};
transporter.sendMail(mailOptions, (error, info) => {
if (error) {
return console.log(error);
}
console.log('Message %s sent: %s', info.messageId, info.response);
});
fs.unlinkSync(path); // even tried fs.unlink , does not delete file
// fs.unlinkSync(someother file); this one works
}
So when i do fs.unlink' orfs.unlinkSync`, if the file is already there it works but the files that is generated as in path doesn't get deleted.

NodeJs is asynchronous so you need to handle every blocks properly. your code shows that some times before completely creating the PDF itself the file upload to dropbox will start if the PDF creation is slow.
And deletion of the PDF file happens before the mail sending, so you get some err but you did not logged you error in fs.unlink(). Divide you code as blocks and use callback for better performance and flow.
Your code should be like this to work properly..
if (result) {
var filename = user.number+ ".pdf";
var path = './public/files/'+filename ;
var options = { filename: path, format: 'Legal', orientation: 'portrait', directory: './public/files/',type: "pdf" };
html = result;
//Generate the PDF first
pdf.create(html, options).toFile(function(err, res) {
if (err){
return console.log(err);
} else {
//If success then read the PDF file and then upload to dropbox
var dbx = new dropbox({ accessToken: mytoken });
fs.readFile( path,function (err, contents) {
if (err) {
console.log('Error: ', err);
} else {
dbx.filesUpload({path: "/"+filename ,contents: contents }).then(function (response) {
// Once the file upload is done then send mail
console.log("done")
sendMail('xyz', user.email, 'Confirmation received', filename, path, function(err, result){
// once mail is successful then delete the file finally
fs.unlinkSync(path); //if you need you can use callback with this for confirmation of deletion
});
}).catch(function(err) {
console.log(err);
});
}
});
}
});
function sendMail(sender, receiver, subject, filename, path, callback){
var mailOptions = {
from: sender, // sender address
to: receiver, // list of receivers
subject: subject, // Subject line
attachments : [{
filename: filename,
path : path
}]
};
transporter.sendMail(mailOptions, (err, info) => {
if (error) {
callback(err, null);
} else {
console.log('Message %s sent: %s', info.messageId, info.response);
callback(null, info)
}
});
}
}

Related

email attachment in Angular 7 and Node.js

I have a contact form that send email with attachment using Angular 7 and node.js,
it works fine when you send email with attachment but it doesnt work without attachment
this is contact form
Typescript
onSubmitClick() {
const formData: FormData = new FormData();
this.fileToUpload && formData.append("file", this.fileToUpload, this.fileToUpload.name);
for (const key of Object.keys(this.form.value)) {
const value = this.form.value[key];
formData.append(key, value);
}
this.onSubmitClick; {
this.form.reset();
}
this.httpClient.post("http://localhost:3000/api/v1/contact/", formData)
.subscribe((response: any) => console.log(response));
}
handleFileInput(files: FileList) {
this.fileToUpload = files.item(0);
}
}
Node.js file
const mailOptions = {
from: 'xxxxxxx#xxx.com',
to: 'xxxxxxx#xxx.com',
subject: 'Segnalazione Portale',
//text: req.body.Nome,
html:'<b>Nome: </b>'+req.body.Nome+
'<br><b>Cognome: </b>'+req.body.Cognome
+'<br><b>Codice Fiscale: </b>'+req.body.CF
+'<br><b>Email: </b>'+req.body.Email
+'<br><b>Messagio: </b>'+req.body.message,
attachments: [
{
filename: file.name,
path: "tmp/" + file.name
}
]
};
transporter.sendMail(mailOptions, function (err, info) {
if (err) {
console.log(err);
return res.json({ err });
} else {
console.log(info);
return res.json({ info });
}
});
});
}
});
module.exports = router;
any idea why?
thanks in advance!

Using Jade mail template in Nodemailer

I have a contactform created with Nodemailer. Now I want a Jade tempate mail being send whenever the customer submits the contactform.
I already got it working and the mail template is already being send, but somehow the content of the Jade file is being presented in the 'subject' header of the mail. And everyting is presented with all the HTML tags. So, somewhere it goes wrong.
This is my Nodemailer code:
router.post('/contact/send', function(req, res) {
var transporter = nodeMailer.createTransport({
service : 'Gmail',
auth : {
user: process.env.GMAIL_USER,
pass: process.env.GMAIL_PASS
}
});
var mailOptions = {
from: req.body.name + ' <' + req.body.email + '>',
to: 'xxxxx#gmail.com',
subject:'Website verzoek',
text:'Er is een website verzoek binnengekomen van '+ req.body.name+' Email: '+req.body.email+'Soort website: '+req.body.website+'Message: '+req.body.message,
html:'<p>Websiteverzoek van: </p><ul><li>Naam: '+req.body.name+' </li><li>Email: '+req.body.email+' </li><li>Soort website: '+req.body.website+' </li><li>Message: '+req.body.message+' </li></ul>'
};
transporter.sendMail(mailOptions, function (err, info) {
if(err) {
console.log(err);
res.redirect('/#contact');
} else {
console.log('Message send');
res.redirect('/#contact');
}
});
var toAddress = req.body.email;
var sendMail = function(toAddress, subject, content, next) {
var mailTemplate = {
from: 'xxxxxx#gmail.com',
to: toAddress,
subject: subject,
html: content
};
transporter.sendMail(mailTemplate, next);
};
var template = process.cwd() + '/views/mails/mail.jade';
fs.readFile(template, 'utf8', function(err, file) {
if (err) {
console.log('Error');
} else {
var compiledTmpl = jade.compile(file, {filename: template});
var context = {title: 'Express'};
var html = compiledTmpl(context);
sendMail(toAddress, html, function(err, response) {
if(err) {
console.log('ERROR!');
} else {
console.log('Template send');
}
});
}
});
});
The problem is a typo mistake. Your sendMail function takes subject as second paramter.
var sendMail = function(toAddress, subject, content, next) {
var mailTemplate = {
from: 'xxxxxx#gmail.com',
to: toAddress,
subject: subject,
html: content
};
transporter.sendMail(mailTemplate, next);
};
Your are passing the compiled html as a second parameter to the function. So it takes the html as header.
sendMail(toAddress, html, function(err, response) {
if(err) {
console.log('ERROR!');
} else {
console.log('Template send');
}
});
Cheers.

Downloading progress in Google Drive

In my Meteor server app, I am downloading a file from Google Drive using this code,
var dest = fs.createWriteStream('/data/'+data.name);
drive.files.get({
fileId: data.id,
alt: 'media',
auth: jwtClient
})
.on('end', Meteor.bindEnvironment(function() {
}))
.on('error', function(err) {
console.log('Error during download', err);
})
.pipe(dest);
How can I get the progress of the download? For example, i want every 30 seconds to display progress of the download using console.log()
Can I use .on('data')? I am using google drive nodejs v3 provided by Google.
You can get File meta (id, name, size) from drive.files.list with file name, then you can download the file.
Use
Node.js Quickstart for google drive to authenticate.
I am using progress-stream to measure % data received.
var callAfterDownload = function (fileName, callback) {
drive.files.list({
auth: oauth2Client,
pageSize: 1,
q: 'name=\'' + fileName + '\'',
fields: 'nextPageToken, files(id, name, size)'
}, function (err, response) {
if (err) {
console.log('The API returned an error: ' + err)
callback(['Error while download'])
} else {
var files = response.files
//when only one file is matched we will download
if (files.length === 1) {
var file = files.pop()
console.log('%s (%s)', file.name, file.id)
var dest = fs.createWriteStream(file.name)
var progress = Progress({time:100, length: file.size})
//downloading matched file from drive
drive.files.get({
auth: oauth2Client,
fileId: file.id,
alt: 'media'
}).on('error', function (err) {
console.log('Error during download', err)
callback(['Error while download'])
}).pipe(progress).pipe(dest)
//checking progress of file
progress.on('progress', function(progress) {
console.log('download completed ' +progress.percentage.toFixed(2) + '%')
});
//when write stream has finally written to file
dest.on('finish', callback)
} else {
console.log('EXITING......More than one/no file exist with same name, make sure you have unique file name.')
callback()
}
}
})
}
function downloadDriveFile () {
var fileName = 'testfile.doc'
callAfterDownload(fileName, function (err) {
if(err) throw err
//your logic to do anything with the file
})
}
downloadDriveFile();

How to upload files to s3 synchronously using node.js api

I have the following piece of code:
array.forEach(function (item) {
// *** some processing on each item ***
var params = {Key: item.id, Body: item.body};
s3bucket.upload(params, function(err, data) {
if (err) {
console.log("Error uploading data. ", err);
} else {
console.log("Success uploading data");
}});
});
Because s3bucket.upload is being executed asynchronously - the loop finishes before uploading all the items.
How can I force s3bucket.upload to be synchronous?
Meaning don't jump to next iteration until this item was uploaded (or failed) to S3.
Thanks
you can use https://github.com/caolan/async#each each or eachSeries
function upload(array, next) {
async.eachSeries(array, function(item, cb) {
var params = {Key: item.id, Body: item.body};
s3bucket.upload(params, function(err, data) {
if (err) {
console.log("Error uploading data. ", err);
cb(err)
} else {
console.log("Success uploading data");
cb()
}
})
}, function(err) {
if (err) console.log('one of the uploads failed')
else console.log('all files uploaded')
next(err)
})
}
Better to use promises as suggested in one of the comments:
const uploadToS3 = async (items) => {
for (const item of array) {
const params = { Key: item.id, Body: item.body };
try {
const data = await s3bucket.upload(params).promise();
console.log("Success uploading data");
} catch (err) {
console.log("Error uploading data. ", err);
}
}
}
You could pass a post back function, this way the rest of the code is executed only when the upload has been completed. This does not answer your question but could be an alternative option:
array.forEach(function (item) {
// *** some processing on each item ***
var params = {Key: item.id, Body: item.body};
var f1=function(){
// stuff to do when upload is ok!
}
var f2=function(){
// stuff to do when upload fails
}
s3bucket.upload(params, function(err, data) {
if (err) {
f2();
console.log("Error uploading data. ", err);
// run my function
} else {
// run my function
f1();
console.log("Success uploading data");
}});
});

How can I cause a newly created .csv file to be downloaded to the user?

I have created a button on my website, that when clicked will create a .csv file. What I want is for this file to be downloaded to the user immediately after the file has been created. Here is what I have so far:
var data = ...; // stuff
var fields = ...; // stuff
json2csv({ data: data, fields: fields }, function(err, csv) {
if (err) {
console.log(err);
}
fs.writeFile('test.csv', csv, function(err) {
if (err) throw err;
console.log('file saved');
// now, download this file to the user. How?
});
});
The .csv file is created, but I want the file to then be immediately downloaded to the user. Ideally, the .csv file would be streamed directly to the user without it ever being saved on my server, but I'm not sure how to do this. Any help would be much appreciated.
If you are using express, you can use sendFile. Assuming your code has access to the response object, you can send the file like this:
var data = ...; // stuff
var fields = ...; // stuff
json2csv({ data: data, fields: fields }, function(err, csv) {
if (err) {
console.log(err);
}
fs.writeFile('test.csv', csv, function(err) {
if (err) throw err;
console.log('file saved');
var options = {
root: __dirname
};
res.sendFile('test.csv', options, function (err) {
if (err) {
console.log(err);
res.status(err.status).end();
}
else {
console.log('Sent:', fileName);
}
});
});
});
As for sending the file without saving it to your server, you can do that setting the Content-Disposition header:
var data = ...; // stuff
var fields = ...; // stuff
json2csv({ data: data, fields: fields }, function(err, csv) {
if (err) {
console.log(err);
}
res.set({
'Content-Disposition': 'attachment; filename=test.csv',
'Content-Type': 'text/csv'
});
res.send(csv);
});
You can construct a HTTP response with the appropriate file type and send it if you are not using Express:
res.writeHead(200, {
'Content-Type': 'text/csv'
});
res.write(csv); // or csv.pipe(res) if csv is a readable stream
res.end();

Resources