Adding files to same folder with nodeJS - javascript

I want to add mp3, lrc, wav, txt to the server and the folder name would be title and all of the extensions mentioned above would have specified names. As seen in the code, the mp3 would be "vocal.mp3".
addSong(event) {
jQuery('#addItemSave').text("Please wait!");
this._service.addSong(this.authorText, this.titleText, this.durationText, this.genre).subscribe(
res => {
this.data.push(res.data[0]);
this.addSongFilesToServer();
});
}
private addSongFilesToServer() {
this._service.addSongFilesToServer(this.titleText,
this.mp3file, this.lrcfile, this.pitchfile, this.thumbfile).subscribe(
res => {
console.log("Done! Now hide loading icon or what ever...");
jQuery('#addItemSave').text("Save");
jQuery('#addNewSongDialog').modal('hide');
jQuery('#addNewSongDialog').find("input,textarea,select")
.val('')
.end()
.find("input[type=checkbox], input[type=radio]")
.prop("checked", "")
.end();
});
}
addSongFilesToServer(title, mp3, lrc, txt, thumb) {
let url = this._config.ServerWithApiUrl + "uploadFiles";
let body : FormData = new FormData();
body.append('mp3', mp3, "vocal.mp3");
body.append('txt', txt, "pitches.txt");
body.append('lrc', lrc, "lyric.lrc");
body.append('thumb', thumb, "thumbnail.png");
body.append('title', title);
this._config.headers.delete('Content-Type');
return this._http.post(url, body, { headers: this._config.headers })
.map(res => res.json()).catch(function(err){
throw err;
});
}
addSong(event) is called when a button is pressed on the page and the all of the files that need to be passed on, are being passed on. The only problem here is that mp3, lrc, wav, txt go all under different folders with their their, for example vocal.mp3.
Just to illustrate, this is what I am getting at the moment :
├───songs
│ ├───vocal
│ │ vocal.mp3
│ ├───pitches
│ │ pitches.txt
...
And this is what I need:
├───songs
│ ├───title
│ │ vocal.mp3
│ │ lyric.lrc
│ │ pitches.txt
...
And the server side:
Router.post('/uploadFiles', (req, res) => {
var title = req.body.title || "title";
var storage = multer.diskStorage({
destination: function (req, file, cb) {
var dir = "../songs/" + file.originalname.split('.')[0];
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}
cb(null, dir);
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
var upload = multer({ storage : storage}).any();
upload(req,res,function(err){
if(err){
return res.status(500).send({
code: 500, message: 'could not upload file: ' + err, error: err });
}else {
return res.status(200).send({
code: 200, message: 'All files uploaded!', err: ""});
}
});
});

You can see in the example that you actually coded that way
var storage = multer.diskStorage({
destination: function (req, file, cb) {
var dir = "../songs/" + file.originalname.split('.')[0];
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}
cb(null, dir);
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
The file.originalname.split('.')[0] actually splits the extension and takes the filename.
so it will be var dir = "../songs/" + title; plain and simple.
var storage = multer.diskStorage({
destination: function (req, file, cb) {
////////////////////////////
var dir = "../songs/" + title;
///////////////////////
if (!fs.existsSync(dir)){
fs.mkdirSync(dir);
}
cb(null, dir);
},
filename: function (req, file, cb) {
cb(null, file.originalname);
}
});
Also, body-parser doesn't handle multipart bodies, which is what FormData is submitted as. So the req.body.title will not work.
Check this for reference: How to handle FormData from express 4
Most probably you will need to send the title in another way

Related

Error: ENOENT: no such file or directory Nodejs

I'm trying to upload a file and store it in an uploads folder, but I get this error: no such file or directory
I get the message success in console but I get this error anyway.
POST /auth/register 500 21.023 ms - 260
Error: ENOENT: no such file or directory, open E:\IMPORTANT\INFO-DEV\DEV\ANGULAR NODEJS\API AUTH\uploads\1671534381494.jpeg
Here is my configuration code for upload.
const path = require("path");
const multer = require("multer");
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "uploads/");
},
filename: function (req, file, cb) {
const extension = path.extname(file.originalname);
cb(null, Date.now() + extension);
},
});
const upload = multer({
storage: storage,
fileFilter: function (req, file, callback) {
if (
file.mimetype == "image/png" ||
file.mimetype == "image/jpg" ||
file.mimetype == "image/jpeg"
) {
callback(null, true);
console.log("Image téléchargé avec succès"); // success message
} else {
callback(null, false);
console.log("Seulement du fichier de type png, jpg ou jpeg"); // error message
}
},
limits: {
fileSize: 1024 * 1024 * 2,
},
});
module.exports = upload;
I got the same error, but I was able to solve it by getting my current path.
import multer from "multer";
// Set up multer storage options
const storage = multer.diskStorage({
destination: function (req, file, cb) {
console.log("🚀 ~ file: upload.ts:11 ~ file", process.cwd());
cb(null, `${process.cwd()}/src/Images`);
},
filename: function (req, file, cb) {
cb(null, file.fieldname + "-" + Date.now());
},
});
// Create a multer instance with the storage options
const upload = multer({ storage });
export default upload;
The issue is that your uploads folder doesn't exist or you set the path incorrectly.
I don't know where exactly you created uploads folder (and if you created it at all).
So in the destination param you should pass either:
path.join(__dirname, '/uploads') - in case that folder is in the same location where current js file is located.
Or path.join(process.cwd(), '/uploads') - in case if uploads folder is in the root of the project (where you run npm start etc.)
So, in short words you need to make sure folder exists and then make sure the path is correct.
P.S.
Using ../../ syntax should also work, you can try ../uploads or ../../uploads if, for example, that folder is on higher levels of your folders structure.
Change this line
cb(null, './uploads/');
this line
cb(null, "uploads/");
or try
cb(__dirname, "uploads/");
you can try your path name as like
img: {
data: fs.readFileSync(
path.join(__dirname + "../../uploads" + req.file.filename)
),
contentType: "image/png",
},

