app.js code -
I don't know why this is getting an error in node module - npm mongoose-findorcreate
I checked the node module but there's no fault in ES6, I'm also attaching the module code below
// jshint esversion:6
require('dotenv').config()
const express=require("express")
const bodyParser = require("body-parser")
const ejs=require("ejs")
const mongoose=require("mongoose")
const bcrypt=require("bcrypt")
const session=require("express-session")
const passport=require("passport")
const flash = require('connect-flash')
const passportLocalMongoose = require("passport-local-mongoose");
const findOrCreate = require("mongoose-findorcreate");
const LocalStrategy=require("passport-local").Strategy;
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const app=express();
app.use(express.urlencoded({extended:false})) //Not using bodyParser, using Express in-built body parser instead
app.set("view engine","ejs")
app.use(express.static("public"))
app.use(bodyParser.urlencoded({extended: true}));
app.use(session({
secret:"Justarandomstring.",
resave:false,
saveUninitialized:false
}))
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
mongoose.connect("mongodb://127.0.0.1:27017/userDB")
const userSchema= new mongoose.Schema({
username : String,
password : String,
googleId: String
});
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
const User=new mongoose.model("User",userSchema)
//Creating Local Strategy. passport-local-mongoose 3 lines of code for Strategy,
//Serialiazation, Deserialization not working due to recent changes in Mongoose 7
passport.use(new LocalStrategy((username,password,done)=>{ //done is a callback function
try{
User.findOne({username:username}).then(user=>{
if (!user){
return done(null,false, {message:"Incorrect Username"})
}
//using bcrypt to encrypt passoword in register post route and compare function in login post round.
//login post route will check here during authentication so need to use compare here
bcrypt.compare(password,user.password,function(err,result){
if (err){
return done(err)
}
if (result) {
return done(null,user)
}
else {
return done (null,false, {message:"Incorrect Password"})
}
})
})
}
catch (err){
return done(err)
}
}))
//serialize user
passport.serializeUser(function(user, done) {
done(null, user.id);
});
//deserialize user
passport.deserializeUser(function(id, done) {
console.log("Deserializing User")
try {
User.findById(id).then(user=>{
done(null,user);
})
}
catch (err){
done(err);
}
});
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret:process.env.CLIENT_SECRET,
callbackURL: "http://localhost:3000/auth/google/secrets",
userProfileURL: "https://www.googleapis.com//oauth2/v3/userinfo"
},
(accessToken, refreshToken, profile, cb)=>{
console.log(profile);
User.findOrCreate({ googleId: profile.id }, (err, user) =>{
return cb(err, user);
});
}
));
//get routes
app.get("/",function(req,res){
res.render("home")
})
app.get('/auth/google',
passport.authenticate('google', { scope: ['profile'] }));
app.get('/auth/google/secrets',
passport.authenticate("google", { failureRedirect: '/login'}),
function(req, res) {
// Successful authentication, redirect home.
res.redirect("/secrets");
});
app.get("/login",function(req,res){
console.log(req.flash("error"))
res.render("login");
})
app.get("/register",function(req,res){
res.render("register")
})
app.get("/secrets",function(req,res){
if (req.isAuthenticated()){
res.render("secrets")
}
else {
res.redirect("/login")
}
})
app.get("/logout",function(req,res){
req.logout(function(err){
if(err){
console.log(err)
}
res.redirect("/");
});
})
//post routes
app.post("/register",function(req,res){
bcrypt.hash(req.body.password,10,function(err,hash){ //10 is SaltRounds
if (err){
console.log(err)
}
const user= new User ({
username:req.body.username,
password:hash
})
user.save()
passport.authenticate('local')(req,res,()=>{res.redirect("/secrets")})
})
})
app.post('/login',passport.authenticate('local',
{ successRedirect:"/secrets", failureRedirect: '/login', failureFlash:true}
));
//listen
app.listen(3000, ()=> {
console.log("Server Running on Port 3000")
})
The module code link:
/*!
* Mongoose findOrCreate Plugin
* Copyright(c) 2012 Nicholas Penree <[email protected]>
* MIT Licensed
*/
function findOrCreatePlugin(schema, options) {
schema.statics.findOrCreate = function findOrCreate(conditions, doc, options, callback) {
var self = this;
// When using Mongoose 5.0.x and upper, we must use self.base.Promise
var Promise = self.base.Promise.ES6 ? self.base.Promise.ES6 : self.base.Promise;
if (arguments.length < 4) {
if (typeof options === 'function') {
// Scenario: findOrCreate(conditions, doc, callback)
callback = options;
options = {};
} else if (typeof doc === 'function') {
// Scenario: findOrCreate(conditions, callback);
callback = doc;
doc = {};
options = {};
} else {
// Scenario: findOrCreate(conditions[, doc[, options]])
return new Promise(function(resolve, reject) {
self.findOrCreate(conditions, doc, options, function (ex, result, created) {
if (ex) {
reject(ex);
} else {
resolve({
doc: result,
created: created,
});
}
});
});
}
}
this.findOne(conditions, function(err, result) {
if (err || result) {
if (options && options.upsert && !err) {
self.update(conditions, doc, function(err, count) {
self.findById(result._id, function(err, result) {
callback(err, result, false);
});
});
} else {
callback(err, result, false);
}
} else {
for (var key in doc) {
conditions[key] = doc[key];
}
// If the value contain `$` remove the key value pair
var keys = Object.keys(conditions);
for (var z = 0; z < keys.length; z++) {
var value = JSON.stringify(conditions[keys[z]]);
if (value && value.indexOf('$') !== -1) {
delete conditions[keys[z]];
}
}
var obj = new self(conditions);
obj.save(function(err) {
callback(err, obj, true);
});
}
});
};
}
/**
* Expose `findOrCreatePlugin`.
*/
module.exports = findOrCreatePlugin;
I'm getting an error of:
TypeError: Cannot read properties of undefined (reading 'ES6')
at Function.findOrCreate (C:\Users\KIIT\Desktop\Web Development\Secrets - Starting Code\node_modules\mongoose-findorcreate\index.js:10:37)
at Strategy._verify (C:\Users\KIIT\Desktop\Web Development\Secrets - Starting Code\app.js:101:10)
at C:\Users\KIIT\Desktop\Web Development\Secrets - Starting Code\node_modules\passport-oauth2\lib\strategy.js:205:24
at C:\Users\KIIT\Desktop\Web Development\Secrets - Starting Code\node_modules\passport-google-oauth20\lib\strategy.js:122:5
at passBackControl (C:\Users\KIIT\Desktop\Web Development\Secrets - Starting Code\node_modules\oauth\lib\oauth2.js:134:9)
at IncomingMessage.<anonymous> (C:\Users\KIIT\Desktop\Web Development\Secrets - Starting Code\node_modules\oauth\lib\oauth2.js:157:7)
at IncomingMessage.emit (node:events:525:35)
at endReadableNT (node:internal/streams/readable:1359:12)
at process.processTicksAndRejections (node:internal/process/task_queues:82:21)
This is from Angela Yu's Complete Web development Bootcamp. A very small fix for this: Inside the GoogleStrategy
just replace the findOrCreate
method with findOne
.
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: 'http://localhost:3000/auth/google/secrets'
},
async function (accessToken, refreshToken, profile, done) {
try {
console.log(profile);
// Find or create user in your database
let user = await User.findOne({ googleId: profile.id });
if (!user) {
// Create new user in database
const username = Array.isArray(profile.emails) && profile.emails.length > 0 ? profile.emails[0].value.split('@')[0] : '';
const newUser = new User({
username: profile.displayName,
googleId: profile.id
});
user = await newUser.save();
}
return done(null, user);
} catch (err) {
return done(err);
}
}
));
Here's my complete code for app.js implementing both Google Sign-in and Facebook sign-in:
require("dotenv").config();
const express = require("express");
const app = express();
const ejs = require("ejs");
const GoogleStrategy = require('passport-google-oauth20').Strategy;
const mongoose = require("mongoose");
const bcrypt = require("bcrypt");
const session = require("express-session");
const passport = require("passport");
const FacebookStrategy = require('passport-facebook').Strategy;
const LocalStrategy = require("passport-local").Strategy;
app.use(express.urlencoded({
extended: false
})); // Not using bodyParser, using Express in-built body parser instead
app.set("view engine", "ejs");
app.use(express.static("public"));
app.use(session({
secret: "Our little secret.",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
mongoose.connect("mongodb://127.0.0.1:27017/userDB");
const userSchema = new mongoose.Schema({
username: String,
password: String,
googleId: String,
facebookId: String,
secret: String
});
const User = new mongoose.model("User", userSchema);
// Creating Local Strategy. passport-local-mongoose 3 lines of code for Strategy,
// Serialiazation, Deserialization not working due to recent changes in Mongoose 7
passport.use(new LocalStrategy((username, password, done) => { //done is a callback function
User.findOne({
username: username
}).then(user => {
if (!user) {
return done(null, false, {
message: "Incorrect Username"
})
}
// using bcrypt to encrypt password in register post route and compare function in login post round.
// login post route will check here during authentication so need to use compare here
bcrypt.compare(password, user.password).then((isMatch) => {
if (isMatch) {
return done(null, user)
} else {
return done(null, false, {
message: "Incorrect Password"
})
}
}).catch((err) => {
return done(err)
});
}).catch((err) => {
return done(err)
});
}));
// serialize user
passport.serializeUser(function(user, done) {
done(null, user.id);
});
// deserialize user
passport.deserializeUser(function(id, done) {
User.findById(id).then(user => {
done(null, user);
}).catch((err) => {
return done(err)
});
});
passport.use(new GoogleStrategy({
clientID: process.env.GOOGLE_CLIENT_ID,
clientSecret: process.env.GOOGLE_CLIENT_SECRET,
callbackURL: 'http://localhost:3000/auth/google/secrets'
}, async function(accessToken, refreshToken, profile, done) {
try {
console.log(profile);
// Find or create user in your database
let user = await User.findOne({
googleId: profile.id
});
if (!user) {
// Create new user in database
const username = Array.isArray(profile.emails) && profile.emails.length > 0 ? profile.emails[0].value.split('@')[0] : '';
const newUser = new User({
username: profile.displayName,
googleId: profile.id
});
user = await newUser.save();
}
return done(null, user);
} catch (err) {
return done(err);
}
}));
passport.use(new FacebookStrategy({
clientID: process.env.FACEBOOK_APP_ID,
clientSecret: process.env.FACEBOOK_APP_SECRET,
callbackURL: 'http://localhost:3000/auth/facebook/secrets'
}, async function(accessToken, refreshToken, profile, done) {
try {
console.log(profile);
// Find or create user in your database
let user = await User.findOne({
facebookId: profile.id
});
if (!user) {
// Create new user in database
const newUser = new User({
username: profile.displayName,
facebookId: profile.id
});
user = await newUser.save();
}
return done(null, user);
} catch (err) {
return done(err);
}
}));
//get routes
app.get("/", function(req, res) {
res.render("home");
});
app.get("/login", function(req, res) {
res.render("login");
});
app.get("/register", function(req, res) {
res.render("register");
});
app.get("/secrets", function(req, res) {
User.find({
secret: {
$ne: null
}
}).then((foundUsers) => {
res.render("secrets", {
usersWithSecrets: foundUsers
})
}).catch((err) => {
console.log(err)
});
});
app.get("/logout", function(req, res) {
req.logout(function(err) {
if (err) {
console.log(err);
}
res.redirect("/");
});
});
app.get("/auth/google", passport.authenticate("google", {
scope: ["profile"]
}));
app.get("/auth/google/secrets", passport.authenticate("google", {
failureRedirect: "/login"
}), function(req, res) {
// Successful authentication, redirect home.
res.redirect("/secrets");
});
app.get('/auth/facebook', passport.authenticate('facebook'));
app.get('/auth/facebook/secrets', passport.authenticate('facebook', {
failureRedirect: '/login'
}), function(req, res) {
// Successful authentication, redirect to secrets page.
res.redirect('/secrets');
});
app.route("/submit").get(function(req, res) {
if (req.isAuthenticated()) {
res.render("submit");
} else {
res.rediret("/login");
}
}).post(function(req, res) {
const submittedsecret = req.body.secret;
User.findById(req.user.id).then((foundUser) => {
if (foundUser) {
foundUser.secret = submittedsecret;
foundUser.save().then(() => {
res.redirect("/secrets")
}).catch((err) => {
console.log(err)
});
}
}).catch((err) => {
console.log(err)
});
});
// post routes
app.post("/register", function(req, res) {
bcrypt.hash(req.body.password, 10, function(err, hash) { // 10 is SaltRounds
if (err) {
console.log(err);
}
const user = new User({
username: req.body.username,
password: hash
})
user.save();
passport.authenticate('local')(req, res, () => {
res.redirect("/secrets");
})
})
});
app.post('/login', passport.authenticate('local', {
successRedirect: "/secrets",
failureRedirect: '/login'
}));
// listen
app.listen(3000, () => {
console.log("Server Running on Port 3000");
});