Node.js Multer doesn't save image on my project folder - node.js

I've have to do some maintenace on a Node.js project, and I can't get to upload a image.
I've already seen many post about uploading images into node.js but I can't figure out what happening with my code.
my routes/index.js (like my app.js)
var keystone = require("keystone");
var middleware = require("./middleware");
var importRoutes = keystone.importer(__dirname);
// Common Middleware
keystone.pre("routes", middleware.initLocals);
keystone.pre("render", middleware.flashMessages);
// Import Route Controllers
var routes = {
views: importRoutes("./views")
};
// Setup Route Bindings
exports = module.exports = function (app) {
// Views
app.get("/", routes.views.index);
app.all("/cadastroEvento", routes.views.cadastroEvento);
};
my routes/views/cadastroEvento
var keystone = require("keystone");
var async = require("async");
var env = require("../env");
var Cloudant = require("cloudant");
var multer = require("multer");
var upload = multer({ dest : "/" }).single("file");
// Conexão com o MongoDB
var Evento = keystone.list("Evento");
var mongoDb = require("mongodb");
var MongoClient = mongoDb.MongoClient;
var urlDb = env.urlDb;
exports = module.exports = function (req, res) {
var view = new keystone.View(req, res);
var locals = res.locals;
var url = view.req.originalUrl;
locals.tipo = url.substr(url.indexOf("?") + 1);
locals.section = "cadastroEvento";
locals.formData = req.body || {};
locals.validationErrors = {};
// POST
view.on("post", { action : "cadastroEvento" }, function (next) {
// Seta campos para mensagem de erro
locals.erroNome = false;
locals.erroDataInicio = false;
locals.erroDataFim = false;
locals.erroAoSalvar = false;
locals.erroAoConectar = false;
locals.eventoCadastrado = false;
locals.erroValidacao = false;
// Valida os campos
var validacao = validaCampos(req);
// HERE I DO THE UPLOAD OF THE IMAGE
upload(req, res, function(err)
{
if(err) {
return res.end("Error uploading file." + err);
}
res.end("File is uploaded");
});
console.log("Files: " + JSON.stringify(req.files));
... REST OF CODE NOT RELATED TO THE IMAGE UPLOAD ...
};
In my cadastroEvento.jade I have a form with method='post' enctype="multipart/form-data" and a input type="file" and name="file"
After the post, i receive the message: "File is uploaded"
but no image appears in my folder...
My
console.log("Files: " + JSON.stringify(req.files)); returns this:
Files: {"file":{"fieldname":"file","originalname":"Screenshot_2.png","name":"47707bab7b0b7bf03a882e88f5a0715d.png","encoding":"7bit","mimetype":"image/png","path":"C:\\Users\\JOS-HI~1\\AppData\\Local\\Temp\\47707bab7b0b7bf03a882e88f5a0715d.png","extension":"png","size":7895,"truncated":false,"buffer":null}}
Any help on where is my error would be appreciated.
Thanks

Related

NodeJS & express file upload with XMLHttpRequest - not working

I am uploading a file using this form and by the time xhr submits it the server does not recognize req.xhr === true, as such I can not process the file upload. What am I missing?
<form encType="multipart/form-data" method="post">
<Button onClick={(event)=>startUploadFile(event)} type="button">Upload</Button>
<input type="file" name="file" id="file" multiple="multiple" onChange={onChangeHandler} />
</form>
Client side
const [upFile, setUpFile] = useState('')
const onChangeHandler = event => {
setUpFile(event.target.files[0]);
}
const startUploadFile = e => {
setSpin('visible')
setMsg(`Uploading Media ...`)
e.preventDefault()
const data = new FormData()
data.append('file', upFile)
var formData = new FormData();
var xhr = new XMLHttpRequest();
var onProgress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded/e.total)*100;
console.log('percentage = ' + percentComplete)
}
};
formData.append('files', upFile); // this is a state object set onChange
xhr.open('post', '/upload', true);
xhr.addEventListener('error', onError, false);
xhr.addEventListener('progress', onProgress, false);
xhr.send(formData);
xhr.addEventListener('readystatechange', onReady, false);
}
Server side
const express = require('express'),
app = express.Router(),
cors = require('cors'),
fs = require('fs-extra');
app.use(cors())
app.post('/uploadFile', (req, res) => {
if (req.xhr || req.headers.accept.indexOf('json') > -1) {
// not accepted (req.xhr is false always) why?
}
});
In expressjs you need to install multer or formidable package to upload file from client side application then you will receive your file in req.files object.
Thanks to #Nikas for the remarks - here is working solution if anyone needs it or something like it.
For the client side:
const startUploadFile = e => {
setSpin('visible')
setMsg(`Uploading Media ...`)
e.preventDefault()
const data = new FormData()
data.append('file', upFile)
var formData = new FormData();
var xhr = new XMLHttpRequest();
var onProgress = function(e) {
if (e.lengthComputable) {
var percentComplete = (e.loaded/e.total)*100;
console.log('% uploaded:' + percentComplete)
}
};
var onReady = function(e) {
console.log('ready')
};
var onError = function(err) {
console.log('something went wrong with upload');
};
formData.append('files', upFile); // this is a state object set onChange
xhr.open('post', '/media/uploadFile', true);
xhr.addEventListener('error', onError, false);
xhr.addEventListener('progress', onProgress, false);
xhr.send(formData);
xhr.addEventListener('readystatechange', onReady, false);
}
server side:
const express = require('express'),
app = express.Router(),
cors = require('cors'),
fs = require('fs-extra'),
formidable = require('formidable');
app.post('/uploadFile', (req, res) => {
const path = './client/public/upload/';
var form = new formidable.IncomingForm();
form.uploadDir = path;
form.encoding = 'binary';
form.parse(req, function(err, fields, files) {
if (err) {
console.log(err);
res.send('upload failed')
} else {
var oldpath = files.files.path;
var newpath = path + files.files.name;
fs.rename(oldpath, newpath, function (err) {
if (err) throw err;
res.send('complete').end();
});
}
});
})

