Trying to code the backend, and this throws an error in the console. What could be the problem? I imported user.js as a requirement, but still does not work.
Error: mongoose.Error.MissingSchemaError(name); Schema hasn't been registered for model "User". Use mongoose.model(name, schema)
Passport.js
const passport = require('passport');
const user = require('../schema/user');
const LocalStrategy = require('passport-local').Strategy;
const mongoose = require('mongoose');
const User = mongoose.model('User');
passport.use(new LocalStrategy({
usernameField: 'email'
},
(username, password, done) => {
User.findOne({ email: username }, (err, user) => {
if (err) { return done(err); }
if (!user) {
return done(null, false, {
message: 'Incorrect username.'
});
}
if (!user.validPassword(password)) {
return done(null, false, {
message: 'Incorrect password.'
});
}
return done(null, user);
});
}
));
User.js
const mongoose = require("mongoose");
const crypto = require('crypto');
const jwt = require('jsonwebtoken');
const userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
name: {
type: String,
required: true
},
hash: String,
salt: String
});
userSchema.methods.setPassword = function (password) {
this.salt = crypto.randomBytes(16).toString('hex');
this.hash = crypto
.pbkdf2Sync(password, this.salt, 1000, 64, 'sha512')
.toString('hex');
};
userSchema.methods.validPassword = function (password) {
const hash = crypto
.pbkdf2Sync(password, this.salt, 1000, 64, 'sha512')
.toString('hex');
return this.hash === hash;
};
userSchema.methods.generateJwt = function () {
const expiry = new Date();
expiry.setDate(expiry.getDate() + 7);
return jwt.sign({
_id: this._id,
email: this.email,
name: this.name,
exp: parseInt(expiry.getTime() / 1000, 10),
}, process.env.JWT_SECRET );
};
module.exports = mongoose.model('User', userSchema);
in passport.js file, you don't need to require require('mongoose') and mongoose.model('User'), so delete them and change user to User like this:
const passport = require('passport');
const User = require('../schema/user');// change user to User
const LocalStrategy = require('passport-local').Strategy;
Related
Am trying to create users and their posts. Each user has an array of posts, a user can create a post and the user is being verified by a jwt token when he/she logins. This is what i get after i try to make a post. I would really appreciate if you could help me out on this one
ValidationError: Post validation failed: content: Cast to Boolean failed for value "My first post" (type string) at path "content" because of "CastError", user: Path user is required
userSchema:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
username:{
type:String,
required:true
},
email:{
type:String,
required:true
},
password:{
type:String,
required:true
},
posts:[{
type:mongoose.Schema.Types.ObjectId, ref:"Post"
}]
})
module.exports = mongoose.model('User', userSchema)
post schema
const mongoose = require('mongoose');
const postSchema = new mongoose.Schema(
{
user:{type:mongoose.Schema.Types.ObjectId,
required:true,
ref:'User'
},
title:{
type:String,
required:true
},
content:{
type:Boolean,
required:true
},
createdAt:{
type:Date,
default: new Date()
},
likes:{
type:Number,
default:0
}
})
module.exports = mongoose.model('Post', postSchema)
postcontroller
const Post = require('../models/Posts')
const User = require('../models/User')
const expressAsyncHandler = require('express-async-handler')
const getAllPosts = async (req,res)=>{
const posts = await Post.find().lean()
if(!posts?.length){
res.status(400).json({message:"No posts Found"})
}
const postsWithUsers = await Promise.all(posts.map(async(post) =>{
const user = await User.findById(post.user).lean().exec()
return {...post, username: user.username}
}))
res.json(postsWithUsers)
}
const createPost = expressAsyncHandler(async(req, res) =>{
const { title, content} = req.body
// console.log(id)
if( !title||!content){
return res.status(400).json({message:"All Fields"})
}
const new_post = await Post.create({
// user,
title,
content
})
if(new_post){
return res.status(201).json({
//_id:new_post._id,
title:new_post.title,
content:new_post.content,
likes:new_post.likes,
created_on:new_post.createdAt,
//user:new_post.user
})
}else{
return res.status(400).json({message:"Invalid Data received"})
}
})
module.exports = {
createPost,
getAllPosts
}
authcontroller
const User = require('../models/User');
const bcrypt = require('bcrypt');
const jwt = require('jsonwebtoken');
const asyncHandler = require('express-async-handler')
const login = asyncHandler(async(req,res) =>{
const {email, password} = req.body
if(!email||!password){
return res.status(400).json({message:"All Fields are Required"})
}
const user = await User.findOne({email}).exec()
if(!user){
return res.status(401).json({message:"user does not Exist"})
}
const match = await bcrypt.compare(password, user.password)
if(!match) return res.status(401).json({message:"Unauthorized"})
const accessToken = jwt.sign(
{
"UserInfo": {
"username": user.username,
"posts":user.posts
}
},
process.env.ACCESS_TOKEN_SECRET,
{ expiresIn: '7d' }
)
const refreshToken = jwt.sign(
{
"UserInfo":{
"username":user.username,
"posts":user.posts
}
},
// console.log(user.username),
process.env.REFRESH_TOKEN_SECRET,
{ expiresIn: '7d' },
//console.log(user.posts)
)
res.cookie('jwt', refreshToken, {
httpOnly: true, //accessible only by web server
secure: true, //https
sameSite: 'None', //cross-site cookie
maxAge: 7 * 24 * 60 * 60 * 1000 //cookie expiry: set to match rT
})
res.json({ accessToken })
})
module.exports = login
authmiddleware
const jwt = require('jsonwebtoken')
const verifyJWT = (req,res,next) =>{
const authHeader = req.headers.authorization || req.headers.Authorization
if (!authHeader?.startsWith('Bearer ')) {
return res.status(401).json({ message: 'You Need to Login First' })
}
const token = authHeader.split(' ')[1]
jwt.verify(
token,
process.env.ACCESS_TOKEN_SECRET,
(err, decoded) =>{
if(err) return res.status(403).json({message:"Thats Forbidden"})
req.user = decoded.UserInfo.username
next()
}
)
}
module.exports = verifyJWT
I'm working with routes on node js. I created a user model shown below -
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const jwt = require("jsonwebtoken");
const validator = require("validator");
require("dotenv").config();
const userSchema = mongoose.Schema(
{
email: {
type: String,
required: true,
unique: true,
trim: true,
lowercase: true,
validate(value) {
if (!validator.isEmail) {
throw new Error("Invalid Email");
}
},
},
password: {
type: String,
required: true,
trim: true,
},
role: {
type: String,
enum: ["user", "admin"],
default: "user",
},
name: {
type: String,
required: true,
maxlength: 21,
},
phone: {
required: true,
type: Number,
maxlength: 12,
},
},
{ timestamps: true },
);
userSchema.pre("save", async function (next) {
if (user.isModified("password")) {
// hash the password
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(this.password, salt);
this.password = hash;
}
next();
});
const User = mongoose.model("User", userSchema);
module.exports = {
User,
};
And then I created a file containing user routes shown below -
const express = require("express");
const router = express.Router();
require("dotenv").config();
const { User } = require("../../models/userModel");
router.route("/signup").post(async (req, res) => {
// const { email, password, name, phone } = req.body;
console.log(req.body);
// try {
// // Check if user email exists
// // create user instance and hash password
// const user = new User({
// email: req.body.email,
// password: req.body.password,
// name: req.body.name,
// phone: req.body.phone,
// });
// // generate jwt token
// console.log("user is saving");
// const userDoc = await user.save();
// // send email
// // save....send token with cookie
// res
// .cookie("access-token", "jflsakjusdilfjadslfj32j43lrf")
// .status(200)
// .send(userDoc);
// } catch (error) {
// res
// .status(400)
// .json({ message: "Error while creating user", error: error });
// }
const user = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password,
phone: req.body.phone,
});
user
.save()
.then((doc) => {
console.log("User saved");
res.send(doc);
})
.catch((err) => {
console.log(err);
});
});
module.exports = router;
But don't know why I'm getting this error -
ReferenceError: user is not defined
at model.<anonymous> (D:\CovidHelpers\CovidHelpers\server\models\userModel.js:46:3)
at callMiddlewareFunction (D:\CovidHelpers\CovidHelpers\node_modules\kareem\index.js:483:23)
at model.next (D:\CovidHelpers\CovidHelpers\node_modules\kareem\index.js:58:7)
at _next (D:\CovidHelpers\CovidHelpers\node_modules\kareem\index.js:107:10)
at D:\CovidHelpers\CovidHelpers\node_modules\kareem\index.js:508:38
at processTicksAndRejections (internal/process/task_queues.js:75:11)
I have just created a new project in mongodb, gave database and network access and it's connecting successfully but also getting this error
I have done this before also and it was working fine but don't know why am I getting this now :(
Any help is appreciated
save is document middleware and in document middleware functions, this refers to the document. So in your case, I believe it should be this.isModified("password") instead of user.isModified("password").
You can delete userSchema.pre() middleware and transfer the password hashing logic inside the router. Also you can simplify your router code like this:
router.route("/signup").post(async (req, res) => {
try {
const salt = await bcrypt.genSalt(10);
const hash = await bcrypt.hash(req.body.password, salt);
req.body.password = hash;
let user = await User.create(req.body)
res.status(200).json(user)
} catch (error) {
res.status(400).json({ error: error });
}
});
RECOMMENDATION:
I would recommend you to try the great Mongoose plugin called passport-local-mongoose that will do this for you out of the box, and it will also give you some nice authentication features if you are using passport for authentication.
Package: https://www.npmjs.com/package/passport-local-mongoose
You don't actually get access to the document, in the mongoose's pre('save') hook.
For your usecase, you can do the hasing before you save the user.
I have three models: user, teacher, student. The users, teachers, students collections appear in the database. But everything is saved in the users collection. How to set up in the code below that student is saved in the students collection, not in users.
model
const mongoose = require('mongoose');
extend = require('mongoose-extend-schema');
const Schema = mongoose.Schema;
const userSchema = new Schema({
name: {
type: String,
trim: true,
required: true,
maxLength: 32
},
surname: {
type: String,
trim: true,
required: true,
maxLength: 32
},
email: {
type: String,
unique: true,
trim: true,
required: true,
lowercase: true
},
initials: String
});
const studentSchema = extend(userSchema, {
teachers: []
});
const teacherSchema = extend(userSchema, {
isActiveTutor: {
type: Boolean,
default: false
}
})
const User = mongoose.model('User', userSchema);
const Student = mongoose.model('Student', studentSchema);
const Teacher = mongoose.model('Teacher', teacherSchema);
module.exports = {
User,
Student,
Teacher
}
controllers
const User = require('../models/user');
const Student = require('../models/user');
const Teacher = require('../models/user');
const jwt = require('jsonwebtoken');
const nodemailer = require('nodemailer');
const expressJwt = require('express-jwt');
module.exports.signup = (req, res) => {
const {name, surname, email, password, initials, role} = req.body;
Student.User.findOne({email}).exec((err, student) => {
if (student) {
return res.status(400).json({
error: "Email is taken"
})
}
}
}
module.exports.accountActivationStudent = (req, res) => {
const {token} = req.body;
if(token) {
jwt.verify(token, process.env.JWT_ACCOUNT_ACTIVATION, function(err, decoded) {
if(err) {
console.log('JWT VERIFY IN ACCOUNT ACTIVATION ERROR', err);
return res.status(401).json({
error: 'Expired link. Signup again'
})
}
const {name, surname, email, password} = jwt.decode(token);
const student = new Student.User ({name, surname, email, password});
student.save((err, student) => {
if(err) {
console.log('SAVE Student IN ACCOUNT ACTIVATION ERROR', err);
return res.status(401).json({
error: 'Error saving student in database. Try signup again'
});
}
return res.json({
message: 'Signup success. Please signin'
});
});
});
} else {
return res.json({
message: 'Something went wrong. Try again'
})
}
};
new Student is your schema
try to like this
router.post('/', async (req, res) => {
const _studentSave = await new Student({ name, surname, email, password, initials, role });
const saveProcess = await _studentSave.save();
try{
res.json(saveProcess)
}catch(error){
throw error
}
})
I am new to MERN stack development and trying the JWT authentication. During this I am facing that my server is not working they crashed every time.
Yesterday It was working but today It's not working. Now they are showing this error.
This is error showing on console
MissingSchemaError: Schema hasn't been registered for model "users".
Here is my Schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
avatar: {
type: String
},
date: {
type: Date,
default: Date.now
}
});
const User = mongoose.model('users', UserSchema);
module.exports = User;
This code is in the routes folder - user.js file
// user.js
const express = require('express');
const router = express.Router();
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
const jwt = require('jsonwebtoken');
const passport = require ('passport');
const validateRegisterInput = require('../validation/register');
const validateLoginInput = require('../validation/login');
const User = require('../models/User');
//Register Post Router
router.post('/register', function(req, res){
const {errors, isValid} = validateRegisterInput(req.body);
if(!isValid){
return res.status(400).json(errors);
}
User.findOne({
email: req.body.email
}).then(user => {
if(user){
return res.status(400).json({
email: 'Email already exists'
});
}
else {
const avatar = gravatar.url(req.body.email, {
s: '200',
r: 'pg',
d: 'mm'
});
const newUser = new User({
name: req.body.name,
email: req.body.email,
password: req.body.password,
avatar
});
bcrypt.genSalt(10, (err, salt) => {
if(err)
console.error('There was an error', err);
else{
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err)
console.error('There was an error', err);
else{
newUser.password = hash;
newUser
.save()
.then(user => {
res.json(user)
});
}
});
}
});
}
});
});
//Login Post Router
router.post('/login', (req, ress) => {
const {errors, isValid} = validateLoginInput(req.body);
if(isValid){
return res.status(400).json(errors);
}
const email = req.body.email;
const password = req.body.password;
User.findOne({email})
.then(user => {
if(!user) {
errors.email = 'User not found'
return res.status(404).json(errors);
}
bcrypt.compare(password, user.password)
.then(isMatch => {
if(isMatch){
const payload = {
id: user.id,
name: user.name,
avatar: user.avatar
}
jwt.sign(payload, 'secret', {
expiresIn: 3600
}, (err, token) => {
if(err)
console.error('There is some error in token', err);
else{
res.json({
success: true,
token: `Bearer ${token}`
});
}
});
}
else{
errors.password = 'Incorrect Password';
return
res.status(400).json(errors);
}
});
});
});
router.get('/me', passport.authenticate('jwt', {session: false}), (req, res) => {
return res.json({
id: req.user.id,
name: req.user.name,
email: req.user.email
});
});
module.exports = router;
I keep getting the same error "User is not a function" when I call my API method.
Has anybody got an ideas why this might be.
Api method:
//need to export the api methods.
var User = require('../models/user');
var passport = require('passport');
module.exports.create = function(req, res) {
//TODO: error checking.
var user = new User();
console.log(req);
user.firstName = req.body.firstName;
user.secondName = req.body.secondName;
user.email = req.body.email;
user.setPassword(req.body.password);
user.save(function(err) {
res.status(200);
});
};
user model:
var mongoose = require('mongoose');
var crypto = require('crypto');
var userSchema = new mongoose.Schema({
email: {
type: String,
unique: true,
required: true
},
firstName: {
type: String,
required: true
},
lastName: {
type: String,
required: true
},
hash: String,
salt: String
});
userSchema.methods.setPassword = function(password){
};
userSchema.methods.validPassword = function(password) {
};
mongoose.model('User', userSchema);
Let me know if I need to enter any more files.
Thanks
You need to export the mongoose model you created at the end of the User Model file. Something like
module.exports = mongoose.model('User', userSchema);