Sequelize Associations in Node/express JS - node.js

I am new to sequelize SQL ORM nodejs. I am facing problem with associations.When I try to make a join query. It throws an association error. here is my code snippet.
server.js
app.get("/", (req, res) => {
db_conn.syncModels(req, res);
});
db_connection.js
require("dotenv").config();
const { Sequelize, DataTypes } = require("sequelize");
const crypto = require("crypto");
class DbConnection {
constructor() {
this.db = {};
this.sequelizeObj = new Sequelize(
process.env.DB_NAME,
process.env.DB_USER,
process.env.DB_PASS,
{
host: process.env.DB_URI,
dialect: "mysql",
logging: true,
}
);
this.userRoles = [
{
role_name: "SuperAdmin",
},
{
role_name: "Admin Assistant",
},
{
role_name: "HR Manager",
},
{
role_name: "Department Head",
},
{
role_name: "Assistant Manager",
},
{
role_name: "Employee",
},
];
this.defaultUser = {
user_name: "SuperAdmin",
user_email: "superadmin#" + process.env.BASE_URL,
user_password: crypto
.createHash("md5")
.update("SuperAdmin")
.digest("hex"),
role_id: 100000,
};
}
sequelize() {
return this.sequelizeObj;
}
connect() {
this.sequelizeObj
.authenticate()
.then(() => {
console.log("Connection has been established successfully.");
})
.catch((error) => {
if (error.message.includes("Unknown database")) {
this.createdb();
} else {
console.error("Unable to connect to the database: ", error);
}
});
}
async createdb() {
try {
const sequelize = new Sequelize(
"",
process.env.DB_USER,
process.env.DB_PASS,
{
host: process.env.DB_URI,
dialect: "mysql",
logging: true,
}
);
const createdb = await sequelize.query(
`CREATE DATABASE IF NOT EXISTS ${process.env.DB_NAME};`
);
console.log("Database Created")
} catch (err) {
console.log(err);
}
}
disconnect() {
this.sequelizeObj
.close()
.then(() => {
console.log("Connection has been closed successfully.");
})
.catch((error) => {
console.error("Unable to disconnect: ", error);
});
}
syncModels(payload, cb) {
this.db.Sequelize = Sequelize;
this.db.sequelize = this.sequelizeObj;
this.db.sequelize
.sync({ force: true })
.then((res) => {
console.log("Environment Configured");
})
.then(async () => {
await this.db.user_roles.bulkCreate(this.userRoles);
})
.then(() => {
console.log("User Roles Created");
})
.then(() => {
cb.status(200).send("Environment Configured");
})
.catch((err) => {
cb.status(400).send("Environment Configuration Error " + err);
});
// specifying models
this.db.users = require("../Auth/models/auth.model")(
this.sequelizeObj,
DataTypes
);
this.db.user_roles = require("../Auth/models/roles.model")(
this.sequelizeObj,
DataTypes
);
// Method 01
// Relation of user and user-roles
this.db.users.hasOne(this.db.user_roles, {
foreignKey: "role_id",
as: "role",
});
this.db.user_roles.belongsTo(this.db.users, {
foreignKey: "role_id",
as: "role",
});
}
random_password(length) {
var result = "";
var characters =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
var charactersLength = characters.length;
for (var i = 0; i < length; i++) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
}
return result;
}
}
module.exports = DbConnection;
Users.model.js
module.exports = (sequelize, DataTypes) => {
const Users = sequelize.define(
"users",
{
user_id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
unique: true,
},
user_name: {
type: DataTypes.STRING,
allowNull: false,
},
user_email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
user_password: {
type: DataTypes.STRING,
allowNull: false,
},
role_id: {
type: DataTypes.INTEGER,
allowNull: false,
},
},
{
initialAutoIncrement: 1900000,
}
);
// Method 02
Users.associate = (models) => {
Users.hasOne(models.UserRoles, { foreignKey: "role_id" });
};
return Users;
};
UserRoles.model.js
module.exports = (sequelize, DataTypes) => {
const UserRoles = sequelize.define(
"user_roles",
{
role_id: {
type: DataTypes.INTEGER,
allowNull: false,
autoIncrement: true,
primaryKey: true,
unique: true,
},
role_name: {
type: DataTypes.STRING,
allowNull: false,
},
},
{
initialAutoIncrement: 100000,
}
);
// Method 02
UserRoles.associate = (models) => {
UserRoles.hasMany(models.Users, { as: "users", foreignKey: "user_id" });
};
return UserRoles;
};
My query is as follows:
findUser(body, callback) {
let jwt = new JsonWebToken();
let encrypted = crypto
.createHash("md5")
.update(body.password)
.digest("hex");
this.Users.findOne({
includes: [
model: 'user_roles'
]
where: {
user_email: body.email,
user_password: encrypted,
},
})
.then((res) => {
console.log(res)
})
.catch((err) => {
callback.status(302).send("Error Found" + err);
});
}
The error is throws as follows:
Error FoundSequelizeEagerLoadingError: user_roles is not associated to users!
Any help would be appreciated.
Thanks

