There is model code:
'use strict';
const bcrypt = require('bcrypt');
module.exports = (sequelize, DataTypes) => {
const User = sequelize.define('User', {
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
},
password: {
type: DataTypes.STRING,
allowNull: false,
},
}, {
hooks: {
beforeCreate: user => {
const salt = bcrypt.genSaltSync();
user.password = bcrypt.hashSync(user.password, salt);
}
},
});
User.prototype.isPasswordValid = password => {
console.log('current_email');
console.log(this.email);
//return bcrypt.compareSync(password, this.password);
};
User.associate = models => {
// associations can be defined here
};
return User;
};
When I execute this code:
const user = await User.findOne({ where: { email } });
if (!user || !user.isPasswordValid(password)) {
ctx.body = {
result: RESULT_CODE.ERROR,
error: ERROR_CODE.UNAUTHORIZED,
};
return;
}
I see the following output:
current_email
undefined
I don't understand why I can't get access to fields of user.
Versions:
"sequelize": "4.3.1",
"sequelize-cli": "4.0.0"
Try using an usual function and not an arrow function
User.prototype.isPasswordValid = function(password) {
console.log('current_email');
console.log(this.email);
//return bcrypt.compareSync(password, this.password);
};
Related
Each time i register a user and then tries to login, postman says invalid credentials, i checked the isPasswordMatched several times but i cant solve the issue.
if i got a successfully login, postman is suppose to logout the loginUserctrl function first object before switching to "Invalid credentials"
/* controller/userCtrl.js file */
const User = require("../models/userModel");
const asyncHandler = require("express-async-handler");
const { find } = require("../models/userModel");
const { generateToken } = require("../config/jwtToken");
const createUser = asyncHandler(async(req, res) => {
const email = req.body.email;
const findUser = await User.findOne({email: email });
if (!findUser) {
//Create a new User
const newUser = await User.create(req.body);
res.json(newUser);
}else {
//user Allready Exist
throw new Error("User already exists");
}
});
const loginUserctrl = asyncHandler(async (req, res) => {
const {email, password } = req.body;
// check if user exits or not
const findUser = await User.findOne({ email });
if(findUser && (await findUser.isPasswordMatched(password))) {
res.json({
_id: findUser?._id,
firstname: findUser?.firstname,
lastname: findUser?.lastname,
email: findUser?.email,
mobile: findUser?.mobile,
token: generateToken(findUser?._id)
});
}else{
throw new Error("Invalid Credentials");
}
});
//Get all users
const getAllUser = asyncHandler(async (req, res) =>{
try{
const getUsers = await User.find();
res.json(getUsers);
}catch (error) {
throw new Error(error);
}
});
//Get a single user
const getaUser = asyncHandler(async (req, res) => {
const { id } = req.params;
try{
const getaUser = await User.findById(id);
res.json({getaUser});
} catch (error){
throw new Error(error)
}
});
//update a user
const updatedUser = asyncHandler(async (req, res) => {
const { _id } = req.user;
try {
const updatedUser = await User.findByIdAndUpdate(
_id,
{
firstname: req?.body?.firstname,
lastname: req?.body.lastname,
email: req?.body?.email,
mobile: req?.body?.mobile,
},{
new: true,
})
res.json(updatedUser);
} catch (error){
throw new Error(error);
}
})
//delete a single user
const deleteaUser = asyncHandler(async (req, res) => {
const { id } = req.params;
try{
const deleteaUser = await User.findByIdAndDelete(id);
res.json({
deleteaUser,
})
} catch (error){
throw new Error(error)
}
})
const blockUser = asyncHandler(async(req,res)=>{
const {id} = req.params;
try{
const block = User.findByIdAndUpdate(
id,{
isBlocked: true,
},
{
new: true,
}
);
res.json({
messages: "user Blocked",
})
}catch(error){
throw new Error(error);
}
})
const unblockUser = asyncHandler(async(req,res)=>{
const { id } = req.params;
try{
const unblock = User.findByIdAndUpdate(
id,{
isBlocked: false,
},
{
new: true,
},
);
res.json({
messages: "user unblocked",
})
}catch (error){
throw new Error(error)
}
});
module.exports = {
createUser,loginUserctrl,
getAllUser,getaUser,deleteaUser,
updatedUser,blockUser,unblockUser};
/*Models/userModels.js file */
const mongoose = require('mongoose'); // Erase if already required
const bcrypt = require('bcrypt');
// Declare the Schema of the Mongo model
var userSchema = new mongoose.Schema({
firstname:{
type:String,
required:true,
},
lastname:{
type:String,
required:true,
},
email:{
type:String,
required:true,
unique:true,
},
mobile:{
type:String,
required:true,
unique:true,
},
password:{
type:String,
required:true,
},
role: {
type: String,
default: "user",
},
isBlocked: {
type: Boolean,
default: false,
},
cart: {
type: Array,
default: [],
},
address: [{ type: mongoose.Schema.Types.ObjectId, ref: "Address" }],
wishlist: [{ type: mongoose.Schema.Types.ObjectId, ref: "Product" }],
},
{
timestamps: true,
}
);
userSchema.pre("save", async function (next){
const salt = await bcrypt.genSaltSync(10);
this.password = await bcrypt.hash(this.password,salt);
});
userSchema.methods.isPasswordMatched = async function (enteredPassword){
return await bcrypt.compare(enteredPassword, this.password);
}
//Export the model
module.exports = mongoose.model('User', userSchema);
how is everything ? I really need your help!
I'm building an API to register authenticated users, with storage in the mongo atlas database (cloud). I'm currently experiencing the following error: TypeError subscription error: User.hashPassword is not a function. I've done several researches, in several questions here on stackoverflow and on other sites, after testing all the solutions the error persists.
my user.model.js file looks like this:
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt');
const userSchema = new Schema(
{
userName: { type: String, unique: true, required: true },
email: { type: String, required: true, unique: true },
emailToken: { type: String, default: null },
emailTokenExpires: { type: Date, default: null },
active: { type: Boolean, default: false},
password: { type: String, required: true},
resetPasswordToken: { type: String, default: null },
resetPasswordExpires: { type: Date, default: null },
emailToken: {type: String, default: null},
emailTokenExpires: {type: Date, default: null},
},
{
timestamps: {
createdAt: "createdAt",
updatedAt: "updatedAt",
},
}
);
const User = mongoose.model("user", userSchema);
module.exports.hashPassword = async (password) => {
try {
const salt = await bcrypt.genSalt(10); // 10 rounds
return await bcrypt.hash(password, salt);
} catch (error) {
throw new Error("Hashing failed", error);
}
};
module.exports = User;
and my user.controller.js file looks like this:
const Joi = require("joi");
require("dotenv").config();
const { v4: uuid } = require("uuid");
const { sendEmail } = require("./helpers/mailer");
const User = require("./user.model");
//Validate user schema
const userSchema = Joi.object().keys({
email: Joi.string().email({ minDomainSegments: 2 }),
password: Joi.string().required().min(4),
confirmPassword: Joi.string().valid(Joi.ref("password")).required(),
});
exports.Signup = async (req, res) => {
try {
const result = userSchema.validate(req.body);
if (result.error) {
console.log(result.error.message);
return res.json({
error: true,
status: 400,
message: result.error.message,
});
}
//Check if the email has been already registered.
var user = await User.findOne({
email: result.value.email,
});
if (user) {
return res.json({
error: true,
message: "Email is already in use",
});
}
const hashPassword = await User.hashPassword(result.value.password);
const id = uuid(); //Generate unique id for the user.
result.value.userId = id;
//remove the confirmPassword field from the result as we dont need to save this in the db.
delete result.value.confirmPassword;
result.value.password = hashPassword;
let code = Math.floor(100000 + Math.random() * 900000); //Generate random 6 digit code.
let expiry = Date.now() + 60 * 1000 * 15; //Set expiry 15 mins ahead from now
const sendCode = await sendEmail(result.value.email, code);
if (sendCode.error) {
return res.status(500).json({
error: true,
message: "Couldn't send verification email.",
});
}
result.value.emailToken = code;
result.value.emailTokenExpires = new Date(expiry);
const newUser = new User(result.value);
await newUser.save();
return res.status(200).json({
success: true,
message: "Registration Success",
});
} catch (error) {
console.error("signup-error", error);
return res.status(500).json({
error: true,
message: "Cannot Register",
});
}
};
Error displayed in terminal:
Danilo#DANILO-PC D:\Meus Documentos\Área de Trabalho\api-auth-pokestore
$ node app.js
Server started listening on PORT : 5000
Database connection Sucess.
signup-error TypeError: User.hashPassword is not a function
at exports.Signup (D:\Meus Documentos\Área de Trabalho\api-auth-pokestore\src\users\user.controller.js:39:37)
at processTicksAndRejections (internal/process/task_queues.js:94:5)
image terminal
Look at this part of your code:
module.exports.hashPassword = async (password) => { ... };
module.exports = User;
You're setting hashPassword in your exports, then completely replacing your exports with User. You probably wanted to do something like this instead:
User.hashPassword = async (password) => { ... };
module.exports = User;
or move your module.exports.hashPassword = ... so it's after the module.exports = ....
I'm trying to update an invitation when the invited user registers. The invitation has an auth property which is a nested object, which itself has a property with the key "used." I'm just trying to explicitly declare the value to be true, and save, using async/await. But it's not updating. Is there a better way to do this?
My function:
exports.invitedSignup = async (req, res, next) =>
{
const { firstName, lastName, company, password, email, companyCode, token } = req.body;
console.log(email);
try
{
const user = await User.findOne({ email });
const invitation = await Invitation.findOne({ email }).sort({ field: 'asc', _id: -1 }).limit(1);
if (user) { return res.status(422).send({ error: "User is already registered" }); };
if (!invitation) { return res.status(422).send({ error: "No invitation on record" }); };
if (token !== invitation.auth.token)
{
return res.status(422).send({ error: "Something has gone wrong, please sign up again" });
}
try
{
invitation.auth.used = true;
const updateInvitation = await invitation.save();
console.log("authorization: " + invitation.auth.used);
} catch (e)
{
return next(e);
}
try
{
const saveUser = new User({
firstName: firstName,
lastName: lastName,
email: req.body.email,
password: password,
company: company,
companyCode: companyCode,
role: 1,
auth: { used: true }
});
const newUser = await saveUser.save();
const { email, firstname, lastname } = newUser;
res.json({ token: tokenForUser(newUser), email, firstName, lastName });
}
catch (e)
{
return next(e);
}
}
catch (e)
{
return next(e);
}
};
The invitation schema:
const mongoose = require('mongoose');
const Schema = mongoose.Schema;
const bcrypt = require('bcrypt-nodejs');
//define model
const invitationSchema = new Schema({
email: { type: String, unique: true, lowercase: true, unique: true },
inviter: String,
company: String,
companyCode: String,
created: Date,
auth: {
token: String,
used: Boolean,
expires: Date,
}
});
invitationSchema.pre('save', function (next)
{
const invitation = this;
bcrypt.genSalt(10, (err, salt) =>
{
const tomorrow = new Date();
invitation.created = tomorrow;
tomorrow.setDate(tomorrow.getDate() + 1);
if (err) { return next(err); };
invitation.auth = { token: salt, used: 0, expires: tomorrow };
next();
});
});
//create model class
const ModelClass = mongoose.model('invitation', invitationSchema);
//export model
module.exports = ModelClass;
http://mongoosejs.com/docs/schematypes.html#mixed
person.anything = { x: [3, 4, { y: "changed" }] };
person.markModified('anything');
person.save(); // anything will now get saved
I have just coding the todolist api project on NodeJS & Express. I follow some instruction using Sequelize to interact with DB: SQLite. But I encounter with Sequelize to create class method as below:
user.js
var bcrypt = require('bcrypt');
var _ = require('underscore');
module.exports = (sequelize, DataTypes) => {
var User = sequelize.define('user', {
email: {
type: DataTypes.STRING,
allowNull: false,
unique: true,
validate: {
isEmail: true
}
},
salt: {
type: DataTypes.STRING
},
password_hash: {
type: DataTypes.STRING
},
password: {
type: DataTypes.VIRTUAL,
allowNull: false,
validate: {
len: [6, 100]
},
set: function (value) {
var salt = bcrypt.genSaltSync(10);
var hashedPassword = bcrypt.hashSync(value, salt);
this.setDataValue('password', value);
this.setDataValue('salt', salt);
this.setDataValue('password_hash', hashedPassword);
}
}
}, {
hooks: {
beforeValidate: (user, options) => {
if (typeof user.email === 'string') {
user.email = user.email.toLowerCase();
}
}
}
});
return User;
// Class methods
User.prototype.toPublicJSON = function() {
var json = this.toJSON();
return _.pick(json, 'id', 'email', 'createdAt', 'updatedAt');
};
User.authenticate = (body) => {
return new Promise ((resolve, reject) => {
if (typeof body.email !== 'string' || typeof body.password !== 'string') {
return reject();
}
user.findOne({
where: {
email: body.email
}
}).then((user) => {
if (!user || !bcrypt.compareSync(body.password, user.get('password_hash'))) {
return reject();
}
resolve(user);
}, (e) => {
reject();
})
});
};
}
db.js
var Sequelize = require('sequelize');
var sequelize = new Sequelize(undefined, undefined, undefined, {
'dialect': 'sqlite',
'storage': __dirname + '/data/dev-todo-api.sqlite'
});
db = {};
db.todo = sequelize.import(__dirname + '/models/todo.js');
db.user = sequelize.import(__dirname + '/models/user.js');
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
user.js
app.post('/users/login', (req, res) => {
var body = _.pick(req.body, 'email', 'password');
db.user.authenticate(body).then((user) => {
res.json(user.toPublicJSON());
}, () => {
res.status(401).send();
});
})
Error: db.user.authenticate is not function.
I think I can use function authenticate after user.js return variable User. Please advise me how to resolve this problem. Thanks all.
The problem is not with sequelize. Rather you are defining the methods after return, so the code that is responsible for creating the methods is never reached.
return User;
// Class methods
User.prototype.toPublicJSON = function() {
var json = this.toJSON();
return _.pick(json, 'id', 'email', 'createdAt', 'updatedAt');
};
User.authenticate = (body) => {
You should move the return User statement at the end of your arrow function and your code should work.
Can someone help me figure out how to use my sequelize instance methods on my controller?
I wrote my model like that:
const bcrypt = require('bcryptjs');
module.exports = (sequelize, Sequelize) => {
const Patient = sequelize.define('Patient', {
email: {
type: Sequelize.STRING,
allowNull: false,
},
password : {
type: Sequelize.STRING,
allowNull: false,
},
}, {
classMethods: {
associate: (models) => {
// associations can be defined here
}
},
instanceMethods: {
generateHash: function (password) {
return bcrypt.hash(password, 8, function(err, hash){
if(err){
console.log('error'+err)
}else{
return hash;
}
});
},
validPassword: function(password) {
return bcrypt.compareSync(password, this.password);
}
}
});
return Patient;
};
but when I launch it on my controller which I made like that
const jwt = require('jsonwebtoken');
const passport = require('passport');
const Patient = require('../models').Patient;
module.exports = {
///
create(req, res) {
return Patient
.create({
email: req.body.email,
password: Patient.prototype.generateHash(req.body.password)
})
.then(patient => res.status(201).send(patient))
.catch(error => res.status(400).send(error));
},
};
I get this error for the request:
TypeError: Cannot read property 'generateHash' of undefined
First of all you should use bcrypt.hashSync() because you want to assign asynchronous function call to the password - it won't work.
generateHash: function(password){
try {
return bcrypt.hashSync(password, 8);
} catch (e) {
console.log('error: ' + e);
}
}
In order to use instance method you should do
Patient.build().generateHash(req.body.password);
build() creates new instance of model so then you can run the instance method. Or you can declare the generateHash as a class method so you could run it like that
Patient.generateHash(req.body.password);