How to create a method inside Sequelize Model? - javascript

I wrote a class which extends a Model, and I need create a method to compareSync password:
const { Model, DataTypes } = require('sequelize');
class User extends Model {
static init(sequelize) {
super.init({
username: DataTypes.STRING,
password: DataTypes.STRING,
role: DataTypes.STRING,
status: DataTypes.INTEGER
},
{
sequelize,
hooks: {
beforeCreate: (user) => {
const salt = bcrypt.genSaltSync();
user.password = bcrypt.hashSync(user.password, salt);
}
}
}
)
}
static associate(model) {
this.belongsToMany(models.Movie, { through: models.Ratings });
}
}
module.exports = User;
The hook is working, I thought to add after beforeCreate a:
instanceMethods: {
validPassword: function (password) {
return bcrypt.compareSync(password, this.password);
}
}
Using this class how I can define an user method?

I got this:
const { Model, DataTypes } = require('sequelize');
const bcrypt = require("bcrypt")
class User extends Model {
static init(sequelize) {
super.init({
username: DataTypes.STRING,
password: DataTypes.STRING,
role: DataTypes.STRING,
status: DataTypes.INTEGER
},
{
sequelize,
hooks: {
beforeCreate: (user) => {
const salt = bcrypt.genSaltSync();
user.password = bcrypt.hashSync(user.password, salt);
}
}
}
)
}
static associate(model) {
this.belongsToMany(models.Movie, { through: models.Ratings });
}
validPassword(password) {
return bcrypt.compareSync(password, this.password);
}
}
module.exports = User;
If I wanna use the method inside controller for example:
const login = async (req, res) => {
const { username, password } = req.params;
const user = await User.findOne({
where: { username }
});
if (!user) {
return res.status(400).send("User not find!")
}
if(!user.validPassword(password)){..}
res.send(user)
}

Related

Error in hashing password with bcrypt-nodejs

Have been trying to create a password hash in my nodejs code
But it not working and not showing any error message for me to debug.
And my user is not creating also.
I dont know if there is a better way to do it.
This is my file which is responsible for the code...Model/User.js
const Promise = require('bluebird')
const bcrypt = Promise.promisifyAll(require('bcrypt-nodejs'))
function hashPassword (user) {
const SALT_FACTOR = 8
if (!user.changed('password')) {
return;
}
return bcrypt
.genSaltSyncAsync(SALT_FACTOR)
.then(salt => bcrypt.hashAsync(user.password, salt, null))
.then(hash => {
user.setDataValue('password', hash)
})}
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeCreate: hashPassword,
beforeUpdate: hashPassword,
beforeSave: hashPassword
}
})
User.prototype.comparePassword = function (password) {
return bcrypt.compareAsync(password, this.password)
}
return User }
Does the following snippet help in any way?
const bcrypt = require('bcryptjs');
const userAbc = {
email: 'user#user.com',
password: '1234'
}
async function hashPassword(user) {
try {
const hashedPassword = await bcrypt.hash(user.password, 12);
user.password = hashedPassword;
console.log(user);
} catch (err) {
console.log(err);
}
}
hashPassword(userAbc);
I did change the bcrypt-nodejs to bcryptjs then replace genSaltSyncAsync to genSaltSync and everyother Async to Sync and it worked.

Relation between Users and cryptodata Sequelize database

