I have this signup method to save a user.
exports.signup = function(req, res) {
// Initialize the variables
var user = new User(req.body);
var message = null;
user.provider = 'local';
// save the user
user.save(function(err) {
if (err) {
console.log(err);
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.status(400).send(err);
} else {
res.json(user);
}
});
}
});
};
Her is my Schema.
var UserSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
index: true,
match: [/.+\#.+\..+/, "Please fill valid e-mail address"]
},
username: {
type: String,
trim: true,
unique: "Username should be unique",
required: true
},
password: {
type: String,
validate: [
function (password) {
return password && password.length > 6;
},
"Password should be greater than six letters"
]
},
salt: {
type: String
},
provider: {
type: String,
required: "Provider is required"
},
providerId: String,
providerData: {},
created: {
type: Date,
default: Date.now()
}
});
When I make a post request in an empty collection, the first is saved, but after that i am getting this error.
MongoError: Projection cannot have a mix of inclusion and exclusion.
at Function.MongoError.create (/home/sinnedde/WebstormProjects/mean-chatapp/node_modules/mongodb-core/lib/error.js:31:11)
at queryCallback (/home/sinnedde/WebstormProjects/mean-chatapp/node_modules/mongodb-core/lib/cursor.js:212:36)
at /home/sinnedde/WebstormProjects/mean-chatapp/node_modules/mongodb-core/lib/connection/pool.js:455:18
at _combinedTickCallback (internal/process/next_tick.js:67:7)
at process._tickCallback (internal/process/next_tick.js:98:9)
POST /signup 500 1445.231 ms - 615
Please help.
First req.body
{
"name":"John",
"email": "johndoe#gmail.com",
"username": "john123",
"password": "password"
}
Second req.body
{
"name":"Jane",
"email": "janedoe#gmail.com",
"username": "jane123",
"password": "password"
}
Related
I'm just starting out whit node and mongoose and I'm trying to create a user, then create a stripe customer with a stripe generated id and save the response in a user Map field stripeDetails.
Here is the schema:
const mongoose = require('mongoose');
const userSchema = new mongoose.Schema({
name: { type: String, required: true },
email: { type: String, required: true },
photoUrl: { type: String, required: true },
phoneNumber: { type: String, required: false },
address: { type: String, required: false },
zipCode: { type: String, required: false },
city: { type: String, required: true },
region: { type: String, required: true },
country: { type: String, required: true },
isVerified: { type: Boolean, required: false, default: false },
lastLogin: { type: Number, required: false, default: Date.now },
stripeDetails: {type: Map, required: false}
},
{ timestamps: true });
module.exports = mongoose.model('User', userSchema, 'Users');
I tried setting the stripeDetails field like
.then(stripeCustomer => {
console.log('Stripe.customer.create', stripeCustomer);
result.set('stripeDetails', stripeCustomer);
result.save();
...
but is not working.. I settle to update the record's field but is a bit messy..
exports.createUser = async (req, res) => {
const user = req.body;
console.log('User is :', user);
/// Creat use in DB
User.create(
user,
function (err, result) {
if (err) {
console.log('Mongoose createUser error: ', err);
res.statut(503).send({ error: "Internal error" });
return;
}
console.log('Mongoose createUser: ', result);
res.status(200).send({
message: "User created successfully!",
data: result
});
/// Create stripe customer
stripe.customers.create({
"address": {
"city": user.city,
"state": user.region,
"country": user.country,
"postal_code": user.zipCode
},
"balance": 0,
"created": Date.now,
"email": user.email,
"name": user.name,
"phone": user.phoneNumber,
"preferred_locales": [],
"shipping": null,
"tax_exempt": "none"
})
.then(stripeCustomer => {
console.log('Stripe.customer.create', stripeCustomer);
// save stripe details to db
//not working..
// result.set('stripeDetails', stripeCustomer);
// result.save();
// working
User.findByIdAndUpdate(
result.id,
{stripeDetails: stripeCustomer},
{ new: true },
function(err, result) {
if (err) {
console.log('Stripe customer not updated to db: ', err);
}
if (result != null){
console.log('Stripe customer updated to DB', result);
} else {
console.log('Stripe customer to update not found in db ');
}
}
);
})
.catch(error => {
console.log('Stripe.customer.create error: ', error);
});
}
);
};
also I can't access the stripeDetails.id value for when I need to delete the user..
exports.deleteUserById = async (req, res) => {
const id = req.params.id;
User.findByIdAndDelete(
id,
function (err, result) {
if (err) {
console.log('Mongoose deleteUserById error: ', err);
res.statur(505).send({ errro: "Internal error" });
}
if (result != null) {
console.log('Mongoose deleteUserById: ', result);
res.status(200).send({
message: "User found!",
data: result
});
console.log('stripe id is: ', result.stripeDetails['id']);
stripe.customers.del(`${result.stripeDetails['id']}`)
.then(stripeCustomer => {
console.log('Stripe.customer.delete', stripeCustomer);
})
.catch(error => {
console.log('Stripe.customer.delete error: ', error);
});
} else {
console.log("Mongoose deleteUserById: user not found");
res.status(404).send({ message: "User not found" });
}
});
}
I could use the mongoose _id as the stripe id but I rather use their own separate id generators and keep the ids separate, and get used to work with maps in mongoose. Can you see what I'm doing wrong with in writing and reading stripeDetails?
Try to change stripeDetails in Schema to be of type Object:
stripeDetails: {type: Object, required: false}
Now you can do this:
.then(stripeCustomer => {
result.stripeDetails.details = stripeCustomer;
User.findByIdAndUpdate(result.id, result).then((result)=>{
console.log('User updated.');
})
})
Note that when you are using Map as a type, you should access the value of a key with .get(). So try to access stripe_id like this:
let stripe_id = result.stripeDetails.get("id");
stripe.customers.del(stripe_id)
.then(stripeCustomer => {
console.log('Stripe.customer.delete', stripeCustomer);
})
.catch(error => {
console.log('Stripe.customer.delete error: ', error);
});
Check it here.
This is my Profile Schema:
const mongoose = require('mongoose');
const ProfileSchema = new mongoose.Schema({
user: {
// Special field type because
// it will be associated to different user
type: mongoose.Schema.Types.ObjectId,
ref: 'user',
},
company: {
type: String,
},
website: {
type: String,
},
location: {
type: String,
},
status: {
type: String,
required: true,
},
skills: {
type: [String],
required: true,
},
bio: {
type: String,
},
githubusername: {
type: String,
},
experience: [
{
title: {
type: String,
required: true,
},
company: {
type: String,
required: true,
},
location: {
type: String,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
education: [
{
school: {
type: String,
required: true,
},
degree: {
type: String,
required: true,
},
fieldofstudy: {
type: String,
required: true,
},
from: {
type: Date,
required: true,
},
to: {
type: Date,
},
current: {
type: Boolean,
default: false,
},
description: {
type: String,
},
},
],
social: {
youtube: {
type: String,
},
twitter: {
type: String,
},
facebook: {
type: String,
},
linkedin: {
type: String,
},
instagram: {
type: String,
},
},
date: {
type: Date,
default: Date.now,
},
});
module.exports = Profile = mongoose.model('profile', ProfileSchema);
This is my view api. It doesn't work. it only return Cast to ObjectId failed for value { 'experience._id': '5edcb6933c0bb75b3c90a263' } at path _id for model profile
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findById({
'experience._id': req.params.viewexp_id,
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
How can I fix this? I tried looking at the stackoverflow of the same errors. still it doesn't seem to work.
and this is what I am trying to hit
The problem is that you have to convert your string _id to mongoose object id using this function mongoose.Types.ObjectId and my suggestion is to use findOne function instead of findById,
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
let id = mongoose.Types.ObjectId(req.params.viewexp_id);
const exp = await Profile.findOne(
{ "experience._id": req.params.viewexp_id },
// This will show your sub record only and exclude parent _id
{ "experience.$": 1, "_id": 0 }
);
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
var mongoose = require('mongoose');
router.get('/experience/viewing/:viewexp_id', auth, async (req, res) => {
try {
const exp = await Profile.findOne({
'experience._id': mongoose.Types.ObjectId(req.params.viewexp_id),
});
if (!exp) {
return res.status(404).json({ msg: 'Experience not found' });
}
res.json(exp);
} catch (err) {
console.error(err.message);
res.status(500).send(err.message);
}
});
You are saving object id . but your param id is string. convert it in ObjectId. Please check my solution.
router.post(
"/",
[
auth,
[
check("status", "status is required").not().isEmpty(),
check("skills", "skills is required").not().isEmpty(),
],
],
async (req, res) => {
const errors = validationResult(req);
if (!errors.isEmpty()) {
return res.status(400).json({ errors: errors.array() });
}
const {
company,
website,
location,
bio,
status,
githubuername,
skills,
youtube,
facebook,
twitter,
instagram,
linkedin,
} = req.body;
const profileFileds = {};
profileFileds.user = req.user.id;
if (company) profileFileds.company = company;
if (website) profileFileds.website = website;
if (location) profileFileds.location = location;
if (bio) profileFileds.bio = bio;
if (status) profileFileds.status = status;
if (githubuername) profileFileds.githubuername = githubuername;
if (skills) {
profileFileds.skills = skills.split(",").map((skill) => skill.trim());
}
//Build profile object
profileFileds.social = {};
if (youtube) profileFileds.social.youtube = youtube;
if (twitter) profileFileds.social.twitter = twitter;
if (facebook) profileFileds.social.facebook = facebook;
if (linkedin) profileFileds.social.linkedin = linkedin;
if (instagram) profileFileds.social.instagram = instagram;
try {
let profile = await Profile.findOne({ user: req.user.id });
if (profile) {
//update
profile = await Profile.findOneAndUpdate(
{ user: req.user.id },
{ $set: profileFileds },
{ new: true }
);
return res.json(profile);
}
//Create profile
profile = new Profile(profileFileds);
await profile.save();
res.json(profile);
} catch (err) {
console.error(err.message);
res.status(500).send("server Error");
}
}
);
Hey I am new to Sails I am having an issue while submitting form when in my model username and email is set to unique in my input field if I put username and email which already exist in database I am just getting error for unique username not for email if I fix username then I will get error for email but I want both errors to be shown at one go
Here is the model code:
username: {
type: "string",
required: true,
unique: true,
},
name: {
type: "string",
required: true,
},
title: {
type: "string",
},
email: {
type: "string",
isEmail: true,
required: true,
unique: true,
},
password: {
type: "string",
minLength: 6
},
This is controller code
var result=await Users.create(req.allParams(),function(err,data){
if(err)
{
console.log(err);
}
else
{
console.log(data)
}
});```
your controller should be like
module.exports = {
create: async (req, res) => {
//get your params and body using req.params or req.body
try {
//controller's logic here
let user = await Users.create(data).fetch();
res.status(200)
.send({ user })
} catch (error) {
//catch all errors here
res.status(500)
.send({ err:error })
}
},
when I am trying to login with the defined url , at a point of bcrypting compare password it fails.
login route:-
router.post('/:compId/administration/login' , (req, res, next) => {
Admin.find({'admins.email': req.body.email},{ companyID: req.params.compId })
.exec()
.then(admin => {
if(admin.admins.length < 1) {
return res.status(401).json({
message: "Auth failed. admin not found."
})
}
bcryptt.compare(req.body.password, admin.admins.password, (err, result) =>{
if (err) {
return res.json({
message: "Auth failed. Check email and password"
});
}
if (result && admin.admins.verified === "true"){
const adminEmaill = "xyz#info.com";
const role2 = admin.admins.email===adminEmaill? "superadmin" : "admin";
const token = jwt.sign(
{
email: admin.admins.email,
phoneNo: admin.admins.phoneNumber,
role2,
comID: admin.admins.companyID
},
process.env.JWT_KEY,
{
expiresIn : "1h"
});
return res.status(200).json({
message: "Auth Successful",
token : token
});
}
else{
console.log("admin is not verified");
return res.json({
message: "Admin is not verified"
});
}
});
})
.catch(err =>{
if (err.code == 500)
res.status(500).send(["Something went wrong in login"]);
else
return next(err);
});
});
On response it is not validating my user and throwing message: "Auth failed. Check email and password" in response.
I think I have some error in defining my password path.
My model:-
var adminSchema = new mongoose.Schema({
companyName : {
type: String,
required: "Company name can't be empty.",
required: false
},
companyID: {
type: String,
},
admins: {
email : {
type: String,
required: "Email can't be empty.",
unique: true
},
password: {
type: String,
required: "Password name can't be empty."
},
firstName : {
type: String,
required: "First name can't be empty."
},
lastName : {
type: String,
required: "Last name can't be empty."
},
phoneNumber : {
type: String,
required: "Reqired for further contact. Can't be empty."
},
verified: String,
role: String,
emailResetTokenn: String,
saltSecret: String,
users:[ userSchema ]
}
});
adminSchema.pre('save', function (next){
bcryptt.genSalt(10, (err, salt) => {
bcryptt.hash(this.admins.password, salt, (err, hash) => {
this.admins.password = hash ;
this.admins.saltSecret = salt;
next();
});
});
});
I am not getting why I am getting this ? Is defining of my password is correct ? How can I do this when I have password in nested object ?
You need to call findOne method on mongoose model.
Admin.findOne({'admins.email': req.body.email, companyID: req.params.compId}) ...
The result of find method is an array
Here I am trying to verify mobile number in user module. I have created token and I sent to user but whenever user is trying to verify using that particular token 'Password' and 'salt' automatically got changed. How to avoid this? Some one help me out .. here I want to update only
user.Mobileverification = 'verfied';
user.Mobileverificationcode = undefined;
user.mobileVerificationExpires = undefined;
Above three variables got changed but I don't know why password and salt has changed?
I have given my routes below:
app.route('/auth/mobilereset/:token').get(users.mobileresetResetToken);
app.route('/auth/mobilereset/:token').post(users.mobilereset);
controller:
exports.mobileresetResetToken = function(req, res) {
User.findOne({
Mobileverificationcode :req.params.token,
mobileVerificationExpires: {
$gt: Date.now()
}
// resetPasswordToken: req.params.token,
// resetPasswordExpires: {
// $gt: Date.now()
// }
}, function(err, user) {
if (!user) {
res.send({
message: 'Invalid token'
});
} else {
console.log('working fine');
}
});
};
exports.mobilereset = function(req, res, next) {
async.waterfall([
function(done) {
User.findOne({
Mobileverificationcode: req.params.token,
mobileVerificationExpires: {
$gt: Date.now()
}
}, function(err, user) {
if (!err && user) {
user.Mobileverification = 'verfied';
user.Mobileverificationcode = undefined;
user.mobileVerificationExpires = undefined;
user.save(function(err) {
if (err) {
return res.status(400).send({
message: errorHandler.getErrorMessage(err)
});
} else {
req.login(user, function(err) {
if (err) {
res.status(400).send(err);
} else {
// Return authenticated user
res.json(user);
done(err, user);
}
});
}
});
} else {
return res.status(400).send({
message: 'reset token is invalid or has expired.'
});
}
});
},
], function(err) {
if (err) return next(err);
});
};
model:
var UserSchema = new Schema({
username: {
type: String,
unique: 'testing error message',
required: 'Please fill in a username',
trim: true
},
password: {
type: String,
default: '',
// validate: [validateLocalStrategyPassword, 'Password should be longer']
},
email: {
type: String,
trim: true,
default: '',
// validate: [validateLocalStrategyProperty, 'Please fill in your email'],
// match: [/.+\#.+\..+/, 'Please fill a valid email address']
},
Mobilenumber: {
type: String,
default: ''
},
roles: {
type: [{
type: String,
enum: ['user', 'admin']
}],
default: ['user']
},
salt: {
type: String
},
provider: {
type: String,
required: 'Provider is required'
},
providerData: {},
additionalProvidersData: {},
updated: {
type: Date
},
created: {
type: Date,
default: Date.now
},
/* For reset password */
Mobileverificationcode: {
type: String,
},
mobileVerificationExpires: {
type: Date
},
Mobileverification: {
type: String,
trim: true,
default: 'Not Verified',
},
resetPasswordToken: {
type: String
},
resetPasswordExpires: {
type: Date
}
});
I don't know if you removed this or not but in MEAN.js user model, you have to be careful with the following code block:
/**
* Hook a pre save method to hash the password
*/
UserSchema.pre('save', function (next) {
if (this.password && this.isModified('password')) {
this.salt = crypto.randomBytes(16).toString('base64');
this.password = this.hashPassword(this.password);
}
next();
});
Which will be called right before you save the user data. That's probably why password and salt keep changing... You are calling user.save in mobile.reset() and that code block above is still present somewhere.
Update:
A possible way of doing it is:
/**
* Hook a pre save method to hash the password
*/
UserSchema.pre('save', function (next) {
if(!this.isModified('Mobileverification') && !this.isModified('Mobileverificationcode') && !this.isModified('mobileVerificationExpires')) {
if (this.password && this.isModified('password')) {
this.salt = crypto.randomBytes(16).toString('base64');
this.password = this.hashPassword(this.password);
}
}
next();
});
However it might need a few adjustments, such as improving this pre-save hook according to your needs and testing password changing and mobile verification to see if nothing is broken.