"Cannot read properties of undefined (reading '0') - node.js

I am making a guide's update controller which include name, email, password, avatar[image] and guidelicence[pdf]. It gives the error cannot read undefined at(0) but the same logic runs for signup. I am using multer and cloudinary for form data, and have been stuck for 2 days.
Update Route
routes.put(
"/:userID",
upload.fields([
{ name: "avatar", maxCount: 1 },
{ name: "guidelicense", maxCount: 1 },
]),
update
);
Update Controller
exports.update = async (req, res) => {
try {
// handle the form data
const {
fullname,
password,
email,
address,
isAvalaible,
phonenumber,
cnic,
} = req.body;
// handle the image file
const avatar = req.files.avatar[0];
console.log(req.files.avatar[0]);
// handle the PDF file
const guideLicense = req.files.guidelicense[0];
console.log(req.files.guidelicense[0]);
// upload the image to Cloudinary
cloudinary.uploader.upload(
avatar.path,
{ resource_type: "image" },
(err, image) => {
if (err) throw err;
// store the image URL in the database
const avatarUrl = image.url;
// upload the PDF to Cloudinary
cloudinary.uploader.upload(
guideLicense.path,
{ resource_type: "raw" },
(err, file) => {
if (err) throw err;
// store the PDF URL in the database
const guideLicenseUrl = file.url;
// update the guide's information in the database
Guides.findOneAndUpdate(
{ email },
{
fullname,
password,
avatarUrl,
guideLicenseUrl,
address,
isAvalaible,
phonenumber,
cnic,
},
(err, guide) => {
if (err) throw err;
res.status(200).json({ message: "Guide updated successfully" });
}
);
}
);
}
);
} catch (error) {
res.status(500).json({ message: error.message });
}
};
multer configuration
if (!fs.existsSync("./uploads")) {
fs.mkdirSync("./uploads");
}
// Multer config
module.exports = multer({
storage: multer.diskStorage({
destination: function (req, file, cb) {
cb(null, "./uploads");
},
filename: function (req, file, cb) {
cb(null, file.originalname);
},
}),
limits: { fileSize: 1024 * 1024 * 5 },
fileFilter: (req, file, cb) => {
let ext = path.extname(file.originalname);
if (ext !== ".jpg" && ext !== ".jpeg" && ext !== ".png" && ext !== ".pdf") {
cb(new Error("File type is not supported"), false);
return;
}
cb(null, true);
},
});
i wanted to get guide updated successfully but got
{
"message": "Cannot read properties of undefined (reading '0')"
}
error

You need to parse the req before accessing it.
Use the parsed "request" to access the data.
const request = JSON.parse(req);

Related

React Native && Node js How to upload image

I am having trouble uploading an image from my react native app. I have a react app that uploads images to the backend from camera as a file.
let pic = await camera.current.takePictureAsync({
quality: 1,
base64: true,
});
setPicture(pic);
Then
onPress={() => {
const formData = new FormData();
formData.append("file", {
name: picture + "",
type: picture.type,
uri:
Platform.OS === "ios"
? picture.uri.replace("file://", "")
: picture.uri,
});
console.log(formData);
httpClient
.post("demo/testsaveimg", formData)
.then((request) => {
if (request.data == "ok") {
console.log(request.data);
}
});
}}
This is my Formdata to service
and then, here is my service
app.post('/testsaveimg', async function (req, res, next) {
let storageUploadFile = multer.diskStorage({
destination: (req, file, next) => {
const folder = './test/'
if (!fs.existsSync(folder)) {
fs.mkdirSync(folder)
}
next(null, folder)
},
filename: (req, file, next) => {
const ext = file.mimetype.slice("/")[1]
next(null, `${file.fieldname}-${Date.now()}.${ext}`)
}
})
let UploadFile = multer({ storage: storageUploadFile }).single("files");
UploadFile(req, res, async function (err) {
console.log(req.file);
if (err instanceof multer.MulterError) {
return res.status(500).json(err);
} else if (err) {
console.log(99);
return res.status(500).json(err);
}
if (req.file != undefined) {
console.log("ok");
res.json("ok")
} else {
console.log("no");
res.json("no")
}
})
})
But there are no pictures in the folder "./test/" and response is "no"
that means "req.file = undefined"
What steps am I doing wrong?
or is there another way to write?