MEAN API using node-restful no response

I'm trying to setup API for multiple projects that use same database structure (running on same CMS) but when I'm trying to reach some data I get no response.
index.js
var express = require("express");
var cors = require("cors");
var mongoose = require("mongoose");
var bodyParser = require("body-parser");
var methodOverride = require("method-override");
var _ = require("lodash");
var passport = require("passport");
var dbconfig = require("./app/config/database");
// Create the application
var app = express();
var user = require("./app/routes/User");
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());
app.use(methodOverride('X-HTTP-Method-Override'));
var connections = [];
// Auto CORS
app.use(cors());
/* Mnual CORS Start
app.use(function(req, res, next){
res.header("Access-Controll-Allow-Origin", "*");
res.header("Access-Controll-Allow-Methods", "GET,PUT,POST,DELETE");
res.header("Access-Controll-Allow-Headers", "Content-Type");
next();
});
/* Manual Cords end */
// Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
require("./app/config/passport")(passport);
app.get("/", (req, res) => {
res.json({ msg: "Nothing here mate" });
});
//------------ THIS IS WORKING ----------------
app.get("/db/:database/navigation", (req, res) => {
var dbname = req.params.database;
var conn = connections[dbname];
var navs = conn.model("navigation", app.models[dbname].navigation);
// Send json data/error
if (navs) navs.find({}, (err, data) => res.json(data));
else res.json({ error: true, msg: "Model not found" });
});
// -------------------------------------------------------
// Setup databases for all projects
_.each(dbconfig.databases, db => {
var appModels = require("./app/models/index");
var processed = 0;
// We will use prefix for all routes /db/:database/
var routePrefix = "/db/" + db.name;
// Use user section
app.use(routePrefix + "/user", user);
// Connection callback - we need to wait for modules to initialize
var connect = () => {
// Initialize connection
connections[db.name] = new mongoose.Mongoose().createConnection(db.url);
// Create some callbacks
connections[db.name].on("connected", () => { console.log("Connected to database " + db.url); });
connections[db.name].on("error", onDatabaseError)
// Once we initialize connection, we need to setup all routes
connections[db.name].once("open", function () {
// Load routes
var routes = require('./app/routes');
// Loop trough routes and use all of them
_.each(routes, function (controller, route) {
var newRoute = routePrefix + route;
app.use(newRoute, controller(app, newRoute, db.name));
});
});
};
// Initialize models
_.each(appModels, (model, index) => {
// Create object if doenst exist
if (app.models == null)
app.models = {};
if (app.models[db.name] == null) {
app.models[db.name] = { [model.name]: model.model };
}
else {
app.models[db.name] = Object.assign(app.models[db.name], { [model.name]: model.model });
}
processed++;
// if this was the last process we are ready to connect
if (processed === appModels.length)
connect();
});
});
app.listen(3000);
app/models/index.js
module.exports = [
{
name: "navigation",
model: require('./Navigation.js')
},
...
];
app/routes.js
module.exports = {
'/navigation': require('./controllers/NavigationController'),
....
};
app/controllers/NavigationController.js
var restful = require("node-restful");
module.exports = function(app, route, dbname){
console.log(route);
var rest = restful.model(
"navigation",
app.models[dbname].navigation
).methods(['get', 'put', 'post', 'delete']);
rest.register(app, route);
// Return middleware
return function(req, res, next){
next();
};
};
Navigation.js is basically just a schema. If I set up route manually like this:
app.get("/db/:database/navigation", (req, res) => {
var dbname = req.params.database;
var conn = connections[dbname];
var navs = conn.model("navigation", app.models[dbname].navigation);
// Send json data/error
if (navs) navs.find({}, (err, data) => res.json(data));
else res.json({ error: true, msg: "Model not found" });
});
it works just fine. I guess I need to assign connection somewhere to restful but I have no idea where. If I use single connection with mongoose.connect() everything works perfectly, but that's not what I need :)
Does anyone have any idea what to do next to get this to work? Will appreciate any help, thanks.
Kind of dug into it and made an extension to change driver reference
Here are all the changes, hope it helps someone in future :)
extensions/restful/index.js
var restful = require("node-restful"),
model = require("./model"),
mongoose = require('mongoose');
exports = module.exports = restful;
exports.model = model;
exports.mongoose = mongoose;
extensions/restful/model.js
exports = module.exports = model;
exports.changeDriver = function(driver){
mongoose = driver;
}
// original model function from node-restful/lib/model.js
function model() {
var result = mongoose.model.apply(mongoose, arguments),
default_properties = defaults();
if (1 === arguments.length) return result;
for (var key in default_properties) {
result[key] = default_properties[key];
}
return result;
}
app/controllers/navigation.js
var restful = require("../extensions/restful");
module.exports = function(app, route, db)
{
restful.model.changeDriver(db.mongoose);
// Setup controller REST
var rest = restful.model(
"navigation",
app.models[db.name].navigation
).methods(['get', 'put', 'post', 'delete']);
// Register this endpoint with the application
rest.register(app, route);
// Return middleware
return function(req, res, next){
next();
};
};
index.js
....
var connect = () => {
// Initialize connection
var $db = databases[_db.name] = {
mongoose: new mongoose.Mongoose(),
name: _db.name
};
$db.mongoose.connect(_db.url);
// Create some callbacks
$db.mongoose.connection.on("connected", () => { console.log("Connected to database " + _db.url); });
$db.mongoose.connection.on("error", (err) => { console.log("Database error: " + err); });
// Once we initialize connection, we need to setup all routes
$db.mongoose.connection.once("open", function () {
// Custom routes for user section
var userRoutes = new UserRoutes($db.mongoose);
app.use(routePrefix + "/user", userRoutes.getRouter());
// Load routes
var routes = require('./app/routes');
// Loop trough routes and use all of them
_.each(routes, function (controller, route) {
var newRoute = routePrefix + route;
app.use(newRoute, controller(app, newRoute, $db));
});
});
};
....

