Sequelize findAll is not a function - mysql

I'm making a project with Sequelize and I'm stucked in this step. The problem is that when I try to log in and the passport-local code is executed, when it reaches the User.findAll(...) it throws that findAll is not a function.
If I make console.log(User) it shows [function].
My structure:
/config/config.js
/config/passport.js
/models/index.js
/models/nuke_users.js (generated by sequelize-auto)
/index.js
config.js:
//Setting up the config
var Sequelize = require('sequelize');
var sequelize = new Sequelize('rocarenav2', 'root', '123456', {
host: "localhost",
port: 3306,
dialect: 'mysql'
});
module.exports = sequelize;
passport.js:
// config/passport.js
// load all the things we need
var LocalStrategy = require('passport-local').Strategy;
// load up the user model
var User = require('../models/nuke_users');
var crypto = require('crypto');
function hashPasswordForNuke(password) {
return md5password = crypto.createHash('md5').update(password).digest('hex');
}
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
User.findById(id, {})
.then(function (user) {
done(err, user);
})
.catch(function (error){
done(error);
});
});
// =========================================================================
// LOCAL LOGIN =============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-login', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField : 'email',
passwordField : 'password',
passReqToCallback : true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) { // callback with email and password from our form
User.findAll({
where: {
'user_email': email
}
}).then(function (user) {
if(!user)
return done(null, false, req.flash('loginMessage', 'No user found.')); // req.flash is the way to set flashdata using connect-flash
// if the user is found but the password is wrong
if ((user.user_password).localeCompare(hashPasswordForNuke(password)) === -1)
return done(null, false, req.flash('loginMessage', 'Oops! Wrong password.')); // create the loginMessage and save it to session as flashdata
return done(null, user);
})
.catch(function (error){
done(error);
});
}));
};
models/index.js
'use strict';
var fs = require('fs');
var path = require('path');
var Sequelize = require('sequelize');
var basename = path.basename(module.filename);
var config = require(__dirname + '/../config/config');
var db = {};
//Create a Sequelize connection to the database using the URL in config/config.js
var sequelize = config;
//Load all the models
fs
.readdirSync(__dirname)
.filter(function(file) {
return (file.indexOf('.') !== 0) && (file !== basename) && (file.slice(-3) === '.js');
})
.forEach(function(file) {
var 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);
}
});
//Export the db Object
db.sequelize = sequelize;
db.Sequelize = Sequelize;
module.exports = db;
/models/nuke_users.js
/* jshint indent: 2 */
module.exports = function(sequelize, DataTypes) {
return sequelize.define('nuke_users', {
user_id: {
type: DataTypes.INTEGER(11),
allowNull: false,
primaryKey: true,
autoIncrement: true
},
username: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: "",
references: {
model: 'reps_table',
key: 'PostName'
}
},
user_email: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ""
},
user_avatar: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ""
},
user_password: {
type: DataTypes.STRING,
allowNull: false,
defaultValue: ""
}
}, {
tableName: 'nuke_users'
});
};
/index.js
...
var models = require('./models/');
...
So, what am I doing wrong?

The nuke_users module is exporting a function that, when called, returns the Model. Because you aren't calling this function, it is not returning the Model, and thus the function you are looking for does not exist.
To call this exported function you would need to pass in the sequelize instance and DataTypes, as so:
var User = require('../models/nuke_users')(sequelize, DataTypes);
In your case you are using a loader in the index.js file, and it is exporting the db object which contains the models keyed by their name.
var models = require('../models'); // loads index.js
var User = models.nuke_user; // the model keyed by its name
User.findOne(...); // search the model

Instead of returning the model, export it from NukeUser.js:
const NukeUser = sequelize.define('nuke_users', {
// ...
});
module.exports = NukeUser;
Then in index.js:
const NukeUser = require('../models/NukeUser');
NukeUser.findAll() //.then() ...

You need to check the models route in the collections, for example, in my case, I had read() as a method in my collections like that:
async read(id) {
try {
if(id) {
return await this.model.findOne({where: {id: id}});
} else {
return await this.model.findAll();
}
} catch (e) {
console.error(`Error in reading data with the id: ${id}`);
}
}
So, findAll() wouldn't work. Instead, I used read()

Related

Nodejs Sequelize and passport Js, stuck on executing query when registing user