uploading files from react to node js with multer

I want to upload files from the form data in react which is being posted by axios like this.
const addNewProduct = () => {
const newProduct = {
name: name,
cost: cost,
size: size,
color: color,
material: material,
discount: discount,
description: description,
category: category
};
const nulls = Object.values(newProduct).filter(p => p === null);
if(nulls.length === 0 && images.imageFiles) {
let productFormData = new FormData();
productFormData.append('productInfo', JSON.stringify(newProduct));
productFormData.append('productImages', images.imageFiles);
const addUrl = "http://localhost:8080/cpnl/addproduct";
axios({
method: "POST",
url: addUrl,
data: productFormData,
headers: { "Content-Type": "multipart/form-data" }
})
.then((response) => {
console.log(response.data.msg);
})
.catch((response) => {
console.error(response);
});
}else {
Notiflix.Notify.Warning("Check your inputs!");
console.log(nulls);
console.log("product: \n" + JSON.stringify(newProduct));
}
};
then I want to upload images with multer to images folder. this is my code:
const storage = multer.diskStorage({
destination: "./public/images",
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
const upload = multer({
storage: storage,
limits:{fileSize: 1000000},
fileFilter: function(req, file, cb){
checkFileType(file, cb);
}
}).array("productImages", 5);
function checkFileType(file, cb) {
// Allowed ext
const filetypes = /jpeg|jpg|png/;
// Check ext
const extname = filetypes.test(path.extname(file.originalname).toLowerCase());
// Check mime
const mimetype = filetypes.test(file.mimetype);
if(mimetype && extname){
return cb(null,true);
} else {
cb('Error: Images Only!');
}
}
//receive form data from front-end and add new product to database
router.post('/addproduct', async (req, res) => {
upload(req, res, (err) => {
if(err) {
res.status(400).json({
msg: err
});
} else {
if(req.files == undefined) {
res.status(400).json({
msg: "Error: No file selected! please contact the developer."
});
} else {
data = req.body.productInfo;
res.status(200).json({
msg: "Files uploaded!"
});
console.log( "images: " + req.files);
console.log("data" + data);
}
}
});
});
first problem: I'm getting image files inside req.body.productImages and not inside req.files
second problem: when I send the request node js throws me this error:
TypeError: upload is not a function
why everything is messed up!?
Edit: I restarted the server and now I'm getting data but the files are not being uploaded. no error is shown.
UPDATE: second problem fixed
First Problem : You have used .array("productImages", 5); in your upload function. use .array("files", 5); to get the file in req.files.
Second Problem : I guess there is some typo error in your code upload(req, res, (err)... there is one extra bracket it should be only upload(req,res,err )...

How can i change the size of images with multer with sharp?

I built a web app and want to resize my images to be smaller for better quality to my profile pictures. I am using "multer" for upload picture and sharp package for resizing.
For some reason i get this error:
"[0] [Error: D:\DevConnectors\public\resized\5f4f4e0bb295ba36042536bf.jpg: unable to open for write
[0] windows error: The storage control block address is invalid."
My code:
const storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, DIR)
},
filename: (req, file, cb) => {
var typeFile = file.originalname.split(".").pop()
const fileName = req.user.id + "." + typeFile
cb(null, fileName)
},
})
var upload = multer({
storage: storage,
fileFilter: (req, file, cb) => {
if (
file.mimetype == "image/png" ||
file.mimetype == "image/jpg" ||
file.mimetype == "image/jpeg"
) {
cb(null, true)
} else {
return cb(new Error("Only .png, .jpg and .jpeg format allowed!"), false)
}
},
})
const Profile = require("../../moduls/Profile")
const User = require("../../moduls/User")
//#route GET/api/profile/me
//#desc Get current users profile
//#access Private
router.post(
"/upload",
[auth, upload.single("imageProfile")],
async (req, res) => {
try {
console.log(req.file)
const { filename: image } = req.file
await sharp(req.file.path)
.resize(150)
.jpeg({ quality: 50 })
.toFile(path.resolve(req.file.destination, "resized", image))
fs.unlinkSync(req.file.path)
const url = req.protocol + "://" + req.get("host")
let user = await User.findById(req.user.id)
const profile = await Profile.findOne({ user: req.user.id })
//Update
if (user) {
user.avatar = url + "/public/" + req.file.filename
await user.save()
return res.json(profile)
}
} catch (err) {
console.log(err)
}
}
)
This happens at this line :
path.resolve(req.file.destination,'resized',image))
What am i doing wrong? i am using sharp docs.
Try this
Configuration of multer ( change it according to your needs)
import multer from "multer";
import sharpe from "sharp";
const upload = multer({ //multer configuration
//dest: "avatars", //so that buffer is available in route handler
limits: {
fileSize: 1000000,
},
fileFilter(req, file, cb) { // object method shorthand syntax
if (!file.originalname.match(/\.(jpg|jpeg|png)$/)) { //.match for using regex b/w (//)
return cb(new Error("Please upload a IMAGE"));
}
cb(undefined, true);
},
});
handle sharp in your route handle like this.
router.post(
"path",
upload.single("avatar"),
async (req, res) => {
const buffer = await sharpe(req.file.buffer)
.png()
.resize({
width: 300,
height: 300
})
.toBuffer();
req.user.avatar = buffer;
await req.user.save();
res.send();
},
(error, req, res, next) => {
//to tell express this how mutler/s error should be handled
res.status(400).send({
error: error.message,
});
}
);
I had the same problem, and in my case the issue was that the directory (in your case "resized") didn't exist yet. So either create it manually or programmatically like this:
const targetPath = path.resolve(req.file.destination, 'resized')
if (!existsSync(targetPath)) {
mkdirSync(targetPath);
}
await sharp(...)

