0

I have the following schema for user and sp. sp is short for service provider. Service provider is a user, it has a reference to user. I am trying to signup and singin using PassportJS module of NodeJS. I have been able to signup an sp and I could see the data persisted in MongoDB collections in users and sps collections, but I am not able to display the complete data of sp on the profile page. I get to display only its user data. For example, I don't see the sp's spname data in the profile page after authentication.

Following is some of the code:

Schema for user:

var userSchema = mongoose.Schema({
        ip: String,
        local            : {
            email        : String,
            password     : String
        }
        name: String ,
        created: { type: Date, default: Date.now },
    })
    .plugin(mongooseRole, {
        roles: ['public', 'user', 'sp', 'admin'],
        accessLevels: {
            'public': ['public', 'user', 'sp', 'admin'],
            'anon': ['public'],
            'user': ['user', 'admin'],
            'sp': ['sp', 'admin'],
            'admin': ['admin']
    }
});
var User = mongoose.model("User", userSchema);

Schema for sp:

var spSchema = mongoose.Schema({
    user: { type: Schema.ObjectId, ref: 'User' },
    spname: String,
});
var SP = mongoose.model("SP", spSchema);

PassportJS code for logging in:

//serialization/deserialization code
    // used to serialize the user for the session
    passport.serializeUser(function(user, done) {
        done(null, user.id);
    });

    // used to deserialize the user
    passport.deserializeUser(function(id, done) {
        User.findById(id, function(err, user) {
            done(err, user);
        });
    });


//authentication code
    passport.use('local-login', new LocalStrategy({
            usernameField : 'email',
            passwordField : 'password',
            passReqToCallback : true
        },
        function(req, email, password, done) {

            User.findOne({ 'local.email' :  email }, function(err, user) {

                if(user.role == 'sp') {
                    SP.findOne({ user: user._id }).populate('user').exec(function(err, sp) {
                        if (err)
                            return done(err);
                        if (!sp.user)
                            return done(null, false, req.flash('loginMessage', 'No sp user found.')); 

                        if (!sp.user.validPassword(password))
                            return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); 
                        return done(null, sp);
                    });
                } 

                if (err)
                    return done(err);

                if (!user)
                    return done(null, false, req.flash('loginMessage', 'No user found.')); 

                if (!user.validPassword(password))
                    return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); 

                return done(null, user);
            });

        }));

Displaying the profile:

app.get('/profile', isLoggedIn, function (req, res) {

    res.render('profile', {
        user: req.user
    });
});

profile.ejs

<%= user %>

Could somebody help me with what should I be doing to display the whole sp object with all its data?

skip
  • 12,193
  • 32
  • 113
  • 153

1 Answers1

1

You're only querying User schema while deserializing. You need to deserialize sp if you want it. I'm not entirely sure about your situation but it seems that you're either authenticating a User or an SP, in which case you should similarly either deserializing User or SP (if User returns empty). Something like this maybe:

// used to deserialize the user
passport.deserializeUser(function(id, done) {
    User.findById(id, function(err, user) {
        if (user.role == 'sp')
            SP.findOne({user: user_id}).populate('user').exec(function(err, sp) {
                done(err, sp);
            });
        else done(err, user);
    });
});
laggingreflex
  • 32,948
  • 35
  • 141
  • 196
  • Thanks for the reply reflex. I am authenticating against only one collection `users`, only the additional data for `sp` is in the `sps` collections. Please tell me if authentication could be done using multiple table. Once I have a user authenticated, I check whether the given user is a normal user with `user` role, or if its an service provider with role `sp`. In the code answered by you for `deserializeUser`, would the code even run after `if(!err && user) return done(err, user);` if there is no error and the `user` is found? Would the `SP` data not lost if the user is found? – skip Oct 18 '14 at 03:12
  • I had tried the following code, but it did not work either: `passport.deserializeUser(function(id, done) { User.findById(id, function(err, user) { if(user.role = 'sp') { SP.findOne({user: user_id}).populate('user').exec(function (err, sp) { if (!err) { done(err, sp); } } } done(err, user); }); });` What mistake am I committing here? – skip Oct 18 '14 at 03:12
  • @laggingreflexes: I tried exactly that, but it did not work. There is a typo in your answer, just like I had it in my comment, it should be `==` in `if (user.role == 'sp')`. Thanks for the reply. I am not sure why am I still getting just the data for the user schema even when it says that its a user with role `sp`? – skip Oct 18 '14 at 05:25
  • @skip On second looks it should be `user.roles`. Be sure by logging `console.log(user.roles)`? – laggingreflex Oct 18 '14 at 07:02
  • No reflex, `var newUser = newUser({email: 'email@email.com', role: 'user'});` this is an example of how you give a new user a `role`. You could check that at https://www.npmjs.org/package/mongoose-role. And also I've got the data persisted for both `user` and `sp` correctly as I could see it with user having a `role` key. So `user.role` is fine. – skip Oct 18 '14 at 07:10
  • 1
    @skip Are you still able to `console.log(user.role)`? – laggingreflex Oct 18 '14 at 07:14
  • Yes reflex, the `user.role` is being compared as well for `if(user.role == 'sp')` and at many other places in the app. – skip Oct 18 '14 at 07:21
  • @skip Can you `console.log(sp)` from the `SP.findOne(...,function(err, sp){...` callback? – laggingreflex Oct 18 '14 at 07:30
  • @legginreflex: `console.log(sp)` displays the whole `sp` on the console, populated with `user` (`sp.user`). – skip Oct 18 '14 at 07:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/63268/discussion-between-laggingreflex-and-skip). – laggingreflex Oct 18 '14 at 07:52