Saving 3 schema simultaneously in MongoDB - node.js

I'm trying to save in 3 schema (User, UserDetail and Team) data in mongo DB simultaneously but I receive an error
(node:14432) UnhandledPromiseRejectionWarning: Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
Here's my code
self.createTeam = function (req, res) {
Logger.request(req);
Logger.requestBody(req);
bcrypt.hash(req.body.password, 10, function (err, hash) {
if (err) {
return res.status(500).json({
error: err
})
} else {
req.body.password = hash;
const team = new Teams({
_id: new mongoose.Types.ObjectId(),
domain: req.body.domain,
avatarOriginal: req.body.avatarOriginal,
avatar_180x180: req.body.avatar_180x180,
avatar_180x100: req.body.avatar_180x100,
name: req.body.name,
createdAt: Date.now(),
updatedAt: Date.now()
});
const user = new User({
_id: new mongoose.Types.ObjectId(),
username: req.body.username,
email: req.body.email,
password: hash,
createdAt: Date.now(),
updatedAt: Date.now()
});
const userDetail = new UserDetail({
_id: new mongoose.Types.ObjectId(),
user_id: user._id,
team_id: team._id,
firstName: req.body.firstName,
lastName: req.body.lastName,
createdAt: Date.now(),
updatedAt: Date.now()
})
team.save().then(function (result) {
return user.save();
}).then(function (result) {
return userDetail.save();
}, function (err) {
res.status(500).json({
error: err
});
}).then(function (user) {
Logger.response(req, user);
res.status(200).json({
success: 'New team and user has been created'
})
})
}
})
}
Please help thank you

Related

add username and password one table and other data in another using node js with rest api

I have one model is user in that model I was added email, username, password and name , when I have insert this data using node JS with the help of rest API, so that condition all 4 records are stored in one table
but I want email and name is stored in registration table and username and password stored in login table ,when I put login request using postman it with username name and password credentials it gives the successful response.
I am new to Node
My controller is
exports.user_signup = (req, res, next) => {
User.find({ username: req.body.username })
.exec()
.then(user => {
if (user.length >= 1) {
return res.status(409).json({
message: "Mail exists"
});
} else {
bcrypt.hash(req.body.password, 10, (err, hash) => {
if (err) {
return res.status(500).json({
error: err
});
} else {
const user = new User({
_id: new mongoose.Types.ObjectId(),
username: req.body.username,
password: hash,
email: req.body.email,
contact: req.body.contact,
});
user
.save()
.then(result => {
// console.log(result);
res.status(201).json({
message: "User created"
});
})
.catch(err => {
console.log(err);
res.status(500).json({
error: err
});
});
}
});
}
});
};
My Postman post method is in JSON form
{
"username":"tene",
"password":"tene",
"email":"tene#gmail.com",
"contact":1234567890
}
You can try this:
import mongoose from 'mongoose'
const { Schema } = mongoose
const userSchema = new Schema(
{
registrationTable : {
email: { type: String, required: true },
mobileNo: { type: String, required: true }
},
loginTable: {
username: { type: String, required: true },
password: { type: String, required: true }
}
},
{ timestamps: true }
)
const UserModel = mongoose.model('User', userSchema)
It will depend on you if you wanna make registration and login table as an object or array, but this will sure help.
required: true will be for, you need that value necessary, if you dont want some value just remove this.

Update user profile is not working when click the update button in Angular