this is the problem I am having:
I have 3 models(users,favorites,cryptocoins)
'use strict';
const { Model} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Cryptocoin extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
}
Cryptocoin.init({
coinId:{
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
coinName: DataTypes.STRING,
coinPrice: DataTypes.INTEGER,
coinAmount: DataTypes.INTEGER,
totalValue: DataTypes.STRING,
boughtOn: DataTypes.DATE
}, {
sequelize,
modelName: 'Cryptocoin',
});
return Cryptocoin;
};
'use strict';
const { Model } = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class Favorite extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
// define association here
}
}
Favorite.init({
favoriteId: {
type:DataTypes.INTEGER,
primaryKey:true,
autoIncrement:true,
},
userId:{
type:DataTypes.INTEGER,
references:{
model:'Users',
key:'userId',
},
onDelete:'CASCADE',
},
coinId:{
type:DataTypes.INTEGER,
references:{
model:'Cryptocoins',
key:'coinId',
},
onDelete:'CASCADE',
},
}, {
sequelize,
modelName: 'Favorite',
});
return Favorite;
};
'use strict';
const { Model} = require('sequelize');
module.exports = (sequelize, DataTypes) => {
class User extends Model {
/**
* Helper method for defining associations.
* This method is not a part of Sequelize lifecycle.
* The `models/index` file will call this method automatically.
*/
static associate(models) {
}
}
User.init({
userId: {
allowNull: false,
autoIncrement: true,
primaryKey: true,
type: DataTypes.INTEGER
},
userName: DataTypes.STRING,
passWord: DataTypes.STRING
}, {
sequelize,
modelName: 'User',
});
return User;
};
These all have migrations which work.
Now I have passport.js file which holds the passport stategies
const bcrypt = require('bcrypt');
module.exports = function (passport, Auth) {
const LocalStrategy = require('passport-local').Strategy;
passport.use('local-signup', new LocalStrategy(
{
usernameField: 'username',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
}, function (req, username, password, done) {
console.log("Signup for - ", username)
const generateHash = function (password) {
return bcrypt.hashSync(password, bcrypt.genSaltSync(8), null);
}
Auth.findOne({
where: {
userName: username
}
}).then(function (user) {
//console.log(user);
if (user) {
return done(null, false, {
message: 'That username is already taken'
});
} else {
const userPassword = generateHash(password);
const data = {
username: username,
password: userPassword,
};
Auth.create(data).then(function (newUser, created) {
if (!newUser)return done(null, false);
if (newUser) return done(null, newUser)
});
}
});
}
));
This file is called via app.js like so
just a snippet of the code in app.js
const models = require('./models');
app.use(session({
genid: (req) => {
return uuid.v1();
},
name: 'Crypto-session',
store:new fileStore(),
secret: '------',
resave:false,
saveUninitialized:false,
}))
app.use(passport.initialize());
app.use(passport.session());
require('./config/passport')(passport,models.User);
Now when going to my /register route and inputing a username and password this is what happens
Signup for - randomUser
Executing (default): SELECT `userId`, `userName`, `passWord`, `createdAt`, `updatedAt` FROM `Users` AS `User` WHERE `User`.`userName` = 'randomUser' LIMIT 1;
Executing (default): INSERT INTO `Users` (`userId`,`createdAt`,`updatedAt`) VALUES (DEFAULT,?,?);
And it's stuck at the executing (default) part, It gets uploaded to the database but without any username or password, console logging both of them shows they are being populated with values from my form.
Any idea how I can fix this issue ?
note: I am fairly new to express and nodeJs in general.
Answer: After brainstorming and reading docs a bit these where the issues.
Ensure the deserializeUser function is either await or then based e.g
// deserialize user
passport.deserializeUser(function (id, done) {
Auth.findByPk(id).then(function (user) {
if (user) {
done(null, user.get());
} else {
done(user.errors, null);
}
});
});
Ensure you have a redirect in you route.post method e.g
// route for register action
app.post('/register',passport.authenticate('local-signup',{ successRedirect: '/',
failureRedirect: '/register' }),function (req, res) {
});
Ensure all of your passport js fields match the database fields e.g
I had username and password, but in my database it is userName and passWord.
changing these like so
const data = {
userName: username,
passWord: userPassword,
};
Uploads everything to the database.

passport authentication callback not calling passport middleware

I am trying to test if a GET request to a specific route is protected by using JSON Web Tokens with passport JwtStrategy; however, it seems like the passport.use middleware function I have in my server.js file is not executing. The console.log I have in there never shows up in my shell/terminal. My login route works, but not the profile route. I am using postman and I entered http://localhost:3000/profile for the GET method and in the Headers tab I chose Authorization for Key and for the Value I copied and pasted the long JSON web token string, but it keeps saying unauthorized. That is because my passport.use function is never getting executed.
//Server.js file
var JwtStrategy = require("passport-jwt").Strategy;
var ExtractJwt = require("passport-jwt").ExtractJwt;
var User = require("../models/user");
var config = require('./secret');
app.use(passport.initialize());
app.use(passport.session());
let options = {};
//pass token back and forth
options.jwtFromRequest = ExtractJwt.fromAuthHeader();
options.secretOrKey = config;
passport.use(new JwtStrategy(options, (jwt_payload, done) => {
*******************************************
//this console log doesn't show up in shell which makes be believe its never getting here
*******************************************
console.log("JWT PAYLOAD", jwt_payload)
User.getUserById(jwt_payload._id, (err, user) => {
if(err){
return done(err, false);
}
if(user){ //null for error
return done(null, user);
}else{
return done(null, false);
}
});
}));
//Routes file where the passport.authenticate callback is called
var passport = require('passport');
var jwt = require('jsonwebtoken');
var secret = require('../config/secret')
var User = require('../models/user');
router.post('/login', (req, res) => {
var username = req.body.username;
var password = req.body.password;
console.log("SECRET2", secret);
console.log("SECRET", secret.secret);
User.getUserByUsername(username, (err, user) => {
if(err){
throw err;
}
if(!user){
return res.json({ success: false, msg: "User not found"});
}
User.comparePassword(password, user.password, (err, isMatch) => {
if(err){
throw err;
}
if(isMatch){
var token = jwt.sign(user, secret.secret, {
expiresIn: 604800 //1 week in seconds, token expires and requires to log back in
});
console.log('TOKEN IN LOGIN ROUTE', token)
res.json({
//tokens are then stored in local storage or cookie
success: true,
token: 'JWT ' + token,
user: {
id: user._id,
name: user.name,
username: user.username,
email: user.email
}
});
}else{
return res.json({ success: false, msg: "Incorrect password"});
}
});
});
});
router.get('/profile', passport.authenticate('jwt', {session:false}), (req, res) => {
res.json({user: req.user});
});
//User model
var mongoose = require('mongoose');
var bcrypt = require('bcryptjs');
var Schema = mongoose.Schema;
var UserSchema = new Schema({
name: {
type: String,
trim: true,
required: "First Name is Required"
},
email: {
type: String,
required: true
},
username: {
type: String,
required: true
},
password: {
type: String,
required: true
}
});
var User = mongoose.model("User", UserSchema);
module.exports = User;
//Alternate syntax for exporting Schema
// var User = module.exports = mongoose.model("User", UserSchema);
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.getUserByUsername = function(username, callback){
var query = { username: username }
User.findOne(query, callback);
}
//Custom User model function that will take in the newUser object and hash the password.
module.exports.addUser = function(newUser, callback){
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err){
throw err
}
newUser.password = hash;
newUser.save(callback);
});
});
}
module.exports.comparePassword = function(password, hash, callback){
bcrypt.compare(password, hash, (err, isMatch) => {
if(err){
throw err
}
callback(null, isMatch);
});
}
Update:
I tried putting a space after 'JWT' in for the value for Authorization in the postman, but it still does not work and the console log is not showing. Is it because I am somehow not exporting or linking the passport.use I have defined in my server.js to my GET '/profile' route in my routes file?
Update 2: Added model and Login route
Maybe it is necessary to include more code to see your issue, but it seems like the strategy is not being exported correctly. When you create a new strategy, you can include an 'alias' to use it in the entry point:
passport.use('local-login', new JwtStrategy(options, (jwt_payload, done) => {
....
}
router.get('/profile', passport.authenticate('local-login', {session:false}), (req, res) => {
res.json({user: req.user});
});

how to update user table in node js

mycode is--
updateUser: function(req, res) {
var data = req.body;
var option = {
name: data.name,
mobile: data.mobile,
domain: data.domain,
}
userModel.update(option, function (error, rows) {
console.log('###############',error || rows);
if(!res){
//TODO: Error handling
console.log("ERROR", res);
res.status(200).send({"status_code": 0, 'message': 'Some error occured'});
return;
}
res.status(200).send({"status_code": 1, 'message': 'Succesfully Updated'});
})
},
the problem is updated all user coloumn.
in the code how to give id of the particular update data.
If you are not writing some very low level driver, I would recommend to use ORM like https://github.com/sequelize/sequelize. The very first example on their homepage shows:
var Sequelize = require('sequelize');
var sequelize = new Sequelize('database', 'username', 'password');
var User = sequelize.define('user', {
username: Sequelize.STRING,
birthday: Sequelize.DATE
});
sequelize.sync().then(function() {
return User.create({
username: 'janedoe',
birthday: new Date(1980, 6, 20)
});
}).then(function(jane) {
console.log(jane.get());
jane.update({
username: 'a very different username now'
}).then(function() {
console.log(jane.get());
})
});
You should use Bookshelf.js, good ORM, easy to use

Node.js MySQL model designing

I'm developing a node.js application using MySQL database but I'm stuck with making models on the node.js side of my application. I've used Mongoose before to produce schemas and use models to do database functions but i couldn't find such support for MySQL. Can anyone suggest a proper way to isolate my database functions in node.js like I could do with Mongoose. here's my app.js and users model i'm using right now.
app.js
var express= require("express");
var bodyParser = require("body-parser");
var mysql = require("mysql");
var UserModel= require("./models/User.js")
var app=express();
var sql = mysql.createConnection({
host: "localhost",
user: "root",
password: "1234",
database: "dricm"
});
sql.connect(function (err) {
if(err){
console.log("error");
}else{
console.log("connected");
}
});
app.set("views", "./views");
app.use(express.static("node_modules/bootstrap/dist"));
app.use(express.static("public"));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false}));
app.get('/', function (req, res) {
res.render("signup.jade");
});
app.post('/signup', function (req, res) {
var obj= {
username: req.body.username,
password: req.body.password
};
UserModel.createUser(obj);
res.redirect("/");
});
app.listen(3000, function () {
console.log("server running at 3000");
});
User.js (probable model)
var mysql= require("mysql");
var bcrypt = require("bcryptjs");
var sql = mysql.createConnection({
host: "localhost",
user: "root",
password: "1234",
database: "dricm"
});
sql.connect(function (err) {
if(err){
console.log("error");
}else{
console.log("connected");
}
});
var User= {
}
User.createUser = function createUser(newUser) {
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(newUser.password,salt, function (err, hash) {
newUser.password = hash;
var query = sql.query("INSERT INTO USERS set ?", newUser, function (err, res) {
console.log(query);
if(err) {
console.log("error");
}
else{
console.log(res.insertId);
}
});
});
});
}
module.exports= User;
What you are looking for is called an ORM (Object-relational mapping) Mongoose is one for MongoDB (Which is a NOSQL document oriented database)
There are other ORMs for relational databases that work with Node.js, The most popular right now is Sequelize which I have personally used and recommend.
With Sequelize you can put your models in different files just like Mongoose however in order to load them on, you need to add them with a simple script inside your index.js
Imagine the following Workspace:
--models/
----User.js
----Permissions.js
--index.js
And your model definitions should be something like this:
User.js
const UserModel = (sequelize, Sequelize) => {
const {INTEGER, STRING, FLOAT, BOOLEAN, DATE} = Sequelize
const User = sequelize.define('User', {
UserId: {type: INTEGER, primaryKey: true, autoIncrement: true},
Username: {type: STRING, primaryKey: true, allowNull: false},
Password: STRING
})
return User
}
module.exports = UserModel
Permissions.js
const PermissionsModel = (sequelize, Sequelize) => {
const {INTEGER, STRING, FLOAT, BOOLEAN, DATE} = Sequelize
const Permissions = sequelize.define('Permissions', {
Role: {type: STRING, allowNull: false},
ControllerAddress: {type: STRING, allowNull: false}
})
return Permissions
}
module.exports = PermissionsModel
Now you need to use the following script to use them inside your index.js
let normalizedPath = require('path').join(__dirname, "models")
require('fs').readdirSync(normalizedPath).forEach((file) => {
sequelize.import('./models/' + file)
})
let {User, Permissions} = sequelize.models
Now you can use the User and Permissions instances to control them and call functions like:
User.create({Username, Password})

