How to debug a mongoose action within node.js - javascript

I am using mongoose to connect mongoDB and my node.js app. However, when I create or update a model instance, it won't change the Database, how can I go inside to debug what happens in the create or update action? I do check the MongoDB interface, delete and find and list action works just fine:
Here are those two docs that I have:
// index.js
const mongoose = require('mongoose')
const User = require('../model/user')
mongoose.Promise = global.Promise;
// connect to DB
const db = mongoose.connect('mongodb://localhost:27017/myImportantDates', {
useNewUrlParser: true,
useUnifiedTopology: true,
});
// create a user
const addUser = (user) =>{
let newUser = new User(user)
if (newUser.save()){
console.log(newUser) // it will console.log the newly created user, but it is not in the database
mongoose.disconnect()
}else{
console.log(newUser.errors)
}
}
// list all users
const listAllUsers = () =>{
User.find().then((users)=>{
console.log("Totally there are " + users.length + " users.");
console.log(users);
mongoose.disconnect();
}).then(()=>process.exit())
}
// find one user
const findUserByEmail = (email) => {
User.find({email},(err,docs)=>{
if(err){
console.log(err)
}else{
console.log(`Already found ${docs.length} matches.` )
console.log(docs)
}
mongoose.disconnect()
})
}
// update a user and make sure pass {new:true} option so that the doc in callback return the doc after updated
const updateUser = (email,user) => {
User.findOneAndUpdate( { email }, user, { new: true }, (err,doc) =>{
if(err){
console.log(err);
return
}else{
console.log(doc)
}
mongoose.disconnect()
})
}
// remove a user
const deleteUser = email => {
User.deleteOne( { email },(err,res) =>{
if(err){
console.log(err);
return
}
console.log("Deleted Successfully.");
mongoose.disconnect()
})
}
module.exports = {
addUser,
listAllUsers,
findUserByEmail,
updateUser,
deleteUser
}
//user_methods.js
const { program } = require('commander');
const {addUser,listAllUsers,findUserByEmail,updateUser,deleteUser} = require('./model_methods/user_methods')
const inquirer = require('inquirer')
const questions = [
{
type: 'input',
name: 'name',
message: 'user name'
},
{
type: 'input',
name: 'email',
message: 'user email'
},
{
type: 'input',
name: 'password',
message: 'user password'
},
];
program
.version('0.0.1')
.description("testing");
program
.command('list')
.alias('l')
.description('List all users')
.action(()=>listAllUsers())
program
.command('add')
.alias('a')
.description('Add a user')
.action(()=>{
inquirer.prompt(questions)
.then( answers => {
addUser(answers)
}).then(() => {
process.exit()
})
.catch(err =>{
console.log(error)
})
})
program
.command('find <email>')
.alias('f')
.description('find a user through email')
.action((email)=>{
findUserByEmail(email)
})
program
.command('update <email>')
.alias('u')
.description('update a user through email')
.action((email)=>{
inquirer.prompt(questions)
.then( ( email,answers ) => {
updateUser(email, answers)
}).then(() => {
process.exit()
})
.catch(err =>{
console.log(error)
})
})
program
.command('delete <email>')
.alias('d')
.description('delete a user through email')
.action((email)=>{
deleteUser(email)
})
program.parse(process.argv)
I will run node index.js <command> to reach those methods.

Currently, the process is getting exited before the save happens. According to your current code, it looks like you don't need to call the process.exit() explicitly. The application will exist on its own when the addUser operation is completed.
Also, you need to update the addUser method. You should only close the connection after successfully saving the record
// create a user
// create a user
const addUser = (user) =>{
let newUser = new User(user)
newUser.save((err, result) => {
console.log("inside save method")
if (err) console.log(err);
else {
console.log(result);
mongoose.disconnect();
}
})
}

Related

