bensaufley/code-words-api

View on GitHub
models/user.js

Summary

Maintainability
A
45 mins
Test Coverage
'use strict';

const Sequelize = require('sequelize'),
      bcrypt = require('bcrypt-nodejs'),
      config = require('../config'),
      sequelizeInstance = config.sequelize;

const setSecurePassword = (user, options) => {
  if (!user.password) return Promise.resolve(options);

  return new Promise((resolve, reject) => {
    bcrypt.genSalt(10, (err, salt) => {
      // istanbul ignore if
      if (err) reject(err);
      else resolve(salt);
    });
  }).then((salt) => {
    return new Promise((resolve, reject) => {
      bcrypt.hash(user.get('password'), salt, null, (err, hash) => {
        // istanbul ignore if
        if (err) reject(err);
        else resolve(hash);
      });
    });
  }).then((hash) => {
    user.set('passwordDigest', hash);
    return options;
  });
};

class User extends Sequelize.Model {
  authenticate (password) {
    return new Promise((resolve, reject) => {
      bcrypt.compare(password, this.passwordDigest, (err, result) => {
        // istanbul ignore if
        if (err) return reject(err);
        else resolve(result);
      });
    })
      .then((result) => result ? this : null);
  }

  serialize() {
    return {
      id: this.id,
      username: this.username
    };
  }

  static login(username, password) {
    if (!username) return Promise.resolve(null);
    return User.findOne({ where: { username: username } })
      .then((user) => user ? user.authenticate(password) : null);
  }
}

User.init({
  id: {
    type: Sequelize.UUID,
    defaultValue: Sequelize.UUIDV4,
    primaryKey: true
  },
  username: {
    type: Sequelize.STRING(24),
    allowNull: false,
    set: function (val) {
      this.setDataValue('username', val.toLowerCase().trim());
    },
    validate: {
      is: {
        args: [/^[a-z][a-z\d\-.]*[a-z\d]$/i],
        msg: 'must be composed of letters, numbers, dashes, and periods, begin with a letter, and end with a letter or number'
      },
      len: {
        args: [6, 24],
        msg: 'must be six to twenty-four characters in length'
      },
      notEmpty: { msg: 'is required' }
    }
  },
  passwordDigest: {
    field: 'password_digest',
    type: Sequelize.STRING,
    validate: {
      notEmpty: true
    }
  },
  password: {
    type: Sequelize.VIRTUAL,
    allowNull: true,
    validate: {
      len: {
        args: [7, 50],
        msg: 'must be seven to fifty characters in length'
      }
    }
  }
}, {
  sequelize: sequelizeInstance,
  indexes: [
    { unique: true, fields: ['username'] }
  ],
  tableName: 'users',
  underscored: true
});

User.beforeCreate(setSecurePassword);
User.beforeUpdate(setSecurePassword);

module.exports = User;