I am trying to get a file from html form and store it in another folder. It's basically cloud function, and I am new to both node.js and firebase so don't know what I am doing wrong. What I manage to do is:
const fileMiddleware = require('express-multipart-file-parser');
app.post("/sendMail", (req, res) => {
const {
fieldname,
filename,
encoding,
mimetype,
buffer,
} = req.files[0];
console.log(req.files[0].originalname);
var fs = require('fs')
var oldPath = req.files[0].originalname;
var newPath = '/functions/'+oldPath;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
});
});
Whenever I try to move file, I got path issues. The error is as follows:
[Error: ENOENT: no such file or directory, rename 'C:\Users\Maisum Abbas\now\functions\sendMail.txt'
> 'C:\functions\sendMail.txt'] {
> errno: -4058,
> code: 'ENOENT',
> syscall: 'rename',
> path: 'C:\\Users\\Maisum Abbas\\now\\functions\\sendMail.txt',
> dest: 'C:\\functions\\sendMail.txt'
> }
Also, this is the path where I want to actually move the file but oldpath is already setup like this.
C:\Users\Maisum Abbas\now\functions\sendMail.txt
Since I needed to attach a file with email, it was causing path issues. I tried it with multer and it works. What I did:
//call libraries here
var storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, 'resume/');
},
filename: function (req, file, callback) {
callback(null, file.fieldname + '-' + Date.now());
}
});
var upload = multer({ storage : storage}).single('filetoupload');
app.post("/careerMail", (req, res) => {
const { name } = req.body;
const { email } = req.body;
const { phone } = req.body;
upload(req,res,function(err) {
if(err) {
return res.end("Error uploading file.");
}
});
const dest = 'mymail';
const mailOptions = {
from: email, // Something like: Jane Doe <janedoe#gmail.com>
to: dest,
subject: 'Candidate Application', // email subject
html: `<div>
<strong>From:</strong> ` +
name +
`<br /><br />
<strong>Email:</strong> ` +
email +
`<br /><br />
<strong>Phone:</strong> ` +
phone +
`<br /><br />
</div>
`,// email content in HTML
attachments: [
{
filename: req.files[0].originalname,
content: req.files[0].buffer.toString("base64"),
encoding: "base64"
}
]
and rest of the code...
I suggest rethinking this approach altogether. You won't be able to move files around in a deployed function. The nodejs runtime filesystem doesn't allow any files to be written anywhere in the filesystem, except for os.tmpdir() (which is /tmp on Linux).
If you need to write a file temporarily, you should definitely only use that tmp space. Be aware that files written there occupy memory and should be deleted before the function terminates, or you could leak memory.
You can read files that you deployed with your code, but you should do that through relative paths.
I ran into same problem while moving file. I sort this problem by using a function to get the application root folder and then concatenate rest of the location.
//place this file on application root.
//import where you need to get the root path.
const path = require('path');
module.exports = (function(){
return path.dirname(require.main.filename || process.mainModule.filename);
})();
//taking your case move location.
const rootPath = //require the above module.
const newPath = rootPath + /functions/' +oldPath;
fs.rename(oldPath, newPath, function (err) {
if (err) throw err
console.log('Successfully renamed - AKA moved!')
});
Related
I want to delete a file named myfile with any extension.
const fs = require('fs')
const ext = '' ; //this extension may be anything
const path = './myfile.'+ext ;
fs.unlink(path, (err) => {
if (err) {
console.error(err)
return
}
//file removed
})
The error I get:
no such file or directory named myfile
But there is a file named myfile.jpg which I want to delete. Let's pretend that we don't know the extension. How can I delete it?
unlink doesn't support regex to delete file. You will probably need to loop through the the folder and find the filename start with 'myfile' and delete it accordingly.
const fs = require('fs');
const director = 'path/to/directory/'
fs.readdir(directory, (err, files) => {
files.forEach(file => {
if(file.split('.')[0] == 'myfile') fs.unlink( directory + file );
});
});
I want to post an image to server.But before that I want to make sure that directory is create, before placing an image to a correct folder.The folder that I want to create is year/month/day/[image]. I am able to generate the folder on my local PC, but when I want to apply on the server, an error message is displayed and the folder is not created.I don't know what mistake that I have made, I hope someone can help me solve this problem.
Thank you in advance.
PWD
ERROR
return binding.mkdir(pathModule._makeLong(path), Error: ENOENT: no
such file or directory, mkdir
'/home/eis/development/eis-api-dev/picture/2020/06/01/'
CODE
var storage = multer.diskStorage({
destination: function (req, file, cb) {
///output: home/eis/development/eis-api-dev/picture/2020/06/01/
const dir = path.join(__dirname,_const.IMAGE_FILE_PATH+_const.generateImagePath(null,null,null));
console.log("path:"+dir);
fs.exists(dir,exists =>{
if(!exists){
//mkdirp.sync(dir);
return fs.mkdirSync(dir,{recursive: true},error => cb(error,dir));
}
return cb(null,dir)
});
},
filename: function (req, file, cb) {
cb(null, file.originalname)
}
})
try to create using mkdirp
if (!fs.existsSync(directoryPath)){
mkdirp(directoryPath, function (err) {
if (err) {
console.log("Error Creating Directory "+directoryPath);
}
else {
console.log("Creating Directory "+directoryPath);
}
}
I just have to upgraded latest nodejs version and its worked.
To create a directory asynchronously
const fs = require('fs');
const path = 'newfolder/xyz/';
fs.exists(path, exists => {
if (exists) {
console.log('The directory exists...!!');
}
else {
fs.mkdir(path, { recursive: true }, (error) => {
console.log(error);
if (error)
// print or display your error
else {
return path;
}
});
}
});
I'm using Multer to manage image uploads, and when running my app on my local machine everything works perfectly. But now that I'm trying to deploy to Heroku I get this error in my application logs:
Unhandled rejection Error: EROFS: read-only file system, mkdir
'/public'
...which seems like it's trying to create a directory rather than using the existing one (like it does on my local machine)
This is my the code I'm using for Multer:
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'public/img/') },
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + file.originalname)
} })
var upload = multer({storage: storage})
router.post('/:propertyid', upload.single('img'), function(req, res) {
Property.update({
img: req.file.filename
}, {
where: {
id: req.params.propertyid,
}
}).then(updatedProperty => {
res.redirect('/admin/' + updatedProperty)
})
});
The public/img directory already exists and when testing it, it runs fine with correct filenames and end up in the correct place. Any help is appreciated! Thanks!
Heroku dynos have an ephemeral filesystem. This answer by Naaman Newbold, explains very well what that means.
TL;DR:
Dynos' filesystem shouldn't be used to store any permanent storage or data besides what is deployed. In order to do use a storage, AWS S3 can be used.
You can Use fs-extra to create folder it will sync and create folder like below in below code I am creating directory by user_id and uploading multiple images so i have used fs.mkdirsSync(path) in my code
let fs = require('fs-extra');
let storage = multer.diskStorage({
destination: function (req, file, cb) {
let Id = req.body.id;
let path = `tmp/daily_gasoline_report/${Id}`;
fs.mkdirsSync(path);
cb(null, path);
},
filename: function (req, file, cb) {
// console.log(file);
let extArray = file.mimetype.split("/");
let extension = extArray[extArray.length - 1];
cb(null, file.fieldname + '-' + Date.now() + "." + extension);
}
})
I have this cloud function that I wrote to upload file to google cloud storage:
const gcs = require('#google-cloud/storage')({keyFilename:'2fe4e3d2bfdc.json'});
var filePath = file.path + "/" + file.name;
return bucket.upload(filePath, {
destination: file.name
}).catch(reason => {
console.error(reason);
});
I used formidable to parse the uploaded file and I tried to log the properties of the uploaded file and it seems fine; it is uploaded to a temp dir '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/ but when I try to upload the file to the gcs am getting this error:
{ Error: EACCES: permission denied, stat '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg'
at Error (native)
errno: -13,
code: 'EACCES',
syscall: 'stat',
path: '/tmp/upload_2866bbe4fdcc5beb30c06ae6c3f6b1aa/thumb_ttttttt.jpg' }
I am using this html form to upload the file:
<!DOCTYPE html>
<html>
<body>
<form action="https://us-central1-appname.cloudfunctions.net/uploadFile" method="post" enctype="multipart/form-data">
Select image to upload:
<input type="file" name="fileToUpload" id="fileToUpload">
<input type="submit" value="Upload Image" name="submit">
</form>
</body>
</html>
I got a solution from the Firebase Support Team
So first thing:
var filePath = file.path + "/" + file.name;
we dont need the file.name since the file.path is full path of the file (including the file name).
So changed it to this instead:
var filePath = file.path;
Second, the function terminates before the asynchronous work in 'form.parse(...)' is completed. That means the actual file upload might still be in progress while the function execution has ended.
The fix for that is to wrap the form.parse(...) in a promise:
exports.uploadFile = functions.https.onRequest((req, res) => {
var form = new formidable.IncomingForm();
return new Promise((resolve, reject) => {
form.parse(req, function(err, fields, files) {
var file = files.fileToUpload;
if(!file){
reject("no file to upload, please choose a file.");
return;
}
console.info("about to upload file as a json: " + file.type);
var filePath = file.path;
console.log('File path: ' + filePath);
var bucket = gcs.bucket('bucket-name');
return bucket.upload(filePath, {
destination: file.name
}).then(() => {
resolve(); // Whole thing completed successfully.
}).catch((err) => {
reject('Failed to upload: ' + JSON.stringify(err));
});
});
}).then(() => {
res.status(200).send('Yay!');
return null
}).catch(err => {
console.error('Error while parsing form: ' + err);
res.status(500).send('Error while parsing form: ' + err);
});
});
Lastly, you may want to consider using the Cloud Storage for Firebase in uploading your file instead of Cloud functions. Cloud Storage for Firebase allows you to upload files directly to it, and would work much better:
It has access control
It has resumable uploads/downloads (great for poor connectivity)
It can accept files of any size without timeout-issues
If you want to trigger a Cloud Function on file upload even, you can
do that and a lot more
I managed this by downloading the file to the tmp instead.
You will need:
const mkdirp = require('mkdirp-promise');
Then, inside onChange. I created tempLocalDir like so:
const LOCAL_TMP_FOLDER = '/tmp/';
const fileDir = (the name of the file); //whatever method you choose to do this
const tempLocalDir = `${LOCAL_TMP_FOLDER}${fileDir}`;
Then I use mkdirp to make the temp directory
return mkdirp(tempLocalDir).then(() => {
// Then Download file from bucket.
const bucket = gcs.bucket(object.bucket);
return bucket.file(filePath).download({
destination: tempLocalFile
}).then(() => {
console.log('The file has been downloaded to', tempLocalFile);
//Here I have some code that converts images then returns the converted image
//Then I use
return bucket.upload((the converted image), {
destination: (a file path in your database)
}).then(() => {
console.log('JPEG image uploaded to Storage at', filePath);
})//You can perform more actions of end the promise here
I think my code achieves that you were trying to accomplish. I hope this helps; I can offer more code if necessary.
I have file, which I believe should be imported as a module, but it when I try to import into my main file (see main.js), I get the follow error:
Error: Cannot find module 'sessionStore.js'
I'm made sure that the file in in the correct location. Any ideas what else could cause this?
main.js
var express = require('express');
var bodyParser = require('body-parser');
var util = require('util');
var toMarkdown = require('to-markdown');
var jsdiff = require('diff');
var marked = require('marked');
var pg = require('pg');
//need to get sessions to work and use server credentials instead of password
var sessionStore = require('sessionStore.js');
var PodioJS = require('podio-js').api;
var podio = new PodioJS({authType: 'password', clientId: "xxx", clientSecret: "xxx" },{sessionStore:sessionStore});
sessionStore.js
var fs = require('fs');
var path = require('path');
function get(authType, callback) {
var fileName = path.join(__dirname, 'tmp/' + authType + '.json');
var podioOAuth = fs.readFile(fileName, 'utf8', function(err, data) {
// Throw error, unless it's file-not-found
if (err && err.errno !== 2) {
throw new Error('Reading from the sessionStore failed');
} else if (data.length > 0) {
callback(JSON.parse(data));
} else {
callback();
}
});
}
function set(podioOAuth, authType, callback) {
var fileName = path.join(__dirname, 'tmp/' + authType + '.json');
if (/server|client|password/.test(authType) === false) {
throw new Error('Invalid authType');
}
fs.writeFile(fileName, JSON.stringify(podioOAuth), 'utf8', function(err) {
if (err) {
throw new Error('Writing in the sessionStore failed');
}
if (typeof callback === 'function') {
callback();
}
});
}
module.exports = {
get: get,
set: set
};
have you tried using relative paths? If they're in the same directory, then
var sessionStore = require('./sessionStore');
without the .js
The error you're getting is because node can't find your sessionStore module in the node_modules directory.
If the module identifier passed to require() is not a native module, and does not begin with '/', '../', or './', then node starts at the parent directory of the current module, and adds /node_modules, and attempts to load the module from that location.
https://nodejs.org/api/modules.html#modules_file_modules
You probably want to use a relative path to your file. Something like: require('./sessionStore')
A module prefixed with '/' is an absolute path to the file. For example, require('/home/marco/foo.js') will load the file at /home/marco/foo.js.
A module prefixed with './' is relative to the file calling require(). That is, circle.js must be in the same directory as foo.js for require('./circle') to find it.