firebase - Log in again after the user has registered for the first time [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
Hi everyone I have such a problem,
After a user signs up for my site, for the first time, I want to log in with the user one more time.
I want that after he registers, connect again.
I tried to do it asynchronously, but it does not always work, sometimes I try to log in before the user is registers, I do not know why it does not work.
I want there to be a login only after registration, to force it.
handleSubmit = async () => {
const newUserData = {
email: 'test#mail.com',
password: '123456',
confirmPassword: '123456',
handle: 'test'
};
await signupUser(newUserData);
await signinChat(newUserData);
}
export const signupUser = (newUserData) => (dispatch) => {
axios
.post('/signup', newUserData)
.then((res) => {
console.log(res);
})
.catch((err) => {
console.log(err);
});
};
//basically call to this function to signup
exports.signup = (req, res) => {
const newUser = {
email: req.body.email,
password: req.body.password,
confirmPassword: req.body.confirmPassword,
handle: req.body.handle,
};
db.doc(`/users/${newUser.handle}`)
.get()
.then((doc) => {
if (doc.exists) {
return res.status(400).json({ handle: "this handle is already taken" });
} else {
return firebase
.auth()
.createUserWithEmailAndPassword(newUser.email, newUser.password);
}
})
.then((data) => {
userId = data.user.uid;
return data.user.getIdToken();
})
.then((idToken) => {
token = idToken;
const userCredentials = {
handle: newUser.handle,
email: newUser.email,
};
const userPreferences = {
handle: newUser.handle
};
return db.doc(`/users/${newUser.handle}`).set(userCredentials);
})
.then(() => {
return res.status(201).json({ token });
})
.catch((err) => {
console.error(err);
if (err.code === "auth/email-already-in-use") {
return res.status(400).json({ email: "Email is already is use" });
} else {
return res
.status(500)
.json({ general: "Something went wrong, please try again" });
}
});
};
export const signinChat = (user) => {
return async (dispatch) => {
const db = firebase.firestore();
firebase.auth()
.signInWithEmailAndPassword(user.email, user.password)
.then(data => {
console.log(data);
const currentUser = firebase.auth().currentUser;
const name = `${user.handle}`;
currentUser.updateProfile({
displayName: name,
})
.then(() => {
db.collection('users')
.doc(data.user.displayName)
.update({
isOnline: true,
})
.then(() => {
const loggedInUser = {
handle: user.handle,
uid: data.user.uid,
email: user.email
}
localStorage.setItem('user', JSON.stringify(loggedInUser));
console.log('User logged in successfully...!');
})
.catch(error => {
console.log(error);
});
});
})
.catch(error => {
console.log(error);
})
}
}
When I try to connect a second time, sometimes it does not work, for example:
image to show the error:

Forgot password functionality using NodeJs/Knex/Nodemailer and it is not working properly

Note: this is my first time posting, if you have feedback please let me know
Goal: I am building some endpoints that let a user reset their password if they forgot it. Flow would look like this:
User doesn't know password so they click on forgot password.
User types in email and clicks send
User receives email with link to reset password. Clicks on link and is redirected to type in their new password.
They click 'save' and they are redirected to login to sign in with their new password
I am using Insomnia to hit the endpoints for testing.
Things that are working:
When providing an email to reset password, Nodemailer does send out an email.
When updating the password it does show 'password updated' and gives a 200 status.
Bugs:
After trying to log in with that new password, it is not saving to the database. Only the old password will allow you to log back in.
Things I have tried:
I tried changing my user.model to use my findByEmail function and ran into some weird bugs, which then led me down a rabbit hold of issues.
I tried console logging quite a few things to see if I could trace the path.
I tried changing the user.update function but was not able to get it to work.
Here is my code:
Any guidance would be appreciated. If you need to look at any other files please let me know.
Forgot.password.js
const router = require('express').Router();
const crypto = require('crypto')
const User = require('../models/users.model')
const nodemailer = require('nodemailer')
router.post('/forgotpassword', (req, res) => {
let {
email
} = req.body
console.log(req.body)
// if (req.body.email === '') {
// res.status(400).json({ message: 'Email is required'})
// } console.error(req.body.email)
User.findBy({
email
})
.first()
.then(user => {
if (user === null) {
res.status(403).json({
message: 'Email not in db'
})
} else {
const token = crypto.randomBytes(20).toString('hex')
User.update({
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 3600000,
})
const transporter = nodemailer.createTransport({
service: 'gmail',
auth: {
user: `${process.env.EMAIL_USER}`,
pass: `${process.env.EMAIL_PASS}`
}
})
const mailOptions = {
from: `${process.env.EMAIL_USER}`,
to: `${user.email}`,
subject: '[Promoquo] Reset Password Link',
text: 'You are receiving this because you (or someone else) have requested the reset of the password for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process within one hour of receiving it:\n\n' +
`http://localhost:5000/reset/${token}\n\n` +
'If you did not request this, please ignore this email and your password will remain unchanged.\n',
}
transporter.sendMail(mailOptions, (err, res) => {
if (err) {
console.log('ERROR coming from forgot.password js and it sucks', err)
} else {
console.log('here is the res', res)
res.status(200).json({
message: 'recovery email sent hell yes'
})
}
})
}
res.status(200).json({
message: 'Reset password email has been sent WOOHOO 🎉'
})
})
.catch(error => {
res.status(500).json({
message: 'ERROR on last catch forgotpassword.js, likely no user exists',
error
})
console.log(error)
})
})
module.exports = router
Update.password.js
const router = require('express').Router();
const passport = require('passport')
const bcrypt = require('bcrypt')
const User = require('../models/users.model')
const BCRYPT_SALT_ROUNDS = 12
router.put('/updatePasswordViaEmail', (req, res) => {
User.find({
where: {
username: req.body.username,
resetPasswordToken: req.body.resetPasswordToken,
resetPasswordExpires: Date.now() + 3600000,
}
})
.then(user => {
if (user == null) {
console.error('password reset link has expired')
res.status(403).json({ message: 'Password reset link is invalid or has expired' })
} else if (user != null) {
console.log('user exists in db')
bcrypt.hash(req.body.password, BCRYPT_SALT_ROUNDS)
.then(hashedPassword => {
User.update({
password: hashedPassword,
resetPasswordToken: null,
resetPasswordExpires: null,
})
})
.then(() => {
console.log('log for THEN updating password')
res.status(200).json({ message: 'password updated' })
})
} else {
console.error('no user exists in db to update')
res.status(401).json({ message: 'no user exists in db to update'})
}
})
})
module.exports = router
Users.model.js
const db = require('../dbConfig')
module.exports = {
add,
find,
findBy,
findById,
findByEmail,
findByType,
update
};
function find() {
return db('users').select('id', 'username', 'email', 'password');
}
function findBy(filter) {
return db('users').where(filter);
}
async function add(user) {
const [id] = await db('users').insert(user);
return findById(id);
}
function findById(id) {
return db('users').where({ id }).first();
}
function findByEmail(email) {
return db('users').where({ email }).first();
}
function findByType(type) {
return db('users').where({ type }).first();
}
function update(changes, id) {
return db('users').where({ id }).update(changes)
}
20200913211559_users.js (this is the table)
exports.up = function(knex) {
return knex.schema.createTable('users', tbl => {
tbl.increments();
tbl.string('firstname', 30).notNullable();
tbl.string('lastname', 30).notNullable();
tbl.string('username', 30).notNullable()
tbl.string('email', 50).notNullable()
tbl.string('password', 128).notNullable();
tbl.string('type').notNullable();
tbl.boolean('confirmed').defaultTo('false');
tbl.string('resetPasswordToken');
tbl.date('resetPasswordExpires');
})
};
exports.down = function(knex) {
return knex.schema.dropTableIfExists('users')
};
Your User.update() lines aren't running (you either need to return their promises into the chains of promises, or hook into their callbacks). async/await is your friend here to avoid "callback hell."
const user = await User.find({
where: {
username: req.body.username,
resetPasswordToken: req.body.resetPasswordToken,
resetPasswordExpires: Date.now() + 3600000,
}
})
if (!user) { /* ... */ }
const token = crypto.randomBytes(20).toString('hex')
await User.update({ // await here!
resetPasswordToken: token,
resetPasswordExpires: Date.now() + 3600000,
})

Bookshelf - get the id when a new record is created

I'm using bookshelf with mysql for my project and can't figure out how I can get the id when I'm creating a new record. Instead it just returns undefined.
// model.js
const User = bookshelf.model('User', {
tableName: 'user',
hidden: ['password']
});
// main.js
User.forge(attributes)
.save()
.then(function (newRow) {
console.log(newRow.id); // Should return the id
})
.catch(function (err) {
// Handle errors
});
newRow object contains fields only from attributes. To get row id we need to read this row from database.
Possibly this is a crutch, but I don't know a better solution.
const User = bookshelf.model('User', {
tableName: 'user',
hidden: ['password']
});
// main.js
User.forge(attributes)
.save()
.then(function (newRow) {
console.log(newRow.id); // undefined
User.where(attributes).fetch()
.then((createdUser) => {
console.log(createdUser); // any id (1 for example)
})
.catch(function (err) {
// Handle errors
});
})
.catch(function (err) {
// Handle errors
});
P.S Better to use javascript async/await syntax intead of Promise.then()/Promise.catch()
const User = bookshelf.model('User', {
tableName: 'user',
hidden: ['password']
});
// main.js (in a async function)
try {
const newRow = await User.forge(attributes).save();
console.log(newRow.id); // undefined
const createdUser = await User.where(attributes).fetch();
console.log(createdUser); // any id (1 for example)
} catch (err) {
// Handle errors
}
const User = bookshelf.model('User', {
tableName: 'user',
hidden: ['password']
});
// main.js
const user = await new User().save(attributes);
const {id} = user.toJSON()
or
const User = bookshelf.model('User', {
tableName: 'user',
hidden: ['password']
});
// main.js
User.forge(attributes)
.save()
.then(function (newRow) {
let {id} = newRow.toJSON();
console.log(id); // Should return the id
})
.catch(function (err) {
// Handle errors
});
The problem is that you are not calling toJSON to serialize.

should I validate uniques in Mongoose before using save?

I am new to Node and Javascript in general and I was wondering if I should validate uniqueness by using FindOne before using .save.
My User schema does have Unique:true set for email and username and my current code works like a charm since mongoose returns an error message for uniques.
I wanted to know if it was better to validate for uniqueness before attempting to save for effiency or something?
Current code as follow :
export const createUser = (data) => {
return new Promise( async (resolve, reject) => {
const userData = JSON.parse(data);
const newUser = new User(userData);
await newUser.save((err) => {
if(err){
const msg = err.errmsg.toLowerCase();
const errormsg = msg.includes('email') ? 'Email already in use' : msg.includes('username') ? 'Username already in use' : 'Unexpected error.'
reject(JSON.stringify({error: errormsg}));
}
resolve(JSON.stringify({status: 200, created: true}));
});
});
};
Implemented here :
public register(req, res){
validateRegisterForm(req.body).then(data => {
createUser(data).then(resp => {
res.send(resp);
}).catch(err => {
res.send(err);
})
}).catch(err => {
res.send(err);
});
}

Using async in app startup script not returning any results

I am trying to run the following script in my Node app to check if any users exist and if not, create first admin user. Yet the script simply do nothing, return nothing even while using Try/Catch so can someone please tell me what I am missing / doing wrong here? or how I can possibly catch the error (if any)? Thanks
import pmongo from 'promised-mongo';
import crypto from 'crypto';
const salt = 'DuCDuUR8yvttLU7Cc4';
const MONGODB_URI = 'mongodb://localhost:27017/mydb';
const db = pmongo(MONGODB_URI, {
authMechanism: 'ScramSHA1'
}, ['users']);
async function firstRunCheckAndCreateSuperAdmin(cb) {
const username = 'admin2#test2.com';
try {
const user = await db.users.findOne({ role: 'admin'});
console.log(user);
if(!user) return cb('No user found');
} catch(e) {
cb('Unexpected error occurred');
}
if(!user) {
console.log('No admin detected.');
const adminPassword = crypto.pbkdf2Sync ( 'password', salt, 10000, 512, 'sha512' ).toString ( 'hex' );
await db.users.update({username: username}, {$set: {username: username, password: adminPassword, role: 'admin'}}, {upsert: true});
}
db.close();
process.exit();
}
firstRunCheckAndCreateSuperAdmin(function(err, resultA){
if(err) console.log(err);
});
You are not returning any callback when there is no admin user in the following code snippet
if (!user) {
console.log('No admin detected.');
const adminPassword = crypto.pbkdf2Sync ( 'password', salt, 10000, 512, 'sha512' ).toString ( 'hex' );
await db.users.update({username: username}, {$set: {username: username, password: adminPassword, role: 'admin'}}, {upsert: true});
// call cb(user) here
}
Please see comment.
import pmongo from 'promised-mongo';
import crypto from 'crypto';
const salt = 'DuCDuUR8yvttLU7Cc4';
const MONGODB_URI = 'mongodb://localhost:27017/mydb';
const db = pmongo(MONGODB_URI, {
authMechanism: 'ScramSHA1'
}, ['users']);
async function firstRunCheckAndCreateSuperAdmin(cb) {
const username = 'admin2#test2.com';
try {
const user = await db.users.findOne({
role: 'admin'
});
console.log(user);
//(1) If user is undefined, then launch cb with an error message;
if (!user) return cb('No user found');
} catch (e) {
//(2) If something is wrong, then launch cb with an error message;
cb('Unexpected error occurred');
}
//This part of the code will only be reached if user is defined.
//This is a dead code as if user is undefined, it would have exited at (1)
if (!user) {
console.log('No admin detected.');
const adminPassword = crypto.pbkdf2Sync('password', salt, 10000, 512, 'sha512').toString('hex');
await db.users.update({
username: username
}, {
$set: {
username: username,
password: adminPassword,
role: 'admin'
}
}, {
upsert: true
});
}
//So if user exists, it will close db and exit without calling cb.
db.close();
process.exit();
}
firstRunCheckAndCreateSuperAdmin(function(err, resultA) {
if (err) console.log(err);
});
Note:
If you are using async/await, then you don't need to use callback.
If you are using callback, then you don't need to have a return statement.
If the intention of the function is suppose to have a return value, make sure all code path returns a value.
I have tried to rewrite your code to make it smaller and to remove all node-style callback types of async code from it. I replaced update with insertOne since you only have one user to insert (not multiple to update). Also I have added 500 ms timeout when calling firstRunCheckAndCreateSuperAdmin in case it "hangs". It should log something at the end :)
import pmongo from 'promised-mongo'
import crypto from 'crypto'
import {
promisify
} from 'util'
const pbkdf2 = promisify(crypto.pbkdf2)
const salt = 'DuCDuUR8yvttLU7Cc4'
const MONGODB_URI = 'mongodb://localhost:27017/mydb'
const db = pmongo(MONGODB_URI, {
authMechanism: 'ScramSHA1'
}, ['users']);
const username = 'admin2#test2.com'
async function firstRunCheckAndCreateSuperAdmin() {
let user = await db.users.findOne({
role: 'admin'
});
if (!user) { // no user lets create one
user = await db.users.insertOne({
username: username,
password: (await pbkdf2('password', salt, 10000, 512, 'sha512')).toString('HEX'),
role: 'admin'
});
}
return user
}
const timeout = delay => message => new Promise((_, reject) => setTimeout(reject, delay, new Error(message)))
Promise
.race([firstRunCheckAndCreateSuperAdmin(), timeout(500)('Rejected due to timeout')])
.then(user => console.log(`Got user ${JSON.stringify(user)}`))
.catch(error => console.error(error))

Categories

Resources