NodeJS - Converting GPX to Geojson return empty array

I have a form where the user upload a GPX file and is then converted into Geojson, I use mapbox/togeojson module to achieve it and I have this code :
const togeojson = require ('togeojson')
const jsdom = require('jsdom');
const { JSDOM } = jsdom;
const fs = require ('fs');
const DOMParser = require('xmldom').DOMParser;
const multer = require('multer');
const upload = multer({ dest: 'uploads/' })
module.exports = (express, Courses) => {
var courses_router = express.Router()
courses_router.route('/')
.post(upload.single('gpxFile'),(req, res, next) => {
let file = req.file
if (file) {
console.log("Uploaded : " + file.originalname + " to " + file.path)
fs.readFile(file.path, (err, data) => {
// let gpxJSDOM = new JSDOM(data)
let gpx = new DOMParser().parseFromString(file.path, 'text/xml');
let converted = togeojson.gpx(gpx)
})
}
// var path = utils.ModifyString(req.body.title)
// return false;
// course_container.CreateCourses(Courses, req, res, path)
})
When I log the result of converted, I get : { type: 'FeatureCollection', features: [] }, which looks like Geojson structure but is not filled with the corresponding datas (I have checked on an online convertor that my GPX datas are good)
I also tried using JSDOM as this tutorial suggests but with no results, I guess there is some data manipulation that is wrong on my code but I have no clue where.
Found the answer ! I didn't need the read the file, I just had to get the path of the uploaded file and then pass it to the new DOMParser() function to finally be converted in GeoJson (And didn't need JSDOM at all)
const course_container = require('./../../containers/CourseContainer');
const utils = require('./../../../utils/functions')
const togeojson = require ('togeojson')
const fs = require ('fs');
const DOMParser = require('xmldom').DOMParser;
const multer = require('multer');
const path = require('path');
const upload = multer({ dest: 'uploads/' })
module.exports = (express, Courses) => {
var courses_router = express.Router()
courses_router.route('/')
.post(upload.single('gpxFile'),(req, res, next) => {
var file = req.file
if (file) {
var absolutePath = path.resolve(file.path);
var gpx = new DOMParser().parseFromString(fs.readFileSync(absolutePath, 'utf8'));
var geoJson = togeojson.gpx(gpx)
}
var course_path = utils.ModifyString(req.body.title)
course_container.CreateCourses(Courses, req, res, course_path, geoJson)
})

Multiple image upload using Node.js

I am working on Node.js and trying to handle multiple image.
I am using following code to upload a single image and then saving the path in string format to the database.
var multiparty = require("multiparty");
var form = new multiparty.Form();
form.parse(req, function(err, fields, files) {
var img = files.image[0];
var fs = require('fs');
fs.readFile(img.path, function(err, data) {
var path = "/path/to/upload/" + img.originalFilename;
fs.writeFile(path, data, function(error) {
if (error) console.log(error);
});
});
})
Now how to handle multiple image.
Any help will be appreciated!
var express = require('express'),
app = express(),
formidable = require('formidable'),
util = require('util'),
fs = require('fs-extra'),
bodyparser=require('body-parser'),
qt = require('quickthumb'),
path = require('path');
var mongoose = require('mongoose');
mongoose.connect('mongodb://localhost/db');
var Images = require('./model.js');
app.use(qt.static(__dirname + '/'));
app.use(bodyparser());
app.set('view engine','ejs');
app.post('/upload',function (req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files) {
});
form.on('field',function(name,value){
});
form.on('end', function(fields, files) {
for(var x in this.openedFiles)
{
//Images is my model
var img = new Images();
var temp_path = this.openedFiles[x].path;
/* The file name of the uploaded file */
var file_name = this.openedFiles[x].name;
//console.log('file '+file_name);
img.size = this.openedFiles[x].size;
img.type = this.openedFiles[x].type;
/* Location where we want to copy the uploaded file */
var new_location = 'uploads/';
console.log(img.nam=new_location+file_name);
img.save(function(err,imgobj) {
if (err)
throw err;
});
//to copy the file into a folder
fs.copy(temp_path, new_location + file_name, function(err) {
if (err) {
console.log(err);
}
});//fscopy
}//for loop
});//form end
res.send('Done!!');
});//post
app.listen(3000);
console.log('started server');

