Unexpected token . on module.exports.function - javascript

I'm trying to create a API register route, but when I try to use User.function - AddUser, which I created in model file it says that there is unexpected token .. Here is the code:
router.post('/register', (req, res, next) => {
let newUser = new User({
username: req.body.username,
name: req.body.name,
email: req.body.email,
password: req.body.password,
photoUrl: req.body.photoUrl
})
User.addUser(newUser, (err, user) => {
if (err) {
res.send('Failed');
} else {
res.send('Registered');
}
});
});
Here is the model file code:
const mongoose = require('mongoose');
const schema = mongoose.Schema;
const bcryptjs = require('bcryptjs');
const userSchema = new schema({
username: { type: String, required: true },
name: { type: String },
email: { type: String, required: true },
password: { type: String, required: true },
photoUrl: { type: String }
});
const User = module.exports = mongoose.model('User', userSchema, 'users');
module.exports.addUser(newUser, callback) => {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser.save(callback);
});
});
}

In your model file code, add a = like following
module.exports.addUser = (newUser, callback) => {
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser.save(callback);
});
});
}

Related

User password hash cut short with MongoDB

I am creating a MERN app, with routes restricted based on role authentication. So when the server starts it looks for a superuser after it connects to MongoDB, if it doesn't find one then it prompts for the creation thereof:
(async () =>
{
const MONGO_URI = process.env.MONGO_URI;
await mongoose.connect(MONGO_URI, {
useNewUrlParser: true,
}).then(() => console.log("Mongo success")).catch(err => console.log(err));
const User = require('./models/User');
const Role = require('./_inc/role');
const superUser = await User.findOne({ role: Role.Superuser });
if (!superUser)
{
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
});
rl._writeToOutput = function(str)
{
if (rl.stdoutMuted)
{
rl.output.write('*');
}
else
{
rl.output.write(str);
}
}
const prom = (str, muted = false) => new Promise(resolve => {
rl.question(str, resolve);
rl.stdoutMuted = muted;
});
const username = await prom('Username: ');
const email = await prom('Email: ');
const password = await prom('Password: ', true);
rl.history = rl.history.slice(1);
rl.close();
const newUser = new User({
name: username,
email, password,
role: Role.Diosito,
picture: '',
method: {
local: true,
},
});
bcrypt.genSalt(10, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.catch(err => console.log({
error: 'se ocurrió un error por intentar crear al usario'
}));
});
}
})();
Unfortunately at some point the password hash is cut short to the first 29 characters.
Here is the User schema:
const userModel = {
name: {
type: String,
},
email: {
type: String,
unique: true,
},
picture: {
type: String,
},
password: {
type: String,
},
role: {
type: String,
required: true,
},
banned: {
type: Boolean,
default: false,
},
method: {
google: Boolean,
local: Boolean,
},
};
const UserSchema = new Schema(userModel);
Any help is appreciated, thank you
You need to call the bcrypt.hash method inside the bcrypt.genSalt callback
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.catch(err => console.log({
error: 'se ocurrió un error por intentar crear al usario'
}));
});
});
The problem is that bcrypt.genSalt is only generating the salt value, not the hashed password, so that's why the password is cut short. You also need to call bcrypt.hash(password, salt)
bcrypt.genSalt(10, function(err, salt) {
bcrypt.hash(password, salt, function(err, hash) {
newUser.password = hash;
newUser
.save()
.catch(err => console.log({
error: 'se ocurrió un error por intentar crear al usario'
}));
});
});
You can read more about here https://heynode.com/blog/2020-04/salt-and-hash-passwords-bcrypt/

Axios posting error TypeError: Cannot read property 'create' of undefined

I'm building a mock facebook app using MERN Stack. When I try to save posts to my database, it keeps throwing two errors. One is in the back end and says TypeError: Cannot read property 'create' of undefined and the other is in the front end and says Unhandled Rejection (Error): Request failed with status code 500
This is my front end API.js page
import axios from "axios";
export default {
// Gets all posts
getPosts: function() {
return axios.get("/api/users/posts");
},
// Gets the post with the given id
getPost: function(id) {
return axios.get("/api/users/posts/" + id);
},
// Deletes the post with the given id
deletePost: function(id) {
return axios.delete("/api/users/posts/" + id);
},
// Saves a post to the database
savePost: function(postData) {
return axios.post("/api/users/posts", postData);
}
};
This is my handleSubmit function
handleFormSubmit = (event) => {
// Preventing the default behavior of the form submit (which is to refresh the page)
event.preventDefault();
// Saving post to database
API.savePost(this.state)
.then(data => {
console.log("data: ", data);
this.setState({
title: data.data.title,
body: data.data.body,
});
});
};
This is my back end postController.js, where TypeError: Cannot read property 'create' of undefined is being thrown.
const db = require("../models");
console.log("--------------------------------------");
console.log("Controller Reached");
console.log("--------------------------------------");
// Defining methods for the postController
module.exports = {
findAll: function(req, res) {
console.log("----------------------findAll------------------------ ");
console.log("req.query: ", req.query);
db.User.posts
.find(req.query)
.sort({ date: -1 })
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
findById: function(req, res) {
db.User.posts
.findById(req.params.id)
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
create: function(req, res) {
console.log("create func");
console.log("req.body: ", req.body);
db.User.posts
.create(req.body) //error here
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
update: function(req, res) {
db.User.posts
.findOneAndUpdate({ _id: req.params.id }, req.body)
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
},
remove: function(req, res) {
db.User.posts
.findById({ _id: req.params.id })
.then(dbModel => dbModel.remove())
.then(dbModel => res.json(dbModel))
.catch(err => res.status(422).json(err));
}
};
And these are my backend API routes for the posts (I removed other routes that weren't related to the issue)
const router = require("express").Router();
const db = require("../../models");
const passport = require("passport");
const postController = require("../../controllers/postController");
router
.route("/posts")
.post(postController.create)
.get(postController.findAll)
.put(postController.update)
.delete(postController.remove);
console.log("/posts reached");
// Matches with "/api/books/:id"
router
.route("/posts/:id")
.get(postController.findById)
.put(postController.update)
.delete(postController.remove);
//router get for login >>> router.get("/")
//router post for logout
//router.get for profile page
module.exports = router;
edit: This is my user model
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const passport = require("passport");
const Schema = mongoose.Schema;
//const passportLocalMongoose = require('passport-local-mongoose');
const userSchema = new Schema({
email: {type: String, required: true},
password: {type: String, required: true},
firstname: String,
lastname: String,
following: [{
User: String,
id: {type: mongoose.Schema.Types.ObjectId }
}],
followers: [{
User: String,
id: {type: mongoose.Schema.Types.ObjectId }
}],
posts: [{
title: String,
body: String,
postedBy: {type: mongoose.Schema.Types.ObjectId},
dateCreated: Date,
comments: [{body:"string", by: mongoose.Schema.Types.ObjectId}],
}],
dateCreated: Date,
savedFiles:[{}],
favoritePosts: [],
avatarImage: [{Image: String}],
jumboImg: [{Image: String}],
profile: {
job: String,
location: String,
school: String,
bio: String,
interests: []
}
});
var User = (module.exports = mongoose.model("User", userSchema));
module.exports.createUser = function (newUser, callback) {
console.log("createUser - newUser", newUser)
bcrypt.genSalt(10, function (err, salt) {
bcrypt.hash(newUser.password, salt, function (err, hash) {
newUser.password = hash;
newUser.save(callback);
});
});
};
module.exports.getUserByEmail = function (email, callback) {
console.log("getUserByEmail", email)
var query = { email: email };
console.log(query);
User.findOne(query, callback);
};
module.exports.getUserById = function (id, callback) {
console.log("getUserById", id);
User.findById(id, callback);
};
module.exports.comparePassword = function (candidatePassword, hash, callback) {
console.log("comparePassword")
bcrypt.compare(candidatePassword, hash, function (err, isMatch) {
if (err) throw err;
callback(null, isMatch);
});
};
var LocalStrategy = require("passport-local").Strategy;
passport.use(
new LocalStrategy({ usernameField: "email" }, function (
email,
password,
done
) {
console.log("LocalStrategy");
User.getUserByEmail(email, function (err, user) {
if (err) throw err;
if (!user) {
return done(null, false, { message: "Unknown User" });
}
User.comparePassword(password, user.password, function (err, isMatch) {
if (err) throw err;
if (isMatch) {
return done(null, user);
} else {
return done(null, false, { message: "Invalid password" });
}
});
});
})
);
passport.serializeUser(function (user, done) {
console.log("serializeUser", user.id)
done(null, user.id);
});
passport.deserializeUser(function (id, done) {
console.log("deserializeUser", id);
User.getUserById(id, function (err, user) {
console.log("deserializeUser - user", `name="${user.name}" \nemail="${user.email}"\npassword=${user.password} `);
done(err, user);
});
});
Any help would be greatly appreciated.
User.posts is undefined because .posts is a property of instance of User. Thus you need to instantiate the user first. In this case, by finding an existing object from User collection.
Since you defined User.posts as primitive arrays, not reference to another collection, the code will be something like below.
create: function (req, res) {
// 1. find the existing user (I guess passport does the job)
db.User.findById(req.body.userid).then((user) => {
// 2. add an post
user.posts.push({
title: req.body.title,
body: req.body.body,
postedBy: req.body.userid,
dateCreated: Date.now(),
comments: [],
});
// 3. persist the changes
user.save();
});
}
If you want to separate the collection, which I believe better, you need to create a new object on the separated collection with the reference to the user posted.
// Post schema
var postSchema = new Schema({
title: String,
body: String,
postedBy: { type: mongoose.Schema.Types.ObjectId, ref: "User" },
dateCreated: Date,
comments: [{ body: "string", by: mongoose.Schema.Types.ObjectId }],
});
// The controller
create: function(req, res) {
// 1. find the existing user (or you get id from Passport session)
db.User.findById(req.body.userid).then((user) => {
// 2. add an post set "postedBy" as the user
return Post.create({
postedBy: user._id,
title: req.body.title,
body: req.body.body,
dateCreated: Date.now(),
});
});
}
Here is the official documentation about referencing: https://mongoosejs.com/docs/populate.html
Hope this helps.

Mongoose cannot find the desired output

I have three schemas.
User.js:
const mongoose = require("mongoose");
const bcrypt = require("bcryptjs");
const userSchema = new mongoose.Schema({
name: {
type: String,
required: true,
},
email: {
type: String,
unique: true,
required: true,
},
password: {
type: String,
required: true,
},
});
userSchema.pre("save", function (next) {
const user = this;
if (!user.isModified("password")) {
return next();
}
bcrypt.genSalt(10, (err, salt) => {
if (err) {
return next(err);
}
bcrypt.hash(user.password, salt, (err, hash) => {
if (err) {
return next(err);
}
user.password = hash;
next();
});
});
});
userSchema.methods.comparePassword = function (candidatePassword) {
const user = this;
return new Promise((resolve, reject) => {
bcrypt.compare(candidatePassword, user.password, (err, isMatch) => {
if (err) {
return reject(err);
}
if (!isMatch) {
return reject(false);
}
resolve(true);
});
});
};
mongoose.model("User", userSchema);
Project.js:
const mongoose = require("mongoose");
const diamondSchema = new mongoose.Schema({
criteria: {
novelty: String,
technology: String,
complexity: String,
pace: String,
},
});
const projectSchema = new mongoose.Schema({
userId: {
type: mongoose.Schema.Types.ObjectId,
ref: "User",
},
projectName: {
type: String,
default: "",
},
projectBudget: {
type: Number,
},
projectDuration: {
type: Number,
},
industry: {
type: String,
},
companyName: {
type: String,
},
numberOfEmployees: {
type: Number,
},
diamond: [diamondSchema],
});
mongoose.model("Project", projectSchema);
Recommendation.js:
const mongoose = require("mongoose");
const diamondSchema = new mongoose.Schema({
criteria: {
novelty: String,
technology: String,
complexity: String,
pace: String,
},
});
const recommendationSchema = new mongoose.Schema({
diamond: [diamondSchema],
description: {
type: String,
},
});
mongoose.model("Recommendation", recommendationSchema);
And two route files.
authRoutes.js:
const express = require("express");
const mongoose = require("mongoose");
const User = mongoose.model("User");
const jwt = require("jsonwebtoken");
const router = express.Router();
router.post("/signup", async (req, res) => {
const { name, email, password } = req.body;
try {
const user = new User({ name, email, password });
await user.save();
const token =
//token has payload-->user id
jwt.sign({ userId: user._id }, "MY_SECRET_KEY");
res.send({ token });
} catch (err) {
//invalid data
return res.status(422).send(err.message);
}
});
router.post("/signin", async (req, res) => {
const { email, password } = req.body;
if (!email || !password) {
return res.status(422).send({ error: "Must provide email and password" });
}
const user = await User.findOne({ email });
if (!user) {
return res.status(404).send({ error: "Invalid email or password" });
}
try {
await user.comparePassword(password);
const token = jwt.sign({ userId: user._id }, "MY_SECRET_KEY");
res.send({ token });
} catch (err) {
return res.status(422).send({ error: "Invalid email or password" });
}
});
module.exports = router;
projectRoutes.js:
const express = require("express");
const mongoose = require("mongoose");
const requireAuth = require("../middlewares/requireAuth");
const Project = mongoose.model("Project");
const Recommendation = mongoose.model("Recommendation");
const router = express.Router();
router.use(requireAuth);
router.get("/projects", async (req, res) => {
const projects = await Project.find({ userId: req.user._id });
res.send(projects);
});
router.post("/projects", async (req, res) => {
const {
projectName,
projectBudget,
projectDuration,
industry,
companyName,
numberOfEmployees,
diamond,
} = req.body;
if (
!projectName ||
!projectBudget ||
!projectDuration ||
!industry ||
!companyName ||
!numberOfEmployees ||
!diamond
) {
return res.status(422).send({ error: "Must provide all project details" });
}
try {
const project = new Project({
projectName,
projectBudget,
projectDuration,
industry,
companyName,
numberOfEmployees,
diamond,
userId: req.user._id,
});
await project.save();
//res.send(project);
} catch (err) {
res.status(422).send({ error: err.message });
}
try {
const rec = await Recommendation.find({ diamond });
//console.log(diamond);
console.log(description);
res.send(rec);
} catch (err1) {
res.status(422).send({ error: err1.message });
}
});
module.exports = router;
Using postman, in the projectRoutes.js file, when I try to send the post request on
localhost:3000/projects, I am trying to create a new project and in response I want description. My logic is that, after I save the new project in projects collection, I am trying to find the document with the SAME DIAMOND OBJECT criteria in recommendations collection which is also present in projects collection. Meaning, I have pre-defined records in recommendations collection and projects collection::
So I need some way so that when I try to add a new project for a user, the criteria object in diamond array I set matches to the criteria object in diamond array in pre-defined one of recommendations documents and in the post request localhost:3000/projects I can return description in response. As I'm doing console.log(description) in projectRoutes.js, it's showing as undefined. I don't know why. Hope it makes sense.
Basically, the idea is there will be limited number of recommendations with unique criterias. So whenever a new project is created based on the criteria, a recommendation is displayed to the user.
Assuming you have only one array element in a project and in an a recommendation
const {
projectName,
projectBudget,
projectDuration,
industry,
companyName,
numberOfEmployees,
diamond,
} = req.body;
const [projectDiamond] = diamond // get the first object in the diamond array
const { criteria } = projectDiamond // extract criteria
const recommendation = await Recommendation.find({ 'diamond.criteria': criteria });
Please note that the order of criteria fields must match, since we are looking up a matching object in an array.
Reference: https://docs.mongodb.com/manual/tutorial/query-arrays/#query-an-array

Postman: TypeError: User.findOne is not a function

Postman: TypeError: User.findOne is not a function
Hi, I'm trying to run the POST request at the end of the lecture and I got this error.
I think the problem is with the User.findOne method.
My code as follows:
//users.js
const express = require('express');
const router = express.Router();
const gravatar = require('gravatar');
const bcrypt = require('bcryptjs');
// Load User Model
const User = require('../../models/User');
//#route GET api/users/test
//#description Test users route
//#access Public
router.get('/test', (req, res) => res.json({
msg: 'Users Works'
}));
//#route GET api/users/register
//#description Register a user
//#access Public
router.post('/register', (req, res) => {
User.findOne({
email: req.body.email
}).then(user => {
if (user) {
return res.status(400).json({
email: 'Email already exists'
});
} else {
const avatar = gravatar.url(req.body.email, {
s: '200',
r: 'pg',
d: 'mm'
});
const newUser = new User({
name: req.body.name,
email: req.body.email,
avatar,
password: req.body.password
});
// encryption of password, throw and catch of error
bcrypt.genSalt(10, (err, salt) => {
bcrypt.hash(newUser.password, salt, (err, hash) => {
if (err) throw err;
newUser.password = hash;
newUser
.save()
.then(user => res.json(user))
.catch(err => console.log(err));
});
});
}
});
});
module.exports = router

Authentication using Token , passport jwt , Express

I'm working on this little project and i'm having difficulties , Everything works fine in my api except that when i want to authenticate a user using a token , it says "unauthorized". any help would be much appreciated.
this is my passport.js file :
const jwtStrategy = require('passport-jwt').Strategy;
const extractJwt = require('passport-jwt').ExtractJwt;
const User = require('../models/user');
const config = require('../config/database');
module.exports = function(passport){
let opts = {};
opts.jwtFromRequest =
extractJwt.fromAuthHeaderWithScheme('jwt');
opts.secretOrKey = config.secret;
passport.use(new jwtStrategy(opts, function(jwt_payload, done)
{
User.getUserById(jwt_payload.data._id, function(err, user) {
if (err) {
return done(err, false);
}
if (user) {
return done(null, user);
} else {
return done(null, false);
}
});
}));
}
And this is my user.js file (i think that the fault is in the getUserById function :
const mongoose = require('mongoose');
const bcrypt = require('bcryptjs');
const config = require('../config/database');
//User schema
const userSchema = mongoose.Schema({
name: {
type: String
},
email: {
type: String,
required: true
},
username: {
type: String,
required: true
},
password: {
type: String,
required: true,
}
});
const User = module.exports = mongoose.model('User', userSchema);
module.exports.getUserById = function(id, callback){
User.findById(id, callback);
}
module.exports.getUserByUsername = function(username, callback){
const query = {username: username}
User.findOne(query, callback);
}
module.exports.addUser = function(newUser, callback){
bcrypt.genSalt(10, function(err, salt){
bcrypt.hash(newUser.password,salt,function(err, hash){
if(err) throw err;
newUser.password= hash;
newUser.save(callback);
});
});
}
module.exports.comparePassword = function (candidatePassword,
hash, callback){
bcrypt.compare(candidatePassword, hash, function(err, isMatch){
if(err) throw err;
callback(null, isMatch);
});
}

Categories