We are using Angular with Node.js Express.We try to update user details from settings page but when click the update button it throws:
Failed to load resource: net::ERR_CONNECTION_RESET
It seems can't send an update through the observable. When I check this URL in Node:
http://localhost:3000/api/chatapp/user/edit-user It says {"message":"No Authorization"} in the browser. Here is the code.
Angular
EditUser(body): Observable<any> {
return this.http.post(`${BASEURL}/user/edit-user`, body);
}
TS
private populateForm() {
const unusedFields = [
'_id',
...
...
];
const userInfo = Object.assign({}, this.user);
unusedFields.forEach((field) => delete userInfo[field]);
this.SettingsForm.setValue(userInfo);
}
private buildSettingsForm() {
this.SettingsForm = this.fb.group({
email: [null, [Validators.required, Validators.email], this.forbiddenEmails],
firstName: [null, [Validators.required, Validators.pattern('[a-zA-Z ]*')]],
jobTitle: [null, [Validators.required]],
lastName: [null, [Validators.required, Validators.pattern('[a-zA-Z ]*')]],
username: [null, [Validators.required, Validators.pattern('(?=.*[a-z])(?=.*[A-Z])(?=.*[0-9])')]]
});
this.SettingsForm.setValidators(this.minimumAge(18));
}
UpdateUser() {
this.usersService.EditUser(this.SettingsForm.value).subscribe(
data => {
console.log(data);
this.router.navigate(['main']);
},
err => console.log(err)
);
}
Also Node.js:
async EditUser(req, res,next) {
User.findById(req.user.id, function (err, user) {
if (!User) {
return res
.status(httpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'User is not found' });
}
const schema = Joi.object().keys({
username: Joi.string()
.min(4)
.max(10)
.required(),
email: Joi.string()
.email()
.required(),
firstName: Joi.string().required(),
lastName: Joi.string().required(),
jobTitle: Joi.string().required(),
});
const { error, value } = Joi.validate(req.body, schema);
if (error && error.details) {
return res.status(HttpStatus.BAD_REQUEST).json({ msg: error.details })
}
const email = Helpers.lowerCase(req.body.email);
const username = Helpers.lowerCase(req.body.username);
const firstName = req.body.firstName;
const lastName = req.body.lastName;
const jobTitle = req.body.jobTitle;
User.email = email;
User.firstName = firstName;
User.lastName = lastName;
User.username = username;
User.jobTitle = jobTitle;
User.update()
});
}
}
Router
router.post('/user/edit-user', AuthHelper.VerifyToken, UserCtrl.EditUser);
MongoDb
const userSchema = mongoose.Schema({
username: { type: String },
email: { type: String },
isVerified: { type: Boolean, default: false },
password: { type: String },
passwordResetToken: String,
passwordResetExpires: Date,
firstName: { type: String },
lastName: { type: String },
jobTitle: { type: String },
...
...
module.exports = mongoose.model('User', userSchema);
I think something is wrong in both Node.js controller and in Angular function. What is wrong? How can we fix this error?
did you send the token with the request ?!
you've forget to construct the schema
const userSchema = new mongoose.Schema({
username: { type: String },
email: { type: String },
...
)}
to catch the error you might pass a callback as an argument to save function.
user.save(function (err, updatedUser) {
if (err) {
/* Handle the error */
};
});
you might use set user.set({ [key]: value }); instead of direct access by dot notation e.g user.firstname
in your situation it will be like
user.set({
email: email,
firstName: firstName,
lastName: lastName,
username: username,
jobTitle: jobTitle
})
your final code will be
async EditUser(req, res, next) {
User.findById(req.user.id, function (err, user) {
if (!user) {
return res
.status(httpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'User is not found' });
}
const schema = Joi.object().keys({
username: Joi.string()
.min(4)
.max(10)
.required(),
email: Joi.string()
.email()
.required(),
firstName: Joi.string().required(),
lastName: Joi.string().required(),
jobTitle: Joi.string().required(),
});
const { error, value } = Joi.validate(req.body, schema);
if (error && error.details) {
return res.status(HttpStatus.BAD_REQUEST).json({ msg: error.details })
}
const email = Helpers.lowerCase(req.body.email);
const username = Helpers.lowerCase(req.body.username);
const firstName = req.body.firstName;
const lastName = req.body.lastName;
const jobTitle = req.body.jobTitle;
user.set({
email: email,
firstName: firstName,
lastName: lastName,
username: username,
jobTitle: jobTitle
});
user.save(function (error, updatedUser) {
if (error) {
/* Handle it */
}
})
});
}
you can read more about in mongoose documents for more details
Update mongoose document
as note, in populateForm method you can filter the object upon the unusedFields array without use delete keyword

How to update user details according to this model and controller in Node.js express

I am trying to update user data in the settings page. Where he/she can change all details like name, last name, birthday and so on. Here is the auth controller:
module.exports = {
async CreateUser(req, res) {
const schema = Joi.object().keys({
username: Joi.string()
.min(4)
.max(10)
.required(),
email: Joi.string()
.email()
.required(),
firstName: Joi.string()
.required(),
lastName: Joi.string()
.required(),
position: Joi.string()
.required(),
password: Joi.string()
.min(5)
.required(),
});
const { error, value } = Joi.validate(req.body, schema);
if (error && error.details) {
return res.status(HttpStatus.BAD_REQUEST).json({ msg: error.details })
}
const userEmail = await User.findOne({
email: Helpers.lowerCase(req.body.email)
});
if (userEmail) {
return res
.status(HttpStatus.CONFLICT)
.json({ message: 'Email already exist' });
}
const userName = await User.findOne({
username: Helpers.firstUpper(req.body.username)
});
if (userName) {
return res
.status(HttpStatus.CONFLICT)
.json({ message: 'Username already exist' });
}
return bcrypt.hash(value.password, 10, (err, hash) => {
if (err) {
return res
.status(HttpStatus.BAD_REQUEST)
.json({ message: 'Error hashing password' });
}
const age = moment().diff(moment([value.byear, value.bmonth - 1, value.bday]), 'years');
const body = {
username: Helpers.firstUpper(value.username),
email: Helpers.lowerCase(value.email),
firstName: value.firstName,
lastName: value.lastName,
position: value.position,
password: hash,
};
User.create(body)
.then(user => {
const token = jwt.sign({ data: user }, dbConfig.secret, {
expiresIn: '5h'
});
res.cookie('auth', token);
res
.status(HttpStatus.CREATED)
.json({ message: 'User created successfully', user, token });
})
.catch(err => {
res
.status(HttpStatus.INTERNAL_SERVER_ERROR)
.json({ message: 'Error occured' });
});
});
},
User model
const userSchema = mongoose.Schema({
username: { type: String },
email: { type: String },
isVerified: { type: Boolean, default: false },
firstName: { type: String },
lastName: { type: String },
position: { type: String },
password: { type: String },
I guess I shoud have a route like this:
router.post('/user/settings', AuthHelper.VerifyToken, user.editUser);
How should it look like editUser controller according to above CreateUser function? I am using Angular in the front-end. But I think it doesn't matter. I assume 90 percent should be the same as CreateUser but what exactly should be changed so the user can update his/her details in settings form and change data in the model?
So you want to update some of user's fields (such as firstName, lastName and etc.), not replacing the whole information. Then you might want to get the current user's data first and then update only those allowed fields.
Please find the sample code below.
/**
* User router
*/
router.put('/user/:userId', AuthHelper.VerifyToken, user.editUser);
// This function will be triggered when Express finds matching route parameter
router.param('userId', function (req, res, next, id) {
User.findOne(id, function (err, user) {
if (err) {
next(err);
} else if (user) {
// When it finds user information, bind that to request object, which will be used in the other middlewares.
req.user = user;
next();
} else {
next(new Error('failed to load user'));
}
});
});
/**
* User controller
*/
exports.editUser = (req, res, next) => {
let { user } = req;
// You pick only allowed fields from submitted body
const allowedFields = { firstName: req.body.firstName, lastName: req.body.lastName, birthday: req.body.birthday };
// Override the current user data with new one
user = Object.assign(user, allowedFields);
user.save((err, savedUser) => {
if (err) {
return next(err);
}
res.json(savedUser.toJSON());
});
};

Unable to reference from token schema token mongodb express passport

i need help with this problem been dealing it for days.
i am trying to make a verification email route by using passport to hash passwords while issuing a verification token to the user.
here is my code for index.js in controllers folder
const User = require("../models/user");
const Token = require("../models/token")
const crypto = require("crypto");
const nodemailer = require("nodemailer");
var smtpTransport = nodemailer.createTransport({
service: 'Gmail',
auth: {
user: process.env.GMAILUSER,
pass: process.env.GMAILPW
}
});
module.exports = {
async postRegister(req, res, next) {
var user = new User({
name: req.body.name,
email: req.body.email,
isVerified: false,
username: req.body.username
});
await User.register(user, req.body.password);
res.redirect('/');
var token = new Token({ _userId: user._id, token: crypto.randomBytes(16).toString('hex') });
token.save(function (err) {
if (err) { return res.status(500).send({ msg: err.message
});
}
var mailOptions = {
to: user.email,
from: 'xxxt#xxx.com',
subject: 'xxxxx verify email',
text:'You are receiving this because you need to verify your email for your account.\n\n' +
'Please click on the following link, or paste this into your browser to complete the process:\n\n' +
'http://' + req.headers.host + '/confirmation/' + token.token + '\n\n' +
'If you did not request this, please ignore this email.\n'
};
smtpTransport.sendMail(mailOptions, function(err) {
if (err) { return res.status(500).send({ msg: err.message }); }
res.status(200).send('A verification email has been sent to ' + user.email + '.');
});
})
},
confirmationPost(req,res, next) {
Token.findOne({ token: req.params.token }, function (err, token) {
if (!token)
{console.log("sss")
} else {
User.findOne({ _id: token._userId, email: req.body.email }, function (err, user) {
if (!user) return console.log(user)
if (user.isVerified) return res.status(400).send({ type: 'already-verified', msg: 'This user has already been verified.' });
user.isVerified = true;
user.save(function (err) {
if (err) { return res.status(500).send({ msg: err.message }); }
res.status(200).send("The account has been verified. Please log in.");
})
});
};
})
}
}
This is my Token Schema
const mongoose = require('mongoose');
const passportLocalMongoose = require('passport-local-mongoose');
const Schema = mongoose.Schema;
const tokenSchema = new mongoose.Schema({
_userId: {
type: Schema.Types.ObjectId,
ref: 'User' },
token: {
type: String,
required: true },
createdAt: {
type: Date, required: true,
default: Date.now, expires: 43200 }
});
tokenSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('Token', tokenSchema);
lastly my user schema
const mongoose = require('mongoose');
const passportLocalMongoose = require('passport-local-mongoose');
const Schema = mongoose.Schema;
const UserSchema = new Schema({
username: String,
name: String,
email: { type: String, unique: true },
image: String,
isVerified: { type: Boolean, default: false },
password: String,
passwordResetToken: String,
passwordResetExpires: Date,
posts: [
{
type: Schema.Types.ObjectId,
ref: 'Post'
}
]
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model('User', UserSchema);
everything works fine until the part where the email verification was sent to my email and when i clicked on the link. It gives an error, i tried to console.log
and found that this line from controllers folder index.js
confirmationPost(req,res, next) {
Token.findOne({ token: req.params.token }, function (err, token) {
if (!token)
{console.log("err")
} else {
User.findOne({ _id: token._userId, email: req.body.email }, function (err, user) {
gives me back null.
how do i link that current line to get the token from the registered user?
i've used postman to send a get request to the confirmation route while giving it back the same token and it works.

[Mongoose]How can I use the same model twice with two different schemas within app.js

I am trying to access the same database/model for a sign-up and sign-in function but everytime I try to run my node app I get this error message "cannot overwrite 'user' model once compiled" here's my code:
//sign-up schema
var Schema = new mongoose.Schema({
_id: String,
name: String,
username: String,
password: String,
age: Number
});
var user = mongoose.model('users', Schema);
//sign-up login
app.post('/new', function(req, res) {
new user({
_id: req.body.email,
name: req.body.name,
username: req.body.username,
password: req.body.password,
age: req.body.age
}).save(function(err, doc){
if(err) res.json(err);
else res.send('Successfully Signed up');
});
});
//login schema
var Schema = mongoose.Schema;
var UserDetail = new Schema({
username: String,
password: String
}, {
collection: 'users'
});
var UserDetails = mongoose.model('users', UserDetail);
//login logic
passport.use(new LocalStrategy(function(username, password, done) {
process.nextTick(function() {
UserDetails.findOne({
'username': username,
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false);
}
if (user.password != password) {
return done(null, false);
}
return done(null, user);
});
});
}));
You can still use the same schema to lookup.
Schema
var Schema = new mongoose.Schema({
_id: String,
name: String,
username: String,
password: String,
age: Number
});
var user = mongoose.model('users', Schema);
Registration
app.post('/new', function(req, res) {
new user({
_id: req.body.email,
name: req.body.name,
username: req.body.username,
password: req.body.password,
age: req.body.age
}).save(function(err, doc) {
if (err) res.json(err);
else res.send('Successfully Signed up');
});
});
Login
passport.use(new LocalStrategy(function(username, password, done) {
process.nextTick(function() {
user.findOne({
'username': username
}, function(err, user) {
if (err) {
return done(err);
}
if (!user) {
return done(null, false);
}
if (user.password !== password) {
return done(null, false);
}
return done(null, user);
});
});
}));
If you don't want to return the password in the response, just add
delete user.password;
before the callback.

Resources