Home Reference Source Repository

src/models/user.js

// Import the neccesary modules.
import bcrypt from 'bcrypt-nodejs';
import jwt from 'jsonwebtoken';
import mongoose from 'mongoose';

/**
 * The user schema used by mongoose.
 * @type {Schema}
 * @see http://mongoosejs.com/docs/guide.html
 */
const _userSchema = new mongoose.Schema({
  _id: {
    type: String,
    required: true,
    index: {
      unique: true
    }
  },
  firstname: {
    type: String,
    required: true
  },
  lastname: {
    type: String,
    required: true
  },
  email: {
    type: String,
    required: true, unique: true
  },
  username: {
    type: String,
    required: true, unique: true
  },
  password: {
    type: String,
    required: true
  },
  beers: [{
    type: String,
    ref: 'Beer'
  }]
}, {
  versionKey: false
});

/**
 * Function executed before saving the user.
 * @param {function} next - The next function for Express.
 * @returns {void}
 */
function pre(next) {
  const user = this;
  if (!user.isModified('password')) return next();
  bcrypt.genSalt(10, (err, salt) => {
    if (err) return next(err);
    bcrypt.hash(user.password, salt, null, (err, hash) => {
      if (err) return next(err);
      user.password = hash;
      return next();
    });
  });
}

/**
 * Verify if a password is correct.
 * @param {String} password - The password to verify.
 * @param {function} callback - The function to return.
 * @returns {function} - The callback function.
 */
function verifyPassword(password, callback) {
  bcrypt.compare(password, this.password, (err, isMatch) => {
    if (err) return callback(err);
    return callback(null, isMatch);
  });
}

/**
 * Generate a JSON webtoken for a user.
 * @returns {Object} - The generated webtoken.
 */
function generateJWT() {
  const today = new Date();
  const exp = new Date(today);
  exp.setDate(today.getDate() + 60);
  const { _id, username } = this;
  return jwt.sign({
    _id, username,
    exp: parseInt(exp.getTime() / 1000, 10)
  }, process.env.SECRET || 'SECRET');
}

/**
 * Add a beer from the 'beers' array.
 * @param {Sting} beer - The beer to add.
 * @returns {Promise} - A promise to save the user.
 */
function addBeer(beer) {
  this.beers.push(beer.name);
  return this.save();
}

/**
 * Remove a beer from the 'beers' array.
 * @param {Sting} beer - The beer to remove.
 * @returns {Promise} - A promise to save the user.
 */
function removeBeer(beer) {
  const index = this.beers.indexOf(beer.name);
  this.beers.splice(index, 1);
  return this.save();
}

// Adding the functions to the user model.
_userSchema.pre('save', pre);
_userSchema.methods.verifyPassword = verifyPassword;
_userSchema.methods.generateJWT = generateJWT;
_userSchema.methods.addBeer = addBeer;
_userSchema.methods.removeBeer = removeBeer;

/**
 * A model object for users.
 * @type {User}
 */
export default mongoose.model('User', _userSchema);