So I am having an issue with multer that i can't figure out. When I add an item with an image everything works with no issues but if I try to add an item with no image it fails. I have an if statement that will define a default image if req.file is undefined but it fails with the error saying req.file.filename is undefined ... Here is the code
Multer setup:
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, "./public/uploads");
},
filename: function(req, file, callback) {
callback(null, Date.now() + file.originalname);
}
});
var upload = multer({ storage: storage }).single("file");
route:
router.post("/item/add", middleware.isLoggedIn, (req, res) => {
User.findById(req.user._id, (err, user) => {
upload(req, res, err => {
if (err) {
req.flash("error", "failed to upload file");
return res.redirect("/products");
}
var item = new Item();
item.name = req.body.name;
item.description = req.body.description;
item.price = req.body.price;
item.createdBy = { id: req.user._id, username: req.user.username };
if (typeof req.file === undefined) {
item.image = "/uploads/no-img.png";
} else {
item.image = "/uploads/" + req.file.filename;
}
item.save(function(err) {
if (err) {
res.send(err);
}
return res.redirect("/products");
});
});
});
});
So I guess my question is... How would I set this up where it wont fail with no image selected?
Your problem is here:
if (typeof req.file === undefined) {
typeof returns a string.
Your check should be if (typeof req.file === "undefined") {
Related
I am developing a MEAN stack app for photo upload and I'm encountering an issue with the follow error. Currently testing this endpoint with postman, everytime I upload an image to the folder the server will stop running and I recieve this error. Any help would be appreciated
node_modules\multer\lib\make-middleware.js:45make-middleware.js:45
next(err)
^
TypeError: next is not a function
In my post.controller.js
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads');
},
filename: function (req, file, cb) {
cb(null, file.originalname + '-' + Date.now() + '-' + getExtension(file));
},
});
const upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5,
},
});
const getExtension = (file) => {
// this function gets the filename extension by determining mimetype. To be exanded to support others, for example .jpeg or .tiff
var res = '';
if (file.mimetype === 'image/jpeg') res = '.jpg';
if (file.mimetype === 'image/png') res = '.png';
return res;
};
(exports.create = upload.single('imagePath')),
async (req, res, next) => {
try {
console.log(req.file, req.body);
const { title, date } = req.body;
const imagePath = req.file.path;
const post = new Posts({
title,
date,
imagePath,
});
await post.save();
return res.status(200).json({
success: true,
post,
});
} catch (error) {
return res.status(500).json({
success: false,
message: 'Server Error',
error: error,
});
}
};
And my posts.route.js
const express = require('express');
const PostsController = require('../controllers/posts.controller');
const Auth = require('../auth/auth');
const multer = require('multer');
const route = express.Router();
route.post('/create', Auth.authenticateJWT, (req, res) => {
PostsController.create(req, res);
});
route.get('/', Auth.authenticateJWT, (req, res) => {
PostsController.getAllPosts(req, res);
});
route.get('/:id', Auth.authenticateJWT, (req, res) => {
PostsController.getPost(req, res);
});
module.exports = route;
You should define create as:
exports.create = async (req, res, next) => {
try {
console.log(req.file, req.body);
const { title, date } = req.body;
const imagePath = req.file.path;
const post = new Posts({
title,
date,
imagePath,
});
await post.save();
return res.status(200).json({
success: true,
post,
});
} catch (error) {
return res.status(500).json({
success: false,
message: 'Server Error',
error: error,
});
}
};
Export the upload variable:
const storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads');
},
filename: function (req, file, cb) {
cb(null, file.originalname + '-' + Date.now() + '-' + getExtension(file));
},
});
exports.upload = multer({
storage: storage,
limits: {
fileSize: 1024 * 1024 * 5,
},
});
And use it as a middleware:
route.post('/create', Auth.authenticateJWT, PostsController.upload('imagePath'), PostsController.create);
Here i'm trying to save the image in database using multer but image type is saving as a text format but not in .png , .jpeg, .jpg format,
PLease help me where i'm doing wrong thanks in advance
Schema:-
module.exports = mongoose => {
const Role = mongoose.model(
"role",
mongoose.Schema(
{
roleType : { type:String },
image: { type: String,
data: Buffer}
}
)
);
return Role;
};
controller (Creating an instance):-
exports.addRoleFields = async (req, res) => {
const rolesList = new Role ({
roleType : req.body.roleType,
roleImg : req.file.path,
});
rolesList
.save(rolesList)
.then(data => {
res.status(200).send({ data, statusCode: "200" });
})
.catch(err => {
res.status(500).send({
message: err.message || "Some error occurred while creating.",
statusCode: "500"
});
})
}
}
routes:-
module.exports = app => {
const multer = require("multer"),
storage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, 'uploads')
},
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
})
const uploadImg = multer({storage: storage}).single('image');
const roles = require("../controllers/roles.js");
var router = require("express").Router();
router.post("/addRole", uploadImg , roles.addRoleFields);
app.use('/api/roles', router);
};
I simply changed this
filename: function(req, file, cb) {
cb(null, file.fieldname + '-' + Date.now())
}
to
filename: function (req, file, cb) {
cb(null, file.originalname);
}
its working and saving the file
try this for mongodb client
const storage = multer.diskStorage({
destination: async function (req, file, cb) {
let path = 'uploads/' + req.body.path;
if (!fs.existsSync(path)) {
fs.mkdirSync(path, { recursive: true }, (err) => {
if (err) throw err;
});
}
await cb(null, path);
},
filename: function (req, file, cb) {
cb(null, req.body.filename)
}
});
var upload = multer({ storage: storage })
const router = express.Router();
// Upload Image
router.post("/upload", upload.single('image'), (req, res, next) => {
return res.json({
image: req.file.path
});
});
in this upload.single('image'), file should be the name in which formdata carries the file.
in your case,
router.post("/addRole", uploadImg('image'), (req, res)=>{
});
mongoose model
const imgSave = new mongoose.Schema({
img:{
data: Buffer,
contentType: String
}
});
app.post('/manage/edit/:id', uploads, function (req, res) {
if (req.file === undefined) {
req.body.image = '/uploads/' + req.file.no - image.png;
} else {
req.body.image = '/uploads/' + req.file.filename;
}
var id = req.params.id;
Addbook.findOneAndUpdate({
_id: id
}, req.body, function (err) {
if (err) {
return err;
}
res.redirect('/manage/book-details')
});
});
I am using multer package
I have two ways of uploading images to my server one is with Array and the other is using fields.
The only thing that works is the uploadArray for the /status route.. when i'm uploading to /update it gives me this error SyntaxError: Unexpected token < in JSON at position 0.. The controller for the /update is just the same as the postController.js the only difference it that i update fields instead of save new one.
/utils/lib/account.js
const storage = multer.memoryStorage();
// These two image might be available in the req.files depending on what was sent
const upload = multer({storage}).fields([{ name: 'photo', maxCount: 1 }, { name: 'cover', maxCount: 1 }]);
const uploadArray = multer({storage}).array('image', 12);
exports.upload = (req, res, next) => {
upload(req, res, function (err) {
if (err) {
console.log(err);
}
next();
});
};
exports.uploadArray = (req, res, next) => {
uploadArray(req, res, function (err) {
if(err){
console.log(err);
}
next();
});
};
/routes.js
router.route('/status')
.all(helper.verifyToken)
.all(helper.uploadArray)
.get(status.get)
.post(status.new) // file uploads
.delete(status.delete);
router.route('/update')
.all(helper.verifyToken)
.all(helper.upload)
.post(account.update_profile) // file uploads
The only thing that works here is the uploadArray
/postController.js
new:
(req, res) => {
const uri = new DataUri();
const promises = [];
const images = [];
//Get buffer from files
for(let key in req.files){
const obj = req.files[key];
uri.format('.png', obj.buffer);
let uriContent = uri.content;
promises.push(uploadAsync(uriContent)); //upload each image
}
//Init upload
function uploadAsync(buffer){
return new Promise((resolve, reject) => {
cloudinary.v2.uploader.upload(buffer, function(error, result) {
if(error){
reject(error);
}
if(result.url){
images.push(result.url);
resolve(images);
}
});
});
}
Promise.all(promises)
.then(results => {
// Init post model
console.log('test1')
const post = new Post({
post_img: images,
post_description: req.body.description,
post_by: req.body.id,
photoURL: req.body.id,
post_comments: []
});
// Save data
post.save(function(err) {
if(err) {
res.send(err);
}
var leanObject = post.toObject(); // Transform instance to plain JS Object for modification
// Modifications
leanObject['post_by'] = {
_id: leanObject['post_by'],
display_name: req.body.user, // Add current user display name
photo_url: req.body.user_photo
};
res.json({message: 'Success', type: 'success', code: 200, data: leanObject});
});
})
.catch(err => {
console.log(err);
});
},
i export all the secret Api and password and cloudinary credentials to heroku using heroku config:set what syntax do i use now to replace process.env that i was using in development since i am not using .env file in the production. i am looking for syntax to replace the process.env
here is my code:
//----------------------------------------------------------------------------//
//--------------------------Dependencies For Route----------------------------//
//----------------------------------------------------------------------------//
var express = require("express");
var router = express.Router();
var Campground = require("../models/campground");
var middleware = require("../middleware");
var NodeGeocoder = require('node-geocoder');
var multer = require('multer');
var async = require("async");
//Node Geocoder API Configuration
var options = {
provider: 'google',
httpAdapter: 'https',
apiKey: process.env.GEOCODER_API_KEY,
formatter: null
};
var geocoder = NodeGeocoder(options);
//Multer Storage
var storage = multer.diskStorage({
filename: function(req, file, callback) {
callback(null, Date.now() + file.originalname);
}
});
//Multer Filter
var imageFilter = function (req, file, cb) {
// accept image files only
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/i)) {
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
};
//Storing Image + Filter
var upload = multer({ storage: storage, fileFilter: imageFilter});
//Cloudinary Configuration
var cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: 'dnposhqpc',
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET
});
// INDEX - SHOW ALL CAMPGROUNDS
router .get("/", function(req, res){
var perPage = 8;
var pageQuery = parseInt(req.query.page);
var pageNumber = pageQuery ? pageQuery : 1;
var noMatch = null;
if (req.query.search) {
const regex = new RegExp(escapeRegex(req.query.search), 'gi');
// GET ALL CAMPGROUNDS FROM THE DB
Campground.find({"name": regex}, function(err, allCampgrounds){
if(err || !allCampgrounds){
console.log(err);
req.flash("error", "Something went wrong!");
} else {
if(allCampgrounds.length < 1){
noMatch = "No campground match that query, please try again.";
}
res.render("campgrounds/index", {campgrounds:allCampgrounds, page: 'campgrounds', noMatch: noMatch});
}
});
} else {
Campground.find({}).skip((perPage * pageNumber) - perPage).limit(perPage).exec( function(err, allCampgrounds){
Campground.count().exec(function (err, count) {
if(err) {
console.log(err);
} else {
res.render("campgrounds/index", {campgrounds:allCampgrounds, page: 'campgrounds', noMatch: noMatch,
campgrounds: allCampgrounds,
current: pageNumber,
pages: Math.ceil(count / perPage)
});
}
});
})
}
});
//----------------------------------------------------------------//
//-----------------CREATE NEW CAMPGROUNDS -----------//
//----------------------------------------------------------------//
//CREATE - ADD NEW CAMPGROUND TO DB
router.post("/", middleware.isLoggedIn, upload.single('image'), function(req, res){
// local variables
// Request The Name
var name = req.body.name;
// Request The Image
var image = req.body.image;
var imageId = req.body.imageId;
// Request The descriptions
var desc = req.body.descriptions;
// Request The Price
var price = req.body.price;
// Request The Author's ID + Username
var author = {
id: req.user._id,
username: req.user.username
};
//Location Code - Geocode Package
geocoder.geocode(req.body.location, function (err, data ) {
//Error Handling For Autocomplete API Requests
//Error handling provided by google docs -https://developers.google.com/places/web-service/autocomplete
if (err || data.status === 'ZERO_RESULTS') {
req.flash('error', 'Invalid address, try typing a new address');
return res.redirect('back');
}
//Error handling provided by google docs -https://developers.google.com/places/web-service/autocomplete
if (err || data.status === 'REQUEST_DENIED') {
req.flash('error', 'Something Is Wrong Your Request Was Denied');
return res.redirect('back');
}
// Error handling provided by google docs -https://developers.google.com/places/web-service/autocomplete
if (err || data.status === 'OVER_QUERY_LIMIT') {
req.flash('error', 'All Requests Used Up');
return res.redirect('back');
}
//Credit To Ian For Fixing The Geocode Problem - https://www.udemy.com/the-web-developer-bootcamp/learn/v4/questions/2788856
var lat = data[0].latitude;
var lng = data[0].longitude;
var location = data[0].formattedAddress;
//Reference: Zarko And Ian Helped Impliment the Image Upload - https://github.com/nax3t/image_upload_example
cloudinary.uploader.upload(req.file.path, function (result) {
//image variable needs to be here so the image can be stored and uploaded to cloudinary
image = result.secure_url;
imageId= result.public_id;
//Captures All Objects And Stores Them
var newCampground = {name: name, image: image, description: desc, price: price, author:author, location: location, lat: lat, lng: lng, imageId: imageId};
// Create a new campground and save to DB
Campground.create(newCampground, function(err, newlyCreated){
if(err || !newlyCreated){
//Logs Error
req.flash('error', err.message);
return res.redirect('back');
} else {
//redirect back to campgrounds page
//Logs Error
console.log(newlyCreated);
//Flash Message
req.flash("success", "Campground Added Successfully");
//Redirects Back To Featured Campgrounds Page
res.redirect("/campgrounds");
}
});
});
});
});
// NEW - SHOW FORM TO CREATE NEW CAMPGROUND
router.get("/new", middleware.isLoggedIn, function(req, res) {
res.render("campgrounds/new");
});
// SHOW - SHOW ONLY ONE CAMPGROUND FROM THE DB
router.get("/:id", function(req, res) {
// find campround with the Provided id
Campground.findById(req.params.id).populate("comment").exec(function(err, foundcampground){
if(err || !foundcampground){
console.log(err);
req.flash("error", "Sorry, that campground does not exist!");
res.redirect("back"); // you need to redirect the user in case there isn't anything found by the provided id
} else {
console.log(foundcampground);
// render the show template
res.render("campgrounds/show", {campground: foundcampground});
}
});
});
// EDIT CAMPGROUND ROUTE
router.get("/:id/edit", middleware.checkCampgroundOwnership, function(req, res) {
Campground.findById(req.params.id, function(err, foundcampground){
if(err || !foundcampground){
console.log(err);
req.flash("error", "campground not found");
return res.redirect("back");
}
res.render("campgrounds/edit", {campground: foundcampground});
});
});
//----------------------------------------------------------------//
//-----------------Update CAMPGROUNDS -----------//
//----------------------------------------------------------------//
// UPDATE CAMPGROUND ROUTE
router.put("/:id", middleware.checkCampgroundOwnership, upload.single('image'), function(req, res, next){
async.waterfall([
function(done) {
geocoder.geocode(req.body.campground.location, function (err, data) {
if (err || !data.length) {
req.flash('error', 'Invalid address');
return res.redirect('back');
}
done(null, data);
});
},
function(data, done) {
// handle image uploading
Campground.findById(req.params.id, function(err, foundCampground) {
if(err || !foundCampground) {
console.log(err);
req.flash("error", err.message);
return res.redirect("back");
} else {
done(null, foundCampground, data);
}
});
},
function(foundCampground, data, done) {
if(req.file) {
cloudinary.v2.uploader.destroy(foundCampground.imageId, function(err, result) {
if(err) {
req.flash("error", err.message);
return res.redirect("back");
} else {
done(null, foundCampground, data);
}
});
} else {
done(null, foundCampground, data);
}
},
function(foundCampground, data, done) {
// if new image uploaded, destroy the old one
if(req.file) {
cloudinary.uploader.upload(req.file.path, function(result) {
req.body.campground.imageId = result.public_id;
req.body.campground.image = result.secure_url;
done(null, foundCampground, data);
});
} else {
done(null, foundCampground, data);
}
},
function(foundCampground, data) {
// update
// var newCampground = {name: req.name, price: price, image: image, imageId: imageId, description: desc, author:author, location: location, lat: lat, lng: lng};
req.body.campground.lat = data[0].latitude;
req.body.campground.lng = data[0].longitude;
req.body.campground.location = data[0].formattedAddress;
Campground.findByIdAndUpdate(req.params.id, req.body.campground, function(err, campground){
if(err){
req.flash("error", err.message);
res.redirect("back");
} else {
req.flash("success","Successfully Updated!");
res.redirect("/campgrounds/" + campground._id);
}
});
}
], function(err) {
if (err) return next(err);
res.redirect('/campgrounds');
});
});
// DESTORY CAMPGROUND ROUTE
router.delete("/:id", middleware.checkCampgroundOwnership, function(req, res) {
Campground.findByIdAndRemove(req.params.id, function(err, foundcampground){
if(err || !foundcampground){
req.flash("error", "Something went wrong!");
res.redirect("/campgrouns");
} else {
req.flash("success", "You have successfully deleted a campground");
res.redirect("/campgrounds");
}
});
})
// Middleware
function escapeRegex(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};
module.exports = router;
Thanks for your assistance
You use the same syntax.
For example, if I did:
heroku config:set EXAMPLE_NAME=sainteverest
then I can do the following:
console.log(process.env.EXAMPLE_NAME)
// sainteverest