file still uploads with multer even after failed form validation - node.js

I have a form for adding a product which lets a user input product name, description etc. and also allows an image upload.
In my app.js file which is my entry point, I have:
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'uploads');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
}
};
app.use(multer({ storage: fileStorage , fileFilter: fileFilter, limits: { fileSize: 100000} }).single('image'));
Here is my controller:
exports.postAddListing = (req, res, next) => {
const title = req.body.title;
const category = req.body.category;
const description = req.body.description;
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(422).render('account/add-listing', {
pageTitle: 'Add Item',
path: '/account/add-listing',
errorMessage: errors.array(),
successMessage: null,
oldInput: {
title: title,
description: description
}
});
}
const image = req.file;
const imageUrl = image.path;
const product = new Product({
title: title,
category: category,
description: description,
userId: req.user,
datePosted: Date.now(),
imageUrl: imageUrl
});
product.save()
.then(result => {
const successMessage = req.flash('success', 'Item sucessfully added');
res.redirect('/account/add-listing');
})
.catch(err => console.log(err));
};
I am using express-validator for form validation. The problem I have is that if I for example leave all fields empty but choose an image, validation will fire and I will get error messages but the image will still upload. If form validation fails I don't want the image to upload but not sure how to achieve that.

Related

Multer typescript error next(err) is not a function

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);

Upload multiple files in node.js using multer

I am creating a node.js app in which there will be an option of uploading the documents.
The front-end Scenario: There will be three fields 1) profile picture 2) user's ID card no 1 (eg. PAN card) 3) user's Id card no 2 (eg. AADHAR card) -> this all field will be in a single page
Now the concern is whenever user uploads the documents I want to save it in a such a way that profile_picture should be considered as 0, user's ID card no 1 should be considered as 1 and so on.
The user schema:
const userSchema = new mongoose.Schema(
{
profile_picture: { type: Array },
documents: {
type: Array,
},
...
{
timestamps: true,
}
);
The uploadDocument service function:
exports.uploadDocuments = async (_id, file) => {
let document = await User.findByIdAndUpdate(
{ _id },
{
$set: { registration_process_value: 99 },
$push: file, //The actual problem is here
},
{ new: true }
);
return document;
};
the controller:
exports.uploadDocuments = catchAsync(async (req, res) => {
try {
check_user = await getUser.getUser(req.data.id);
if (!check_user) return res.status(404).json({ message: "User not found" });
if (check_user.registration_process_value >= 4) {
let uploadDocument = await userService.uploadDocuments(
check_user.id,
req.files
);
return res.status(200).json({ data: uploadDocument });
}
return res.status(404).json({ message: "You are not a verified user" });
} catch (error) {
return res.status(400).json({ message: error });
}
});
The multer function:
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./src/uploads/");
},
filename: function (req, file, cb) {
cb(
null,
file.fieldname + "-" + Date.now() + path.extname(file.originalname)
);
},
});
var upload = multer({
storage: storage,
fileFilter: function (req, file, cb) {
var filetypes = /jpeg|jpg|png|pdf/;
var mimetype = filetypes.test(file.mimetype);
var extname = filetypes.test(path.extname(file.originalname).toLowerCase());
if (mimetype && extname) {
return cb(null, true);
}
cb("Please upload valid file");
},
}).fields([
{ name: "documents", maxCount: 2 },
{ name: "profile_picture", maxCount: 1 },
]);
I literally have no idea how to accomplish that. Can anyone assist me here?

Using multer when I upload an image it shows me a message that image has been successfully added but does not added to upload folder

