not updating if file is not selected in nodejs using multer - node.js

I am trying to update the data. It's working fine if I select the file but there is a problem when I just want to update any field excluding file input type. I am not able to update in such a condition.
How can I resolve it?
var storage = multer.diskStorage({
destination: function (req, file, cb) {
cb(null, './public/uploads/')
},
filename: function (req, file, cb) {
cb(null, file.originalname+Date.now()+path.extname(file.originalname))
}
});
var upload = multer({
storage:storage,
});
app.post('/editProfile', auth, upload.single('image'), async (req, res, next) => {
try {
const userEmail = req.user.email;
const name = req.body.name;
const filename = req.file.filename;
const contact = req.body.contact;
console.log(filename + "fghj");
if(filename) {
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
filename:filename
}
});
}
else {
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
}
});
}
res.redirect('profile');
}
catch (e) {
console.log(`while edit profile ${e}`);
res.status(400).send(e);
}
})

You are trying to get filename but remember you didn't send a file in your scenario. Here:
const filename = req.file.filename;
First, you should check if a file is exist or not.
You can revise your code like this:
app.post('/editProfile', auth, upload.single('image'), async (req, res, next) => {
try {
const userEmail = req.user.email;
const name = req.body.name;
// const filename = req.file.filename; Remove this line from here
const contact = req.body.contact;
if (req.file) {
const filename = req.file.filename // And, use that code when you make sure that you have a file
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
filename: filename
}
});
}
else {
const edited = await User.updateOne({ 'email': userEmail }, {
$set: {
name: name,
contact: contact,
}
});
}
res.redirect('profile');
}
catch (e) {
console.log(`while edit profile ${e}`);
res.status(400).send(e);
}
})

Related

how to upload image files to server and MongoDB