I'm trying to build a relation between the users and his favorite cryptocurrency.
Meaning, multiple Users can have the same crypto as their favorites.
Coin.js
module.exports = (sequelize, DataTypes) => {
const Coin = sequelize.define('Coin', {
cryptoName: DataTypes.STRING,
})
Coin.associate = function(models) {
Coin.belongsToMany(models.CoinsUserRelations, {foreignKey: 'CoinID', through: 'CoinsUserRelations'})
}
return Coin
}
User.js
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
firstName: DataTypes.STRING,
lastName: DataTypes.STRING,
email: {
type: DataTypes.STRING,
unique: true
},
password: DataTypes.STRING
}, {
hooks: {
beforeSave: hashPassword
}
})
User.associate = function(models) {
User.belongsToMany(models.CoinsUserRelations, {foreignKey: 'UserID', through: 'CoinsUserRelations'})
}
return User
}
These are my 2 tables at the moment and now I'm trying to build a relation between them. and I keep receiving this error on my console which I do not understand why.
I've edited multiple time to resolve the issue, This was the result with the help of Anatoly
CoinsUserRelations.js
module.exports = (sequelize, DataTypes) => {
const CoinsUsersRelations = sequelize.define('CoinsUsersRelations', {
UserID: {
type: DataTypes.INTEGER,
},
CoinID: {
type: DataTypes.INTEGER,
}
})
return CoinsUsersRelations
}
I'm really unsure on why I get this error if I'm actually defining the model before creating the relations..
Index.js
const fs = require('fs')
const path = require('path')
const Sequelize = require('sequelize')
const config = require('../config/config')
const db = {}
const sequelize = new Sequelize(
config.db.database,
config.db.user,
config.db.password,
config.db.options
)
fs
.readdirSync(__dirname)
.filter((file) =>
file !== 'index.js'
)
.forEach((file) => {
const model = sequelize.import(path.join(__dirname, file))
db[model.name] = model
})
Object.keys(db).forEach(function (modelName) {
if (db[modelName].associate) {
db[modelName].associate(db)
}
})
db.sequelize = sequelize
db.Sequelize = Sequelize
module.exports = db
Edit part for a bug called SequelizeEagerLoadingError
module.exports = {
async getUserFavoriteCrypto (req, res) {
try {
const coins = await db.Users.findOne({
where: {
UserID : req.query.userId
},
attributes: ['UserID'],
include: [{
model: db.Coins,
required: false
}]
})
console.log(coins)
res.send({
coins: coins
})
} catch (err) {
res.status(400).send({
error: err
})
}
}
}
You should register all models and only after that all their associations in one place. See my answer on a similar problem

How to insert data in many-to-many relationship (Sequelize)

My Product model:
const { Model, DataTypes } = require('sequelize');
class Product extends Model {
static init(connection) {
super.init({
name: DataTypes.STRING,
description: DataTypes.TEXT,
purchase_price: DataTypes.DOUBLE,
sale_price: DataTypes.DOUBLE
}, {sequelize: connection});
}
static associate(models) {
this.belongsToMany(models.Purchase, {
foreignKey: 'product_id', through: 'products_purchases', as: 'purchases'
});
}
}
module.exports = Product;
My Purchase Model:
const { Model, DataTypes } = require('sequelize');
const Product = require('../models/Product');
class Purchase extends Model {
static init(connection) {
super.init({
request_number: DataTypes.STRING,
datetime: {
type: DataTypes.DATE,
defaultValue: DataTypes.NOW
},
email: DataTypes.STRING,
status: DataTypes.ENUM([
'orderPlaced', 'paymentMade','paymentConfirmed', 'forwardedProduct','productReceived','orderCanceled'
])
}, {sequelize: connection});
}
static associate(models) {
this.belongsTo(models.User, {foreignKey: 'user_id', as: 'user'});
this.belongsToMany(models.Product, {
foreignKey: 'purchase_id', through: 'products_purchases', as: 'products'
});
}
}
module.exports = Purchase;
And finally my ProductPurchase Model:
(Note that there is some extra columns in the relationship table)
const { Model, DataTypes } = require('sequelize');
class ProductPurchase extends Model {
static init(connection) {
super.init({
product_value: DataTypes.FLOAT,
product_quantity: DataTypes.INTEGER
}, {
sequelize: connection,
modelName: 'products_purchases'
});
}
}
module.exports = ProductPurchase;
I want to insert data into purchases table and also into products_purchases. I tried to do it the way below, but I don't know how to send the data of the extra columns from ProductPurchase:
async store(req, res) {
try {
const { user_id } = req.params;
const user = await User.findByPk(user_id);
if (!user) {
return res.status(400).json('User not found!');
}
// productsData = [{ productId, productPrice, quantity }];
const { request_number, datetime, email, status, productsData } = req.body;
const purchase = await Purchase.create({
request_number, datetime, email, status, user_id
});
const productsIds = productsData.map(product => {
return product.productId;
});
const products = await Product.findAll({
where: {id: productsIds}
});
await purchase.addProduct(products);
return res.json(products);
} catch (error) {
return res.status(500).json(error);
}
}
Can anybody help me?