Related

node.JS / sequelize associate db tables

I am trying to associate two database tables, but I do not know exactly where to add the code in my configuration:
config.js
const Sequelize = require("sequelize");
const sequelize = new Sequelize("training", "postgres", "test", {
host: "localhost",
dialect: "postgres",
dialectOptions: {
ssl: {
require: true,
rejectUnauthorized: false // <<<<<<< YOU NEED THIS
}
},
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000,
},
})
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
// db.sequelize.gallery = require("../models/gallery")(DataTypes);
// db.tags = require("../models/tags.js")(sequelize, Sequelize);
// gallery.hasMany(db.tags, { as: "item" });
// db.tags.belongsTo(db.gallery, {
// foreignKey: "item",
// as: "item",
// });
module.exports = { db, JWT_SECRET: "secretString",}
If I add the commented code here I get the error that require is not a function.
This is how my models look like:
gallery.js
const { db } = require("../config/configProvider")();
module.exports = function(DataTypes) {
const Gallery = db.sequelize.define(
"items",
{
// },
date: {
type: DataTypes.DATE(),
// required: true,
},
url: {
type: DataTypes.STRING,
// required: true,
},
description: {
type: DataTypes.STRING,
},
location: {
type: DataTypes.STRING,
},
rating: {
type:DataTypes.INTEGER,
}
},
{ timestamps: false }
);
return Gallery;
};
index.js
const sequelize = require("sequelize");
const DataTypes = sequelize.DataTypes;
const Types = require("./models/types")(sequelize, DataTypes);
const Tags = require("./models/tags")(sequelize, DataTypes);
config.db.sequelize
.authenticate()
.then(() => {
console.log("Connection has been established successfully.");
})
.catch((err) => {
console.error("Unable to connect to the database:", err);
});
If I create index.js in models (where I could add the db associations, how would I call it in main file index.js?
gallery.js
Gallery.associate = function(models) {
gallery.hasMany(db.tags, { as: "item" });
};
tag.js
Tag.associate = function (models) {
tags.belongsTo(db.gallery, {
foreignKey: "item",
as: "item",
});
}

How to build model with sequelize for belong to many association

This is what I wrote in Country.js (exactly the same as User.js except datatypes) :
module.exports = function(sequelize, DataTypes) {
const Country = sequelize.define('country',
{
id: {
type: DataTypes.INTEGER,
primaryKey: true,
autoIncrement: true
},
code: {
type: DataTypes.INTEGER
},
alpha2: {
type: DataTypes.STRING
},
alpha3: {
type: DataTypes.STRING
},
name_en: {
type: DataTypes.STRING
},
name_fr: {
type: DataTypes.STRING
}
},
{
freezeTableName: true,
timestamps: false
});
Country.associate = ( models ) => {
models.Country.belongsToMany(models.User, {
through: 'country_user',
as: 'user',
foreignKey: 'id_country'
});
};
return Country;
}
This is my query :
router.get('/thisuserCountries', function(req, res, next){
User(db, Sequelize.DataTypes).findOne({
include: [{
model: Country(db, Sequelize.DataTypes),
as: 'countries',
required: false,
attributes: ['id'],
}],
where: {
email: 'jerome.charlat#gmail.com'
}
})
.then(user => {
if(user) {
res.json(user)
}
else {
res.send('User does not exist')
}
})
.catch(err => {
res.send('error: ' + err)
})
})
This is my db.js :
const Sequelize = require('sequelize')
const db = new Sequelize('travel_memories', 'root', '', {
host: 'localhost',
dialect: 'mysql',
port: 3306
})
db
.authenticate()
.then(() => {
console.log('Connection has been established successfully.');
})
.catch(err => {
console.error('Unable to connect to the database:', err);
});
const models = {
Country: db.import('../models/Country'),
User: db.import('../models/User'),
CountryUserJoin: db.import('../models/Country_user')
};
Object.keys(models).forEach((modelName) => {
if('associate' in models[modelName]){
models[modelName].associate(models);
}
});
module.exports = db
Postman says : error SequelizeEagerLoadingError: country is not associated to user!
But, I think I should write in the through parameter the model User_country when I associate tables in each model. So i tried to write something like :
Country.associate = ( models ) => {
models.Country.belongsToMany(models.User, {
through: models.Country_user,
as: 'user',
foreignKey: 'id_country'
});
};
And console says when I launch server, before querying anything :
SequelizeAssociationError: country.belongsToMany(user) requires through option, pass either a string or a model.
So I am blocked. I used the example in documentation to write the assocation with models.foo. But in fact models comes from nowhere..
Thanks again for your help !
There's not a lot of documentation about this, but here it says that you should use a through option when querying or selecting belongs-to-many attributes, just like this:
...
User(db, Sequelize.DataTypes).findOne({
include: [{
model: Country(db, Sequelize.DataTypes),
as: 'countries',
required: false,
through: {
attributes: ['id']
}
}],
where: {
email: 'jerome.charlat#gmail.com'
}
})
...

Error when trying to insert row to table because of UUID foreign key with sequelize.js

I am using sequelize.js with node.js and postgres.
I got 2 simple tables from an example as a 'POC' of sorts.
I changed the ID to be UUID and I am having an issue with the insert into the second table ( with the UUID FK ).
I am using postman to test it.
I am creating todo rows with UUID with no issues,
Then I am trying to create a todo item which has a todo id as foreign key
and it seems that it is failing to recognize that ID!
I tried a manual script in postgres and it worked.
I am probably missing something code wise but I cant figure out what.
here is the error which is being returned to me in postman -
{
"name": "SequelizeDatabaseError",
"parent": {
"name": "error",
"length": 96,
"severity": "ERROR",
"code": "22P02",
"file": "uuid.c",
"line": "137",
"routine": "string_to_uuid",
"sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
},
"original": {
"name": "error",
"length": 96,
"severity": "ERROR",
"code": "22P02",
"file": "uuid.c",
"line": "137",
"routine": "string_to_uuid",
"sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
},
"sql": "INSERT INTO \"TodoItems\" (\"id\",\"content\",\"complete\",\"createdAt\",\"updatedAt\",\"todoId\") VALUES ($1,$2,$3,$4,$5,$6) RETURNING *;"
}
Here are the relevant js files -
todoItems.js controller -
const TodoItem = require('../dal/models').TodoItem;
const uuid = require('uuid/v4');
module.exports = {
create(req, res) {
return TodoItem
.create({
content: req.body.content,
todoId: req.params.todoId,
})
.then(todoItem => res.status(201).send(todoItem))
.catch(error => res.status(400).send(error));
},
update(req, res) {
return TodoItem
.find({
where: {
id: req.params.todoItemId,
todoId: req.params.todoId,
},
})
.then(todoItem => {
if (!todoItem) {
return res.status(404).send({
message: 'TodoItem Not Found',
});
}
return todoItem
.update({
content: req.body.content || todoItem.content,
complete: req.body.complete || todoItem.complete,
})
.then(updatedTodoItem => res.status(200).send(updatedTodoItem))
.catch(error => res.status(400).send(error));
})
.catch(error => res.status(400).send(error));
},
destroy(req, res) {
return TodoItem
.find({
where: {
id: req.params.todoItemId,
todoId: req.params.todoId,
},
})
.then(todoItem => {
if (!todoItem) {
return res.status(404).send({
message: 'TodoItem Not Found',
});
}
return todoItem
.destroy()
.then(() => res.status(204).send())
.catch(error => res.status(400).send(error));
})
.catch(error => res.status(400).send(error));
},
};
todos.js controller-
const Todo = require('../dal/models').Todo;
const TodoItem = require('../dal/models').TodoItem;
module.exports = {
create(req, res) {
return Todo
.create({
title: req.body.title,
})
.then((todo) => res.status(201).send(todo))
.catch((error) => res.status(400).send(error));
},
list(req, res) {
return Todo
.findAll({
include: [{
model: TodoItem,
as: 'todoItems',
}],
order: [
['createdAt', 'DESC'],
[{ model: TodoItem, as: 'todoItems' }, 'createdAt', 'ASC'],
],
})
.then((todos) => res.status(200).send(todos))
.catch((error) => res.status(400).send(error));
},
retrieve(req, res) {
return Todo
.findByPk(req.params.todoId, {
include: [{
model: TodoItem,
as: 'todoItems',
}],
})
.then((todo) => {
if (!todo) {
return res.status(404).send({
message: 'Todo Not Found',
});
}
return res.status(200).send(todo);
})
.catch((error) => res.status(400).send(error));
},
update(req, res) {
return Todo
.findByPk(req.params.todoId, {
include: [{
model: TodoItem,
as: 'todoItems',
}],
})
.then(todo => {
if (!todo) {
return res.status(404).send({
message: 'Todo Not Found',
});
}
return todo
.update({
title: req.body.title || todo.title,
})
.then(() => res.status(200).send(todo))
.catch((error) => res.status(400).send(error));
})
.catch((error) => res.status(400).send(error));
},
destroy(req, res) {
return Todo
.findByPk(req.params.todoId)
.then(todo => {
if (!todo) {
return res.status(400).send({
message: 'Todo Not Found',
});
}
return todo
.destroy()
.then(() => res.status(204).send())
.catch((error) => res.status(400).send(error));
})
.catch((error) => res.status(400).send(error));
},
};
todo table create migration -
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.createTable('Todos', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
title: {
type: Sequelize.STRING,
allowNull: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
}),
down: (queryInterface /* , Sequelize */) => queryInterface.dropTable('Todos'),
};
todo-item table create migration -
module.exports = {
up: (queryInterface, Sequelize) =>
queryInterface.createTable('TodoItems', {
id: {
allowNull: false,
primaryKey: true,
type: Sequelize.UUID,
},
content: {
type: Sequelize.STRING,
allowNull: false,
},
complete: {
type: Sequelize.BOOLEAN,
defaultValue: false,
},
createdAt: {
allowNull: false,
type: Sequelize.DATE,
},
updatedAt: {
allowNull: false,
type: Sequelize.DATE,
},
todoId: {
type: Sequelize.UUID,
onDelete: 'CASCADE',
references: {
model: 'Todos',
key: 'id',
as: 'todoId',
},
},
}),
down: (queryInterface /* , Sequelize */) =>
queryInterface.dropTable('TodoItems'),
};
todo model -
const uuid = require('uuid/v4');
'use strict';
module.exports = (sequelize, DataTypes) => {
const Todo = sequelize.define('Todo', {
title: {
type: DataTypes.STRING,
allowNull: false,
}
});
Todo.associate = (models) => {
Todo.hasMany(models.TodoItem, {
foreignKey: 'todoId',
as: 'todoItems',
});
};
Todo.beforeCreate((item, _ ) => {
return item.id = uuid();
});
return Todo;
};
todo-item model -
const uuid = require('uuid/v4');
'use strict';
module.exports = (sequelize, DataTypes) => {
const TodoItem = sequelize.define('TodoItem', {
content: {
type: DataTypes.STRING,
allowNull: false,
},
complete: {
type: DataTypes.BOOLEAN,
defaultValue: false,
}
});
TodoItem.associate = (models) => {
TodoItem.belongsTo(models.Todo, {
foreignKey: 'todoId',
onDelete: 'CASCADE',
});
};
TodoItem.beforeCreate((item, _ ) => {
return item.id = uuid();
});
return TodoItem;
};
What does your router code look like? Are you using correct path parameter for todoId? If you're using express for example. it should look like app.post("/todos/:todoId/todo_items", todoItemController.create) . Note the camelcase todoId . That will ensure that the req.params.todoId you're referencing in todoItems controller would have the right value.
Also, make sure you have a correct body parser to handle req.body.content correctly. In express, this would be done via body body-parser library and app.use(bodyParser.json()) . Add a breakpoint or log statement in the todoItem controller create code and verify that you actually have the correct parameter values.
If you happen to have the error above, it might be because you are nesting other entities in your request body and therefore the UUID is not getting converted from string to a UUID.
For instance if you have a request body like
{
"Transaction": {
"id" : "f2ec9ecf-31e5-458d-847e-5fcca0a90c3e",
"currency" : "USD",
"type_id" : "bfa944ea-4ce1-4dad-a74e-aaa449212ebf",
"total": 8000.00,
"fees": 43.23,
"description":"Description here"
},
}
and therefore in your controller you are creating your entity like
try {
await Transaction.create(
{
id: req.body.Transaction.id,
currency: req.body.Transaction.currency,
type_id: req.body.Transaction.type_id,
total: req.body.Transaction.total,
fees: req.body.Transaction.fees,
description: req.body.Transaction.description,
}......
Your id and type_id are mostly likely not being converted from string to a UUID.
There are multiple ways of tackling this. The most straightforward approach is to do an explicit conversion from string to UUID.
To do this, import parse from the uuid npm module and do the explicit conversion as you can see in the code sample below.
const { parse: uuidParse } = require("uuid");
try {
await Transaction.create(
{
id: uuidParse(req.body.Transaction.id),
currency: req.body.Transaction.currency,
type_id: uuidParse(req.body.Transaction.type_id),
total: req.body.Transaction.total,
fees: req.body.Transaction.fees,
description: req.body.Transaction.description,
}.....
This explicit conversion from string to a UUID will mostly solve the issue.

Instance Methods is not working in Sequelize

I can't seem to set the User model properly. I've implemented some instance methods that don't seem to be working
var UserDetails = mysequelize.sequelize.define('user_tb', {
id: {
autoIncrement: true,
type: mysequelize.sequelize.Sequelize.INTEGER,
allowNull: false,
},
username: {
type: mysequelize.sequelize.Sequelize.STRING,
primaryKey: true,
unique: true,
},
hierarchyid: {
type: mysequelize.sequelize.Sequelize.STRING
},
password: {
type: mysequelize.sequelize.Sequelize.STRING,
validate: {
len: {
args: [6, 15],
msg: "Please enter a password with at least 6 chars but no more than 15"
}
},
allowNull: false
},
customerid: {
type: mysequelize.sequelize.Sequelize.INTEGER
},
statususer: {
type: mysequelize.sequelize.Sequelize.STRING,
allowNull: false
},
userid: {
unique: true,
type: mysequelize.sequelize.Sequelize.STRING,
allowNull: false
},
authtoken: {
unique: true,
type: mysequelize.sequelize.Sequelize.STRING,
allowNull: false
}
},
{
tableName: 'user_tb',
timestamps: false,
freezeTableName: true
});
UserDetails.prototype.toJSON = function(){
var user = this;
var userObject = user.toObject();
return _.pick(userObject,['userid','password']);
};
UserDetails.prototype.findByCredentials = function(userid, password)
{
console.log('Sunddep');
var User = this;
// return User.fin
User.findOne({userid}).then((user)=> {
if(!user)
{
return Promise.reject();
}
return new Promise((resolve,reject) => {
bcrypt.compare(password,user.password,(err,res) => {
if(res)
{
resolve(user);
}
else{
reject();
}
})
})
});
}
UserDetails.prototype.generateAuthToken = function()
{
var user = this;
var access = 'authtoken';
var token = jwt.sign({userid:
user.userid.toHexString(),access},process.env.JWT_SECRET).toString();
user.build({
access: token
});
user.save().then(() =>{
return token;
});
}
module.exports = {UserDetails}
server.js
app.post('/user/login', (req, res) => {
console.log(req.body);
var body = _.pick(req.body, ['userId', 'password']);
user.findByCredentials(body.userId, body.password).then(() => {
res.send('Sundeep');
},
(e) => {
sendData: ({
wsState: '0',
messageCode: 'WS000001',
message: 'No user find with this Id',
userData: []
});
res.status(400).send(sendData)
});
});
Hi, I am getting error while calling instance method from other class. Can any one tell me how can i achieve it
UserDetails.prototype.findByCredentials = function(userid, password) {.....}
But while run the server.js file i getting error like UserDetails.findByCredentials is not a function while calling from other class
Thanks for help in advance.

Using BCrypt with Sequelize Model

I'm trying to use the bcrypt-nodejs package with my sequelize model and was tring to follow a tutorial to incorporate the hashing into my model, but I'm getting an error at generateHash. I can't seem to figure out the issue. Is there a better way to incorporate bcrypt?
Error:
/Users/user/Desktop/Projects/node/app/app/models/user.js:26
User.methods.generateHash = function(password) {
^
TypeError: Cannot set property 'generateHash' of undefined
at module.exports (/Users/user/Desktop/Projects/node/app/app/models/user.js:26:27)
at Sequelize.import (/Users/user/Desktop/Projects/node/app/node_modules/sequelize/lib/sequelize.js:641:30)
model:
var bcrypt = require("bcrypt-nodejs");
module.exports = function(sequelize, DataTypes) {
var User = sequelize.define('users', {
annotation_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
firstName: {
type: DataTypes.DATE,
field: 'first_name'
},
lastName: {
type: DataTypes.DATE,
field: 'last_name'
},
email: DataTypes.STRING,
password: DataTypes.STRING,
}, {
freezeTableName: true
});
User.methods.generateHash = function(password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
};
User.methods.validPassword = function(password) {
return bcrypt.compareSync(password, this.local.password);
};
return User;
}
Methods should be provided in the "options" argument of sequelize.define
const bcrypt = require("bcrypt");
module.exports = function(sequelize, DataTypes) {
const User = sequelize.define('users', {
annotation_id: {
type: DataTypes.INTEGER,
autoIncrement: true,
primaryKey: true
},
firstName: {
type: DataTypes.DATE,
field: 'first_name'
},
lastName: {
type: DataTypes.DATE,
field: 'last_name'
},
email: DataTypes.STRING,
password: DataTypes.STRING
}, {
freezeTableName: true,
instanceMethods: {
generateHash(password) {
return bcrypt.hash(password, bcrypt.genSaltSync(8));
},
validPassword(password) {
return bcrypt.compare(password, this.password);
}
}
});
return User;
}
Other alternative: Use hook and bcrypt async mode
User.beforeCreate((user, options) => {
return bcrypt.hash(user.password, 10)
.then(hash => {
user.password = hash;
})
.catch(err => {
throw new Error();
});
});
There's a tutorial out there on how to get a sequelize/postgreSQL auth system working with hooks and bcrypt.
The guy who wrote the tutorial did not use async hash/salt methods; in the user creation/instance method section he used the following code:
hooks: {
beforeCreate: (user) => {
const salt = bcrypt.genSaltSync();
user.password = bcrypt.hashSync(user.password, salt);
}
},
instanceMethods: {
validPassword: function(password) {
return bcrypt.compareSync(password, this.password);
}
}
Newer versions of Sequelize don't like instance methods being declared this way - and multiple people have explained how to remedy this (including someone who posted on the original tutorial):
The original comment still used the synchronous methods:
User.prototype.validPassword = function (password) {
return bcrypt.compareSync(password, this.password);
};
All you need to do to make these functions asyncronous is this:
Async beforeCreate bcrypt genSalt and genHash functions:
beforeCreate: async function(user) {
const salt = await bcrypt.genSalt(10); //whatever number you want
user.password = await bcrypt.hash(user.password, salt);
}
User.prototype.validPassword = async function(password) {
return await bcrypt.compare(password, this.password);
}
On the node.js app in the login route where you check the password, there's a findOne section:
User.findOne({ where: { username: username } }).then(function (user) {
if (!user) {
res.redirect('/login');
} else if (!user.validPassword(password)) {
res.redirect('/login');
} else {
req.session.user = user.dataValues;
res.redirect('/dashboard');
}
});
All you have to do here is add the words async and await as well:
User.findOne({ where: { username: username } }).then(async function (user) {
if (!user) {
res.redirect('/login');
} else if (!await user.validPassword(password)) {
res.redirect('/login');
} else {
req.session.user = user.dataValues;
res.redirect('/dashboard');
}
});
Bcrypt Is no longer part of node, so I included example with new module of crypto
I am sharing this code from one of working project.
My config file
require('dotenv').config();
const { Sequelize,DataTypes ,Model} = require("sequelize");
module.exports.Model = Model;
module.exports.DataTypes = DataTypes;
module.exports.sequelize = new Sequelize(process.env.DB_NAME,process.env.DB_USER_NAME, process.env.DB_PASSWORD, {
host: process.env.DB_HOST,
dialect: process.env.DB_DISELECT,
pool: {
max: 1,
min: 0,
idle: 10000
},
//logging: true
});
My user model
const { sequelize, DataTypes, Model } = require('../config/db.config');
var crypto = require('crypto');
class USERS extends Model {
validPassword(password) {
var hash = crypto.pbkdf2Sync(password,
this.SALT, 1000, 64, `sha512`).toString(`hex`);
console.log(hash == this.PASSWORD)
return this.PASSWORD === hash;
}
}
USERS.init(
{
ID: {
autoIncrement: true,
type: DataTypes.BIGINT,
allowNull: false,
primaryKey: true
},
MOBILE_NO: {
type: DataTypes.BIGINT,
allowNull: false,
unique: true
},
PASSWORD: {
type: DataTypes.STRING(200),
allowNull: false
},
SALT: {
type: DataTypes.STRING(200),
allowNull: false
}
},
{
sequelize,
tableName: 'USERS',
timestamps: true,
hooks: {
beforeCreate: (user) => {
console.log(user);
user.SALT = crypto.randomBytes(16).toString('hex');
user.PASSWORD = crypto.pbkdf2Sync(user.PASSWORD, user.SALT,
1000, 64, `sha512`).toString(`hex`);
},
}
});
module.exports.USERS = USERS;
And Auth Controller
const { USERS } = require('../../../models/USERS');
module.exports = class authController {
static register(req, res) {
USERS.create({
MOBILE_NO: req.body.mobile,
PASSWORD: req.body.password,
SALT:""
}).then(function (data) {
res.json(data.toJSON());
}).catch((err) => {
res.json({
error: err.errors[0].message
})
})
}
static login(req, res) {
var message = [];
var success = false;
var status = 404;
USERS.findOne({
where:{
MOBILE_NO: req.body.mobile
}
}).then(function (user) {
if (user) {
message.push("user found");
if(user.validPassword(req.body.password)) {
status=200;
success = true
message.push("You are authorised");
}else{
message.push("Check Credentials");
}
}else{
message.push("Check Credentials");
}
res.json({status,success,message});
});
}
}
Old question, but maybe can help someone, you can use sequelize-bcrypt
Example:
const { Sequelize, DataTypes } = require('sequelize');
const useBcrypt = require('sequelize-bcrypt');
const database = new Sequelize({
...sequelizeConnectionOptions,
});
const User = database.define('User', {
email: { type: DataTypes.STRING },
password: { type: DataTypes.STRING },
});
useBcrypt(User);
Usage
User.create({ email: 'john.doe#example.com', password: 'SuperSecret!' });
// { id: 1, email: 'john.doe#example.com', password: '$2a$12$VtyL7j5xx6t/GmmAqy53ZuKJ1nwPox5kHLXDaottN9tIQBsEB3EsW' }
const user = await User.findOne({ where: { email: 'john.doe#example.com' } });
user.authenticate('WrongPassword!'); // false
user.authenticate('SuperSecret!'); // true

Resources