All files / server/models user.js

89.47% Statements 17/19
83.33% Branches 5/6
83.33% Functions 5/6
89.47% Lines 17/19
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 1151x 1x   1x 1x 1x 1x   1x                                               1x                       41x   41x 41x 41x                                 30x                                 5x                               28x                     50x       1x  
const _ = require('lodash');
const bcrypt = require('bcryptjs');
 
const Abstract = require('./abstract');
const config = require('../../config');
const db = require('../db');
const jwt = require('../utils/jwt');
 
const proto = Abstract.prototype;
 
/**
 * A user of the BioPocket platform.
 *
 * ## Database columns
 *
 * * **id** (`bigint`) - Internal ID (used for joins).
 * * **api_id** (`uuid`) - External ID (used in the API).
 * * **email** (`string`) - E-mail address.
 * * **password_hash** (`string`) - Bcrypt hash of the user's password.
 * * **active** (`boolean`) - Indicates whether the user can use the platform or has been deactivated by an administrator.
 * * **roles** (`string[]`) - Roles of the user (used for authorization).
 * * **created_at** (`datetime`) - Time at which the user was created.
 * * **updated_at** (`datetime`) - Time at which the user was last modified (equal to the creation date if never modified).
 *
 * ## Virtual properties
 *
 * * **password** (`string`) - Setting this property generates a new bcrypt hash and updates the `password_hash` column.
 *
 * @class
 * @extends Abstract
 * @see http://bookshelfjs.org
 */
const User = Abstract.extend({
  tableName: 'users',
 
  timestamps: true,
 
  virtuals: _.merge({
    password: {
      get: function() {
        return this._password;
      },
 
      set: function(password) {
        this._password = password;
 
        Eif (_.isString(password) && password.length) {
          const salt = bcrypt.genSaltSync(config.bcryptCost);
          this.set('password_hash', bcrypt.hashSync(password, salt));
        } else {
          this.unset('password_hash');
        }
      }
    }
  }, proto.virtuals),
 
  /**
   * Returns a JWT that can be used to authenticate as this user.
   *
   * @instance
   * @memberof User
   * @param {object} properties - JWT properties, passed to `generateToken` in the `utils/jwt` module.
   * @returns {string} A JWT.
   */
  generateJwt: function(properties) {
    return jwt.generateToken(_.extend({
      sub: this.get('api_id')
    }, properties));
  },
 
  /**
   * Indicates whether this user has the specified password or not.
   *
   * **WARNING:** this method is slow and blocking, as it computes a bcrypt
   * hash synchronously.  Do not overuse it.
   *
   * @instance
   * @memberof User
   * @param {string} password - The password to check.
   * @returns {boolean} True if the user's password is the same as the specified one.
   */
  hasPassword: function(password) {
    return !!password && bcrypt.compareSync(password, this.get('password_hash'));
  },
 
  /**
   * Indicates whether this user has the specified role.
   *
   * **WARNING:** this methods always returns true if the user has the role,
   * even if the user is inactive. It is not sufficient to determine whether
   * the user is currently authorized to perform the role.
   *
   * @instance
   * @memberof User
   * @param {string} role - The role to check.
   * @returns {boolean} True if the specified role is among the user's assigned roles.
   */
  hasRole: function(role) {
    return _.includes(this.get('roles'), role);
  },
 
  /**
   * Indicates whether this user is active. Users may be deactivated by administrators.
   *
   * @instance
   * @memberof User
   * @returns {boolean} True if this user is active.
   */
  isActive: function() {
    return !!this.get('active');
  }
});
 
module.exports = db.bookshelf.model('User', User);