I have multiple routes which need the same userdata from the database. I have a function to check if the user is loggend in but that function dont return the user variables.
route:
app.get('/template', isAuthenticated, function (req, res) {
MongoClient.connect(url, { useNewUrlParser: true, useUnifiedTopology: true }, (err, client) => {
if (err) throw err;
const db = client.db(dbname);
let collection = db.collection('users');
// find data in db
collection.findOne({ _id: userid }).then(user => {
if (user != null) {
res.render('template', { layout: 'temaplte', csrfToken: req.csrfToken(), username: user.username, avatar: user.picture });
} else {
console.log("No user with this id!")
}
}).catch((err) => { console.log(err);
}).finally(() => { client.close(); });
});
});
Is there a way to get the variables users from the db from a function like isAuthenticated? Do I need to write the findOne-function on every route?
Best way to reuse logic in routes is to refactor that functionality into its own middleware.
function loadUserData(req, res, next) {
MongoClient.connect(url, {
useNewUrlParser: true,
useUnifiedTopology: true
}, (err, client) => {
if (err) {
return next(err)
};
const db = client.db(dbname);
let collection = db.collection('users');
// find data in db
collection.findOne({
_id: userid
}).then(user => {
if (user != null) {
req.user = user; // augment the request object with user data (check res.locals docs too)
return next(); // pass control to next middleware
} else {
res.end("No user with this id!");
}
}).catch((err) => {
return next(err);
})
.finally(() => {
client.close();
});
});
}
app.get('/template', isAuthenticated, loadUserData, function(req, res) {
const user = req.user; // loadUserData populated req.user;
res.render('template', {
layout: 'temaplte',
csrfToken: req.csrfToken(),
username: user.username,
avatar: user.picture
});
});
Related
Im learning express authentication using passport and react for frontend and i have a question. How do i access whole authenticated user object? I have db model that looks like that
const userSchema = new mongoose.Schema({
username: {type:String,required:true },
password: {type:String ,required:true},
note: {type:String}
})
My passportConfig.js
const userSchema = require("./user");
const bcrypt = require("bcryptjs");
const localStrategy = require("passport-local").Strategy;
module.exports = function (passport) {
passport.use(
new localStrategy((username, password, done) => {
userSchema.findOne({ username: username }, (err, user) => {
if (err) throw err;
if (!user) return done(null, false);
bcrypt.compare(password, user.password, (err, result) => {
if (err) throw err;
if (result === true) {
return done(null, user);
} else {
return done(null, false);
}
});
});
})
);
passport.serializeUser((user, cb) => {
cb(null, user.id);
});
passport.deserializeUser((id, cb) => {
userSchema.findOne({ _id: id }, (err, user) => {
const userInformation = {
username: user.username,
};
cb(err, userInformation);
});
});
};
My login request and user request
app.post('/login',(req,res,next) => {
passport.authenticate("local",(err,user,info) =>{
if (err) throw err
if(!user) res.send("No user with given login")
else {
req.logIn(user, (err) => {
if (err) throw err
res.send("Succesfully Authenticated")
})
}
})(req,res,next)
})
app.get('/user',(req,res) => {
res.send(req.user)
})
Now in react i want to access my logged user notes and i did this
const signIn = () => {
const user = {
username: login,
password: password
}
Axios({
method: "POST",
data: user,
withCredentials: true,
url: "http://localhost:4000/login",
}).then((res) => {
console.log(res)
getNotes()
});
}
const getNotes = () => {
Axios({
method: "GET",
withCredentials: true,
url: "http://localhost:4000/user",
}).then((res) => {
setNotes(res.data);
console.log(res);
});
}
In my getNotes response console.log i wanted to have all of my logged user object and i got only his username.How do i access his notes?
The req.user is set from the logic within passport.deserializeUser. You can update deserializeUser to have more data stored within the user object.
Example to pass notes to created req.user object:
passport.deserializeUser((id, cb) => {
userSchema.findOne({ _id: id }, (err, user) => {
const userInformation = {
username: user.username,
notes: user.notes
};
cb(err, userInformation);
});
});
I'm havig trouble understanding how to access the properties of a global variable that is set in the middleware of my application
// app.js
app.use(function (req, res, next) {
res.locals.user = req.user || null;
next();
});
I would have thought I could access the req.user.username in my template (using handlebars), but for some reason it is forcing me to iterate over this object.
A consle.log(req.user) shows:
_id: 5f01f9a861f5b33b42a9e,
username: 'onetap',
email: 'test#gmail.com',
password: '$2b$10$VLBS8ZwPKiaXasdfsiiwfg.wyJ1J5CwTKLjS5zXwAsvukHpNmk0HG2',
createdAt: 2020-07-05T16:02:48.081Z,
__v: 0
}
And in my template I have to use an each loop and can't access the properties directly. the req.user is not an array either.
{{user.username}}//undefined
{{#each user}}
{{username}} //onetap
{{/each}}
passport.js file
const LocalStrategy = require("passport-local").Strategy;
const bcrypt = require("bcrypt");
const mongoose = require("mongoose");
// Load User Model
const User = require("../models/User");
module.exports = function (passport) {
passport.use(
new LocalStrategy({ username: "username" }, (username, password, done) => {
// Match User
User.findOne({
username: username,
}).then((user) => {
if (!user) {
return done(null, false, { message: "Invalid Username" });
}
console.log("Checking password");
// Match password
bcrypt.compare(password, user.password, (err, isMatch) => {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Password incorrect" });
}
});
});
})
);
passport.serializeUser(function (user, done) {
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
User.findById(id, function (err, user) {
done(err, user);
});
});
};
I was able to fix this by chaning deserialize to:
passport.deserializeUser(function (id, done) {
User.findById(id)
.lean()
.exec(function (err, user) {
done(err, user);
});
});
I'm building a mock facebook app using MERN Stack. When I try to save posts to my database, it keeps throwing two errors. One is in the back end and says TypeError: Cannot read property 'create' of undefined and the other is in the front end and says Unhandled Rejection (Error): Request failed with status code 500
This is my front end API.js page
import axios from "axios";
export default {
// Gets all posts
getPosts: function() {
return axios.get("/api/users/posts");
},
// Gets the post with the given id
getPost: function(id) {
return axios.get("/api/users/posts/" + id);
},
// Deletes the post with the given id
deletePost: function(id) {
return axios.delete("/api/users/posts/" + id);
},
// Saves a post to the database
savePost: function(postData) {
return axios.post("/api/users/posts", postData);
}
};
This is my handleSubmit function
handleFormSubmit = (event) => {
// Preventing the default behavior of the form submit (which is to refresh the page)
event.preventDefault();
// Saving post to database
API.savePost(this.state)
.then(data => {
console.log("data: ", data);
this.setState({
title: data.data.title,
body: data.data.body,
});
});
};
This is my back end postController.js, where TypeError: Cannot read property 'create' of undefined is being thrown.
const db = require("../models");
console.log("--------------------------------------");
console.log("Controller Reached");
console.log("--------------------------------------");
// Defining methods for the postController
module.exports = {
findAll: function(req, res) {
console.log("----------------------findAll------------------------ ");
console.log("req.query: ", req.query);
db.User.posts
.find(req.query)
.sort({ date: -1 })
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
findById: function(req, res) {
db.User.posts
.findById(req.params.id)
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
create: function(req, res) {
console.log("create func");
console.log("req.body: ", req.body);
db.User.posts
.create(req.body) //error here
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
update: function(req, res) {
db.User.posts
.findOneAndUpdate({ _id: req.params.id }, req.body)
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
remove: function(req, res) {
db.User.posts
.findById({ _id: req.params.id })
.then(dbModel => dbModel.remove())
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
}
};
And these are my backend API routes for the posts (I removed other routes that weren't related to the issue)
const router = require("express").Router();
const db = require("../../models");
const passport = require("passport");
const postController = require("../../controllers/postController");
router
.route("/posts")
.post(postController.create)
.get(postController.findAll)
.put(postController.update)
.delete(postController.remove);
console.log("/posts reached");
// Matches with "/api/books/:id"
router
.route("/posts/:id")
.get(postController.findById)
.put(postController.update)
.delete(postController.remove);
//router get for login >>> router.get("/")
//router post for logout
//router.get for profile page
module.exports = router;
edit: This is my user model
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const passport = require("passport");
const Schema = mongoose.Schema;
//const passportLocalMongoose = require('passport-local-mongoose');
const userSchema = new Schema({
email: {type: String, required: true},
password: {type: String, required: true},
firstname: String,
lastname: String,
following: [{
User: String,
id: {type: mongoose.Schema.Types.ObjectId }
}],
followers: [{
User: String,
id: {type: mongoose.Schema.Types.ObjectId }
}],
posts: [{
title: String,
body: String,
postedBy: {type: mongoose.Schema.Types.ObjectId},
dateCreated: Date,
comments: [{body:"string", by: mongoose.Schema.Types.ObjectId}],
}],
dateCreated: Date,
savedFiles:[{}],
favoritePosts: [],
avatarImage: [{Image: String}],
jumboImg: [{Image: String}],
profile: {
job: String,
location: String,
school: String,
bio: String,
interests: []
}
});
var User = (module.exports = mongoose.model("User", userSchema));
module.exports.createUser = function (newUser, callback) {
console.log("createUser - newUser", newUser)
bcrypt.genSalt(10, function (err, salt) {
bcrypt.hash(newUser.password, salt, function (err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
};
module.exports.getUserByEmail = function (email, callback) {
console.log("getUserByEmail", email)
var query = { email: email };
console.log(query);
User.findOne(query, callback);
};
module.exports.getUserById = function (id, callback) {
console.log("getUserById", id);
User.findById(id, callback);
};
module.exports.comparePassword = function (candidatePassword, hash, callback) {
console.log("comparePassword")
bcrypt.compare(candidatePassword, hash, function (err, isMatch) {
if (err) throw err;
callback(null, isMatch);
});
};
var LocalStrategy = require("passport-local").Strategy;
passport.use(
new LocalStrategy({ usernameField: "email" }, function (
email,
password,
done
) {
console.log("LocalStrategy");
User.getUserByEmail(email, function (err, user) {
if (err) throw err;
if (!user) {
return done(null, false, { message: "Unknown User" });
}
User.comparePassword(password, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Invalid password" });
}
});
});
})
);
passport.serializeUser(function (user, done) {
console.log("serializeUser", user.id)
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
console.log("deserializeUser", id);
User.getUserById(id, function (err, user) {
console.log("deserializeUser - user", `name="${user.name}" \nemail="${user.email}"\npassword=${user.password} `);
done(err, user);
});
});
Any help would be greatly appreciated.
User.posts is undefined because .posts is a property of instance of User. Thus you need to instantiate the user first. In this case, by finding an existing object from User collection.
Since you defined User.posts as primitive arrays, not reference to another collection, the code will be something like below.
create: function (req, res) {
// 1. find the existing user (I guess passport does the job)
db.User.findById(req.body.userid).then((user) => {
// 2. add an post
user.posts.push({
title: req.body.title,
body: req.body.body,
postedBy: req.body.userid,
dateCreated: Date.now(),
comments: [],
});
// 3. persist the changes
user.save();
});
}
If you want to separate the collection, which I believe better, you need to create a new object on the separated collection with the reference to the user posted.
// Post schema
var postSchema = new Schema({
title: String,
body: String,
postedBy: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
dateCreated: Date,
comments: [{ body: "string", by: mongoose.Schema.Types.ObjectId }],
});
// The controller
create: function(req, res) {
// 1. find the existing user (or you get id from Passport session)
db.User.findById(req.body.userid).then((user) => {
// 2. add an post set "postedBy" as the user
return Post.create({
postedBy: user._id,
title: req.body.title,
body: req.body.body,
dateCreated: Date.now(),
});
});
}
Here is the official documentation about referencing: https://mongoosejs.com/docs/populate.html
Hope this helps.
i'm trying to make an option tag for every item which is in my Array in MongoDB. I have tried some ways but EJS throws me everytime the same error "gate is not defined"..
Here is my function in my route:
router.post('/neueBuchung_spediteur', (req, res) => {
User.findOne({username: req.user}, function (err, user) {
res.render('neueBuchung_spediteur', {
gate: user.gate
});
});
And this is my EJS function:
<select id="torauswahl" name="torauswahl" style="padding:10px;font-size: large; width: 300px">
<% for (var i = 0; i < gate.length; i++){%>
<option value="<%=gate[i]%>"><%=gate[i]%></option>
<%}%>
</select>
thats my full JS file for understanding the logic:
const express = require('express');
const router = express.Router();
// Load Buchung model
const Buchung = require('../DB/models/Buchung');
const User = require('../DB/models/User');
const Tor = require(('../DB/models/Tor'));
const { ensureAuthenticated } = require('../DB/config/auth');
const passport = require('passport');
//Startseite Breuninger
router.get ('/startseite_breuninger', ensureAuthenticated, (req, res) => {
Buchung.find(function (err, buchungen) {
if (err)
return res.send(err);
res.render('startseite_breuninger',{
vorname: req.user.vorname,
buchungen: buchungen || []
});
});
});
//startseite Spedi
router.get ('/startseite_spediteur', ensureAuthenticated, (req, res) => {
Buchung.find(function (err, buchungen) {
if (err)
return res.send(err);
res.render('startseite_spediteur',{
buchungen: buchungen || []
});
});
});
//Buhchungsübersicht mitarbeiter
router.get('/buchungsuebersicht', (req, res) => res.render('buchungsuebersicht'));
//Buhchungsübersicht spedi
router.get('/neueBuchung_spediteur', (req, res) => res.render('neueBuchung_spediteur'));
//torauswahl spedi
router.get ('/torauswahl', (req, res) => {
Buchung.find(function (err, buchungen) {
if (err)
return res.send(err);
res.render('torauswahl',{
buchungen: buchungen || []
});
});
});
//torverwaltung mitarbeiter
router.get ('/torverwaltung', (req, res) =>{
Tor.find(function (err, tor) {
if (err)
return res.send(err);
res.render('torverwaltung',{
tor: tor || [],
});
});
});
//Update Benutzerdaten Breuni
router.post('/update_detailansicht_breuninger',(req,res) =>{
const username = req.body.username;
const telefon = req.body.telefon;
const email = req.body.email;
User.update({username: username}, telefon);
res.render('detailansicht_breuninger');
});
//insert
//insert
router.post('/neueBuchung_spediteur',ensureAuthenticated,(req, res) => {
const {sendungsstruktur, datepicker, timepicker1, timepicker2, sendungen, EUP, EWP, pakete, bemerkung, teile } = req.body;
var user = req.user;
if (errors.length > 0) {
User.findOne({ username: req.user}, function (err, user) {
console.log(JSON.stringify(req.user));
if (err) { throw err; }
if (user) {
res.render('neueBuchung_spediteur', {
gate: user.gate || []
});
}
});
}
const newBuchung = new Buchung({
sendungsstruktur,
datepicker,
timepicker1,
timepicker2,
sendungen,
EUP,
EWP,
pakete,
bemerkung,
teile
});
newBuchung.save()
.then(buchung =>{
res.send('saved')
})
.catch(err=>console.log(err));
console.log(newBuchung)
});
router.post(
'/login',
passport.authenticate('local', {
failureRedirect: '/login'
}), (req, res) => {
if (req.user.admin == "spediteur") {
res.redirect('/buchungen/startseite_spediteur');
} else {
res.redirect('/buchungen/startseite_breuninger');
}
});
module.exports = router;
Im thankful for any help :)
I think the issue is that req.user is undefined. Can you try logging req.user during your route function?
router.post('/neueBuchung_spediteur', (req, res) => {
User.findOne({username: req.user}, function (err, user) {
console.log(JSON.stringify(req.user))
res.render('neueBuchung_spediteur', {
gate: user.gate
});
});
Tried this for updating user information , only phone number but it's not getting update.
router.post('/edit', checkAuth, function (req, res, next) {
console.log(req.userData.userId)
User.update({_id: req.userData.userId}, {$set:req.userData.phoneNo}, function (err){
if (err) {
console.log(err);
}
res.status(200).send(req.userData);
});
});
My user controller const mongoose = require ('mongoose');
const User = mongoose.model('User');
module.exports.register = (req, res, next) =>{
var user = new User();
user.fullName = req.body.fullName;
user.email = req.body.email;
user.password = req.body.password;
user.phoneNumber = req.body.phoneNumber;
user.save((err, doc) =>{
if(!err)
res.send(doc);
else{
if (err.code == 11000)
res.status(422).send(["Entered duplicate email address. Please check"]);
else
return next(err);
}
});
}
And then I am authenticating by passing jwt on this field
phoneNo: user[0].phoneNumber
The auth-token verifies and decode the fields
const token = req.headers.authorization.split(" ")[1];
const decoded = jwt.verify(token, process.env.JWT_KEY)
req.userData = decoded;
Update is not working and getting error message Invalid atomic update value for $set. Expected an object, received string .
first of all, you should use PATCH-method - because you are updating only one item in existed object, in body you should send id of user and new value of certain value. If you use mongoose you can try it
User.findOneAndUpdate({ _id: id }, updatedItem, { new: true }, (err, doc) => {
if (err) return res.send(err.message)
if (doc) return res.send(doc);
})
const id = req.body._id;, if you dont use mongoose you should try findAndModify method
Your code
User.update({_id: req.userData.userId}, {$set:req.userData.phoneNo}
Correct code:
User.update({_id: req.userData.userId}, {$set:{phoneNumber:req.userData.phoneNo}}
Try this method:
User.findByIdAndUpdate(req.userData.userId, { $set:{phoneNumber:req.userData.phoneNo}}, { new: true }, function (err, user) {
if (err) console.log(err);
res.send(user);
});