req.params undefined in module

I have an working api for serving images in a route in my server.js and want to abstract it to a separate module.
before:
app.get('/api/image/:filename', function(req, res){
var resourcePath = 'uploads/public/projectnumber/issues/small/' + req.params.filename + '.png';
console.log(resourcePath)
if(fs.existsSync(resourcePath)) {
var file = fs.readFileSync(resourcePath);
res.writeHead(200, 'Content-Type:application/pdf:image/png');
res.end(file,'binary');
}
else {
res.send(400, 'No image found');
}
})
I want something like this:
var ImageRouter = require('./routes/imageRouter');
app.use('/api/image/:filename', ImageRouter);
and I've tried writing it like this in my imageRouter.js file:
var express = require('express');
var fs = require('fs');
var router = express.Router();
router.use(function(req, res, next) {
var resourcePath = 'public/images/' + req.params.filename + '.png';
if(fs.existsSync(resourcePath)) {
var file = fs.readFileSync(resourcePath);
res.writeHead(200, 'Content-Type:application/pdf:image/png');
res.end(file,'binary');
}
else {
res.send(400, 'No image found');
}
next();
});
module.exports = router;
But req.params.filename is undefined. Where have I gone wrong?
Thanks!
You should use get() on your imageRouter.js Router and prefix it on your main app.
use() is for middlewares.
Here is imageRouter.js:
var router = require('express').Router();
var fs = require('fs');
router.get('/:filename', function(req, res) {
var resourcePath = 'public/images/' + req.params.filename + '.png';
if(fs.existsSync(resourcePath)) {
var file = fs.readFileSync(resourcePath);
res.writeHead(200, 'Content-Type:application/pdf:image/png');
res.end(file,'binary');
}
else {
res.send(400, 'No image found');
}
});
module.exports = router;
And your server.js:
var express = require('express');
var app = express();
var ImageRouter = require('./routes/imageRouter');
app.use('/api/image', ImageRouter);

Resources