I want to upload a file locally then upload that file to S3. However Multer only allows one or the other at a time

My goal is the following:
I want to get user uploaded PDF, extract the Text from within that PDF, assign the text to an array object. Once this is done I want to upload that file to an S3 bucket. Right now I am able to to do the first part without much issue. The reason why I am doing the local upload in the first place is so I can do the text extraction from PDF. These methods work on their own. If i want to upload to S3 it will and the database gets populated with the link for me to show it on the front-end but the BulletinMetaText field does not get populated with the extract text.
What way should I go about doing this?
If I have not been clear please let me know what more I can provide..
Multer methods:
let uploadToS3 = multer({
storage: multerS3({
s3: s3,
acl: "private",
bucket: env == "production" ? "xxxx" : "xxxx",
// metadata: function(req, file, cb) {
// console.log(file);
// console.log(req.body);
// cb(null, Object.assign({}, req.body));
// },
key: function(req, file, cb) {
// console.log(file);
cb(null, `${new Date().getFullYear()}/${file.originalname}`);
}
})
}).array("files");
// }).any();
var tempStorage = multer.diskStorage({
destination: function(req, file, cb) {
cb(null, "client/v1.7/src/assets/pdf/");
},
// By default, multer removes file extensions so let's add them back
filename: function(req, file, cb) {
cb(null, `${file.originalname}`);
}
});
var uploadToLocal = multer({ storage: tempStorage }).array("files");
let delay = time => {
return new Promise((resolve, reject) => {
setTimeout(function() {
resolve("DONE");
}, time);
});
};
Node/express Backend
if (req.params.type === "files") {
uploadToLocal(req, res, function(err) {
if (err) {
next({
status: 500, //Server Error
statusMessage: "Error: Failed to save file ",
catchError: err //System error
});
} else {
//TODO
let {
bulletinID,
bulletinUUID,
bulletinActive,
bulletinType,
bulletinCode,
bulletinGroup,
bulletinEn,
bulletinFr,
bulletinTitleEn,
bulletinDescriptionEn,
bulletinTitleFr,
bulletinDescriptionFr,
metaStringTags,
bulletinPermission
} = req.body.model;
uploadToS3(req, res, function(err) {
console.log("upload2Req");
console.log(req.body);
let bulletinFileEn,
bulletinFileFr = "";
// console.log("req.files");
console.log(req.files);
req.files.forEach(file => {
if (file.originalname && file.originalname.includes("_en")) {
console.log("file");
console.log(file);
console.log(file.key);
bulletinFileEn = file.key;
}
if (file.originalname && file.originalname.includes("_fr")) {
bulletinFileFr = file.key;
}
});
console.log(bulletinFileEn);
console.log(bulletinFileFr);
extract(
"client/v1.7/src/assets/pdf/test.pdf",
// req.files.originalname,
{ splitPages: false },
function(err, text) {
if (err) {
console.log(err);
return;
}
console.log("text");
// console.log(text);
bulletinMetaText = text;
if (err) {
next({
status: 500, //Server Error
statusMessage: "Error: Failed to save file locally ",
catchError: err //System error
});
} else {
// !~
let newBulletin = {
bulletinID: bulletinID ? bulletinID : "NULL",
bulletinUUID: bulletinUUID ? bulletinUUID : uuid(),
bulletinActive: bulletinActive ? bulletinActive : true,
postedByUserID: req.user.id,
postedByUserUUID: req.user.userUUID,
bulletinType: bulletinType,
bulletinCode: bulletinCode,
bulletinGroup: bulletinGroup,
bulletinEn: bulletinEn ? true : false,
bulletinFr: bulletinFr ? true : false,
//English Bulletin - File/Link
bulletinTitleEn: bulletinTitleEn,
bulletinDescriptionEn: bulletinDescriptionEn,
bulletinLinkEn: null,
bulletinFileEn: bulletinFileEn,
//French Bulletin - File/Link
bulletinTitleFr: bulletinTitleFr,
bulletinDescriptionFr: bulletinDescriptionFr,
bulletinLinkFr: null,
bulletinFileFr: bulletinFileFr,
metaStringTags: metaStringTags,
bulletinPermission: bulletinPermission,
bulletinTextScrape: bulletinMetaText
};
console.log(newBulletin);
InsertOrUpdateBulletin(newBulletin, req.user)
.then(result => {
res.status(200).json({
data: result,
status: 200, //Created
statusMessage: "Success: Bulletin Created"
});
})
.catch(error => {
next({
status: 500, //Server Error
statusMessage: "Error: Failed to save Bulletin ",
catchError: error //System error
});
});
}
}
);
});
}
});
}
This might help (keyword: might) but it uses express-fileupload. Still allows for server side manipulation of the data.
https://link.medium.com/U1SdsoHMy2

