Email response from db to a user in node.js - node.js

in my appcliation I generate a new user password (PUT request). This has to be sent to the updated users emailadress which is in the database. I am pretty new to node and express and can use some help figuring out how to do this. I consider nodemailer a good option. Here is the code that generates the password and updates the user in the db. Which would be the best way to set this up? thx!
const attemptResetPasswordMember = async (req, res) => {
try {
const genPass = await generatePassword();
const hashedPass = await bcrypt.hash(genPass, 10);
const { userid } = req.body;
await pool.query("Update members SET passhash = $1 WHERE userid = $2", [
hashedPass,
userid,
]);
res.status(200).json({ code: genPass });
} catch (error) {
res.status(500).json({ added: false });
}
};

Related

Not able to delete or get single user from mongoDB using Node.js

I am taking the email of the user from the id of the request(URL) and trying to delete/get the user for this respective email id. Basically email is an id of the users (email is unique for all the users).
The user is not deleted, and for get request, I am getting null.
Delete by Id code:
router.delete("/:id", async(req, res) => {
try{
console.log(req.params.id);
var query = {email:req.params.id}
const user = await User.deleteOne(query);
console.log(user);
res.status(200).json("User has been deleted...");
}catch(err){
res.status(404).json("User not found!");
}
});
Get user by id:
router.get("/:id", async(req, res) => {
try{
const email = req.params.id;
console.log(email);
const user = await User.find({email:req.params.id})
res.status(200).json(user[0]);
}
catch(err){
res.status(500).json(err);
}
});
If I am using static email to fetch the single user, I am getting the correct output, but with variable no output.
Static example:
const user = await User.find({email:'sita#gmail.com'})
if you want to fetch through email id or name etc.
I suggest use query params
for Example
For Delete:
router.delete("/", async(req, res) => {
try{
var query = {email:req.query.email}
const user = await User.deleteOne(query);
res.status(200).json("User has been deleted...");
}catch(err){
res.status(404).json("User not found!");
}
});
For Fetch
for single document use: findOne
for multi Documents use: find
router.get("/", async(req, res) => {
try{
const user = await User.findOne({email:req.query.email})
res.status(200).json(user);
}
catch(err){
res.status(500).json(err);
}
});

Having trouble getting a POST request to work

I'm using Node, Express, & Mongoose trying to get this POST request to work using Postman but it keeps giving me the 500 status error. I also tried posting with just the username & instead of giving me the expected 400 status error it just gave me a 500 error again.
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const User = require('../models/userModel');
const registerUser = async (req, res) => {
try {
//get the username & password from the req.body
const { username, password } = req.body;
//check if the username is unique
const uniqueCheck = await User.findOne(username);
if (uniqueCheck) {
res.status(403).json('Username already exists');
}
//hash password
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
//check all fields are filled
if (!username || !password) {
res.status(400).json('Please fill in all fields')
} else {
//create user with username & password that is assigned to the hash version of it
const user = await User.create(username, { password: hash });
res.status(201).json(user);
}
} catch (error) {
res.status(500).json({ error: 'Problem registering user' });
}
}
As already I told you in the comment, you should ad a console.error statement in the catch block to better understand where is the problem.
Also, if the first if is matched, a response is sent to the client but the code execution will countinue, triyng to repliyng again to the client and giving you another error. You should return in the first if block to avoid it.
Check the following solution with comments on relevant edits
const jwt = require('jsonwebtoken')
const bcrypt = require('bcrypt')
const User = require('../models/userModel');
const registerUser = async (req, res) => {
try {
//get the username & password from the req.body
const { username, password } = req.body;
//check if the username is unique
const uniqueCheck = await User.findOne(username);
if (uniqueCheck) {
return res.status(403).json('Username already exists'); // --> !!! add a return statement here
}
//hash password
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(password, salt);
//check all fields are filled
if (!username || !password) {
res.status(400).json('Please fill in all fields')
} else {
//create user with username & password that is assigned to the hash version of it
const user = await User.create(username, { password: hash });
res.status(201).json(user);
}
} catch (error) {
console.error(error) // --> !!! log errors here
res.status(500).json({ error: 'Problem registering user' });
}
}

How do I go about making the change password route in my restAPI?

I am currently doing this to register users:
const register = async (req, res) => {
const seller = await Seller.create({ ...req.body });
res.status(StatusCodes.CREATED).json({ seller });
};
I am using the pre-save function to hash the passwords:
SellerSchema.pre('save', async function () {
const salt = await bcrypt.genSalt(10);
this.password = await bcrypt.hash(this.password, salt);
});
But when making the password change function which I have made like this:
const updatePassword = async (req, res) => {
const { id } = req.params;
const { oldPassword, newPassword } = req.body;
const seller = await Seller.findOne({ _id: id });
if(!seller) throw new NotFoundError(`No seller with id:${id} exists`)
const isPasswordCorrect = await seller.comparePassword(oldPassword);
if (!isPasswordCorrect) {
throw new UnauthenticatedError('Invalid Credentials');
}
seller.update({ password: newPassword });
await seller.save();
res.status(StatusCodes.OK).json({ seller });
};
But what happens is the pre-save function hashes the existing password before saving; how do I make it hash the incoming password? I know I can remove the pre-save function and just use it in the controller. But is there any way to do this by using the pre-save function?
const updatePassword = async (req, res) => {
const { id } = req.params;
const { oldPassword, newPassword } = req.body;
const seller = await Seller.findOne({ _id: id });
if(!seller) throw new NotFoundError(`No seller with id:${id} exists`)
const isPasswordCorrect = await seller.comparePassword(oldPassword);
if (!isPasswordCorrect) {
throw new UnauthenticatedError('Invalid Credentials');
}
// Correct this line of code
seller.password=newPassword
await seller.save();
res.status(StatusCodes.OK).json({ seller });
};