User Signup using passport+express+mysql+sequelize

I am trying to build a user signup api using Passport, MySql, NodeJS and Sequelize. The only problem that i face is that when a user has signed up once and he tries to sign up again with the same email user is thrown a 401 Unauthorized Error instead of the user object. When i tried to debug the same the response that i was getting from the server was this
[object SequelizeInstance:users]. The files have been mentioned below. Thanks a tonnn in advance!!!.
Passport.js file:
var LocalStrategy = require('passport-local').Strategy;
var mysql = require('mysql');
var Model = require('../models/models.js');
// expose this function to our app using module.exports
module.exports = function(passport) {
// =========================================================================
// passport session setup ==================================================
// =========================================================================
// required for persistent login sessions
// passport needs ability to serialize and unserialize users out of session
// used to serialize the user for the session
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// used to deserialize the user
passport.deserializeUser(function(id, done) {
connection.query("select * from users where id = " + id, function(err, rows) {
done(err, rows[0]);
});
});
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
Model.User.findOne({
where: {
email: email
}
}).then(function(user) {
if (user == null) {
Model.User.create({
email: email,
password: password
}).then(function(user) {
return done(null, user);
}).catch(function(err) {
return done(null, err);
});
} else {
return done(null, false);
}
})
}));
};
The Signup api:
router.post('/signup', passport.authenticate('local-signup'), function(req, res) {
// If this function gets called, authentication was successful.
// `req.user` contains the authenticated user.
console.log(req.user);
if(req.user){
res.send({
success: true,
response: 'signup successful'
});
} else {
res.send({
success: false,
response: 'Email already in use'
});
}
});
The User model is:
//models/users.js
var Sequelize = require('sequelize')
var attributes = {
id: {
type: Sequelize.INTEGER,
primaryKey: true,
autoIncrement: true
},
name: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
},
created_by: {
type: Sequelize.INTEGER
}
}
var options = {
// Add the timestamps attributes (updatedAt, createdAt)
timestamps: true,
// don't delete database entries but set the newly added attribute deletedAt
// to the current date (when deletion was done). paranoid will only work if
// timestamps are enabled
paranoid: true,
// don't use camelcase for automatically added attributes but underscore style
// so updatedAt will be updated_at
underscored: true,
// disable the modification of table names; By default, sequelize will automatically
// transform all passed model names (first parameter of define) into plural.
// if you don't want that, set the following
freezeTableName: true,
// define the table's name
tableName: 'users'
}
module.exports.attributes = attributes
module.exports.options = options
The automated table creation model script is:
// models/models.js
var UserMeta = require('./users.js'),
connection = require('./index.js')
var User = connection.define('users', UserMeta.attributes, UserMeta.options)
// force: true will drop the table if it already exists
User.sync({
force: true,
match: /_servernew$/
}).then(function() {
// Table created
return User.create();
});
// you can define relationships here
module.exports.User = User;
So i came up with the solution. The following code needs to be changed.
router.post('/signup', function(req, res, next) {
passport.authenticate('local-signup', function(err, user, info) {
if(user){
req.logIn(user, function(err) {
if (err) {
return next(err);
} else {
res.send({
success: true,
response: 'signup successful'
});
}
});
}
if(!user){
res.send({
success: false,
response: 'Authentication Failed'
});
}
if(err){
res.send({
success: false,
response: 'Authentication failed'
})
}
})(req, res, next);
});
and the passport.js code should be like this.
// =========================================================================
// LOCAL SIGNUP ============================================================
// =========================================================================
// we are using named strategies since we have one for login and one for signup
// by default, if there was no name, it would just be called 'local'
passport.use('local-signup', new LocalStrategy({
// by default, local strategy uses username and password, we will override with email
usernameField: 'email',
passwordField: 'password',
passReqToCallback: true // allows us to pass back the entire request to the callback
},
function(req, email, password, done) {
Model.User.findOne({
where: {
email: email
}
}).then(function(user, err) {
console.log('I entered'+user);
console.log('I entered'+err);
if(err) {
console.log(err);
return done(null, false);
}
if(user == null) {
Model.User.create({
email: email,
password: password
}).then(function(user) {
return done(null, user);
}).catch(function(err) {
return done(null, err);
});
}
if(user){
return done(null, false);
}
})
}));
It will work just like a charm :D.