Skip to content

Instantly share code, notes, and snippets.

@arunsivasankaran
Created January 6, 2015 19:05
Show Gist options
  • Save arunsivasankaran/5085292275468b03d0c7 to your computer and use it in GitHub Desktop.
Save arunsivasankaran/5085292275468b03d0c7 to your computer and use it in GitHub Desktop.
User Model for LearnDot
'use strict';
var mongoose = require('mongoose');
var _ = require('lodash');
var extend = require('mongoose-schema-extend');
var Schema = mongoose.Schema;
var crypto = require('crypto');
var Sms = require('../../remote/sms')
var authTypes = ['github', 'twitter', 'facebook', 'google'];
var UserSchema = new Schema({
firstName: String,
lastName:String,
fullName: String,
email: { type: String, lowercase: true },
hashedPassword: { type: String, select: false },
phone: String,
provider: String,
salt: {type: String, select: false },
google: {},
github: {},
roles:[]
}, { collection: "users" });
/**
* Virtuals
*/
UserSchema
.virtual('name')
.set(function(name) {
var split = name.split(' ');
this.fullName = name;
this.firstName = split[0];
this.lastName = split[split.length - 1];
})
UserSchema
.virtual('password')
.set(function(password) {
this._password = password;
this.salt = this.makeSalt();
this.hashedPassword = this.encryptPassword(password);
})
.get(function() {
return this._password;
});
UserSchema
.virtual('role')
.get(function() {
return this.__t
})
// Public profile information
UserSchema
.virtual('profile')
.get(function() {
return {
'fullName': this.fullName,
'firstName': this.firstName,
'lastName': this.lastName,
'email': this.email,
'github': this.github
};
});
// Non-sensitive info we'll be putting in the token
UserSchema
.virtual('token')
.get(function() {
return {
'_id': this._id,
'__t': this.role
};
});
/**
Statics
*/
UserSchema.statics.findByRole = function(r) {
return this.find({roles:{$elemMatch: {$eq: r}}});
}
/**
* Validations
*/
// Validate empty email
UserSchema
.path('email')
.validate(function(email) {
if (authTypes.indexOf(this.provider) !== -1) return true;
return email.length;
}, 'Email cannot be blank');
// Validate empty password
UserSchema
.path('hashedPassword')
.validate(function(hashedPassword) {
if (authTypes.indexOf(this.provider) !== -1) return true;
return hashedPassword.length;
}, 'Password cannot be blank');
// Validate email is not taken
UserSchema
.path('email')
.validate(function(value, respond) {
var self = this;
this.constructor.findOne({email: value}, function(err, user) {
if(err) throw err;
if(user) {
if(self.id === user.id) return respond(true);
return respond(false);
}
respond(true);
});
}, 'The specified email address is already in use.');
var validatePresenceOf = function(value) {
return value && value.length;
};
/**
* Pre-save hook
*/
UserSchema
.pre('save', function(next) {
if (!this.isNew) return next();
if (!validatePresenceOf(this.hashedPassword) && authTypes.indexOf(this.provider) === -1)
next(new Error('Invalid password'));
else
next();
});
/**
* Methods
*/
UserSchema.methods = {
addRole: function(r) {
this.roles.addToSet(r);
},
hasRole: function(r) {
return this.roles.indexOf(r) !== -1
},
/**
* Authenticate - check if the passwords are the same
*
* @param {String} plainText
* @return {Boolean}
* @api public
*/
authenticate: function(plainText) {
return this.encryptPassword(plainText) === this.hashedPassword;
},
/**
* Make salt
*
* @return {String}
* @api public
*/
makeSalt: function() {
return crypto.randomBytes(16).toString('base64');
},
/**
* Encrypt password
*
* @param {String} password
* @return {String}
* @api public
*/
encryptPassword: function(password) {
if (!password || !this.salt) return '';
var salt = new Buffer(this.salt, 'base64');
return crypto.pbkdf2Sync(password, salt, 10000, 64).toString('base64');
},
sms: function(msg,cb) {
if(!this.phone) return process.nextTick(function() {
cb(null, {status: 'failed', message: 'no phone number'})
})
var sms = new Sms(this.phone,msg)
sms.send(cb);
},
sendEmail: function(config,cb) {
config.to = this.email;
var email = new Email(config);
email.send(cb);
},
//this seems stupid but its not. its overwritten in the student model. this is the generic
getWorkshops: function(query,cb) {
mongoose.model('Workshop').find(query).sort('order').exec(cb);
}
};
module.exports = mongoose.model('User', UserSchema);
require('../employee/employee.model');
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment