Why I'm getting this error!!
GOOGLE USER: null
/Users//my-blog/api/node_modules/mongodb/lib/operations/insert.js:53
return callback(new error_1.MongoServerError(res.writeErrors[0]));
^
MongoServerError: E11000 duplicate key error collection: blog.users
index: email_1 dup key: { email: "" }
I dropped the whole collection in Mongodb and when I tried again it gave me the same error but the data stored in MongoDB collection, the problem is with the error it stops the whole app from running. I don't know where I went wrong or what I'm missing.
Auth.js Code:
router.get("/google", passport.authenticate("google", {
scope: ["profile", "email"] }));
router.get("/auth/google/callback", passport.authenticate("google", {
successRedirect: "http://localhost:3000/",
failureRedirect: "/googleLogin/failed"
}));
router.get("/googleLogin/success", async (req, res)=>{
if(req.user){
const user = await User.findOne({provider_id: req.user.id,
provider: req.user.provider})
if(user){
res.status(200).json({
success: true,
message: "success",
user: user
})
console.log("GOOGLE USER IS: " + user)
}else{
const checkUserEmail = await User.findOne({email: req.user.email})
if(checkUserEmail){
res.status(401).json({
success: false,
message: "User already Exist with this email id",
})
}else{
const user = await User.create({
username: req.user.name.givenName+ "_" +req.user.name.familyName,
firstName: req.user.name.givenName,
lastName: req.user.name.familyName,
email: req.user.emails[0].value,
provider: req.user.provider,
provider_id: req.user.id,
// profilePic: req.user.photos?.[0]?.value,
});
res.status(200).json({
success: true,
message: "success",
user: user
})
}
}
console.log("GOOGLE USER: ", user);
}
})
router.get("/googleLogin/failed", (req, res)=>{
if(req.user){
res.status(401).json({
success: false,
message: "failure",
})
}
})
I THINK the code keeps running nonstop ! thats why it giving me the error even so the collection is empty, it sign up the user then it sign up again non stop. I think that it should be a done() in the code but I didn't know how to fix it.
Passport.js Setup:
passport.use(new GoogleStrategy({
clientID: process.env.REACT_APP_GOOGLE_CLIENT_ID,
clientSecret: process.env.REACT_APP_GOOGLE_CLIENT_SECRET,
callbackURL: "/auth/google/callback",
passReqToCallback: true,
scope: ["profile", "email"],
},
function(request, accessToken, refreshToken, profile, done){
console.log(profile.emails[0].value);
console.log(profile.photos[0].value);
return done(null, profile)
}
));
passport.serializeUser((user, done)=>{
done(null, user)
})
passport.deserializeUser((user, done)=>{
done(null, user)
})
Here is my User Schema: User.js
const mongoose = require('mongoose');
const UserSchema = new mongoose.Schema({
username: {
type: String,
required: false,
/* Can't create a user with the same username */
unique: true,
minlength: 3,
maxlength: 30,
},
firstName: {
type: String,
required: false,
unique: false,
maxlength: 20,
},
lastName: {
type: String,
required: false,
unique: false,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
},
repeatPassword: {
type: String,
},
profilePic: {
type: String,
default: "",
},
birthday: {
type: String,
required: false,
unique: false,
},
country: {
type: String,
required: false,
unique: false,
},
googleId: {
type: String
},
provider: {
type: String,
default: "email"
},
provider_id: {
type: String,
}
},
{ timestamps: true }
);
module.exports = mongoose.model("User", UserSchema);
Related
My problem is that I receive a validation error on my server when trying to update my user and product collection in mongodb using formik on my front end.
I add a new product as logged in user. All of the authentication is working with JWT token.
"ValidationError: Product validation failed: title: Path title is required., description: Path description is required., price: Path price is required., location: Path location is required., condition: Path condition is required., category: Path category is required."
I've looked everywhere on stack of, and tried everything for 30+ hours. If anyone could help, I'd appreciate it. I feel bad for asking this novice question, but I've been struggling.
Here is my front end code using formik and axios :
const schema = yup.object().shape({
title: yup.string().required('Title is required'),
description: yup.string().required('Description is required'),
price: yup.number().required('Price is required').positive('Price must be a positive number'),
location: yup.string().required('Location is required'),
condition: yup.string().required('Condition is required'),
category: yup.string().required('Category is required'),
});
const addProductFormik = useFormik({
initialValues: {
title: "",
description: "",
price: "",
location: "",
condition: "",
category: "",
},
validationSchema: schema,
onSubmit: async (values) =\> {
try {
const formData = new FormData();
formData.append('title', values.title);
formData.append('description', values.description);
formData.append('price', values.price);
formData.append('location', values.location);
formData.append('condition', values.condition);
formData.append('category', values.category);
console.log(formData.get('title'));
console.log(formData.get('price'));
const url = `http://localhost:3005/product/${user._id}/add-product`;
const config = {
headers: { Authorization: 'Bearer ' + token }
};
console.log(config);
const response = await axios.post(url, formData, config);
console.log(response);
const newProduct = response.data.product;
console.log(newProduct);
// dispatch(addProduct(newProduct));
} catch (error) {
console.log(error)
console.error(error);
}
},
});
Here is my controller function to update my mongo database :
export const createProduct = async (req, res, next) => {
try {
const id = req.params.userId;
const user = await User.findById(id);
if (!user) {
return res.status(404).json({ message: "User not found" });
}
console.log('user was found')
const createdProduct = new Product({
title: req.body.title,
description: req.body.description,
price: req.body.price,
location: req.body.location,
condition: req.body.condition,
category: req.body.category,
});
console.log(createdProduct);
console.log('product was created')
console.log(createdProduct._id);
try {
createdProduct.save();
user.products.push(createdProduct._id);
Product.insertMany(createdProduct);
// JWT token signing
const token = jwt.sign({ userId: user.id }, 'supersecretkey', { expiresIn: '1h' });
res.status(201).json({ product: createdProduct, token });
} catch (err) {
const error = new HttpError(
'Creating product failed, please try again.',
500
);
return next(error);
}
console.log('controller function works!');
} catch (error) {
console.error(error)
res.status(404).json({ message: error.message });
}
};
Here is my Product Schema :
import mongoose from "mongoose";
const Schema = mongoose.Schema;
const ProductSchema = new Schema({
title: {
type: String,
required: true,
},
description: {
type: String,
required: true,
},
price: {
type: Number,
required: true,
},
location: {
type: String,
required: true,
},
condition: {
type: String,
required: true,
},
category: {
type: String,
required: true,
enum: ["Cars", "Electronics", "Clothing", "Furniture", "Other"],
},
seller: {
type: Schema.Types.ObjectId,
ref: "User",
},
createdAt: {
type: Date,
default: Date.now,
},
});
const Product = mongoose.model("Product", ProductSchema);
export default Product;
Here is my User Schema :
import mongoose from "mongoose";
const Schema = mongoose.Schema;
const UserSchema = new Schema({
firstName: {
type: String,
required: true,
min: 2,
max: 50,
},
lastName: {
type: String,
required: true,
min: 2,
max: 50,
},
email: {
type: String,
required: true,
unique: true,
},
password: {
type: String,
required: true,
},
location: {
type: String,
required: true,
},
products: [
{
type: Schema.Types.ObjectId,
ref: "Product",
},
],
createdAt: {
type: Date,
default: Date.now,
},
});
const User = mongoose.model("User", UserSchema);
export default User
Now when I submit the form, there is no error on the front end. I get a 201 response and when I console log the newProduct in the addProductFormik, this is what it says :
_id: '63f27485ed59ed8c6fdff654', createdAt: '2023-02-19T19:12:05.981Z'}
createdAt: "2023-02-19T19:12:05.981Z"
_id: "63f27485ed59ed8c6fdff654"
On the back end, i get this error : "ValidationError: Product validation failed: title: Path title is required., description: Path description is required., price: Path price is required., location: Path location is required., condition: Path condition is required., category: Path category is required."
Now if you look at the console logs made in the controller function, these are the console logs that are logged on the server,
user was found
{
_id: new ObjectId("63f27485ed59ed8c6fdff654"),
createdAt: 2023-02-19T19:12:05.981Z
}
product was created
new ObjectId("63f27485ed59ed8c6fdff654")
controller function works!
So within my controller function, it finds the user in params, the createdProduct is only shown as a new ObjectId and not with all of its fields (title, description, price, etc). Somehow, it makes it through all the try blocks and console logs the controller function works. But my products collection and user collection (user.products) is not updated and I get that validation error.
Since you're using formData, you need to pass in the Content-Type through Axios headers when posting:
headers: { "Content-Type": "multipart/form-data" },
The default type is application/xml which won't work with your data.
You'll also need to make sure your backend is configured to handle that data coming in. body-parser is commonly used for this with Express.
Here's a simple configuration:
const express = require('express')
const bodyParser = require('body-parser')
const app = express()
// parse application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// parse application/json
app.use(bodyParser.json({ limit: '10mb' ))
i am using PostgreSQL with Sequelize ORM to create my db.
I have this models:
models.js
const Users = db.define("users", {
name: {
type: DataTypes.STRING,
},
lastname: {
type: DataTypes.STRING,
},
sector: {
type: DataTypes.STRING,
},
email: { type: DataTypes.STRING, unique: true, allowNull: false },
password: { type: DataTypes.STRING, allowNull: false },
points: { type: DataTypes.INTEGER, defaultValue: 0 },
suscripcion: { type: DataTypes.BOOLEAN, defaultValue: false },
preference_id: { type: DataTypes.STRING },
});
const Pronostico = db.define("pronosticos", {
matchId: {
type: DataTypes.STRING,
unique: true,
},
winner: {
type: DataTypes.STRING,
},
goalHome: {
type: DataTypes.INTEGER,
},
goalAway: {
type: DataTypes.INTEGER,
},
});
//REFRESH TOKEN
const RefreshToken = db.define("refreshTokens", {
token: {
type: DataTypes.STRING,
},
expiryDate: {
type: DataTypes.DATE,
},
userId: {
type: DataTypes.STRING,
},
});
RefreshToken.createToken = async function (user) {
let expiredAt = new Date();
expiredAt.setSeconds(expiredAt.getSeconds() + config.jwtRefreshExpiration);
let _token = uuidv4();
let refreshToken = await this.create({
token: _token,
userId: user.id,
expiryDate: expiredAt.getTime(),
});
return refreshToken.token;
};
RefreshToken.verifyExpiration = (token) => {
return token.expiryDate.getTime() < new Date().getTime();
};
This are the Relationships:
Users.hasMany(Pronostico, { as: "pronosticos" });
Pronostico.belongsTo(Users, { foreignKey: "userId", as: "user" });
RefreshToken.belongsTo(User, {
foreignKey: 'userId', targetKey: 'id'
});
User.hasOne(RefreshToken, {
foreignKey: 'userId', targetKey: 'id'
});
Somewhere on my server, I have this controller which creates a refreshToken:
let refreshToken = await RefreshToken.createToken(user);
The problem is that I get an error that says "column userId doesnt exist in refreshTokens relationship.
Maybe I have some issues with the relationships but I think they are OK.
Any suggestion?
Following are the steps for authentication flow:
User does the registeration by entering his details and he will be
sent an OTP to his mail.
At this time user details stored to
mongoDB.
Usually after validation of OTP, a user can login to
application. But in my case before validating OTP, user can login to
application.
How to solve this please help me. Some of my code shown below.
model.js
var UserSchema = new Schema({
name: String,
email: {type: String, required: true, select: true},
mobile: {type: String, required: true, select: true},
password: {type: String, required: true, select: true},
});
controller.js
vm.submitPost = function(userData){
$http({
url: 'http://192.168.2.8:7200/api/pages/auth/register',
method: 'POST',
data: userData
}).then(function(res) {
if(res.data.success){
$location.path('/pages/auth/otp');
} else {
alert('Please fill all credentials');
}
}, function(error) {
alert(error.data);
});
};
node.js
router.post('/pages/auth/register',function(req, res, next){
var user = new User({
name: req.body.username,
email: req.body.email,
password: req.body.password,
mobile: req.body.mobile,
});
var secret = "mysecretkey";
var code = otp.generate(secret);
var insertOtp = function(db, callback) {
db.collection('otp').createIndex( { "createdAt": 1 }, { expireAfterSeconds: 10 } );
db.collection('otp').insertOne( {
"createdAt": new Date(),
"generatedOtp": code,
"logEvent": 2,
"logMessage": "Success!"
}, function(err, result) {
assert.equal(err, null);
callback(result);
});
};
MongoClient.connect(config.database, function(err, db) {
assert.equal(null, err);
insertOtp(db, function(err,docs) {
db.close();
});
});
var mailOptions={
to : req.body.email,
subject : 'OTP',
text : "Your One-Time Password is "+code
}
transport.sendMail(mailOptions, function(error, response){
if(error){
console.log(error);
res.end("error");
}else{
res.end("sent");
}
});
user.save(function(err){
if(err){
res.send(err);
return;
}
res.json({
success:true,
message: 'User has been created!'
});
});
});
add active attribute to your schema with default value false when user has validated through OTP, then set this attribute to true and allow user to login if this attribute is true.
var UserSchema = new Schema({
name: String,
email: {type: String, required: true, select: true},
mobile: {type: String, required: true, select: true},
password: {type: String, required: true, select: true},
active:{ type: 'Boolean',
default: false}
});
I'm getting my hands on mean stack development. I'm kinda stuck where my requirement is to get posted by functionality. I'm trying to build a simple classified ads app where a user adds/updates/deletes a classified. I'm able to do all of these but now I need to display the name of that particular user on that add who is logged in. I've researched online but couldn't get the solution.
My schema
var UserSchema = new Schema({
username: { type: String, required: true, unique: true },
firstName: { type: String, required: true },
lastName: { type: String, required: true },
email: { type: String, required: true, unique: true, lowercase: true },
phone: { type: Number, min: 10, unique: true },
hash: String,
salt: String
});
var ClassifiedSchema = new Schema({
title: { type: String, required: true, unique: true },
description: { type: String, required: true, },
price: { type: Number, required: true },
created: { type: Date, default: Date.now },
updated: { type: Date, default: null },
contact: {
name: String,
phone: Number,
email: String
},
image: String,
user: { type: mongoose.Schema.Types.ObjectId, ref: 'User' }
});
My route
router.route('/classifieds')
.post(function(req, res) {
var classified = new Classified(req.body);
classified.save(function(err, classified) {
if (err)
res.send(err);
res.json(classified);
});
})
.get(function(req, res) {
Classified.find(function(err, classifieds) {
if (err)
res.send(err);
res.json(classifieds);
});
});
router.route('/register')
.post(function(req, res) {
if (!req.body.username || !req.body.password || !req.body.email || !req.body.firstName || !req.body.lastName) {
return res.status(400).json({message: 'Please fill all the fields!'});
};
var user = new User(req.body);
user.setPassword(req.body.password);
user.save(function(err, user) {
if (err)
res.send(err);
res.json({ token: user.generateJWT()});
});
});
router.route('/login')
.post(function(req, res) {
if (!req.body.username || !req.body.password) {
return res.status(400).json({ message: 'Please fill all the fields!' });
};
passport.authenticate('local', function(err, user, info) {
if (err)
res.send(err);
if (user) {
return res.json({ token: user.generateJWT() });
} else {
return res.status(401).json(info);
};
})(req, res);
});
I want to know how do I get the username while posting the classified? I'm aware of the populate function but I've tried it and it doesn't seem to work.
Update
I've added my register and login route to show you the use of passport.
If you have an authentication system like passport which sets req.user to current logged in user, then:
.get(function(req, res) {
Classified.find({user: req.user},function(err, classifieds) {
if (err)
res.send(err);
res.json(classifieds);
});
});
I have this code:
router.post('/setsuggestions', function(req, res, next){
if(!req.body.username || !req.body.challengessuggestions){
return res.status(400).json({message: challengessuggestions});
}
var query = { username: req.body.username };
/*User.findOneAndUpdate(query, { challengessuggestions: req.body.challengessuggestions }, callback = function(response){
res.json(response);
});*/
/*
User.findOneAndUpdate(
query,
{$push: {"challengessuggestions": {$oid: req.body.challengessuggestions}}},
callback = function(response) {
res.json(response);
}
);*/
User.findOneAndUpdate(
query,
{$push: {challengessuggestions: req.body.challengessuggestions}},
{safe: true, upsert: true},
function(err, model) {
res.json(err);
}
);
});
When I postman like this:
I get the following error:
{ "name": "MongoError", "message": "exception: The field
'challengessuggestions' must be an array but is of type OID in
document {_id: ObjectId('56263b910d1a2f1f0077ffae')}", "errmsg":
"exception: The field 'challengessuggestions' must be an array but is
of type OID in document {_id: ObjectId('56263b910d1a2f1f0077ffae')}",
"code": 16837, "ok": 0 }
This is the schema definition of AppUser:
var UserSchema = new mongoose.Schema({
username: { type: String, lowercase: true, unique: true },
firstname: { type: String},
lastname: { type: String},
difficulty: { type: String},
isstudent: { type: Boolean },
haschildren: { type: Boolean},
gender: { type: String },
email: { type: String, unique: true},
birthdate: String,
isdoingchallenges: { type: Boolean },
challengescompleted: [{ type: ObjectId, ref: 'Challenge' }],
currentchallenge: { type: ObjectId, ref: 'Challenge' },
challengessuggestions: [{ type: ObjectId, ref: 'Challenge' }],
hash: String,
salt: String
});
This is the schema definiton of challenge:
var Challengeschema = new mongoose.Schema({
name: { type: String, initial: true, required: true, index: true },
image: { type: Array },
difficulty: { type: String },
studentfriendly: { type: Boolean },
childfriendly: { type: Boolean },
description: { type: String }
});
I'm sending this in the function that calls the api:
Object {_id: "5631423f8c5ba50300f2b4f6", difficulty: "medium", name:
"Probeer 1 van onze recepten.", __v: 0, childfriendly: true…}
This gives me following error:
D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\lib\schema\obj
ectid.js:134
throw new CastError('ObjectId', value, this.path);
^ Error
at MongooseError.CastError (D:\Stijn\Documenten\EVA-project-Groep-6\Api\node
_modules\mongoose\lib\error\cast.js:18:16)
at ObjectId.cast (D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\m
ongoose\lib\schema\objectid.js:134:13)
at Array.MongooseArray.mixin._cast (D:\Stijn\Documenten\EVA-project-Groep-6\
Api\node_modules\mongoose\lib\types\array.js:124:32)
at Array.MongooseArray.mixin._mapCast (D:\Stijn\Documenten\EVA-project-Groep
-6\Api\node_modules\mongoose\lib\types\array.js:295:17)
at Object.map (native)
at Array.MongooseArray.mixin.push (D:\Stijn\Documenten\EVA-project-Groep-6\A
pi\node_modules\mongoose\lib\types\array.js:308:25)
at Query. (D:\Stijn\Documenten\EVA-project-Groep-6\Api\routes\ind ex.js:144:44)
at D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\node_mo
dules\kareem\index.js:177:19
at D:\Stijn\Documenten\EVA-project-Groep-6\Api\node_modules\mongoose\node_mo
dules\kareem\index.js:109:16
at doNTCallback0 (node.js:408:9)
at process._tickCallback (node.js:337:13) 29 Oct 22:05:38 - [nodemon] app crashed - waiting for file changes before starti ng...
How do I solve this?
Query the User user using findOne() first and use the first found document that's passed to the callback to save the embedded documents with:
router.post('/setsuggestions', function(req, res, next){
if(!req.body.username || !req.body.challengessuggestions){
return res.status(400).json({message: challengessuggestions});
}
var query = { username: req.body.username };
User.findOne(query, function (err, user){
if (err) //throw ...
if (user) {
if (user.challengessuggestions && user.challengessuggestions.length) {
user.challengessuggestions.push(req.body.challengessuggestions);
}
else {
user.challengessuggestions = [req.body.challengessuggestions];
}
// save changes
user.save(function (err) {
if (!err) {
// done ...
}
});
}
});
);