Leonardo Freitas
Leonardo Freitas

Reputation: 101

Helpers in model life cycle Sails 1

Well, I did a helper to encrypt a password, I'm trying to use it in the life cycle of my user model, but when I call the request, it gets in a kind of loop, where it returns no response.

this is my action2 (create user) [Route: 'post /user' : 'user/create' ]

    module.exports = {

  friendlyName: 'Create user',

  description: 'action create user',

  inputs: {
    name: {
      description: 'user name',
      type: 'string',
      required: true
    },
    username: {
      description: 'username unique',
      type: 'string',
      required: true
    },
    email: {
      description: 'user email',
      type: 'string',
      required: true
    },
    password: {
      description: 'user password',
      type: 'string',
      required: true
    },
    nivel: {
      description: 'user nivel access (see in polices)',
      type: 'string',
      required: false
    },
    status: {
      description: 'user status',
      type: 'string',
      required: false
    }
  },

  exits: {
    success: {
      description: 'success by default JSON'
    },
    notFound: {
      description: 'not found',
      responseType: 'notFound'
    }
  },

  fn: async (inputs, exits) => {

    const { name, username, email, password, nivel, status } = inputs;
    var user = await User.create({ name, username, email, password, nivel, status }).fetch();
    if(!user) return exits.notFound();
    return exits.success(user);

  }

}

this is my model (User)

module.exports = {

  attributes: {

    name: {
      type: 'string',
      required: true
    },

    username: {
      type: 'string',
      unique: true,
      required: true
    },

    email: {
      type: 'string',
      unique: true,
      required: true,
      isEmail: true
    },

    password: {
      type: 'string',
      required: true,
      minLength: 3
    },

    passwordResetExpires: {
      type: 'string',
    },

    nivel: {
      type: 'string',
      isIn: ['developer', 'administrator', 'attendant'],
      defaultsTo: 'attendant'
    },

    status: {
      type: 'string',
      isIn: ['activated', 'disabled'],
      defaultsTo: 'activated'
    }

  },

  customToJSON: () => {
    return _.omit(this, ['password', 'passwordResetExpires']);
  },

  // Lifecycle Callbacks

  beforeCreate: (values, cb) => {
      //cipher helper
      sails.helpers.cipher(values.password).exec((err, hash) => {
        if(err){
          return cb(err);
        }
        values.password = hash;
        cb();
      })      
  }

}

this is my helper (cipher)

const bcrypt = require('bcryptjs');

module.exports = {

  friendlyName: 'Chiper helper',

  description: 'Chiper helper for password user and others',

  inputs: {
    password: {
      description: 'user password',
      type: 'string',
      required: true
    }
  },

  exits: {
    success: {
      description: 'success by default JSON'
    },
    notFound: {
      description: 'erro, not found',
      responseType: 'notFound'
    }
  },

  fn: async (inputs, exits) => {

    const { password } = inputs;

    bcrypt.hashSync(password, 10, (err, hash) => {
      if(err) return exits.notFound();
      return exits.success(hash);
    });

  }

}

Upvotes: 1

Views: 354

Answers (1)

Hamza Fatmi
Hamza Fatmi

Reputation: 1255

It's because you are using bcrypt.hashSync, the password hash is done synchronously, there is no callback and no async keyword, you need to change fn to this :

 fn: (inputs, exits) => {
 const { password } = inputs;
 var hash = bcrypt.hashSync(password, 10);
 return exits.success(hash);
}

If you want to do it the asynchronous way, you can do this :

 fn: (inputs, exits) => {

const { password } = inputs;

bcrypt.hash(password, 10, (err, hash) => {
  if(err) return exits.notFound();
  return exits.success(hash);
});
}

You don't need to use async keyword since we are using just callbacks.

Upvotes: 1

Related Questions