How can I wait a Python shell to execute before serving file

I've an express server route which receives a xml file, then parses and return it as json.
When a user sends a file, it saves in a directory './upload', parses it with a Python script then output json in './json-output', which is served.
When I first upload a file, the response comes empty. But when I do the same upload steps (there is a json already created from last upload on './json-output' dir), it serves the json. It seems some asynchronous issue but I couldn't fix it.
app.post('/upload', function(req, res) {
upload(req, res, async function(err) {
if (err) {
res.json({ error_code: 1, err_desc: err });
return;
}
if (!req.file) {
res.json({ error_code: 1, err_desc: 'No file passed' });
return;
}
let fileName = req.file.originalname;
const options = {
args: [ fileName ]
};
const parserPath = path.join(__dirname + '/parser/parser.py');
const readFile = promisify(PythonShell.run);
await readFile(parserPath, options);
fileName = fileName.split('.')[0];
res.sendFile(path.join(__dirname + `/json-output/${fileName}.json`));
});
});
I'm running it inside a docker images
This a quite a "Dirty fix" in my eyes but you could do a while loop EG:
fileName = fileName.split('.')[0];
while (!fs.existsSync(path.join(__dirname + `/json-output/${fileName}.json`)){
console.log('File does not exist!')
}
//Becareful you should delete the file once the res.send is done
res.sendFile(path.join(__dirname + `/json-output/${fileName}.json`));
Decided to read the python-shell docs here an idea:
https://www.npmjs.com/package/python-shell#exchanging-data-between-node-and-python
So, in theory, you can start a new
let pyshell = new PythonShell(path.join(__dirname + '/parser/parser.py'),options);
pyshell.end(function (err,code,signal) {
if (err) throw err;
fileName = fileName.split('.')[0];
res.sendFile(path.join(__dirname + `/json-output/${fileName}.json`));
});

File upload with Multer and Uppy

I'm using Uppy as my drag and drop file upload, but as we all know that Uppy doesn't take care of actually uploading it to the server. Therefore, I am using Multer as my back-end for uploading files to my server. Though, I ran into a snag. When I upload the file, I have multer change the file name to the current date plus the extension. But when I console log it, it comes out "undefined".
functions.js
let path = require('path');
const multer = require('multer');
let myUploadFunction = function _multerFunction(req, res, filePath){
let newFileName;
let storage = multer.diskStorage({
destination: function (req, file, callback) {
callback(null, filePath);
},
filename: function (req, file, callback) {
console.log("Storage Function " , file);
callback(null, newFileName = Date.now() + path.extname(file.originalname));
getNewFileName(newFileName); // Trying to pass this function to the upload.js route but it comes back undefined.
}
});
let upload = multer({ storage : storage}).any();
upload(req, res, function (err) {
if(err) {
return res.end("Error uploading file. "+ err);
}
console.log("New File Name " + newFileName); // This console log does print the new file name
});
};
let getNewFileName = function getNewCreatedFileName(fileName){
return fileName;
};
module.exports.myUploadFunction = myUploadFunction;
module.exports.getNewFileName = getNewFileName;
upload.js
let express = require('express');
let router = express.Router();
let upload = require('../functions/functions');
//const mysql_connection = require('../db'); // Database connection file.
/* POST upload route. */
router.post('/', function(req, res, next) {
upload.myUploadFunction(req, res, 'public/images', 'File is upload successfully');
console.log("From the upload route " + upload.getNewFileName()); // RETURNS UNDEFINED
});
module.exports = router;
I don't know why it comes back undefined. I'm passing the function. Am I missing something else?
I also included the uppy code is you need to see it.
uppy.js
// Import the plugins
const Uppy = require('#uppy/core');
const XHRUpload = require('#uppy/xhr-upload');
const Dashboard = require('#uppy/dashboard');
const uppy = Uppy({
debug: true,
autoProceed: false,
restrictions: {
maxFileSize: 1024000,
maxNumberOfFiles: 3,
minNumberOfFiles: 1,
allowedFileTypes: ['image/*', 'video/*']
}
})
.use(Dashboard, {
trigger: '.UppyModalOpenerBtn',
inline: true,
target: '#drag-drop-area',
replaceTargetContent: true,
showProgressDetails: true,
proudlyDisplayPoweredByUppy: false,
animateOpenClose: true,
note: 'Images and video only, 1–3 files, up to 1 MB',
height: 470,
browserBackButtonClose: true,
theme: 'dark',
metaFields: [
{id: 'caption', name: 'Caption', placeholder: 'describe what the image is about'}
]
});
uppy.on('file-added', (file) =>{
console.log(file);
uppy.setFileMeta(file.meta.id, {
caption: file.name
});
});
uppy.use(XHRUpload, {
id: 'XHRUpload',
endpoint: 'http://localhost:8000/upload',
method: 'POST',
formData: true,
fieldName: 'my_fieldName',
metaFields: ['caption'],
});
uppy.on('upload-success', (file, response) => {
console.log("File uploaded successfully ", file);
});
module.exports = uppy;
If you need to see other code let me know. Thank you!
By the way, I am using browserify to implement Uppy. :)
If Multer isn't the best way to upload a file to a server with Uppy, I will gladly take any better alternative. Thanks!
add this after restrictions in uppy.js:
n - is your new file name
restrictions: {
...
},
onBeforeFileAdded: (c, files) => {
let n = Date.now().toString(36) + Math.random().toString(36).substr(2) + '.' + c.extension.toLowerCase()
const m = {
...c,
name:n
}
return m
}

