Here is a route I have:
router.get('/home', function (req, res) {
User.findOne({_id: req.user._id}, function (err, user) {
if (err) return next(err);
res.render('home', {user: user});
});
});
Basically, in order for someone to view this /home page they need to be logged in, which is where User.findOne comes into play. It will search for the user in the 'user' collection; if it doesn't find the user (if the user isn't logged in), it will return an error. Otherwise, it will show them the /home page.
Now, I want to have a separate Admin section of my website where only users with admin privileges can access the page. I've tried doing something like this:
router.get('/admin', function (req, res) {
User.findOne({_id: req.user._id, admin: true}, function (err, user) {
if (err) return next(err);
res.render('admin', {user: user});
});
});
What I'm trying to get the code to do is to look for 2 parameters: whether the user is logged in, and whether or not in that user document their 'admin' is set to 'true'. Obviously the above code doesn't work, and I don't know how to get this to work better.
EDIT: my user schema:
var schema = mongoose.Schema;
var UserSchema = new schema ({
username: {type: String, unique: true},
email: {type: String, unique: true, lowercase: true, required: true},
password: {type: String, minlength: passMinLength, required: true},
admin: {type: Boolean, default: false},
profile: {
firstName: {type: String, default: ''},
lastName: {type: String, default: ''}
}
});
there is nothing wrong in the query {_id: req.user._id, admin: true} , and it should work if User.Schema contains the admin(Boolean) field also.
Besides, alternate way is to check for admin once you get the User object.
User.findOne({_id: req.user._id}, function (err, user) {
if (err) return next(err);
if(!user){
//considering admin is boolean field
if(!user.admin){
// Not Authorised to access, do something
}
else{
// User verified as Admin
res.render('admin', {user: user});
}
}
// UserId Not found, do something
});
Related
My website has a 'follow' feature, where users can follow each other.
Ideally, a user1 would be able to follow a user2, and have their _id present inside user2.followers, aswell as user2 should be present in user1.following.
My first thought was to simply do something like
/*
UserSchema = new Schema({
username: String,
followers: [
{
type: Schema.Types.ObjectId,
ref: 'user'
}
],
following: [
{
type: Schema.Types.ObjectId,
ref: 'user'
}
]
})
*/
// POST /api/users/follow
let user = await User.findById(userId)
let follow = await User.findById(followId)
if (!user || !follow) {
return errorHandle()
}
user.following.push(follow._id);
follow.followers.push(user._id);
user.save();
follow.save();
/*
User.findById(userId)
.populate('following', 'username')
.then(user => console.log(user.following))
*/
But these would be difficult to scale and maintain (as well as other problems).
So I want to hear from you, the stack community, what a proper way to deal with this system be, as I am new to MongoDB and Databases as a whole.
Any help is appreciated
hey I was getting the same problem I figured it out how it can be done. I have two way of writing the code choose as per your choice.
UserSchema
var UserSchema = new Schema({
name:{
type:String,
required:true
},
email:{
type:String,
required:true
},
password:{
type:String,
required:true
},
following: [
{
user:{
type: Schema.ObjectId,
ref: 'User'
},
}
],
followers: [
{
user:{
type: Schema.ObjectId,
ref: 'User'
},
}
],
date:{
type:Date,
default: Date.now
},
});
First Method
User.js
You can use .then and .catch method
router.post("/user/:user_id/follow-user", (req,res) => {
// finding user by id (to whom user is going to follow)
User.findById(req.params.user_id)
.then(user => {
//check if follow reqest by user2 is already exist in user1 followers
if(user.followers.filter(follower => follower.user.toString()=== req.user._id).length > 0 ){
return res.status(400).json({ alreadyLike : "User already like the post"})
}
// the requested user will push and save to followers of other user to whom request has made
user.followers.push(req.user._id);
var followedUser = user._id;
user.save()
// we will find current user by email you can find it by _id also
User.findOne({ email: req.user.email })
.then(user => {
// now push the user to following of its own and save the user
user.following.push(followedUser);
user.save().then(user => res.json(user))
})
.catch(err => console.log("error cant follow again you jave already followed the user"))
})
})
second method
Normal method by call backs
router.post("/user/:user_id/follow-user", (req,res) => {
// finding user by id (to whom user is going to follow)
User.findById(req.params.user_id, function(err, user) {
// the requested user will push and save to followers of other user to whom request has made
user.followers.push(req.user._id);
var followedUser = user._id;
user.save(function(err){
if(err){
console.log(err)
}
else
{
// Secondly, find the user account for the logged in user
User.findOne({ email: req.user.email }, function(err, user) {
user.following.push(followedUser);
user.save(function(err){
if(err){
console.log(err)
}
else{
//send success response
res.json(user)
}
});
});
}
});
});
});
I am making sure that my db doesnt have duplicate usernames or email addresses for my users using the unique: true attribute, but I am able to create users with duplicate usernames...so something isn't working. I have tried dropping the database, this did not solve the issue. Also in Model.on('index'), sometimes the error is not outputted to the console, sometimes it is. Strange.
var userSchema = mongoose.Schema({
username: {type: String, unique: true, required: true},
password: {type: String, required: true, select: false},
emailAddress: {type: String, unique: true, required: true},
emailVerified: {type: Boolean, default: false},
emailVerificationCode: {type: Number},
friends: []
});
userSchema.pre('save', function(next) {
var user = this;
if (!user.isModified('password')) return next();
bcrypt.genSalt(10, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});
var User = mongoose.model('User', userSchema);
User.on('index', function(err) {
console.log(err);
});
module.exports = User;
And my node router for adding users to the db...
router.post('/register', function(req, res, next) {
var newUser = new User({ username: req.body.username, password: req.body.password, emailAddress: req.body.email });
newUser.save(function(err, newUser) {
if (err) return next(err);
newUser.sendVerificationEmail(function(err, isSent) {
if (err) return next(err);
res.json({ success: true });
});
});
});
He there,
I just started using express / mongoose and I'm new with the concept. Currently trying to update a counter each time a user logges in. I'm using expres 4.8.8, mongoose, 3.8.15, passport 0.2.1
I have the following route, the function is being called on success:
// Set up the 'signin' routes
app.route('/signin')
.get(users.renderSignin)
.post(passport.authenticate('local', {
failureRedirect: '/',
failureFlash: true
}),function(req,res,next){
users.updateLoginCount(req.user.id);
res.redirect('/');
});
Then in the user controller, I want to update the login counter of the user that is currently logging in:
exports.updateLoginCount = function(user_id){
User.findById(user_id, function(err,user){
if(!err){
user.counters.login += 1;
user.save(function(err){
console.log('start save');
if(err) {
console.log(err);
}else{
console.log(user.username + ' logged in for the ' + user.counters.login + ' time');
}
});
}else{
console.log('Error');
}
});
};
Model looks something like:
// Define a new 'UserSchema'
var UserSchema = new Schema({
firstName: String,
lastName: String,
email: {
type: String,
// Validate the email format
match: [/.+\#.+\..+/, "Please fill a valid email address"]
},
username: {
type: String,
// Set a unique 'username' index
unique: true,
// Validate 'username' value existance
required: 'Username is required',
// Trim the 'username' field
trim: true
},
password: {
type: String,
// Validate the 'password' value length
validate: [
function(password) {
return password && password.length > 6;
}, 'Password should be longer'
]
},
salt: {
type: String
},
provider: {
type: String,
// Validate 'provider' value existance
required: 'Provider is required'
},
providerId: String,
providerData: {},
created: {
type: Date,
// Create a default 'created' value
default: Date.now
},
counters:{
login:{
type:Number,
default: 0,
}
}
});
But somehow it doesn't call the user.save(). It also doesn't show any errors, so I have no idea what I'm doing wrong here. It works fine till the user.save() part.
I hope that someone can point out the mistake I'm making. If there is more information needed, please let me know!
Since the node.js is asynchronus I believe that your res.redirect executed before the login update function finishes executing. So, you need to set a callback for your method and run the res.redirect after your update is completed.
You can use mongoose update statement to increase a value like below by the way. Of course go on with the findById if you need other user info.
exports.updateLoginCount = function(user_id, callback){
User.update('_id' : user_id, {$inc: {"counters.login" : 1}}, function(err){
if(err)
console.log(err);
else{
console.log(user_id + " login count increased by one" );
callback();
}
});
}
Calling the method;
...
}),function(req,res,next){
users.updateLoginCount(req.user.id, function(){
res.redirect('/');
});
});
PS: I don't have a chance to test it now though, probably includes some syntax errors :)
I have a pretty basic user model in mongoose. It looks something like this.
var userSchema = new mongoose.Schema({
name: String,
email: String,
username: String,
message: {
active {type: Boolean, default: false},
text: String
}
});
When a user requests a certain page, I use findOne to get data for the user
UserModel.findOne({username: matchLowerCase(req.session.user)}, function (err, doc)
{
if (doc)
{
res.render('main', {
username: doc.username,
//etc
});
}
});
After the user loads the page, I want to set the "message" key to be inactive, like so.
doc.message = {
active: false,
text: ''
}
doc.markModified('message');
doc.save(function (err)
{
console.log('save err', err);
});
For whatever reason, doc.save() is not updating the message key. If I modify any other field in the script, doc.save() works. What am I missing?
I am trying to return an updated object as JSON, where the update was to set an array of objectIDs. I want the returned objected to have that array populated. For example, I have the following (simplified) model:
var UserSchema = new mongoose.Schema({
username: {type: String, unique: true, required: true},
friends: [{type: mongoose.Schema.Types.ObjectId, ref: 'User'}]
});
In my controller, I have:
exports.saveFriends = function(req, res) {
User.findById(req.params.user_id, function(err, user) {
// req.body.friends is JSON list of objectIDs for other users
user.friends = req.body.friends
user.save(function(err) {
user.populate({path: 'friends'}, function(err, ticket) {
if (err) {
res.send(err);
} else {
res.json(user);
}
});
});
});
}
This does in fact save the array properly as ObjectIDs, but the response user always shows "[]" as the array of friends.
Anyone see my issue?