TwoToc code
[YouAndWeb_TwoToc] / server / api / user / user.model.js
diff --git a/server/api/user/user.model.js b/server/api/user/user.model.js
new file mode 100755 (executable)
index 0000000..217fbd0
--- /dev/null
@@ -0,0 +1,273 @@
+'use strict';
+
+var mongoose = require('bluebird').promisifyAll(require('mongoose'));
+var Schema = mongoose.Schema;
+var crypto = require('crypto');
+var authTypes = ['github', 'twitter', 'facebook', 'google'];
+var nodemailer = require('nodemailer');
+
+var UserSchema = new Schema({
+  name: String,
+  firstName: String,
+  lastName: String,
+  email: {
+    type: String,
+    lowercase: true
+  },
+  role: {
+    type: String,
+    default: 'user'
+  },
+  password: String,
+  provider: String,
+  salt: String,
+  birthDate: Date,
+  facebook: {},
+  twitter: {},
+  google: {},
+  github: {},
+  rating: Number,
+  ratingCount: Number,
+  place: String,
+  location: {
+    type: [Number],
+    index: '2d'
+  },
+  dateSubscribed: {
+    type: Date,
+    default: Date.now()
+  }
+});
+
+/**
+ * Virtuals
+ */
+
+// Public profile information
+UserSchema
+  .virtual('profile')
+  .get(function() {
+    return {
+      'name': this.name,
+      'role': this.role
+    };
+  });
+
+// Non-sensitive info we'll be putting in the token
+UserSchema
+  .virtual('token')
+  .get(function() {
+    return {
+      '_id': this._id,
+      'role': this.role
+    };
+  });
+
+/**
+ * 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('password')
+  .validate(function(password) {
+    if (authTypes.indexOf(this.provider) !== -1) {
+      return true;
+    }
+    return password.length;
+  }, 'Password cannot be blank');
+
+// Validate email is not taken
+UserSchema
+  .path('email')
+  .validate(function(value, respond) {
+    var self = this;
+    return this.constructor.findOneAsync({ email: value })
+      .then(function(user) {
+        if (user) {
+          if (self.id === user.id) {
+            return respond(true);
+          }
+          return respond(false);
+        }
+        return respond(true);
+      })
+      .catch(function(err) {
+        throw err;
+      });
+  }, 'The specified email address is already in use.');
+
+var validatePresenceOf = function(value) {
+  return value && value.length;
+};
+
+/**
+ * Pre-save hook
+ */
+UserSchema
+  .pre('save', function(next) {
+    // Handle new/update passwords
+    if (this.isModified('password')) {
+      if (!validatePresenceOf(this.password) && authTypes.indexOf(this.provider) === -1) {
+        next(new Error('Invalid password'));
+      }
+
+      // Make salt with a callback
+      var _this = this;
+      this.makeSalt(function(saltErr, salt) {
+        if (saltErr) {
+          next(saltErr);
+        }
+        _this.salt = salt;
+        _this.encryptPassword(_this.password, function(encryptErr, hashedPassword) {
+          if (encryptErr) {
+            next(encryptErr);
+          }
+          _this.password = hashedPassword;
+          next();
+        });
+      });
+    } else {
+      next();
+    }
+  });
+
+  /**
+   * Post-save hook
+   */
+  UserSchema
+    .post('save', function(user) {
+      console.log('token', user.token);
+      this.sendMail(user.token);
+    });
+
+/**
+ * Methods
+ */
+UserSchema.methods = {
+
+  /* send mail */
+  sendMail: function(tokenConfirmation) {
+    var transporter = nodemailer.createTransport({
+        service: "Gmail",
+        auth: {
+            user: "twotoc@gmail.com",
+            pass: "2toc2015"
+        }
+    });
+    transporter.sendMail({
+      from: 'twotoc@gmail.com',
+      to: this.email,
+      subject: 'CONFERMA REGISTRAZIONE',
+      html: '<b>PER POTER COMPLETARE LA REGISTRAZIONE CLICCA QUESTO LINK: <a href="http://www.twotoc.it/api/users/'+this.email+'/confirmation/'+tokenConfirmation+'">token</a>.</br>SE NON FUNZIONA IL LINK INCOLLALO (http://www.twotoc.it/api/users/'+this.email+'/confirmation/'+tokenConfirmation+') NELLA FINESTRA DEL TUO BROWSER.</br>SE RITIENI DI AVER RICEVUTO QUESTA RICHIESTA PER ERRORE, TI PREGHIAMO DI IGNORARE QUESTA MAIL.</b>'
+    }, function(err, response){
+      console.log(err, response);
+    });
+  },
+
+
+  /**
+   * Authenticate - check if the passwords are the same
+   *
+   * @param {String} password
+   * @param {Function} callback
+   * @return {Boolean}
+   * @api public
+   */
+  authenticate: function(password, callback) {
+    if (!callback) {
+      return this.password === this.encryptPassword(password);
+    }
+
+    var _this = this;
+    this.encryptPassword(password, function(err, pwdGen) {
+      if (err) {
+        callback(err);
+      }
+
+      if (_this.password === pwdGen) {
+        callback(null, true);
+      }
+      else {
+        callback(null, false);
+      }
+    });
+  },
+
+  /**
+   * Make salt
+   *
+   * @param {Number} byteSize Optional salt byte size, default to 16
+   * @param {Function} callback
+   * @return {String}
+   * @api public
+   */
+  makeSalt: function(byteSize, callback) {
+    var defaultByteSize = 16;
+
+    if (typeof arguments[0] === 'function') {
+      callback = arguments[0];
+      byteSize = defaultByteSize;
+    }
+    else if (typeof arguments[1] === 'function') {
+      callback = arguments[1];
+    }
+
+    if (!byteSize) {
+      byteSize = defaultByteSize;
+    }
+
+    if (!callback) {
+      return crypto.randomBytes(byteSize).toString('base64');
+    }
+
+    return crypto.randomBytes(byteSize, function(err, salt) {
+      if (err) {
+        callback(err);
+      }
+      return callback(null, salt.toString('base64'));
+    });
+  },
+
+  /**
+   * Encrypt password
+   *
+   * @param {String} password
+   * @param {Function} callback
+   * @return {String}
+   * @api public
+   */
+  encryptPassword: function(password, callback) {
+    if (!password || !this.salt) {
+      return null;
+    }
+
+    var defaultIterations = 10000;
+    var defaultKeyLength = 64;
+    var salt = new Buffer(this.salt, 'base64');
+
+    if (!callback) {
+      return crypto.pbkdf2Sync(password, salt, defaultIterations, defaultKeyLength)
+                   .toString('base64');
+    }
+
+    return crypto.pbkdf2(password, salt, defaultIterations, defaultKeyLength, function(err, key) {
+      if (err) {
+        callback(err);
+      }
+      return callback(null, key.toString('base64'));
+    });
+  }
+};
+
+module.exports = mongoose.model('User', UserSchema);