Download GitLab repository archive using GitLab API and Node.js

I would like to download (not clone) archive from my GitLab repository, but I get this error
incorrect header check (Zlib._handle.onerror)
This is my function:
var fs = require('fs');
var url = require('url');
var https = require('https');
var path = require('path');
var targz = require('tar.gz');
function downloadFile(source, destination, name) {
var options = {
host: url.parse(source).host,
port: 443,
path: url.parse(source).pathname
};
var file = fs.createWriteStream(destination + path.sep + name);
https.get(options, function(res) {
res.on('data', function(data) {
file.write(data);
}).on('end', function() {
file.end();
console.log('File ' + name + ' downloaded to ' + destination);
targz().extract(destination + '/' + name, destination)
.then(function(){
console.log('Job done!');
})
.catch(function(err){
console.log('Something is wrong ', err.stack);
});
});
});
}
The file which is download is type of tar.gz. I try to set some headers but unsuccessful. Source param is like: https://gitlab.com/api/v3/projects/:ID/repository/archive?token=XXYYZZ
Any help please?
The issue is that your file is not correctly downloaded by https module which result in extraction error from tar.gz module.
You can use request module coordinated with tar.gz with createWriteStream to pipe the extraction directly to the destination folder :
var request = require('request');
var targz = require('tar.gz');
function downloadFile(source, destination, cb) {
var read = request.get(source);
var write = targz().createWriteStream(destination);
read.pipe(write);
write.on('finish', function() {
cb(null);
});
write.on('error', function(err) {
cb(err);
});
}
var source = "https://gitlab.com/api/v3/projects/:ID/repository/archive?token=XXYYZZ";
var destination = "/home/user/some/dir";
downloadFile(source, destination, function(err) {
if (err) {
console.log('Something is wrong ', err.stack);
} else {
console.log('Job done!');
}
});
Note that, for the finish event to be dispatched you will need version 1.0.2 of tar.gz (see this issue) :
npm install tar.gz#1.0.2