Here's my code to upload and save image in database , when I do this
on postman it gives an error of 'undefined' but 'file uploaded
successfully' and neither did my image/file is stored in upload folder
//multerfile
const multer = require('multer');
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'originalname');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString().replace(/:/g, '-') + '-' + file.originalname);
}
});
const filefilter = (req, file, cb) => {
if (file.mimetype === 'image/png' || file.mimetype === 'image/jpg'
|| file.mimetype === 'image/jpeg'){
cb(null, true);
}else {
cb(null, false);
}
}
const upload = multer({storage: storage, fileFilter: filefilter});
module.exports = {upload}
//imagedata model
const mongoose=require('mongoose');
const imageSchema=new mongoose.Schema({
fileName: {
type: String,
required: true
},
filePath: {
type: String,
required: true
},
fileType: {
type: String,
required: true
},
fileSize: {
type: String,
required: true
}
}, {timestamps: true});
module.exports=mongoose.model('imagedata', imageSchema);
//post controller
exports.uploadimage = async (req, res, next) => {
try{
const file= req.file;
console.log(file);
res.status(201).json({messsage:"file uploaded successfully"})
}catch(error){
res.status(400).send(error.message)
}
u have not specified the destination where u want to save the file
create a folder named uploads in ur project and make changes as I have mentioned below:
destination: (req, file, cb) => {
cb(null, 'uploads/originalname');
},

why image is saving as text file in node js

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
}
});

Fake Path File Upload and Retrieve

I am uploading some personal information to Mongo DB via Express Server(Node) and React. The problem is the files aren't uploaded to the 'uploads directory' on my server and on the DB i can see a fake path of the document with file name. How can I retrieve the file to display to user? I am able to retrieve the other personal information
Below are the codes
This is upload middleware
const path = require('path')
const multer = require('multer')
var storage = multer.diskStorage({
destination: function(req, file, cb){
cb(null, __dirname + '/uploads')
},
filename: function(req, file, cb){
let ext = path.extname(file.originalname)
cb(null, Date.now() + ext)
}
})
var upload = multer ({
storage: storage,
fileFilter: function(req, file, callback){
if(
file.mimetype == "image/png" ||
file.mimetype == "document/pdf" ||
file.mimetype == "document/docx"
){
callback(null, true)
}
else{
console.log('Only png, pdf and Docx FILES ALLOWED')
callback(null, false)
}
},
limits: {
fileSize: 1024 * 1024 * 2
}
})
This is Add Project controller
exports.add = (req, res, next) =>{
const { title, category, duration, durationSys, description, budget, addedBy, active,avatar} = req.body
let newProject = new Project({
title,
category,
duration,
durationSys,
description,
budget,
addedBy,
active,
avatar
})
if(req.file){
newProject.avatar = req.file.path
}
newProject.save()
.then(response =>{
res.json({
message: 'Project added successfully'
})
.catch(error =>{
res.json({
message: 'An error ocurred. Try again'
})
})
})
};
This is the route
router.post('/addproject', upload.single("avatar"), add)
Frontend
const Project= ({history}) => {
const [values, setValues] = useState({
title: '',
category: '',
duration:'',
durationSys: '',
description: 'Describe your project vividly here',
avatar: '',
active:'true',
budget:'',
addedBy: (isAuth().email),
buttonText: 'Post'
});
const { title, category, duration, durationSys,description,avatar,
active,addedBy, budget, buttonText } = values;
const handleChange = name => event => {
setValues({ ...values, [name]: event.target.value } );
};
const clickSubmit = event => {
event.preventDefault();
setValues({ ...values, buttonText: 'Posting Project...' });
console.log(avatar)
axios({
method: 'POST',
url: `${process.env.REACT_APP_API}/addproject`,
data: { title, category, duration, durationSys, description,
avatar, active, addedBy, budget }
})
.then(response => {
console.log('PROJECT ADD SUCCESS', response);
setValues({ ...values, title: '', category: '', duration:
'', durationSys: '',budget: '', description:'',avatar: '',
addedBy: '', buttonText: 'Success' });
toast.success(response.data.message);
})
.catch(error => {
console.log('PROJECT ADD ERROR', error.response.data);
setValues({ ...values, buttonText: 'Try Again' });
toast.error(error.response.data.error);
});
};

Resources