I am learning to use passport js in my form application and I am using a user object in an application that uses this model to save a user in database but when I return a user object that has been created and try to update that object by using findOne method I run into user.findOne is not a function error Here is my code.
Thanks in advance for helping me out.
user.js looks something like this
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var usersSchema = new mongoose.Schema({
username:String,
password:String,
email:String
});
usersSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User",usersSchema);
my signup page looks like this
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css2?family=Mitr:wght#500&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/biodata.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<a class="navbar-brand justify-content-around" id="navbar-home" href="/">Home</a>
<div class="ml-auto" id="navbar-joint">
<a class="navbar-brand" href="/signup">Sign Up</a>
<a class="navbar-brand" href="/logout">Logout</a>
</div>
</nav>
<div class="card" id="signup-card">
<div class="card-body" id="signup-card-body">
<form action="/register" method="POST">
<h3 class="d-flex justify-content-center">SIGN UP</h3>
<div class="form-group">
<input type="text" class="form-control form-control-lg" id="username" name="username" placeholder="Username">
</div>
<div class="form-group">
<input type="email" class="form-control" id="email" name="email" placeholder="Email">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-lg" id="inputPassword" name="inputPassword" placeholder="Password">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-lg" id="confirminputPassword" name="confirminputPassword" placeholder="Confirm Password">
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1" name="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">I agree</label>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">Submit</button>
</div>
</form>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
my app.js looks like this
var express = require("express");
var app = express();
var mongoose = require("mongoose");
var passport = require("passport"),
localStrategy = require("passport-local");
const User = require("./models/User");
var expressSession = require("express-session");
mongoose.connect('mongodb://localhost/users', {useNewUrlParser: true, useUnifiedTopology: true}).catch(function(reason){
console.log('Unable to connect to the mongodb instance. Error: ', reason);
});
app.set('view engine', 'ejs');
var bod = require("body-parser");
app.use(bod.urlencoded({extended:true}));
app.use(passport.initialize());
app.use(passport.session());
app.use(expressSession({
secret:"the key",
resave:false,
saveUninitialized:false
}));
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(express.static(__dirname + '/resources'));
/*
var usersSchema = new mongoose.Schema({
username:String,
password:String,
email:String
});
var user = mongoose.model("User",usersSchema);
*/
app.get("/", function(req, res) {
res.render("home");
});
app.get("/home", function(req, res) {
res.render("home");
});
//problem method
app.post("/register",function(req,res){
var userName = req.body.username;
var inputPassword = req.body.inputPassword;
var email = req.body.email;
var exampleCheck1 = req.body.exampleCheck1;
var confirminputPassword = req.body.confirminputPassword;
if(exampleCheck1==="on"){
if(inputPassword===confirminputPassword){
User.register( new User({username:userName}),inputPassword, function(err,user){
console.log(user);
// here I tried to cast the returned object into User.js object but it didn't work
// user = new User();
if(err){
console.log(err);
return res.render("signup");
}
//I am trying to update returned object with email, I am not sure if this is the correct way to do it, would welcome suggestions. but at this point the user.findOne is not a function error is thrown.
user.findOne({username:userName},function(err,user){
user.email = email;
user.save();
console.log(user);
});
passport.authenticate("local")(req,res,function(){
res.render("bioform",{userName:userName});
});
});
}else{
console.log("Passwords doesn't match!!!");
res.render("signup");
}
}else{
console.log("Agree to Terms!!!");
res.render("signup");
}
});
//
app.get("/signup", function(req, res) {
res.render("signup");
});
app.listen(3000,function(){
console.log("Server started");
});
You are trying to call findOne in the object returned by the call to register from passport-local-moongoose.
Instead, you should call it through the User model:
const User = require("./models/User");
[...]
User.register(new User({ username: userName }), inputPassword, function(err, user) {
[...]
// Use User model instead of the object returned in User.register.
User.findOne({ username: userName }, function(err, user) {
// Your logic here.
});
});
Related
using the express-flash package together with passportjs, and I want to flash messages to a user.
App.js
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const sessions = require('express-session');
const passport = require('passport');
const passportInit = require('./config/passport');
const sessionStoreSQL = require('express-mysql-session')(sessions);
const logger = require('morgan');
const flash = require('express-flash');
const favicon = require('serve-favicon');
const app = express();
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
app.use(logger('dev'));
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')))
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.use(cookieParser('keyboard cat'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(sessions({
genid: (req) => {
return uuid.v1();
},
secret:'-----',
resave:false,
saveUninitialized:false,
store:sessionStore
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(flash());
passportInit(passport,userModel);
require('./routes/index')(app,passport);
require('./server/API/get')(app);
I use a custom middle ware function to map my errors to, so I can access all of them in my templates
app.get('*', function(req,res,next){
res.locals.successes = req.flash('success');
res.locals.errors = req.flash('error');
res.locals.warnings = req.flash('warning');
next();
});
Passport.js
passport.use('local-login', new localStategy({passReqToCallback:true},function (req,username,password,done){
const isValidPassword = (userpass,password) => {
return bcrypt.compareSync(password,userpass);
}
Model.findOne({
where:{
'username':username,
},
}).then(function(user){
if(!user) return done(null,false,req.flash('warning','User does not exist'));
if(!isValidPassword(user.password,password)) return done(null,false,req.flash('error','Incorrect password'));
return done(null, user);
}).catch(err => console.log(err));
}))
Here is where I flash messages to the user.
Then I have a EJS component that handles al my alerts
Alerts.ejs
<% if (errors.lenght > 0) { %>
<div class='header alert alert-danger alert-dismissible'>
<strong><i class="fa fa-exclamation-circle"></i> ERROR:</strong> <%- errors.message %>
<i class='fa fa-times'></i>
</div>
<% } %>
<% if (successes.lenght > 0 ) { %>
<div class='header alert alert-success alert-dismissible'>
<strong><i class="fa fa-check-circle"></i> Success!</strong> <%- successes.message %>
<i class='fa fa-times'></i>
</div>
<% } %>
<% if (warnings.lenght > 0) { %>
<div class='header alert alert-warning alert-dismissible'>
<strong><i class="fa fa-check-circle"></i> Warning:</strong> <%- warnings.message %>
<i class='fa fa-times'></i>
</div>
<% } %>
This is then included in my templates e.g login and register like so
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><%= title %> </title>
<% include components/header.ejs %>
</head>
<body>
<% include components/navbar.ejs %>
<div class="container-fluid">
<% include components/alerts.ejs %>
<div class="row justify-content-center">
<div class="col-auto">
<form method="POST" action="/login">
<div class="form-group">
<label for="login-username">Username</label>
<input name="username" type="text" class="form-control" id="loginUsername"
aria-describedby="emailHelp" placeholder="Enter Username">
</div>
<div class="form-group">
<label for="login-password">Password</label>
<input name="password" type="password" class="form-control" id="loginPassword"
placeholder="Password">
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</body>
<% include components/scripts.ejs %>
</html>
Routes.js
/* eslint-disable no-unused-vars */
module.exports = function (app,passport) {
app.get('/', async function (req, res) {
res.render('index', {title:'Home'});
});
app.post('/',function (req,res) {
})
app.get('/cryptofolio/:username',isAuthenticated, function(req,res) {
res.render('cryptofolio', {title:'Cryptofolio'});
})
app.post('/portfolio',function(req,res){
})
app.get('/login',function(req,res){
res.render('login',{title:'Login'});
});
app.post('/login',passport.authenticate('local-login',{successRedirect: '/',failureRedirect:'/login',failureFlash:true}));
app.get('/register',function (req,res){
res.render('register',{title:'Register'});
})
app.post('/register',passport.authenticate('local-register',{successRedirect: '/',failureRedirect:'/register',failureFlash:true}));
app.get('/logout',function (req,res) {
req.logout();
res.redirect('/');
})
function isAuthenticated(req,res,next){
if (req.isAuthenticated()){
return next();
}
res.redirect('/login');
}
};
But when I input wrong information no errors are being flashed like they should.D
i think the check inside the template is returning false, as it needs to be checking for length not lenght
I am trying to develop a small project where I am using passport js for authentication, I am facing challenges in passport.authenticate method in both login and signup pages, it doesn't goes inside the method and does not redirect or render desired destination.
home.ejs file
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css2?family=Mitr:wght#500&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/biodata.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<a class="navbar-brand justify-content-around" id="navbar-home" href="/">Home</a>
<div class="ml-auto" id="navbar-joint">
<a class="navbar-brand" href="/signup">Sign Up</a>
<a class="navbar-brand" href="/logout">Logout</a>
</div>
</nav>
<div class="card">
<div class="card-body">
<form action="/bioform" method="POST">
<h2 class="d-flex justify-content-center">LOGIN</h2>
<div class="form-group">
<input type="text" class="form-control form-control-lg" id="username" name="username" placeholder="Username">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-lg" id="inputPassword" name="inputPassword" placeholder="Password">
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">Submit</button>
</div>
New User
</form>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
signup.ejs file
<!DOCTYPE html>
<html>
<head>
<title></title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<link href="https://fonts.googleapis.com/css2?family=Mitr:wght#500&display=swap" rel="stylesheet">
<link rel="stylesheet" type="text/css" href="css/biodata.css">
</head>
<body>
<nav class="navbar navbar-expand-lg navbar-dark bg-primary">
<a class="navbar-brand justify-content-around" id="navbar-home" href="/">Home</a>
<div class="ml-auto" id="navbar-joint">
<a class="navbar-brand" href="/signup">Sign Up</a>
<a class="navbar-brand" href="/logout">Logout</a>
</div>
</nav>
<div class="card" id="signup-card">
<div class="card-body" id="signup-card-body">
<form action="/register" method="POST">
<h3 class="d-flex justify-content-center">SIGN UP</h3>
<div class="form-group">
<input type="text" class="form-control form-control-lg" id="username" name="username" placeholder="Username">
</div>
<div class="form-group">
<input type="email" class="form-control" id="email" name="email" placeholder="Email">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-lg" id="inputPassword" name="inputPassword" placeholder="Password">
</div>
<div class="form-group">
<input type="password" class="form-control form-control-lg" id="confirminputPassword" name="confirminputPassword" placeholder="Confirm Password">
</div>
<div class="form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck1" name="exampleCheck1">
<label class="form-check-label" for="exampleCheck1">I agree</label>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary btn-lg btn-block">Submit</button>
</div>
</form>
</div>
</div>
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
User.js file
var mongoose = require("mongoose");
var passportLocalMongoose = require("passport-local-mongoose");
var usersSchema = new mongoose.Schema({
username:String,
password:String,
email:String
});
usersSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User",usersSchema);
app.js file
var express = require("express");
var app = express();
var mongoose = require("mongoose");
var passport = require("passport"),
localStrategy = require("passport-local");
const User = require("./models/User");
var expressSession = require("express-session");
mongoose.connect('mongodb://localhost/users', {useNewUrlParser: true, useUnifiedTopology: true}).catch(function(reason){
console.log('Unable to connect to the mongodb instance. Error: ', reason);
});
app.set('view engine', 'ejs');
var bod = require("body-parser");
app.use(bod.urlencoded({extended:true}));
app.use(passport.initialize());
app.use(passport.session());
app.use(expressSession({
secret:"Test Key",
resave:false,
saveUninitialized:false
}));
passport.use(new localStrategy(User.authenticate()));
passport.serializeUser(User.serializeUser());
passport.deserializeUser(User.deserializeUser());
app.use(express.static(__dirname + '/resources'));
app.get("/", function(req, res) {
res.render("home");
});
app.get("/home", function(req, res) {
res.render("home");
});
app.post("/bioform",passport.authenticate("local",{
failureRedirect:"/home"
}),function(req,res){
console.log(req.body);
res.render('bioform', {userName:req.body.username})
});
app.post("/register",function(req,res){
var userName = req.body.username;
var inputPassword = req.body.inputPassword;
var email = req.body.email;
var exampleCheck1 = req.body.exampleCheck1;
var confirminputPassword = req.body.confirminputPassword;
if(exampleCheck1==="on"){
if(inputPassword===confirminputPassword){
User.register( new User({username:userName,email:email}),inputPassword, function(err,user){
console.log("Inside first");
if(err){
console.log(err);
return res.render("signup");
}
passport.authenticate("local",function(err,user,info){
//the control doesn't reach this point.
console.log("Inside second");
if(err){
return console.log(err);
}
if (!user) { return res.redirect('/home'); }
req.logIn(user, function(err) {
if (err) { console.log(err); }
return res.redirect('bioform', {userName:userName});
});
});
/*
//this startegy didn't work either
passport.authenticate("local")(req,res,function(){
console.log("Reached here ");
res.render("bioform",{userName:userName});
});
*/
});
}else{
console.log("Passwords doesn't match!!!");
res.render("signup");
}
}else{
console.log("Agree to Terms!!!");
res.render("signup");
}
});
function isLoggedIn(req,resp,next){
if(req.isAuthenticated()){
return next();
}else{
res.redirect("/home");
}
}
app.get("/signup", function(req, res) {
res.render("signup");
});
app.listen(3000,function(){
console.log("Server started");
});
passport.authenticate() seems to be the problem here, either it will display a Bad Request message or just does nothing and tries to load the requested page without success. Will deeply appreciate your help in this issue. Thanks
Update: Here is what worked for me, I wrote a new post method
app.post("/register",function(req,res){
var username = req.body.username;
var password = req.body.password;
var email = req.body.email;
User.register({username:username,email:email},password,function(err,user){
console.log("post here")
if(err){
return console.log(err);
}
if(!user){
return res.redirect('/signup');
}
req.login(user, function(err){
if(err){
return console.log(err);
}
console.log("post");
res.render("bioform",{currentUser:req.user});
});
});
});
Reverse the order of your middleware - your express sessions should be declared before passport sessions, otherwise passport will be unable to use them:
app.use(expressSession({
secret:"Test Key",
resave:false,
saveUninitialized:false
}));
app.use(passport.initialize());
app.use(passport.session());
You have some other issues as well - passport.authenticate() should not be called in your /register route. You are currently calling req.login() inside of passport.authenticate when it should be called on its own; see this StackOverflow answer as well as Passport Login Docs. You will want to do something like this:
User.register(/* ... */, function(err, user) {
if (err) {
return res.redirect('/signup');
} else {
req.login(user, function(err) {
if (!err) {
return res.redirect('/home');
} else {
// handle error
}
});
}
});
Take a closer look at passport-local-mongoose which has some simplified configuration starting with their 0.2.1 version, passport docs, and this Express LocalStrategy example. Manually register a user in your Mongoose database and test the authentication strategy with that user. Once you have that working you can move on to your /register route, assuming you are attempting to auto-login after registration
I have created a form for signing up a user. I want to fetch the values from the form using body-parser but I am not able to do so. While prinnting in the console it gives undefined printed. I don't get what am I doing wrong. I even tried using postman but it doesn't work. Here is my code:
var express = require('express'),
app = express(),
mongoose = require('mongoose'),
bodyParser = require('body-parser'),
passport = require('passport'),
LocalStrategy = require('passport-local'),
methodOverride = require('method-override'),
flash = require('flash'),
session = require('express-session');
app.get("/about", function(req, res) {
res.render("about");
});
app.get("/register", function(req, res) {
res.render("register");
});
app.post("/register", function(req, res) {
var firstName = req.body.firstName,
lastName = req.body.lastName,
username = req.body.username,
email = req.body.email;
var newUser = new User({
firstName: firstName,
lastName: lastName,
username: username,
email: email
});
console.log(firstName + " " + req.body.password + " " + req.body.c_password);
User.register(newUser, req.body.password, function(err, user) {
if(err) {
return res.render("register", {'error': err.message});
}
passport.authenticate('local')(req, res, function() {
req.flash('success', 'Welcome ' + user.username);
res.redirect('/home');
})
})
});
var port = process.env.PORT || 3000;
app.listen(port, function() {
console.log("Service Running");
});
And here is my form
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<title>Hotel Site</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css" integrity="sha384-Vkoo8x4CGsO3+Hhxv8T/Q5PaXtkKtu6ug5TOeNV6gBiFeWPGFN9MuhOf23Q9Ifjh" crossorigin="anonymous">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css" integrity="sha384-REHJTs1r2ErKBuJB0fCK99gCYsVjwxHrSU0N7I1zl9vZbggVJXRMsv/sLlOAGb4M" crossorigin="anonymous">
<link rel="icon" href="https://www.svgrepo.com/show/12002/hotel.svg" type="image/x-icon">
<link rel="stylesheet" href="/stylesheets/style.css">
<script src="https://code.jquery.com/jquery-3.4.1.min.js" integrity="sha256-CSXorXvZcTkaix6Yvo6HppcZGetbYMGWSFlBw8HfCJo=" crossorigin="anonymous"></script>
</head>
<body>
<div class="container" style="margin-bottom: 4.5rem;">
<h1 style="text-align: center; margin-top: 7rem; margin-bottom: 20px">Sign Up</h1>
<div class="col-lg-6" style="margin: auto;">
<form action="/register" method="POST" enctype="multipart/form-data">
<div class="form-row">
<div class="form-group col-6">
<input class="form-control" type="text" name="firstName" placeholder="First Name" required>
</div>
<div class="form-group col-6">
<input class="form-control" type="text" name="lastName" placeholder="Last Name" required>
</div>
</div>
<div class="form-group">
<input class="form-control" type="text" name="username" placeholder="Username" required>
</div>
<!-- <div class="form-group">
<input class="form-control" type="email" name="email" placeholder="E-mail" required>
</div> -->
<div class="form-group">
<input class="form-control" type="password" name="password" placeholder="Password" required>
</div>
<div class="form-group">
<input class="form-control" type="password" name="c_password" placeholder="Confirm Password" required>
</div>
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Submit</button>
</div>
</form>
Go Back
</div>
</div>
</body>
Help very much appreciated!!!
Express uses middleware, which are functions that have access to incoming requests. Requests can be modified etc. Simply put middleware can be used for lots of things.
You have not setup bodyParser as middleware so it will not work. This can be done by:
app.use(bodyParser.urlencoded({extended: false})) for form data
app.use(bodyParser.json()) for incoming JSON before your routes.
Here's the ExpressJs guide on middle: https://expressjs.com/en/guide/writing-middleware.html
You've successfully imported body-parser into your app, but you've failed to use it. Add the following code before you use your routes.
app.use(bodyParser.urlencoded({ extended: false }))
I hope it was helpful.
When I try and use <% include ./partials/messages %>, <%= include ./partials/messages %>, or even <%= include ./partials/messages { %>, among my file that contains
<!-- REGISTER.EJS -->
<div class="row mt-5">
<div class="col-md-6 m-auto">
<div class="card card-body">
<h1 class="text-center mb-3">
<i class="fas fa-user-plus"></i> Register
</h1>
<% include ./partials/messages %>
<form action="/users/register" method="POST">
<div class="form-group">
<label for="name">Name</label>
<input
type="name"
id="name"
name="name"
class="form-control"
placeholder="Enter Name"
value="<%= typeof name != 'undefined' ? name : '' %>"
/>
</div>
<div class="form-group">
<label for="email">Email</label>
<input
type="email"
id="email"
name="email"
class="form-control"
placeholder="Enter Email"
value="<%= typeof email != 'undefined' ? email : '' %>"
/>
</div>
<div class="form-group">
<label for="password">Password</label>
<input
type="password"
id="password"
name="password"
class="form-control"
placeholder="Create Password"
value="<%= typeof password != 'undefined' ? password : '' %>"
/>
</div>
<div class="form-group">
<label for="password2">Confirm Password</label>
<input
type="password"
id="password2"
name="password2"
class="form-control"
placeholder="Confirm Password"
value="<%= typeof password2 != 'undefined' ? password2 : '' %>"
/>
</div>
<button type="submit" class="btn btn-primary btn-block">
Register
</button>
</form>
<p class="lead mt-4">Have An Account? Login</p>
</div>
</div>
</div>
I receive the follow error "SyntaxError: Unexpected token / in .... while compiling ejs". I am using this to add immediate feedback to users who try and register such as "password invalid" or "email already exist." I believe I have my messages.ejs file set up correctly as such:
<% if(typeof errors != 'undefined') { %>
<% errors.forEach(function(error) { %>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<%= error.msg %>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<%}); %>
<% } %>
<% if(success_msg != '') { %>
<div class="alert alert-success alert-dismissible fade show" role="alert">
<%= success_msg %>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<% } %>
<% if(error_msg != '') { %>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<%= error_msg %>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<% } %>
<% if(error != '') { %>
<div class="alert alert-warning alert-dismissible fade show" role="alert">
<%= error %>
<button type="button" class="close" data-dismiss="alert" aria-label="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<% } %>
I am pretty lost. I believe I have added the const example = require('example'); files correctly. My app.js file looks like
const express = require('express');
const expressLayouts = require('express-ejs-layouts');
const mongoose = require('mongoose');
const flash = require('connect-flash');
const session = require('express-session');
const passport = require('passport');
const app = express();
// Passport Config
require('./config/passport')(passport);
// DB Config
const db = require('./config/keys').mongoURI;
// Connect to MongoDB
mongoose
.connect(
db,
{ useNewUrlParser: true }
)
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
app.use(express.static( 'public' ));
// EJS
app.use(expressLayouts);
app.set('view engine', 'ejs');
// Bodyparser
app.use(express.urlencoded({ extended: false }));
// Express Session
app.use(session({
secret: 'secret',
resave: true,
saveUninitialized: true
}))
// Passport Middleware
app.use(passport.initialize());
app.use(passport.session());
// Connect Flash
app.use(flash());
// Global Variables
app.use((req, res, next) => {
res.locals.success_msg = req.flash('success_msg');
res.locals.error_msg = req.flash('error_msg');
res.locals.error = req.flash('error');
next();
});
// Routes
app.use('/', require('./routes/index'));
app.use('/users', require('./routes/users'));
const PORT = process.env.PORT || 5000;
app.listen(PORT, console.log(`Server started on port ${PORT}`));
My file structure looks like:
>config
auth.js
keys.js
passport.js
>models
User.js
>node_modules
>public
>routes
index.js
users.js
>views
>partials
messages.ejs
dashboard.ejs
layout.ejs
login.ejs
register.ejs
welcome.ejs
.gitignore
app.js
package-lock.json
package.json
README.md
Does anyone have any ideas?
Error message looks like this:
SyntaxError: Unexpected token / in C:\Users\jreed\Desktop\appproject\views\register.ejs while compiling ejs
If the above error is not helpful, you may want to try EJS-Lint:
https://github.com/RyanZim/EJS-Lint
Or, if you meant to create an async function, pass `async: true` as an option.
at new Function (<anonymous>)
at Template.compile (C:\Users\jreed\Desktop\appproject\node_modules\ejs\lib\ejs.js:626:12)
at Object.compile (C:\Users\jreed\Desktop\appproject\node_modules\ejs\lib\ejs.js:366:16)
at handleCache (C:\Users\jreed\Desktop\appproject\node_modules\ejs\lib\ejs.js:215:18)
at tryHandleCache (C:\Users\jreed\Desktop\appproject\node_modules\ejs\lib\ejs.js:254:16)
at View.exports.renderFile [as engine] (C:\Users\jreed\Desktop\appproject\node_modules\ejs\lib\ejs.js:459:10)
at View.render (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\view.js:135:8)
at tryRender (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\application.js:640:10)
at Function.render (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\application.js:592:3)
at ServerResponse.render (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\response.js:1012:7)
at ServerResponse.res.render (C:\Users\jreed\Desktop\appproject\node_modules\express-ejs-layouts\lib\express-layouts.js:77:18)
at router.get (C:\Users\jreed\Desktop\appproject\routes\users.js:13:43)
at Layer.handle [as handle_request] (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\router\layer.js:95:5)
at next (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\router\route.js:137:13)
at Route.dispatch (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\router\route.js:112:3)
at Layer.handle [as handle_request] (C:\Users\jreed\Desktop\appproject\node_modules\express\lib\router\layer.js:95:5)
Here is my users.js file:
<!-- USERS.JS -->
const express = require('express');
const router = express.Router();
const bcrypt = require('bcryptjs');
const passport = require('passport');
// User Model
const User = require('../models/User');
// Login Page
router.get('/login', (req, res) => res.render('login'));
// Register Page
router.get('/register', (req, res) => res.render('register'));
// Register Handle
router.post('/register', (req, res) => {
const {name, email, password, password2} = req.body;
let errors = [];
// Check required fields
if (!name || !email || !password || !password2) {
errors.push({msg: 'Please enter all fields'});
}
// Check passwords match
if (password != password2) {
errors.push({msg: 'Passwords do not match'});
}
// Check password length
if (password.length < 6) {
errors.push({msg: 'Password must be at least 6 characters'});
}
if (errors.length > 0) {
res.render('register', {errors, name, email, password, password2});
} else { // Validation passed
User.findOne({email: email}).then(user => {
if (user) { // User Exists
errors.push({msg: 'Email is already registered'})
res.render('register', {errors, name, email, password, password2});
} else {
const newUser = new User({
name,
email,
password
});
// Hash Password
bcrypt.genSalt(10, (err, salt) => bcrypt.hash(newUser.password, salt, (err, hash) => {
if(err) throw err;
// Set password to hashed
newUser.password = hash;
// Save user
newUser.save()
.then(user => {
req.flash('success_msg', 'Congratulations! You are now registered and can log in.');
res.redirect('/users/login');
})
.catch(err => console.log(err));
}))
}
});
}
});
// Login Handle
router.post('/login', (req, res, next) => {
passport.authenticate('local',{
successRedirect: '/dashboard',
failureRedirect: '/users/login',
failureFlash: true
})(req, res, next);
});
// Logout Handle
router.get('/logout', (req, res) => {
req.logout();
req.flash('success_msg', 'You are logged out.');
res.redirect('/users/login');
});
module.exports = router;
I think I solved it!
<%- include ('partials/messages') %>
I have no idea why that is the only method that works though, trying to research it now.
I am trying to create an Angular app that sends an email using Nodemailer.
I am able to create a standard Angular app that contains a form. I then want to pass data from this form to a .JS file which will then use Nodemailer to send that data to an email address.
All the examples I have found so far for Nodemailer use View engines such as handlebars, etc. but I want to use my angular app's HTML rather than a view engine.
How do I pass data from my Angular app's form to a .JS file to send an email without having to use a View Engine?
Below is what I have so far in my Angular app:
<form method="POST" action="send">
<p>
<label>Name</label>
<input type="text" name="name">
</p>
<p>
<label>Company</label>
<input type="text" name="company">
</p>
<p>
<label>Email Address</label>
<input type="email" name="email">
</p>
<p>
<label>Phone Number</label>
<input type="text" name="phone">
</p>
<p class="full">
<label>Message</label>
<textarea name="message" rows="5"></textarea>
</p>
<p class="full">
<button type="submit">Submit</button>
</p>
</form>
And this is what I have in the tutorial code:
APP.JS
const express = require("express");
const bodyParser = require("body-parser");
const exphbs = require("express-handlebars");
const path = require("path");
const nodemailer = require("nodemailer");
const app = express();
// View engine setup
app.engine("handlebars", exphbs());
app.set("view engine", "handlebars");
// Static folder
app.use("/public", express.static(path.join(__dirname, "public")));
// Body Parser Middleware
app.use(bodyParser.urlencoded({ extended: false }));
app.use(bodyParser.json());
app.get("/", (req, res) => {
res.render("contact");
});
app.post("/send", async (req, res) => {
const output = `
<p>You have a new contact request</p>
<h3>Contact Details</h3>
<ul>
<li>Name: ${req.body.name}</li>
<li>Company: ${req.body.company}</li>
<li>Email: ${req.body.email}</li>
<li>Phone: ${req.body.phone}</li>
</ul>
<h3>Message</h3>
<p>${req.body.message}</p>
`;
try{
var transporter = nodemailer.createTransport({
service: "gmail",
auth: {
user: "myemail#mail.com",
pass: "myPassword"
},
tls: {
rejectUnauthorized: false
}
});
}
catch(err){
console.log(err.message);
}
const mailOptions = {
from: "myemail#mail.com", // sender address
to: "myemail#mail.com", // list of receivers
subject: "Test email", // Subject line
html: output // plain text body
};
let info = await transporter.sendMail(mailOptions);
console.log("Message sent: %s", info.messageId);
console.log("Preview URL: %s", nodemailer.getTestMessageUrl(info));
res.render("contact", { msg: "Email has been sent" });
});
app.listen(3000, () => console.log("Server started..."));
CONTACT.HANDLEBARS
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Acme Web Design</title>
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/animate.css/3.5.2/animate.css" />
<link rel="stylesheet" href="public/css/style.css">
</head>
<body>
<div class="container">
<h1 class="brand"><span>Acme</span> Web Design</h1>
<div class="wrapper animated bounceInLeft">
<div class="company-info">
<h3>Acme Web Design</h3>
<ul>
<li><i class="fa fa-road"></i> 44 Something st</li>
<li><i class="fa fa-phone"></i> (555) 555-5555</li>
<li><i class="fa fa-envelope"></i> test#acme.test</li>
</ul>
</div>
<div class="contact">
<h3>Email Us</h3>
{{ msg }}
<form method="POST" action="send">
<p>
<label>Name</label>
<input type="text" name="name">
</p>
<p>
<label>Company</label>
<input type="text" name="company">
</p>
<p>
<label>Email Address</label>
<input type="email" name="email">
</p>
<p>
<label>Phone Number</label>
<input type="text" name="phone">
</p>
<p class="full">
<label>Message</label>
<textarea name="message" rows="5"></textarea>
</p>
<p class="full">
<button type="submit">Submit</button>
</p>
</form>
</div>
</div>
</div>
</body>
I can post further code if necessary.
So I managed to pass data from the form (root.component.html) to the server (app.js), capture it & print it to the console via the POST method.
Code is below:
root.component.html:
<form #emailForm="ngForm">
<div class="col-md-6">
<div>
<label for="username">
Username
</label>
<input
type="text"
id="username"
[(ngModel)]="username"
required
name="username"
#txtUsername="ngModel"
/>
</div>
<div>
<label for="message">Message</label>
<textarea
id="message"
placeholder="Please enter your message here"
[(ngModel)]="message"
required
name="message"
#txtMessage="ngModel"
></textarea>
</div>
<button
axis-button
class="axis-btn"
title="Submit"
data-kind="primary"
(click)="sendMessage()"
[disabled]="emailForm.invalid"
>
Send Email
</button>
</div>
</form>
root.component.ts:
export class RootComponent implements OnInit {
constructor(private rootService: RootService) {}
username: string;
message: string;
ngOnInit() {
this.getData();
}
getData() {
this.rootService.getAPIData().subscribe(
response => {
console.log('response from GET API is ', response);
},
error => {
console.log('error is ', error);
}
);
}
postData(name: string, message: string) {
this.rootService.postAPIData(name, message).subscribe(
response => {
console.log('response from POST API is ', response);
},
error => {
console.log('error during post is ', error);
}
);
}
sendMessage() {
this.postData(this.username, this.message);
}
}
root.service.ts:
export class RootService {
constructor(private http: HttpClient) {}
getAPIData() {
return this.http.get('https://jsonplaceholder.typicode.com/users');
}
postAPIData(name: string, message: string) {
return this.http.post('/api/postData', {
name: name,
message: message
});
}
}
app.js:
const express = require('express')
const app = express()
const bodyParser = require('body-parser')
app.get('/', (req, res) => {
res.send('Welcome to Node API')
})
app.get('/getData', (req, res) => {
res.json({'message': 'Hello World'})
})
app.post('/postData', bodyParser.json(), (req, res) => {
res.json(req.body) // Prints the request body to the browser console
const output = `Name: ${req.body.name}......Email: ${req.body.message}`;
console.log(output);
})
app.listen(3000, () => console.log('Example app listening on port 3000!'))