Using Multer, how do I delete the previous image file from storage after a user uploaded another image?

I'm a newbie trying to learn Nodejs. I've been trying to resolve an issue using an NPM module called Multer. I can't seem to write the right code to delete a User's image file or overwrite if the user uploads another one. Sorry for the inconvenience. Please help
My Delete Route works perfectly deleting both the "Posts" and "Image". However, my edit Route gives the below error
{"Error":{"errno":-4058,"syscall":"unlink","code":"ENOENT","path":"C:\cms\public\uploads\image-1568050604308.png"}}
const publicUploads = path.join(__dirname, '../../../public/uploads/');
const storage =
multer.diskStorage({
destination: publicUploads,
filename(req, file, cb){
cb(null,`${file.fieldname}-${Date.now()}${path.extname(file.originalname)}`)
}
});
const upload = multer({
storage,
limits: {
fileSize: 1000000
},
fileFilter(req, file, cb){
if(!file.originalname.match(/\.(jpeg|jpg|png)$/)){
return cb(new Error('Please upload an image file'))
}
cb(null, true)
}
})
router.put('/admin/posts/edit/:id', upload.single('image'), async (req, res) => {
const updates = Object.keys(req.body);
const allowedUpdates = ['title', 'body', 'status', 'image', 'allowComments'];
const isValid = updates.every(update => allowedUpdates.includes(update));
if(!isValid){
return res.send({Error: 'Invalid Update'})
}
try {
const post = await Post.findOne({_id: req.params.id});
if(!post){
return res.send({Error: 'Could not find your post'})
}
if(req.file){
fs.unlinkSync(`${publicUploads}${post.image}`);
post.image = req.file.filename
}
updates.forEach(update => {
post[update] = req.body[update]
})
post.allowComments = req.body.allowComments === 'on'? true:false;
await post.save();
req.flash('notice', 'Your post was edited successfully!')
res.status(200).redirect('/admin/posts')
} catch (error) {
res.send({Error: error})
}
}, (error, req, res, next) => {
res.send({Error: error})
})
You can delete the image natively with the Node package "fs". You don't need to use Multer for this:
// Remove old photo
if (oldPhoto) {
const oldPath = path.join(__dirname, "..", "images", oldPhoto);
if (fs.existsSync(oldPath)) {
fs.unlink(oldPath, (err) => {
if (err) {
console.error(err);
return;
}
res.status(200).send(userObj);
});
}
}

Resources