node.js email verification token - node.js

I'm trying to set up a verification step in Mongoose, Express Node application based on this blog post ... http://danielstudds.com/adding-verify-urls-to-an-express-js-app-to-confirm-user-emails-secure-spa-part-6/ that post is over a year old so it kind of surprises me that its the first google result for 'node email verification'. I'm very new to node so I'm reliant on examples. Based on that post I did not see a download so I pieced it together to suit my scenario and here is what my code looks like.
Verification Model
var mongoose = require('mongoose'),
uuid = require('node-uuid'),
User = require('mongoose').model('User');
var verificationTokenSchema = new mongoose.Schema({
_userid : { type: mongoose.Schema.Types.ObjectId, ref: 'User' },
token: {type: String, required: true},
createdAt: {type: Date, required: true, default: Date.now, expires: '4h'}
});
verificationTokenSchema.methods = {
createVerificationToken : function (done) {
var verificationToken = this;
var token = uuid.v4();
verificationToken.set('token', token);
verificationToken.save( function (err) {
if (err) return done(err);
return done(null, token);
});
}
};
exports.verifyUser = function(token, done) {
verificationTokenModel.findOne({token: token}, function (err, doc){
if (err) return done(err);
User.findOne({_id: doc._userId}, function (err, user) {
if (err) return done(err);
user["verified"] = true;
user.save(function(err) {
done(err);
});
});
});
};
var verificationTokenModel = mongoose.model('VerificationToken', verificationTokenSchema);
exports.verificationTokenModel = verificationTokenModel;
Then in my User model I call create like so..
User Model
exports.createUser = function(req, res, next) {
// Do all the stuff that creates the user save it and get the id back
var verificationToken = new verificationTokenModel({_userId: user._id});
verificationToken.createVerificationToken(function (err, token) {
if (err){
err = new Error("Couldn't create verification token");
res.status(400);
return res.send({reason:err.toString()});
}
// Do stuff with the token here and email
This works 'partially' in my db 'verificationtokens' collection the objects don't contain a _userid they contain the _userid (user._id) stored in _id
My first issue is I don't really understand how this works when there isn't a 'constructor'
var verificationToken = new verificationTokenModel({_userId: user._id});
and how do I get this to store the user._id as _userid in the verification collection

I don't use Mongoose, but here is what it happened:
For your first question:
when you run:
var verificationTokenModel = mongoose.model('VerificationToken', verificationTokenSchema);
it creates the constructor.
For the second question:
MongoDB always create documents with a field called "_id", so, the "_id" field in your verification collection is not the "_id" field from your User collection. The reason that _userid is not inserted is because you have a typo:
var verificationToken = new verificationTokenModel({_userId: user._id});
where "_userId" should be "userid"

Related

Update existing user data in database

Currently, I have managed to the save user information inside my database. However I wanted to update the user information inside my database when they logged in if there is changes of information inside Steam database. So it is the same inside my database.
Below are example of information inside my User schema
const UserSchema = mongoose.Schema({
username:{
type: String,
},
profileURL:{
type: String,
},
profileImageURL:{
type: String,
},
steamId:{
type: String,
}
});
Below are example of my app.js. When the user login, I checked if the user steamId exist inside my database, I want to update the user information such as username, profileURL, profileImageURL and its steamID if exist else I create a new user inside my database. How can I achieve this? Currently, I just return done(null, user).
passport.use(new SteamStrategy({
returnURL: 'http://localhost:3000/auth/steam/return',
realm: 'http://localhost:3000/',
apiKey: ''
},
function (identifier, done){
var steamId = identifier.match(/\d+$/)[0];
var profileURL = 'http://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=' + 'api_Key' + '&steamids=' + steamId;
User.findOne({ steamId: steamId}, function(err, user){
if(user){
return done(null, user);
}
else{
request(profileURL, function (error, response, body){
if (!error && response.statusCode === 200)
{
var data = JSON.parse(body);
var profile = data.response.players[0];
var user = new User();
user.username = profile.personaname;
user.profileURL = profile.profileurl;
user.profileImageURL = profile.avatarfull;
user.steamId = steamId;
user.save(function(err){
done(err, user);
});
}
else
{
done(err, null);
}
});
}
});
}));
You could do this with an upsert-enabled update call. Try something like this:
request(profileURL, function(err, response, body){
var data = JSON.parse(body);
var user = {
//... construct user object
}
User.findOneAndUpdate({ steamId: steamId }, user, {upsert: true, new: true, setDefaultsOnInsert: true}, function(err, newUser){
if (err) return handleError(err);
done(null, newUser);
});
});

How to add to User Object Node.JS

I'm new to node so bear with me!
I am working on my auth system. I have login, register and logout done so far. Now I want to update my user in the settings page. How would I go about updating the already added User items such as username, password and email? And most importantly adding new ones such as API Key, and API Secret.
Here is my code:
var UserSchema = mongoose.Schema({
username: {
type: String,
index:true
},
email: {
type: String
},
password: {
type: String
},
apiKey: {
type: String
},
apiSecret: {
type: String
}
});
My user schema, the api key info is not added on registration. Should it be in the schema or will it be added automatically later?
var newUser = new User({
username: username,
email:email,
password: password
});
User.createUser(newUser, function(err, user){
if(err) throw err;
console.log(user);
req.flash('success_msg', 'You are registered and can now login');
res.redirect('/users/login');
});
How I create the new user after verification.
router.post('/settings', function(req, res){
var apiKey = req.body.apiKey;
var apiSecret = req.body.apiSecret;
//INSERT api info into DB here
});
Where I get the API keys from a form and then want to insert them into the User that is currently logged in. This is where my problem is.
Thank you in advance for any help!
Assuming you've access to the logged in user in req like req.user
router.post('/settings', function(req, res) {
var updateFields = {
apiKey: req.body.apiKey,
apiSecret: req.body.apiSecret
}
User.findOneAndUpdate({"_id": req.user._id}, {"$set": updateFields}, {"new": true}})
.exec(function(err, user) {
if (err) {
//handle err
} else {
//user contains updated user document
}
});
});
And yes you should keep all the fields you want to insert even in future in the schema. Else they won't insert into database.

Inserting an array in mongodb using mongoose in a schema where other fields are already added from user registration

I am creating an application for online course.
I have created a schema for user registration. In the schema, I also want to add the name of courses a user in enrolled. Course Name being an array.
User registration is successful. after that I have created a route for /dashboard, where the user sends the POST request to add the course name. That course should be added in the same registration schema field for course Enrolled. However When I save a new object of registration schema, it creates a new document field courseEnrolled field. I want this POST request value to be added in the user's document field of courseEnrolled as an array.
Here is how I have defined my registration schema. Its name in account.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var passportLocalMongoose = require('passport-local-mongoose');
var courseSchema = new Schema({ courseName : String });
var Account = new Schema({
username: {
type: String,
unique: true
},
password: String,
email: String,
firstName: String,
lastName: String,
courseEnrolled: [{courseName : String}]
});
Account.plugin(passportLocalMongoose);
module.exports = mongoose.model('Account', Account);
Here is my passport registration . register.js
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var User = require('../models/account');
var bCrypt = require('bcrypt-nodejs');
var course = require('../models/courseEnrollment');
module.exports = function(passport){
passport.use('register', new LocalStrategy({
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, username, password, done) {
findOrCreateUser = function(){
// find a user in Mongo with provided username
User.findOne({ 'username' : username }, function(err, user) {
// In case of any error, return using the done method
if (err){
console.log('Error in SignUp: '+err);
return done(err);
}
// already exists
if (user) {
console.log('User already exists with username: '+username);
return done(null, false, req.flash('message','User Already Exists'));
} else {
// if there is no user with that email
// create the user
var newUser = new User();
var newCourse = new course();
// set the user's local credentials
newUser.username = username;
newUser.password = createHash(password);
newUser.email = req.body.email;
newUser.firstName = req.body.firstName;
newUser.lastName = req.body.lastName;
newUser.courseEnrolled = req.body.courseEnrolled;
// save the user
newUser.save(function(err) {
if (err){
console.log('Error in Saving user: '+err);
throw err;
}
console.log('User Registration succesful');
return done(null, newUser);
});
}
});
};
// Delay the execution of findOrCreateUser and execute the method
// in the next tick of the event loop
process.nextTick(findOrCreateUser);
})
);
// Generates hash using bCrypt
var createHash = function(password){
return bCrypt.hashSync(password, bCrypt.genSaltSync(10), null);
}
}
I can register a user successfully. After that I have a route for /dashboard, where I handle the POST request to add a course.
Here is the snippet of my /dashboard handling POST request.
var User = require('../models/account');
/* POST dashboard Page */
router.post('/dashboard', isAuthenticated, function (req, res) {
sess = req.session.passport.user;
console.log('session value is: ' + sess);
var newUser = new User();
console.log('newUser id is: ' + newUser._id);
var currentUser = req.user._id;
console.log('current User id is: ' + currentUser);
var myUser = req.user;
console.log('myUsers value is: ' + myUser);
var myUserCourse = req.user.courseEnrolled;
if (sess == currentUser) {
//var newCourse = new course();
console.log('request received: ' + req.body.courseEnrolled);
req.user.courseEnrolled = req.body.courseEnrolled;
newUser.save(function (err, data) {
if(error)
throw error;
else {
console.log('course Updated');
}
});
res.render('home', {user: req.user});
}
});
This newUser.save() function creates a new document in the mongodb and store the courseEnrolled. I want to store the value of req.body.courseEnrolled in the same document field where other user value is defined.
This is getting stored in collection:- 'accounts' for the user
{
"_id" : ObjectId("57f95afd9c78b91c69334f0d"),
"lastName" : "Nehra",
"firstName" : "Ashish",
"email" : "ashish.nehra#stanford.edu",
"password" : "$2a$10$YzLvbQTHFtq5l0ooP0njOux94Rp.pm.Pkb/TugBnCSTUJNhBBonLG",
"username" : "ashish",
"courseEnrolled" : [
"about to change something now"
],
"__v" : 1
}
And there is a new document being created like this in the same collection.
{
"_id" : ObjectId("5803fc4342ca1d3167102300"),
"courseEnrolled" : [ ],
"__v" : 0
}
This is logical because first you do a it on various user objects (req.user / new user):
**var newUser = new User();
This will create a new User object, and then:
newUser.save(function (err, data) {
This will save the newly created user into a new document. If you want to use the .save, rewrite it to (reused your own code):
User.findOne({ 'username' : username }, function(err, user) {
// In case of any error, return using the done method
if (err){
console.log('Error in SignUp: '+err);
return done(err);
}
user.courseEnrolled = req.body.courseEnrolled;
user.save(function (err, data) {
if(err)
throw err;
else {
console.log('course Updated');
}
});

How to model and save in mongoose multi-to-multi relationship?

I want to 2 model, one is user that can belongs to multiple groups, and another is group that can has multiple users.
This is my schemas and models, i don't know whether they the correct:
var Schema = mongoose.Schema;
var UserSchema = new Schema({
joinedGroups:[{type:Schema.Types.ObjectId, ref: 'Group'}]
}
);
var GroupSchema = new Schema({
createdBy: {type: Schema.Types.ObjectId, ref: 'User'},
joinedUsers:[{ type: Schema.Types.ObjectId, ref: 'User' }]
});
var User = mongoose.model('User',UserSchema);
var Group = mongoose.model('Group',GroupSchema);
when receive POST of url:/api/groups with the body of user._id, I want to join this user to new create group, besides, i want to join this new created group to user's joinedGroups and finally i want to response the client of the new group with users in it. Follow is my code of doing this:
app.post('/api/groups', function(req, res){
console.log(req.body);
var userId = req.body.user_id;
var group = {
createdBy : userId
};
Group.create(group, function(err,group){
if(err){
console.log('create group err');
res.send(err);
}
else{
console.log('create group success');
User.update({_id: userId},
{$push: {joinedGroups: group._id}},
function(err,user){
if(err){
console.log('update user err');
res.send(err);
}
else{
Group.update({_id: group._id},
{$push: {joinedUsers: user}},
function(err,group){
if(err){
console.log('update group err:' + err);
res.send(err);
}
else{
group.populate({path:'joinedUsers'},
function(err, group){
if(err){
console.log('populate group err');
res.send(err);
}
else{
console.log('populate group success');
res.json(group);
}
}
);
}
});
}
});
}
});
});
I feel it's really complex, and it occur error :
update group err:CastError: Cast to ObjectId failed for value "1" at path "joinedUsers"
So i want somebody help me with right solution to do this, thanks!
edit:
I also want to support join user in to existed group in PUT /api/group/:group_id like below:
var userId = req.body.user_id;
var groupId = req.params.group_id;
how to do that? thanks!
First of all, your realization is really complex and it can be simplified as this:
var userId = req.body.user_id; // this is an ObjectId
var group = {
createdBy: userId,
joinedUsers: userId
};
Group.create(group, function (err, group) {
if (err || !group) {
return res.send(err);
}
User.findById(userId, function (err, user) {
if (err || !user) {
return res.send(err);
}
user.joinedGroups.push(group._id);
user.save(function (err) {
if (err) {
return res.send(err);
}
group.populate('joinedUsers', function (err, group) {
if (err || group) {
return res.send(err);
}
res.json(group);
});
});
});
});
And the reason why you getting CastError error is: the update method returns 1 as second argument of callback if successfully updated. But your Group#joinedUsers filed expecting User reference.

Cannot call method 'findOne' of undefined at Object.module.exports

Need to knoe why I'mgetting this error? is my approach for validating the user thorugh login form correct here? I'm just new to node.js need your help.
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connect('mongodb://localhost/subscribe');
var mySchema = new mongoose.Schema({
_id : String,
name : String,
phone : String,
age : Number,
password : String
});
var User = mongoose.model('signups', mySchema);
Signup form , to save the registered user in the mongodb collection.
router.post('/signup', function(req, res) {
var user = new User({
_id : req.body.email,
phone : req.body.phone,
age : req.body.age,
password : req.body.password
});
user.save(function (err, doc) {
if (err) {
res.send("There was a problem adding the information to the database.");
}
else {
res.redirect('/');
}
});
});
trying to validate the user credentials
router.post('/adduser',function(req, res){
db.signups.findOne({ $and: [{_id: req.body.useremail}, {password: req.body.password }]}, function(err, item) {
if (err) return res.send("Please provide valid credentials.");
else {
res.redirect('/home');
}
});
});
How to validate the user credentials here?

Resources