Before create doesn't work on my sequelize model

Before create doesn't work on my sequelize model
I created a template, but for some reason my before create doesn't work and I don't know what it can be anymore.
async createUser(req,res){
const { name,email,login,password } = req.body
const verify = await Users.findOne({where:{login: login}});
if(verify){ return res.status(400).json({result: 'User already exists'})}
const user = await Users.create({name,email,login,password});
}
model:
class Users extends Model {
static init(sequelize){
super.init({
name: DataTypes.STRING,
email: DataTypes.STRING,
login: DataTypes.STRING,
password: DataTypes.STRING,
}, {sequelize, tableName:'users'},
{
hooks: {
beforeCreate: (user) => {
console.log('ae');
},
},
}
)
do not enter my before and do not return my console.log
You should put the hooks option inside the second object parameter. Model.init() interface is:
public static init<M extends Model = Model>(this: ModelCtor<M>, attributes: ModelAttributes, options: InitOptions<M>): void;
Here is a working example:
import { sequelize } from '../../db';
import { Model, DataTypes } from 'sequelize';
class User extends Model {}
User.init(
{
name: DataTypes.STRING,
email: DataTypes.STRING,
login: DataTypes.STRING,
password: DataTypes.STRING,
},
{
sequelize,
tableName: 'users',
hooks: {
beforeCreate: (user) => {
console.log('======== ae ========');
},
},
},
);
(async function test() {
try {
await sequelize.sync({ force: true });
await User.create({ name: 'Alanna', email: 'example#gmail.com', login: 'value', password: '123' });
} catch (error) {
console.log(error);
} finally {
await sequelize.close();
}
})();
The execution results:
======== ae ========
Executing (default): INSERT INTO "users" ("id","name","email","login","password") VALUES (DEFAULT,$1,$2,$3,$4) RETURNING *;
Now, the beforeCreate hook of the User model works fine.

Getters and Setters for Virtual fields in Sequelize

I'm trying to hash my password field before storing it in the database. For that reason I've created a virtual field called password and an actual field called hashedPassword. The trouble is that when I try to encrypt the password in beforeCreate hook, it the user.password is undefined. I have tried every thing. I've also defined custom getters and setters for the virtual field. I don't know what I'm doing wrong here. Any help or guidance would be appreciated. Thanks.
import bcrypt from 'bcrypt';
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define(
'User',
{
passwordhash: {
type: DataTypes.STRING,
allowNull: false,
validate: {
notEmpty: true
}
},
password: {
allowNull: false,
type: DataTypes.VIRTUAL,
set(password) {
const valid = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[#$^+=!*()#%&]).{8,30}$/.test(
password
);
if (!valid) {
throw new Error(`Password not valid ${password}`);
}
this.setDataValue('password', password);
},
get() {
return this.getDataValue('password');
}
}
}
},
{
hooks: {
beforeCreate: function hashPassword(user) {
console.log('user is:', user);
return bcrypt
.hash('Abcdefgh1#', 12)
.then(hashed => {
user.passwordhash = hashed;
})
.catch(error => error);
}
}
}
);
User.associate = function(models) {
// associations can be defined here
};
return User;
};
use hooks :
hooks: {
beforeCreate: async (user, options) => {
let salt = await bcrypt.genSalt(10)
let hash = await bcrypt.hash(user.password, salt)
user.password = hash;
}
}
and for updating password fields use this:
User.beforeBulkUpdate(async instance => {
if (instance.attributes.password) {
let salt = await bcrypt.genSalt(10)
let hash = await bcrypt.hash(instance.attributes.password, salt)
instance.attributes.password = hash;
}
})
this works fine for me

Categories

Resources