How to upload file using multer or body-parser

I am a NodeJS beginner, following along a book "Web Development with MongoDB and NodeJS". I am stuck at its chapter 6 with 'multer'. When I use multer for file uploads the server throws the following error:
/Users/fk / Documents / imageuploader / node_modules / express / lib / application.js: 209
throw new TypeError('app.use() requires middleware functions'); ^
TypeError: app.use() requires middleware functions
but when I replace it with bodyParser the server fires up but when I click the upload button it gives me the following error on the browser.
500 TypeError: Cannot read property 'file' of undefined
However, it is supposed to redirect me towards another page, where the uploaded file is shown.
Here is my bodyParser code, please see if I am using it correctly because it gives me "body-parser deprecated" at the starting of the server. I've seen other questions like mine and I followed but none of them really work.
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(bodyParser({
uploadDir: path.join(__dirname, '../public/upload/temp')
}));
Following code shows how I use multer, just in case if there is something I shouldn't be doing please let me know. Which one would be better in case of uploading files, body-parser or multer?
app.use(multer({
dest: path.join(__dirname, '../public/upload/temp')
}));
var saveImage = function() {
var possible = 'abcdefghijklmnopqrstuvwxyz0123456789',
imgUrl = '';
for (var i = 0; i < 6; i += 1) {
imgUrl += possible.charAt(Math.floor(Math.random() * possible.length));
}
var tempPath = req.files.file.path,
ext = path.extname(req.files.file.name).toLowerCase(),
targetPath = path.resolve('./public/upload/' + imgUrl + ext);
if (ext === '.png' || ext === '.jpg' || ext === '.jpeg' || ext === '.gif') {
fs.rename(tempPath, targetPath, function(err) {
if (err) throw err;
res.redirect('/images/' + imgUrl);
});
} else {
fs.unlink(tempPath, function() {
if (err) throw err;
res.json(500, {
error: 'Only image files are allowed.'
});
});
}
};
saveImage();
Preceding block of code is the logic that I am using to upload the file. In the error it is referring to 'file' as undefined which is in the following line in the saveImage function. It is unable to get the path and therefore throws error 500 according to the else part of the saveImage function. Why is 'file' undefined here? I dont get it.
var tempPath = req.files.file.path,
multer() returns a middleware generator that uses the settings you specified, so you cannot pass its return value directly to app.use(). You can see all of the types of middleware it can generate in the documentation, but typically the generated middleware are added at the route level instead of globally like the other body parsers. This is because you will typically pass in the name of the file field(s) that you will be expecting.
For example, this will accept a single file (along with any non-file fields) whose form field name is foo:
var upload = multer({
dest: path.join(__dirname, '../public/upload/temp')
});
// ...
app.post('/upload', upload.single('foo'), function(req, res) {
if (req.file) {
console.dir(req.file);
return res.end('Thank you for the file');
}
res.end('Missing file');
});
Also, body-parser does not currently export a multipart/form-data-capable middleware, so you cannot use that module for handling uploaded files (well, short of passing a base64-encoded string in an application/x-www-form-urlencoded form or something, but that's much less efficient).
Here is the basic code for file upload in MEAN please check
HTML
<form id="frmDoc" name="frmDocument" ng-submit="upload()" class="form-horizontal form-bordered" enctype="multipart/form-data" >
<fieldset>
<div class="form-group">
<label class="col-md-4 control-label" for="val_email">Document<span class="text-danger">*</span></label>
<div class="col-md-4">
<div class="input-group">
<input type="file" name="file" id='file' required="required" />
</div>
</div>
</div>
</fieldset>
<div class="form-group form-actions">
<div class="col-md-8 col-md-offset-4">
<button type="submit" class="btn btn-sm btn-primary"><i class="fa fa-upload"></i> submit</button>
</div>
</div>
</form>
CLIENT SIDE CODE
app.controller ('myctrl',function($scope,$http){
$scope.upload = function () {
var file = angular.element(document.querySelector('#file')).prop("files")[0];
$scope.files = [];
$scope.files.push(file);
$http({
method: 'POST',
url: '/users/upload',
headers: { 'Content-Type': undefined },
transformRequest: function (data) {
var formData = new FormData();
formData.append('model', angular.toJson(data.model));
formData.append('file', data.files[0]);
return formData;
},
data: { model: { title: 'hello'}, files: $scope.files }
}).success(function (res) {
console.log(res)
});
}
});
SERVER SIDE CODE
var multer = require('multer');
var mkdirp = require('mkdirp');
var storage = multer.diskStorage({
destination: function (req, file, cb) {
//var code = JSON.parse(req.body.model).empCode;
var dest = 'public/uploads/';
mkdirp(dest, function (err) {
if (err) cb(err, dest);
else cb(null, dest);
});
},
filename: function (req, file, cb) {
cb(null, Date.now()+'-'+file.originalname);
}
});
var upload = multer({ storage: storage });
router.post('/upload', upload.any(), function(req , res){
console.log(req.body);
res.send(req.files);
});
I corrected the code of the book "Web Development with MongoDB and NodeJS" as follows:
app.use(multer({dest:path.join(__dirname,'../public/upload/temp')}).any());
.
.
.
.
const tempPath = req.files[0].path, // Temporary location of uploaded file
ext = path.extname(req.files[0].originalname).toLowerCase(), // Get file extension of the uploaded file
targetPath = path.resolve(`./public/upload/${imgUrl}${ ext}`); // The final path for the image file
The other parts of code remained intact. It worked and I could upload image files.
Best wishes,
Mehrdad Sheikhan
Code for upload file using Multer and save it to local folder
api- call fileUpload function
fileUpload(req)
.then(uploadRes => {
console.log('uploadRes', uploadRes)
})
.catch(err => {
console.log('err', err)
})
Create file upload service
const multer = require('multer') // import library
const moment = require('moment')
const q = require('q')
const _ = require('underscore')
const fs = require('fs')
let dir = './public'
/** Store file on local folder */
let storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, dir)
},
filename: function (req, file, cb) {
let date = moment(moment.now()).format('YYYYMMDDHHMMSS')
cb(null, date + '_' + file.originalname.replace(/-/g, '_').replace(/ /g, '_'))
}
})
/** Upload files */
let upload = multer({ storage: storage }).array('files')
/** Exports fileUpload function */
module.exports = {
fileUpload: function (req) {
let deferred = q.defer()
/** Create dir if not exist */
if (!fs.existsSync(dir)) {
fs.mkdirSync(dir)
console.log(`\n\n ${dir} dose not exist, hence created \n\n`)
}
upload(req, {}, function (err) {
if (req && (_.isEmpty(req.files))) {
deferred.resolve({ status: 200, message: 'File not attached', data: [] })
} else {
if (err) {
deferred.reject({ status: 400, message: 'error', data: err })
} else {
deferred.resolve({
status: 200,
message: 'File attached',
filename: _.pluck(req.files,
'filename'),
data: req.files
})
}
}
})
return deferred.promise
}
}

Categories