React.js Node.js Express.js Axios Multer MongoDB Mongoose
Wrote this form to register users, the user enters name, email, password, and a file for later use as profile pic/Avatar.
When i tested the form on Postman the opposite has happened, the file was uploaded to the public/uploads/images folder but it didnt post to the user with the rest of the registration data i entered.
But when i tested the form on localhost domain the image filename was saved on the user's Avatar value MongoDB nut was'nt uploaded to the servers folder i chose to upload my uploaded files.
wanted end result:
to register user to websites database with all parameters, uploading the image to the server and image filename to users avatar data
Register Route
router.post("/register", upload.single("avatar"), async (req, res) => {
try {
const validatedValue = await validateRegisterSchema(req.body);
const user = await findUserByEmail(validatedValue.email);
if (user) throw "try different email";
const hashedPassword = await createHash(validatedValue.password);
validatedValue.password = hashedPassword;
await createNewUser(validatedValue);
res.status(201).json({ msg: "user created"});
} catch (error) {
res.status(400).json({ error });
}
});
Multer
destination: (req, file, cb) => {
cb(null, "./public/uploads/images/");
},
filename: function (req, file, cb) {
crypto.pseudoRandomBytes(16, function (err, raw) {
if (err) return cb(err);
cb(null, file.originalname);
});
},
});
const fileFilter = (req, file, cb) => {
if (file.mimetype === "image/jpeg" || file.mimetype === "image/png") {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage,
limit: {
fileSize: 1024 * 1024 * 10,
},
fileFilter,
});
User Model
const Schema = mongoose.Schema;
const usersSchema = new Schema({
name: { type: String, required: true },
email: { type: String, required: true, unique: true },
password: { type: String, required: true },
wishList: { type: Array },
isAdmin: { type: Boolean, default: false },
avatar: { type: String },
});
const Users = mongoose.model("users", usersSchema);
const createNewUser = (userData) => {
const newUser = new Users(userData);
return newUser.save();
Solved
prior code:
const handleAvatarChange = (ev) => {
let newUserInput = JSON.parse(JSON.stringify(userInput));
newUserInput[ev.target.name] = ev.target.files[0].name;
setUserInput(newUserInput);
};
sulution:
const handleAvatarChange = (ev) => {
let newUserInput = JSON.parse(JSON.stringify(userInput));
newUserInput[ev.target.name] = ev.target.files[0]; // removed ".name" left it as file object
setUserInput(newUserInput);
};

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?

"Unauthorized" when attempting to send email with SendGrid in node.js

Not sure what's going on but every time I try to send an email i'm met with a error message. I've literally tried everything I can think of and Nothing. This is the message i'm receiving from postman when I hit the localhost:4000/api/send-mail route. I've been trying to work through this for hours now, if anyone can help that would be amazing. Thanks in advance!!!
{
"message": "Unauthorized",
"code": 401,
"response": {
"headers": {
"server": "nginx",
"date": "Mon, 21 Mar 2022 01:57:04 GMT",
"content-type": "application/json",
"content-length": "116",
"connection": "close",
"access-control-allow-origin": "https://sendgrid.api-docs.io",
"access-control-allow-methods": "POST",
"access-control-allow-headers": "Authorization, Content-Type, On-behalf-of, x-sg-elas-acl",
"access-control-max-age": "600",
"x-no-cors-reason": "https://sendgrid.com/docs/Classroom/Basics/API/cors.html",
"strict-transport-security": "max-age=600; includeSubDomains"
},
"body": {
"errors": [
{
"message": "The provided authorization grant is invalid, expired, or revoked",
"field": null,
"help": null
}
]
}
}
}
my user controllers code
const expressAsyncHandler = require("express-async-handler");
const sgMail = require("#sendgrid/mail");
const generateToken = require("../../config/token/generateToken");
const User = require("../../model/user/User");
const validateMongodbId = require("../../utils/validateMongodbID");
sgMail.setApiKey(process.env.SEND_GRID_API_KEY);
//-------------------------------------
//Register
//-------------------------------------
const userRegisterCtrl = expressAsyncHandler(async (req, res) => {
//Check if user Exist
const userExists = await User.findOne({ email: req?.body?.email });
if (userExists) throw new Error("User already exists");
try {
//Register user
const user = await User.create({
firstName: req?.body?.firstName,
lastName: req?.body?.lastName,
email: req?.body?.email,
password: req?.body?.password,
});
res.json(user);
} catch (error) {
res.json(error);
}
});
//-------------------------------
//Login user
//-------------------------------
const loginUserCtrl = expressAsyncHandler(async (req, res) => {
const { email, password } = req.body;
//check if user exists
const userFound = await User.findOne({ email });
//Check if password is match
if (userFound && (await userFound.isPasswordMatched(password))) {
res.json({
_id: userFound?._id,
firstName: userFound?.firstName,
lastName: userFound?.lastName,
email: userFound?.email,
profilePhoto: userFound?.profilePhoto,
isAdmin: userFound?.isAdmin,
token: generateToken(userFound?._id),
});
} else {
res.status(401);
throw new Error("Invalid Login Credentials");
}
});
//------------------------------
//Users
//-------------------------------
const fetchUsersCtrl = expressAsyncHandler(async (req, res) => {
console.log(req.headers);
try {
const users = await User.find({});
res.json(users);
} catch (error) {
res.json(error);
}
});
//------------------------------
//Delete user
//------------------------------
const deleteUsersCtrl = expressAsyncHandler(async (req, res) => {
const { id } = req.params;
//check if user id is valid
validateMongodbId(id);
try {
const deletedUser = await User.findByIdAndDelete(id);
res.json(deletedUser);
} catch (error) {
res.json(error);
}
});
//----------------
//user details
//----------------
const fetchUserDetailsCtrl = expressAsyncHandler(async (req, res) => {
const { id } = req.params;
//check if user id is valid
validateMongodbId(id);
try {
const user = await User.findById(id);
res.json(user);
} catch (error) {
res.json(error);
}
});
//------------------------------
//User profile
//------------------------------
const userProfileCtrl = expressAsyncHandler(async (req, res) => {
const { id } = req.params;
validateMongodbId(id);
try {
const myProfile = await User.findById(id);
res.json(myProfile);
} catch (error) {
res.json(error);
}
});
//------------------------------
//Update profile
//------------------------------
const updateUserCtrl = expressAsyncHandler(async (req, res) => {
const { _id } = req?.user;
validateMongodbId(_id);
const user = await User.findByIdAndUpdate(
_id,
{
firstName: req?.body?.firstName,
lastName: req?.body?.lastName,
email: req?.body?.email,
bio: req?.body?.bio,
},
{
new: true,
runValidators: true,
}
);
res.json(user);
});
//------------------------------
//Update password
//------------------------------
const updateUserPasswordCtrl = expressAsyncHandler(async (req, res) => {
//destructure the login user
const { _id } = req.user;
const { password } = req.body;
validateMongodbId(_id);
//Find the user by _id
const user = await User.findById(_id);
if (password) {
user.password = password;
const updatedUser = await user.save();
res.json(updatedUser);
} else {
res.json(user);
}
});
//------------------------------
//following
//------------------------------
const followingUserCtrl = expressAsyncHandler(async (req, res) => {
//1.Find the user you want to follow and update it's followers field
//2. Update the login user following field
const { followId } = req.body;
const loginUserId = req.user.id;
//find the target user and check if the login Id exists
const targetUser = await User.findById(followId);
const alreadyFollowing = targetUser?.followers?.find(
(user) => user?.toString() === loginUserId.toString()
);
if (alreadyFollowing) throw new Error("You are already folliwig this user");
//1. Find the user you want to follow and update it's followers field
await User.findByIdAndUpdate(
followId,
{
$push: { followers: loginUserId },
},
{ new: true }
);
//2. Update the login user following field
await User.findByIdAndUpdate(
loginUserId,
{
$push: { following: followId },
isFollowing: true,
},
{ new: true }
);
res.json("You are now following this user");
});
//------------------------------
//unfollow
//------------------------------
const unfollowUserCtrl = expressAsyncHandler(async (req, res) => {
const { unFollowId } = req.body;
const loginUserId = req.user.id;
await User.findByIdAndUpdate(
unFollowId,
{
$pull: { followers: loginUserId },
isFollowing: false,
},
{ new: true }
);
await User.findByIdAndUpdate(
loginUserId,
{
$pull: { following: unFollowId },
},
{ new: true }
);
res.json("You have successfully unfollowed this user");
});
//------------------------------
//Block Users
//------------------------------
const blockUserCtrl = expressAsyncHandler(async (req, res) => {
const { id } = req.params;
validateMongodbId(id);
const user = await User.findByIdAndUpdate(
id,
{
isBlocked: true,
},
{ new: true }
);
res.json(user);
});
//------------------------------
//Block user
//------------------------------
const unBlockUserCtrl = expressAsyncHandler(async (req, res) => {
const { id } = req.params;
validateMongodbId(id);
const user = await User.findByIdAndUpdate(
id,
{
isBlocked: false,
},
{ new: true }
);
res.json(user);
});
//------------------------------
// Account Verification - Send email
//------------------------------
const generateVerificationTokenCtrl = expressAsyncHandler(async (req, res) => {
try {
//build your message
const msg = {
to: "MizTamaraAndrea#gmail.com",
from: "Tamara18_1985#msn.com",
subject: "My first Node js email sending",
text: "I hope this goes through",
};
await sgMail.send(msg);
res.json("Email sent");
} catch (error) {
res.json(error);
}
});
module.exports = {
generateVerificationTokenCtrl,
userRegisterCtrl,
loginUserCtrl,
fetchUsersCtrl,
deleteUsersCtrl,
fetchUserDetailsCtrl,
userProfileCtrl,
updateUserCtrl,
updateUserPasswordCtrl,
followingUserCtrl,
unfollowUserCtrl,
blockUserCtrl,
unBlockUserCtrl,
};
My user Routes Code
const express = require("express");
const {
userRegisterCtrl,
loginUserCtrl,
fetchUsersCtrl,
deleteUsersCtrl,
fetchUserDetailsCtrl,
userProfileCtrl,
updateUserCtrl,
updateUserPasswordCtrl,
followingUserCtrl,
unfollowUserCtrl,
blockUserCtrl,
unBlockUserCtrl,
generateVerificationTokenCtrl,
} = require("../../controllers/users/usersCtrl");
const authMiddleware = require("../../middleware/auth/authMiddleware");
const userRoutes = express.Router();
userRoutes.post("/register", userRegisterCtrl);
userRoutes.post("/login", loginUserCtrl);
userRoutes.post("/send-mail", generateVerificationTokenCtrl);
userRoutes.get("/", authMiddleware, fetchUsersCtrl);
userRoutes.put("/password", authMiddleware, updateUserPasswordCtrl);
userRoutes.put("/follow", authMiddleware, followingUserCtrl);
userRoutes.put("/unfollow", authMiddleware, unfollowUserCtrl);
userRoutes.put("/block-user/:id", authMiddleware, blockUserCtrl);
userRoutes.put("/unblock-user/:id", authMiddleware, unBlockUserCtrl);
userRoutes.get("/profile/:id", authMiddleware, userProfileCtrl);
userRoutes.put("/:id", authMiddleware, updateUserCtrl);
userRoutes.delete("/:id", deleteUsersCtrl);
userRoutes.get("/:id", fetchUserDetailsCtrl);
module.exports = userRoutes;
You have one of two problems here. Either, your API key does not have the permission to send messages, or has been deleted. Create yourself a new API key that has permission to send emails and try again.
Or, I see you appear to be trying to send from an msn.com email address. In order to send from a third party domain like that, you need to have set up single sender verification. This lets SendGrid know that you do have access to that email address and that you are not trying to spoof someone else's.
(Note that when you ship to production, we recommend you use your own domain and authenticate that domain with SendGrid, which will give you much better deliverability.)

How can i if dont send image implement default image on my user?

Hi everyone My users have profile picture but its not required,I dont want. So I need if user send me image while register or updated i take this picture and save, so i can this. My problem if user dont send me image i cant give default image
Its my controller code :
//User Register Controller
const register = async (req, res, next) => {
try {
const {
name,
surname,
username,
phoneNumber,
email,
password,
gender,
profilPicture,
birtDate,
} = req.body;
bcrypt.hash(password, 8, async (err, hash) => {
try {
const user = new User({
name,
surname,
username,
phoneNumber,
email,
password: hash,
gender,
profilPicture: 'http://localhost:4000/' + req.file.path || 'http://localhost:4000/public/images/profilePictures/defaultProfilePicture.png',
birtDate,
});
const createdUser = await user.save();
const token = await createToken(createdUser);
res.status(200).json({ token });
} catch (err) {
res.json(err);
}
});
} catch (error) {
res.json({ message: error.message });
}
};
It's my middleware multer :
const multer = require('multer');
const stor = multer.diskStorage({
destination:function(req,file,cb) {
cb(null,'./public/images/profilePictures')
},
filename:function(req,file,cb){
cb(null,'profilePicture-'+new Date().toISOString().replace(/:/g, '-')+file.originalname);
}
})
const fileFilter = (req, file, cb) => {
if (file.mimetype === 'image/jpeg' || file.mimetype === 'image/png') {
cb(null, true);
} else {
cb(null, false);
}
};
const upload = multer({
storage: stor,
limits: {
fileSize: 1024 * 1024 * 5,
},
fileFilter: fileFilter,
});
module.exports = upload;
My route :
router.post('/register', upload.single('profilPicture'), userController.register);
One way you could do it is set a default within your model
const mongoose = require("mongoose")
const UserSchema = new mongoose.Schema({
profilePicture: {
type: String,
default: 'defaultProfilePicture.png'
}
})
module.exports = mongoose.model("Users", UserSchema)
This way if the user didnt upload a profile picture it would be set to defaultProfilePicture.png
You wouldnt need
profilPicture: 'http://localhost:4000/' + req.file.path || 'http://localhost:4000/public/images/profilePictures/defaultProfilePicture.png',
Just
profilPicture: 'req.file.path'
saving the full URL is never a good idea because you might choose to change it in the future like to remote file store or host your project then the URL will no longer be http://localhost:4000/. You'd ideally save the images unique name and extension.
just try like this :
profilPicture: (req.file) ? 'http://localhost:4000/' + req.file.path : 'http://localhost:4000/public/images/profilePictures/defaultProfilePicture.png';

Problems with Express's functions using Angular

I am making an app that saves and shows books to sell. It's everything ok, but this error began to appear:
GET http://localhost:3000/api/usuarios 404 (Not Found) zone-evergreen.js:2952
This error appears in two files: 'apuntes' and 'usuarios'
Here is the controller's code:
const usu = require('../models/usuario')
const usuarioCtrl = {};
usuarioCtrl.getUsuarios = async (req, res) => {
const usuarios = await usu.find();
res.json(usuarios);
}
usuarioCtrl.createUsuarios = async (req, res) => {
console.log(req.body);
const usuario = new usu({
nombre: req.body.nombre,
apellido: req.body.apellido,
fecha: req.body.fecha,
registro: req.body.registro,
password: req.body.password
});
await usuario.save();
res.json({
'status': 'Usuario Creado'
});
}
usuarioCtrl.getUsuario = async (req, res) => {
const usuarios = await usu.findById(req.params.id);
res.json(usuarios);
}
usuarioCtrl.editUsuario = async (req, res) => {
const { id } = req.params;
const usuario = {
nombre: req.body.nombre,
apellido: req.body.apellido,
fecha: req.body.fecha,
registro: req.body.registro,
password: req.body.password
};
await usu.findByIdAndUpdate(id, { $set: usuario }, { new: true });
res.json({ status: 'Usuario Actualizado' });
};
usuarioCtrl.deleteUsuario = async (req, res) => {
await usu.findByIdAndRemove(req.params.id);
res.json({ status: 'Usuario Borrado' });
}
module.exports = usuarioCtrl;
I'm sure that the index and route's code are right, but I don't know what to do and why this is happening. I have two controllers and two routes files and both have the same logic.
This is my first question in StackOverflow, I thank you for your help. If you need more details about the project, please tell me.
Here's the router:
const express=require('express');
const router1 = express.Router();
const ctrl1=require('../controllers/usuarios.controller');
router1.get('/', ctrl1.getUsuarios );
router1.post('/',ctrl1.createUsuarios);
router1.get('/:id',ctrl1.getUsuario);
router1.put('/:id',ctrl1.editUsuario)
router1.delete('/:id',ctrl1.deleteUsuario);
module.exports=router1;

Resources