Reputation: 115
I don't understand it. I am not able to login. User is already in my database, and when I log in, it simply says:
POST http://localhost:3000/api/v1/users/login 402 (Payment Required)
When I register for the first time, and then login, login is successful. If I logout, and then try to log in with that same email and password, it's throwing me the above error. I'm not even using someone's API. It's my own created one. It's sending me a response of "incorrect password"
Here's the controller:
loginUser: (req, res, next) => {
const { email, password } = req.body
if (!email || !password) {
return res.status(400).json({ message: "Email and password are must" })
}
User.findOne({ email }, (err, user) => {
if (err) {
return next(err)
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invalid email" })
} else if (!user) {
return res.status(402).json({ error: "User not found" })
} else if (!user.confirmPassword(password)) {
return res.status(402).json({ error: "incorrect password" })
}
})
}
User model
const mongoose = require("mongoose")
const bcrypt = require("bcrypt")
const Schema = mongoose.Schema
const userSchema = new Schema({
username: { type: String, required: true },
email: { type: String, reuired: true },
password: { type: String, required: true },
posts:[{ type: Schema.Types.ObjectId, ref: "Post" }]
}, { timestamps: true })
userSchema.pre("save", function (next) {
if (this.password) {
const salt = bcrypt.genSaltSync(10)
this.password = bcrypt.hashSync(this.password, salt)
}
next()
})
userSchema.methods.confirmPassword = function (password) {
return bcrypt.compareSync(password, this.password)
}
const User = mongoose.model("User", userSchema)
module.exports = User
registration controller
registerUser: (req, res) => {
const { username, email, password } = req.body
User.create(req.body, (err, createdUser) => {
if (err) {
return res.status(500).json({ error: "Server error occurred" })
} else if (!username || !email || !password) {
return res.status(400).json({ message: "Username, email and password are must" })
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invaid email" })
} else if (password.length < 6) {
return res.status(400).json({ message: "Password should be of at least 6 characters" })
}
else {
return res.status(200).json({ user: createdUser })
}
})
}
Edit
loginUser: async (req, res, next) => {
const { email, password } = req.body
if (!email || !password) {
return res.status(400).json({ message: "Email and password are must" })
}
await User.findOne({ email }, (err, user) => {
if (err) {
return next(err)
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invalid email" })
} else if (!user) {
return res.status(402).json({ error: "User not found" })
} else if (!user.confirmPassword(password)) {
return res.status(402).json({ error: "incorrect password" })
}
})
}
new post controller
newPost: (req, res) => {
const data = {
title: req.body.title,
content: req.body.content,
user: req.user.userId
}
Post.create(data, (err, newPost) => {
if (err) {
return res.status(500).json({ error: err })
} else if (!newPost) {
return res.status(400).json({ message: "No Post found" })
} else if (newPost) {
User.findById(req.user.userId, (err, user) => {
user.posts.push(newPost._id) //pushing posts documnet objectid to the post array of the user document
user
.save()
.then(() => {
return res.json(200).json({ user })
})
.catch(err => {
return res.status(500).json({ error: err })
})
})
}
})
}
Upvotes: 2
Views: 4569
Reputation: 2888
You might want to refactor your code so that you do the bcrypt
operations in controller not in the model. You are checking this.password
after the user is updated (creating new posts) and since this
is the user, the below code is being met each time you update the user object.
if (this.password) {
const salt = bcrypt.genSaltSync(10)
this.password = bcrypt.hashSync(this.password, salt)
}
So your hashing it every time you update the user (create a post). Instead, remove the above code from the userSchema.pre(...)
and try doing the bcrypt
hashing only when the user first registers.
registerUser: (req, res) => {
var { username, email, password } = req.body
if (password) {
const salt = bcrypt.genSaltSync(10)
password = bcrypt.hashSync(password, salt)
}
User.create(req.body, (err, createdUser) => {
if (err) {
return res.status(500).json({ error: "Server error occurred" })
} else if (!username || !email || !password) {
return res.status(400).json({ message: "Username, email and password are must" })
} else if (!validator.isEmail(email)) {
return res.status(400).json({ message: "Invaid email" })
} else if (password.length < 6) {
return res.status(400).json({ message: "Password should be of at least 6 characters" })
}
else {
return res.status(200).json({ user: createdUser })
}
})
}
This way the hashing occurs only once at the creation of the user and should remain consistent throughout other operations.
As for the Can't set headers after they are sent
error, you might be sending a response twice, since the error appears to come from the posts
controller. You are likely sending the user response and the post response. Maybe don't send the posts response since you will be sending it along in the user response.
More info on the error here.
Upvotes: 1