Already have the following petition of my client, need than on one request to the database extract a document joining to other documents in one, I decided, to use function populate of MongoDB with moongose, but already im stuck in a following problem:
issue
models
models/User.js:
'use strict';
var mongoose, Schema, UserSchema, schemaOptions, bcrypt;
mongoose = require('mongoose');
bcrypt = require('bcrypt');
Schema = mongoose.Schema;
schemaOptions = {
toObject: {
virtuals: true
}
,toJSON: {
virtuals: true
},
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
new: true,
runValidators: true
};
UserSchema = Schema({
_id:{
type:Number,
unique: true,
index: true
},
provider:String,
id:{
type: String
},
displayName:{
type: String,
required: [true, 'Scribe the Full name']
},
name: {
familyName:{type: String,required: [true, 'Scribe the last name']},
givenName:{type: String,required: [true, 'Scribe the first name']},
middleName:{type: String,required: [true, 'Scribe the middle name']}
},
emails:[{
value:{
type: String,
unique: true,
lowercase: true,
index: true,
validate: {
validator: function(v) {
return /^[a-zA-Z0-9\._-]+#[a-zA-Z0-9-]{2,}[.][a-zA-Z]{2,4}$/.test(v);
},
message: '{VALUE} is not a valid email!'}
},
type:{
type: String,
lowercase: true
}
}],
email:{
type: String,
unique: true,
lowercase: true,
index: true,
validate: {
validator: function(v) {
return /^[a-zA-Z0-9\._-]+#[a-zA-Z0-9-]{2,}[.][a-zA-Z]{2,4}$/.test(v);
},
message: '{VALUE} is not a valid email for autenticate!'
},
required: [true, 'Scribe a Email']
},
password: {
type: String,
required: [true, 'Scribe a password']
},
photos:[{
type: String
}],
alias: {
type: String,
required: [true, 'Scribe the alias'],
unique: true
},
birthday:{
type: Date,
required: [true, 'Select a birthday']
},
idiom: {
type: String,
required: [true, 'Select a idiom']
},
country: {
type: Number,
required: [true, 'Select a valid country'],
min:1,
max:231
},
rolId:{
type: { type: mongoose.Schema.ObjectId, ref: 'Rol' }
},
deletedAt: { type: Date, default: null }
},schemaOptions);
// Execute before each user.save() call
UserSchema.pre('save', function(next) {
var user = this;
// Break out if the password hasn't changed
if (!user.isModified('password')) return callback();
// Password changed so we need to hash it
bcrypt.genSalt(10, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});
//metodo para autenticar la clave recibida
UserSchema.methods.verifyPassword = function(password, next) {
bcrypt.compare(password, this.password, function(error, isMatch) {
if (error) {
next(error);
};
next(null, isMatch);
});
};
module.exports = mongoose.model('User',UserSchema);
2. models/Rol.js:
'use strict';
var mongoose, Schema, RolSchema, schemaOptions;
mongoose = require('mongoose');
Schema = mongoose.Schema;
schemaOptions = {
toObject: {
virtuals: true
}
,toJSON: {
virtuals: true
},
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
new: true,
runValidators: true
};
RolSchema = Schema({
_id:{
type:Number,
unique: true,
index: true
},
name:{
type: String,
unique: true,
uppercase: true,
required: [true, 'Scribe a Rol']
},
deleted_at: { type: Date, default: null }
},schemaOptions);
module.exports = mongoose.model('Rol',RolSchema);
controllers/UserController.js:
'use strict';
var validator = require('validator');
var User = require('../models/User');
var Rol = require('../models/Rol');
function loggin(req, res){ console.log(req.user); return
res.status(200).send({user:req.user}); }
function createUser(req, res) {
var params , user, full_name, firstName, secondName, arrayOfName,tempUser;
params = req.body;
full_name = params.name+" "+params.last_name;
arrayOfName = params.name.split(" ");
firstName = arrayOfName[0];
secondName = arrayOfName1;
User.find({},function (error, users) {
if(error){
return res.status(500).send({message: 'Error al devolver los marcadores del servidor'});
}
Rol.findById(params.rol,function (error, rol) {
if(error){
return res.status(500).send({message: 'Error al devolver los roles del servidor'});
}
if(!rol){
return res.status(404).send({message: 'No hay rol creado! con el id: '+params.rol+', comuniquese con el
administrador'});
}
if(users.length === 0){
user = new User();
user._id = 1;
user.displayName = full_name;
user.name.familyName = params.last_name;
user.name.givenName = firstName;
user.name.middleName = secondName;
user.email = params.email;
user.password = params.password;
user.alias = params.username;
user.birthday = params.age;
user.idiom = params.idiom;
user.country = params.ubication;
user.rolId = rol._id;
user.deleted_at = null;
user.save(function (error, userStored){
console.log(error);
if(error){
return res.status(500).send({message:"Error al guardar el usuario por primera ves"});
}
return res.status(200).send({user:userStored});
});
}else{
tempUser = User.findOne({ 'email': params.email }, function (error, userOnDataBase) {
if(error){
return res.status(500).send({message: 'Error al devolver los marcadores del servidor'});
}
if(!userOnDataBase){
user = new User({
"_id":users[0]._id+1,
"displayName":full_name,
"name.familyName":params.last_name,
"name.givenName":firstName,
"name.middleName":secondName,
"email":params.email,
"password":params.password,
"alias":params.username,
"birthday":params.age,
"idiom":params.idiom,
"country":params.ubication,
"rolId":rol._id,
"deleted_at":null
}).save(function (error, userStored){
if(error){
return res.status(500).send({message:"Error al guardar el usuario"});
}
return res.status(200).send({user:userStored});
});
}else{
if (userOnDataBase.email === users[0].email){
return res.status(409).send({message: 'Correo utilizado actualmente existe!'});
}
}
});
}
});
}).limit(1).sort('-_id'); }
function getUser(req, res) {
var id = req.params.id;
res.status(200).send({user_id:id}); }
function updateUser(req, res) {
var id = req.params.id;
res.status(200).send({user_id:id}); }
function deleteUser(req, res) {
var id = req.params.id;
res.status(200).send({user_id:id}); }
module.exports = {
loggin, createUser, getUser, updateUser, deleteUser };
Already the collection rols have documents.
Related
I try to make one method for signup to two types of user ' buyer and seller ' .
When I save seller , I should get all information about their ' storeinfo ' , see my updated code below .
I used populate() but I get an empty array .
Is my idea wrong ?
code for signup
exports.signupUser = async (req, res, next) => {
role = req.body.role
const user = new User(req.body)
const seller = new Seller(req.body)
try{
if(role=='seller'){
await seller.save()
await user.save()
const token = await user.generateToken()
res.status(200).send({
error: null,
apiStatus:true,
data: {user,seller ,token}
})
}
await user.save()
const token = await user.generateToken()
res.status(200).send({
error: null,
apiStatus:true,
data: {user, token}
})
}
catch(error){
res.status(400).send({
error: error.message,
apiStatus:false,
data: 'unauthorized user'
})
}
}
code for login
exports.login = async (req, res) => {
try{
const user = await User.findUserByCredentials(req.body.email, req.body.password)
const token = await user.generateToken()
console.log(user.role)
if(user.role=='seller'){
console.log(user._id)
await User.findOne({_id: user._id}).populate('storeinfo').exec(function(err, user) {
if (err) {console.log(err)}
res.status(200).send({
error: null,
apiStatus:true,
user,token
})})
}
res.status(200).send({
error: null,
apiStatus:true,
data: {user, token}
})
}
catch(error){
res.status(400).send({
error: error.message,
apiStatus:false,
data: 'Something went wrong'
})
}
}
schema user
const userSchema = new Schema({
first_name: { type: String,required:true},
last_name: { type: String,required:true},
email: { type: String, unique: true, required: true, trim: true,lowercase: true ,validate(value) {
if (!validator.isEmail(value)) throw new Error("Invalid Email"); },
},
password: { type: String,minlength: 6,required: true, trim: true, match: /^(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[^a-zA-Z0-9]).{8,}$/},
role: { type: String, enum: ['admin','seller', 'user'], default: 'user' ,required: true},
mobileNumber: { type: String,default:'',trim: true,
validate(value) {
if (!validator.isMobilePhone(value, ["ar-EG"]))
throw new Error("invalid phone number");
},
},
address: {
type: String,
required: true,
trim: true
},
storeinfo:{
type: mongoose.Schema.Types.ObjectId,
ref:'Seller',
},
tokens: [{
token: {
type: String,
required: true
}
}]
}, {
timestamps: true
})
userSchema.methods.generateToken = async function(){
const user = this
const token = jwt.sign({_id: user._id.toString() , role:user.role}, process.env.JWTKEY)
user.tokens = user.tokens.concat({token})
await user.save()
return token
}
// login
userSchema.statics.findUserByCredentials = async(email, password)=>{
const user = await User.findOne({email})
if(!user) throw new Error('invalid email')
const matched = await bcrypt.compare(password, user.password)
if(!matched) throw new Error('invalid password')
return user
}
const User = mongoose.model('User', userSchema)
module.exports = User
seller schema
const SellerSchema = new Schema(
{
storeName: {
required: true,
type: String,
},
category: {
type: String,
required: true
},
image: {
type: String,
// required: true,
},
addresses:[
{
street: String,
locality: String,
aptName: String,
lat: Number,
lng: Number,
}
],
numberOfBranches: Number,
_userId:{ type: Schema.Types.ObjectId, ref: 'User'},
items: [{ type: Schema.Types.ObjectId, ref: "Item" }]
},
{ timestamps: true }
);
const Seller = mongoose.model('Seller', SellerSchema)
module.exports = Seller
When I am deleting a user, I also want to delete all the associated blog posts with that user. I have used MongoDB's pre() middleware. when it is fired it only sets the postedBy property to null in the post and then MongoDB compass the postedBy is still there along with userId
here is User schema.
const crypto = require("crypto");
const mongoose = require("mongoose");
const Post = require("./post");
const userSchema = mongoose.Schema(
{
username: {
type: String,
trim: true,
required: true,
unique: true,
index: true,
lowercase: true,
},
name: {
type: String,
index: true,
required: true,
max: 32,
},
email: {
type: String,
index: true,
required: true,
trim: true,
unique: true,
},
hashed_password: {
type: String,
required: true,
},
role: {
type: Number,
default: 0,
},
profile: {
type: String,
required: true,
},
photo: {
data: Buffer,
contentType: String,
},
salt: String,
resetPassword: {
data: String,
default: "",
},
},
{ timestamp: true }
);
userSchema
.virtual("password")
.set(function (password) {
this._password = password;
this.salt = this.makeSalt();
this.hashed_password = this.encryptPassword(password);
})
.get(function () {
return this._password;
});
userSchema.methods = {
authenticate: function (plainText) {
return this.encryptPassword(plainText) === this.hashed_password;
},
encryptPassword: function (password) {
if (!password) return "";
try {
return crypto
.createHmac("sha1", this.salt)
.update(password)
.digest("hex");
} catch (err) {
return "";
}
},
makeSalt: function () {
return Math.round(new Date().valueOf() * Math.random()) + "";
},
};
userSchema.pre("findByIdAndRemove", function (next) {
Post.deleteMany({ postedBy: this._id }, function (err, result) {
if (err) {
console.log("error");
} else {
console.log(result);
}
});
next();
});
module.exports = mongoose.model("User", userSchema);
here is Post schema
const mongoose = require("mongoose");
const Schema = mongoose.Schema;
const postSchema = new Schema({
postedBy: {
type: Schema.Types.ObjectId,
ref: "User",
},
title: {
type: String,
},
body: {
type: String,
},
name: {
type: String,
},
photo: {
data: Buffer,
contentType: String,
},
updated: Date,
avatar: {
type: String,
},
created: {
type: Date,
default: Date.now,
},
comments: [
{
postedBy: {
type: Schema.Types.ObjectId,
refPath: "onModel",
},
text: String,
created: {
type: Date,
default: Date.now,
},
},
],
likes: [
{
type: Schema.Types.ObjectId,
refPath: "onModel",
},
],
onModel: {
type: String,
enum: ["User", "Imam"],
},
});
module.exports = mongoose.model("Post", postSchema);
this is delete route function
exports.userdelete = (req, res) => {
User.findByIdAndRemove(req.params.id).exec((err, doc) => {
if (err) {
return res.status(400).json({
error: "Something went wrong",
});
}
return res.json({
message: "User deleted",
});
});
};
You Can follow this code
You can use cascade delete in mongoose
User.findOne({...}, function(err, customer) {
Post.remove();
});
I want to create a "users" role in Node.js. I have both "moderator" and "admin" accounts but I want to restrict some pages from the moderator. I have to build a middleware but it restricts both the admin from the protected page.
This is my route:
function checkRole(role) {
return function (req, res, next) {
const user = User.findById(req.user._id);
if (user.roleId === role) {
next();
} else {
req.flash('error_msg', 'Payment Page is Restricted');
res.redirect('back')
}
}
}
And this is my users model:
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var bcrypt = require('bcrypt-nodejs');
var userSchema = new Schema({
name:{
type: String,
required: true
},
email:{
type: String,
required: true
},
gender:{
type: String
},
nickname:{
type: String
},
twitter:{
type: String
},
skype:{
type: String
},
username:{
type: String,
required: true
},
password:{
type: String,
required: true
},
roleId: { type: String, lowercase: true, trim: true, enum: ['admin', 'moderator'] },
resetPasswordToken: String,
resetPasswordExpires: Date
}, {timestamps: true})
userSchema.pre('save', function(next) {
var user = this;
var SALT_FACTOR = 12;
if (!user.isModified('password')) return next();
bcrypt.genSalt(SALT_FACTOR, function(err, salt) {
if (err) return next(err);
bcrypt.hash(user.password, salt, null, function(err, hash) {
if (err) return next(err);
user.password = hash;
next();
});
});
});
userSchema.methods.comparePassword = function(candidatePassword, cb) {
bcrypt.compare(candidatePassword, this.password, function(err, isMatch) {
if (err) return cb(err);
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', userSchema);
I included the checkRole function in the page I want to restrict the moderator from, but the admin is being restricted as well. I don't know where this error is coming from.
already, i want to call a method on my model, for compare the password given with the password encrypted on my database, im used a custom method on my schema, but appear the following error, when tried to execute the controller, i supose than i want to do, only can be used with "new" object, objects than already are on my database cant access to the method, thanks in advance for any help:
issue
models/User.js
'use strict';
var mongoose, Schema, UserSchema, schemaOptions, bcrypt;
mongoose = require('mongoose');
bcrypt = require('bcrypt');
Schema = mongoose.Schema;
schemaOptions = {
toObject: {
virtuals: true
}
,toJSON: {
virtuals: true
},
timestamps: { createdAt: 'created_at', updatedAt: 'updated_at' },
new: true,
runValidators: true
};
UserSchema = Schema({
_id:{
type:Number,
unique: true,
index: true
},
provider:String,
id:{
type: String
},
displayName:{
type: String,
required: [true, 'Scribe the Full name']
},
name: {
familyName:{type: String,required: [true, 'Scribe the last name']},
givenName:{type: String,required: [true, 'Scribe the first name']},
middleName:{type: String,required: [true, 'Scribe the middle name']}
},
emails:[{
value:{
type: String,
unique: true,
lowercase: true,
index: true,
validate: {
validator: function(v) {
return /^[a-zA-Z0-9\._-]+#[a-zA-Z0-9-]{2,}[.][a-zA-Z]{2,4}$/.test(v);
},
message: '{VALUE} is not a valid email!'}
},
type:{
type: String,
lowercase: true
}
}],
email:{
type: String,
unique: true,
lowercase: true,
index: true,
validate: {
validator: function(v) {
return /^[a-zA-Z0-9\._-]+#[a-zA-Z0-9-]{2,}[.][a-zA-Z]{2,4}$/.test(v);
},
message: '{VALUE} is not a valid email for autenticate!'
},
required: [true, 'Scribe a Email']
},
password: {
type: String,
required: [true, 'Scribe a password']
},
photos:[{
type: String
}],
alias: {
type: String,
required: [true, 'Scribe the alias'],
unique: true
},
birthday:{
type: Date,
required: [true, 'Select a birthday']
},
idiom: {
type: String,
required: [true, 'Select a idiom']
},
country: {
type: Number,
required: [true, 'Select a valid country'],
min:1,
max:231
},
rolId:{
type: Number,
required: [true, 'Select a rol'],
default: 1
},
deletedAt: { type: Date, default: null }
},schemaOptions);
// Execute before each user.save() call
UserSchema.pre('save', function(next) {
var user = this;
if(this.isModified('password') || this.isNew){
bcrypt.genSalt(10, function (error, salt){
if(error){
console.log(error);
return next(error);
}
bcrypt.hash(user.password, salt, function (error, hash){
if (error) {
console.log(error);
return next(error);
}
user.password = hash;
console.log("hashing the password!");
next();
});
});
}else{
console.log("the password dont changed!");
return next();
}
});
//metodo para autenticar la clave recibida
UserSchema.methods.verifyPassword = function(password, next) {
bcrypt.compare(password, this.password, function(error, isMatch) {
if (error) {
//return next(error);
next(error);
return false;
};
//return next(null, isMatch);
next(null,isMatch);
return true;
});
};
module.exports = mongoose.model('User',UserSchema);
controllers/UserControllers.js
'use strict';
var validator = require('validator');
var User = require('../models/User');
var Rol = require('../models/Rol');
var config = require('../config/database');
var jwt = require('jwt-simple');
function login(req, res){
var params = req.body;
User.find({email: params.email},function (error, user) {
if (error) {
return res.status(500).send({message: 'Error al devolver los marcadores del servidor'});
};
if (!user) {
return res.status(404).send({message: 'El usuario con el correo designado no se encontro!'});
}else{
User.verifyPassword(params.email, function (error, isMatch){
if(error){
console.log(error);
return false;
}
if (isMatch) {
var token = jwt.encode(user, config.secret);
return res.status(200).send({token:'JWT '+token});
}else{
return res.status(403).send({message: 'La clave no es correcta!'});
}
});
return res.status(200).send({token:user});
}
}).limit(1);
}
.
.
.
module.exports = {
login, createUser, getUser, updateUser, deleteUser
};
I have a problem with mongoose, when i use the method findByIdi receive error :
CastError: Cast to ObjectId failed for value "protected" at path "_id"
My _id is valid tested by mongoose.Types.ObjectId.isValid(_id);
I also tested to convert my string _id to ObjectId: mongoose.Types.ObjectId(_id) same error...
My Model is :
var UserSchema = new Schema({
_id: {type:ObjectIdSchema, default: function () { return new ObjectId()} },
email: { type: String, unique: true, required: true },
pseudonyme: { type: String, unique: true, required: true },
password: { type: String, required: true }})
I use node v6.7.0 and mongoose v4.6.5
Thks in advance for your help,
Full Code :
const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) {
//payload { _id: "58109f58e1bc7e3f28751cdb",email: "antoine.drian#laposte.net",exp: 1477494763,firstName: "antoine",iat: 1477484683,lastName: "drian"}
var isValid = mongoose.Types.ObjectId.isValid(payload._id);
if(!isValid) done(null, false);
var ObjectId = mongoose.Types.ObjectId;
var _id = ObjectId(payload._id);
User.findById( _id , function(err, user) {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
});
models/User.js
var mongoose = require('mongoose');
var Schema = mongoose.Schema;
var ObjectIdSchema = Schema.ObjectId;
var ObjectId = mongoose.Types.ObjectId;
var bcrypt = require('bcrypt');
// set up a mongoose model
var UserSchema = new Schema({
// _id: {type: Schema.Types.ObjectId, auto: true},
email: { type: String, unique: true, required: true },
pseudonyme: { type: String, unique: true, required: true },
password: { type: String, required: true },
profile: {
firstName: { type: String, required: true },
lastName: { type: String, required: true },
birthdate: { type: Date },
gender: { type: String, enum: ['Male', 'Female'] },
}
}, {
timestamps: true
});
UserSchema.pre('save', function(next) {
var user = this;
if (this.isModified('password') || this.isNew) {
bcrypt.genSalt(10, function(err, salt) {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, function(err, hash) {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
} else {
return next();
}
});
UserSchema.methods.comparePassword = function(passw, cb) {
bcrypt.compare(passw, this.password, function(err, isMatch) {
if (err) {
return cb(err);
}
cb(null, isMatch);
});
};
module.exports = mongoose.model('User', UserSchema);
I found the solution it was just a route conflict between two routes with ExpressJS.
There is no relation between the both.
Thks all people for your help
Try removing the _id from your schema.
var UserSchema = new Schema({
email: { type: String, unique: true, required: true },
pseudonyme: { type: String, unique: true, required: true },
password: { type: String, required: true }
});
Try using the playload_id directly without casting it like below
User.findById( payload._id , function(err, user) {
if (err) { return done(err, false); }
if (user) {
done(null, user);
} else {
done(null, false);
}
});
first don't define _id in your Schema, and change 'isValid', use this instead
var UserSchema = new Schema({
email: { type: String, unique: true, required: true },
pseudonyme: { type: String, unique: true, required: true },
password: { type: String, required: true }
})
and if is there an error keep it as first parameter EX : done(err) otherwise use null, EX: done(null, result)
const jwtLogin = new JwtStrategy(jwtOptions, function(payload, done) {
var _id = mongoose.mongo.ObjectId(payload._id);
User.find( {_id : _id} , function(err, user) {
if (err) { return done(err); }
if (user) {
done(null, user);
} else {
done(new Error('User not found!!!'));
}
});
});