How to show validation errors sent from Node.js API to Next.js

I have created a Node.js API and am making requests to it using Next.js
Here is my Node.js controller. I am using express validator for validation.
If I fill in the form correctly, it works and the data is saved in mongo as expected. However, I want to send the validation errors back to the client when the form isn't filled in correctly. If I look in console, I can see the errors in the network tab.
exports.register = async (req, res) => {
// check if user exists in the database already
const emailExists = await User.findOne({ email: req.body.email });
if (emailExists) return res.status(400).send("Email already exists");
// hash password
const salt = await bcrypt.genSalt(10);
// hash the password with a salt
const passwordhash = await bcrypt.hash(req.body.password, salt);
// create new user
var user = new User({
name: req.body.name,
email: req.body.email,
password: passwordhash
});
try {
user = await user.save();
res.send({ user: user._id });
} catch {
res.status(400).send(err);
}
};
In Next.js, here is the code for making the http request
handleSubmit = event => {
const { name, email, password } = this.state;
event.preventDefault();
const user = {
name,
email,
password
};
try {
register(user);
} catch (ex) {
console.log(ex);
}
};
export const register = async user => {
const data = await http.post("http://localhost:8000/api/user/register", user);
console.log(data);
return data;
};
In console all I see is the below. So the console.log I am doing in the catch isn't working.
POST http://localhost:8000/api/user/register 422 (Unprocessable Entity)
Uncaught (in promise) Error: Request failed with status code 422
at createError (createError.js:16)
at settle (settle.js:17)
at XMLHttpRequest.handleLoad (xhr.js:59)
That's because the catch statement isn't being run because the function isn't throwing an exception by itself. You should add the error handling inside the function like this:
try {
register(user);
} catch (ex) {
console.log(ex);
}
};
export const register = async user => {
const data = await http.post("http://localhost:8000/api/user/register", user).catch((e) {
throw new Error(e);
});
console.log(data);
return data;
};
I managed to get it working like this:
try {
const response = await register(user);
console.log(response);
} catch (ex) {
if (ex.response && ex.response.status === 422) {
const errors = ex.response.data.errors;
this.setState({ errors });
}
}

How can I implement transaction concept in mongoose model?

I have three models "userLogin.js","userDetail.js",and "userAddress.js".I want data should be stored simultaneously, if any error occurs it should rolback all the insert actions.this what I have tried. I gives me the error user is not defined . when try to fix them it gives the error "schema is not registered"
const UserLogin=require("../models/userLogin");
const UserDeatil=require("../models/userDetail");
var myModelSchema1 = require('mongoose').model('UserLogin').schema;
var myModelSchema2 = require('mongoose').model('UserDeatils').schema;
exports.user_signup = (req, res, next) => {
UserLogin.find({ email: req.body.email })
.exec()
.then(user => {
if (user.length >= 1) {
return res.status(409).json({
message: "Mail exists"
});
} else {
bcrypt.hash(req.body.password, 10, (err, hash) => {
if (err) {
return res.status(500).json({
error: err
});
} else {
const user = new UserLogin({
_id: new mongoose.Types.ObjectId(),
email: req.body.email,
password: hash,
loginDate:req.body.logindate,
});
const userdetils = new UserDeatil({
_id: new mongoose.Types.ObjectId(),
userId:result.userID,
userName:req.body.username,
dob:req.body.dob,
gender:req.body.gender,
photo: req.file? req.file.path : null,
imei:req.body.imei,
});
insertUsers();
}
});
}
});
};
async function insertUsers(){
try{
const id= transaction.insert(myModelSchema1, user);
const id1= transaction.insert(myModelSchema2, userdetils);
const final = await transaction.run();
}
catch(error){
console.error(error);
const rollbackObj = await transaction.rollback().catch(console.error);
transaction.clean();
c
}
}
first when you define your users schema the email must be uniqe wich when fails when you tries to create anothe user document with the same email,
and with this convention you can move forward like this:
const UserLogin=require("../models/userLogin");
const UserDeatil=require("../models/userDetail");
cosnt signup = async (req ,res)=>{
const { email , password ,...details} = req.body
const createdDocs = []
const hashedPwd = hash(password);
try{
const user = new UserLogin({ email , password: hashedPwd });
await user.save()
createdDocs.push(user)
const userDetails = new UserDetails({...details,userId:user._id});
await userDetails.save()
createdDocs.push(userDetails)
catch(err){
res.json({ status:false, message:err.message})
//emulates the rollback when any thing fails on the try flow
if(createdDocs.length){
const operationsToRollBack = createdDocs.map(doc=>doc.remove)
await Promise.all(operationsToRollBack)
}
}
MongoDB supports multi-document transactions starting from version 4.0.
Ideally, if you need a transactional database you would use an SQL type db.
But if you would still like to enjoy MongoDB while needing transactions, they have introduced an API for this - https://docs.mongodb.com/manual/core/transactions/

Resources