I am using ejs engine instead of pug. When I click register button, I got errors undefined in my register view. There was only little chance that I can get the validation messages, but when I click other links and then back to the register page, the same error occurred again.
Here's my code:
app.js
//app.js code
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var session = require('express-session');
var passport = require('passport');
var expressValidator = require('express-validator');
var LocalStrategy = require('passport-local').Strategy;
var multer = require('multer');
var upload = multer({dest: './uploads'});
var flash = require('connect-flash');
var mongo = require('mongodb');
var mongoose = require('mongoose');
var db = mongoose.connection;
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
// Handle Sessions
app.use(session({
secret:'secret',
saveUninitialized: true,
resave: true
}));
// Passport
app.use(passport.initialize());
app.use(passport.session());
// Validator
app.use(expressValidator({
errorFormatter: function(param, msg, value) {
var namespace = param.split('.')
, root = namespace.shift()
, formParam = root;
while(namespace.length) {
formParam += '[' + namespace.shift() + ']';
}
return {
param : formParam,
msg : msg,
value : value
};
}
}));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(flash());
app.use(function (req, res, next) {
res.locals.messages = require('express-messages')(req, res);
next();
});
app.use('/', routes);
app.use('/users', users);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
user.js
//user.js code
var express = require('express');
var router = express.Router();
var multer = require('multer');
var upload = multer({dest: 'uploads/'});
/* GET users listing. */
router.get('/', function(req, res, next) {
res.render('members', {page_name : 'members'});
});
router.get('/register', function(req, res, next) {
res.render('register', { page_name: 'register' });
});
router.post('/register', upload.single('profileimage'), function(req, res) {
var name = req.body.name;
var username = req.body.username;
var email = req.body.email;
var password = req.body.password;
var password2 = req.body.password2;
if(req.file){
console.log("uploading file");
var profileimage = req.file.filename;
} else{
var profileimage = "noimage.jpg";
}
req.checkBody('name','Name field is required').notEmpty();
req.checkBody('email','Email field is required').notEmpty();
req.checkBody('email','Email is not valid').isEmail();
req.checkBody('username','Username field is required').notEmpty();
req.checkBody('password','Password field is required').notEmpty();
req.checkBody('password2','Passwords do not match').equals(req.body.password);
// Check Errors
errors = req.validationErrors();
//var errors = JSON.stringify(req.validationErrors());
if(errors){
console.log("errors: " + errors);
res.render('register', {errors: errors});
} else{
console.log('No Errors');
res.render("/");
}
});
router.get('/login', function(req, res, next) {
res.render('login', { page_name: 'login' });
});
module.exports = router;
register.ejs
//register.ejs code
<%include layout%>
<div class="container">
<% if(errors){errors.forEach(function(error){%>
<div class="alert alert-danger"><%= error.msg %></div>
<% })} %>
<h4>register</h4>
<form action="/users/register" method="post" enctype="multipart/form-data">
<div class="form-group">
<label for="exampleFormControlInput1">Name</label>
<input type="text" class="form-control" name="name" placeholder="John">
</div>
<div class="form-group">
<label for="exampleFormControlInput1">Email address</label>
<input type="email" class="form-control" name="email" placeholder="name#example.com">
</div>
<div class="form-group">
<label for="exampleFormControlInput1">Username</label>
<input type="text" class="form-control" name="username" placeholder="username">
</div>
<div class="form-group">
<label for="exampleFormControlInput1">Password</label>
<input type="password" class="form-control" name="password" placeholder="password">
</div>
<div class="form-group">
<label for="exampleFormControlInput1">Confirm Password</label>
<input type="password" class="form-control" name="password2" placeholder="confirm password">
</div>
<div class="form-group">
<label for="exampleFormControlInput1">Profile Image</label>
<input type="file" class="form-control" name="profileimage" >
</div>
<button type="submit" class="btn btn-primary">Register</button>
</form>
</div>
Error
ReferenceError: /Users/duanzhen/Documents/web_workspace/12_projects/node_auth/views/register.ejs:5
3| <div class="container">
4|
>> 5| <% if(errors){errors.forEach(function(error){%>
6|
7| <div class="alert alert-danger"><%= error.msg %></div>
8|
errors is not defined
at eval (eval at compile (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/ejs/lib/ejs.js:549:12), <anonymous>:22:8)
at returnedFn (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/ejs/lib/ejs.js:580:17)
at tryHandleCache (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/ejs/lib/ejs.js:223:34)
at View.exports.renderFile [as engine] (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/ejs/lib/ejs.js:437:10)
at View.render (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/view.js:127:8)
at tryRender (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/application.js:640:10)
at Function.render (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/application.js:592:3)
at ServerResponse.render (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/response.js:971:7)
at /Users/duanzhen/Documents/web_workspace/12_projects/node_auth/routes/users.js:12:9
at Layer.handle [as handle_request] (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/router/layer.js:95:5)
at next (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/router/route.js:137:13)
at Route.dispatch (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/router/route.js:112:3)
at Layer.handle [as handle_request] (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/router/layer.js:95:5)
at /Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/router/index.js:281:22
at Function.process_params (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/router/index.js:335:12)
at next (/Users/duanzhen/Documents/web_workspace/12_projects/node_auth/node_modules/express/lib/router/index.js:275:10)
That's because you are trying to access a non existing variable, note that errors variable is only generated and returned to the view if there where validation errors in your form, otherwise it's undefined, that's why in your condition you have to check if errors variable exists, Like this:
if (typeof errors !== 'undefined') { ...
Note: The typeof operator returns a string: the type of the variable, if the variable is not declared it will return undefined
npm uninstall express-validator --save
npm install express-validator#2.20.8 --save
Have a look at my code, it is working
in file 'index.js'
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Home' ,
success:false,
errors:req.session.errors ,
success:req.session.success });
req.session.errors=null;
});
//////////////checking the form validation
router.post('/submit', function(req, res, next) {
req.check('email','Invalid Email Address!!!!!').isEmail();// it's an built in exprexx validator, but we can also write our own
req.check('password','Pssword lenght must be greater than 5!! ').isLength({min:5});
req.check('password','Password is not confirmed!!').equals(req.body.confirmpassword);
var errors=req.validationErrors();
if (errors){
req.session.errors=errors;
req.session.success=false;
}
else{
req.session.success=true;
}
res.redirect('/');
});
module.exports = router;
in file 'index.ejs'
<h1>Fill the form below..</h1><h1></h1>
<h1>It's an example of Express Validator..</h1><h1></h1>
<% if (success) { %>
<h1><span class="badge badge-success">Congrats!! Form validation is secceded!!!</span></h1>
<% } else { %>
<% if (errors) { %>
<div class="alert alert-danger" role="alert">
<h1><span class="badge badge-danger">Errors Occured!! </span></h1>
<% errors.forEach(function(errors) { %>
<h5><%= errors.msg %> </h5>
<% }); %>
</div>
<% } else { %>
<form action="/submit" method="POST">
<div class="form-row">
<div class="col-7">
<input type="email" class="form-control" id="email" placeholder="email" name="email">
</div>
<div class="col">
<input type="password" class="form-control" id="password" placeholder="password" name="password">
</div>
<div class="col">
<input type="password" class="form-control" id="confirmpassword" placeholder="confirmpassword" name="confirmpassword">
</div>
</div>
<h1></h1>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
<% } %>
<% } %>
And of course don't forget to add this lines in 'app.js' file:
//adding validator and session
app.use(expressValidator());
app.use(expressSession({secret:'max',saveUninitialized:false,resave:false}));
<% if(locals.errors){locals.errors.forEach(function(error){%>
<div class="alert alert-danger"><%= error.msg %></div>
<% })} %>
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
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 have a form to register users, but post request is not working
I've checked bodyparser, consign includes order, added enctype to form and still do not work
The route is working, cause it calls my controller, but as you can see at console image, it goes to the controller with undefined req, althought url params are defined at devtools
server.js:
const express = require('express');
const consign = require('consign');
const bodyParser = require('body-parser');
const expressValidator = require('express-validator');
const helmet = require('helmet');
const jwt = require('jsonwebtoken');
require('dotenv-safe').load();
const app = express();
app.set('view engine', 'ejs');
app.set('views', './app/paginas');
app.use(express.static('./app/publico/'));
app.use(bodyParser.urlencoded({extended: true}));
app.use(bodyParser.json());
app.use(expressValidator());
consign(/* {cwd: 'app'} */)
.include('config/conectarBD.js')
.then('app/modelos')
.then('app/controles')
.then('app/rotas')
.into(app);
/* consign()
.include('app/rotas')
.then('config/conectarBD.js')
.then('app/modelos')
.then('app/controles')
.into(app); */
console.log('Instância do app criada');
module.exports = app;
form.ejs:
<div class="row" id="form_registro">
<div class="col-sm-6 offset-sm-3 text-center">
<form action="/registrar" method="POST">
<fieldset>
<legend>Registro</legend>
<div class="form-group">
<label for="form-r-email">Nome:</label>
<input type="text" class="form-control" id="nome" name="nome" placeholder="Seu nome">
</div>
<div class="form-group">
<label for="form-r-email">Email:</label>
<input type="email" class="form-control" id="email" name="email"
placeholder="Seu email">
</div>
<div class="form-group">
<label for="form-r-senha">Senha:</label>
<input type="password" class="form-control" id="senha" name="senha"
placeholder="Sua senha">
</div>
<!-- TODO implementar -->
<div class="form-check">
<input type="checkbox" class="form-check-input" id="exampleCheck2">
<label class="form-check-label" for="exampleCheck1">Lembre de mim</label>
</div>
<button type="submit" class="btn btn-success">Registrar</button>
</fieldset>
<div>
Já tem uma conta?
Registrar!
</div>
</form>
</div>
</div>
route login.js:
module.exports = function(application) {
application.get('/login', function(req, res) {
console.log('Rota pegaPaginaLogin');
application.app.controles.login.pegaPaginaLogin(application, req, res);
});
application.post('/admin/logar', function(req, res) {
console.log('Rota /admin/logar');
application.app.controles.login.logaUsuario(application, req, res);
});
application.post('/registrar', function(req, res) {
console.log('Rota registrar');
console.log('req.body >>>' + req.body);
res.status(500).send('testing');
application.app.controles.login.registraUsuario(application, req, res);
});
}
controller registraUsuario:
module.exports.registraUsuario = function (application, req, res) {
console.log('Controller registraUsuario');
console.log('REQ....' + req)
var usuario = req.body;
/** Validação do formulário */
//TODO validar formatos
req.assert('nome', 'Nome é obrigatório').notEmpty();
req.assert('email', 'Email é obrigatório').notEmpty();
req.assert('senha', 'Senha é obrigatório').notEmpty();
var errosValidacao = req.validationErrors();
console.log(errosValidacao);
if (errosValidacao) {
res.render('login', {
validacao: errosValidacao,
usuario: usuario
});
return;
}
/** Conexão com banco */
var conexao = application.config.conectarBD();
var novoUsuario = new application.app.modelos.UsuariosModel(conexao);
novoUsuario.getUsuario(usuario, function (error, result) {
console.log(result);
novoUsuario.novoUsuario(usuario);
});
}
model UsuariosModel:
function UsuariosModel(conexao) {
this._conexao = conexao;
}
/** Se usuário existir, retorna a id_usuario */
UsuariosModel.prototype.getUsuario = function (usuario, callback) {
console.log('Model getUsuario');
this._conexao.query('SELECT id_usuario FROM usuarios WHERE email = "' + usuario.email + ' and senha = "' + usuario.senha + '"');
}
UsuariosModel.prototype.novoUsuario = function (usuario, callback) {
var hoje = Date.now();
this._conexao.query('INSERT INTO usuarios SET ?', usuario, callback);
}
module.exports = function () {
return UsuariosModel;
};
console:
error:
Your server code is not calling response.send.
Replace your code with this to test:
application.post('/registrar', function(req, res) {
console.log('Rota registrar');
console.log('REQ.query....' + req.params.name);
res.status(500).send('testing');
//application.app.controles.login.registraUsuario(application, req, res);
});
In registraUsuario, you need to call send with your response/status code. Yourclient will block until send is called, or a timeout occurs.
I'm having some problems trying to send an email from my contact form. I'm using the module NodeMailer.
I'm using node.js and I don't really understand how it works... but anyway, I have this form:
<form role="form" method="post" action="/" class="contact-form">
<input type="hidden" name="scrollPosition">
<input type="hidden" name="submitted" id="submitted" value="true">
<div class="col-lg-4 col-sm-4" data-scrollreveal="enter left after 0s over 1s" data-sr-init="true" data-sr-complete="true">
<input required="required" type="text" name="name" placeholder="Your Name" class="form-control input-box" value="">
</div>
<div class="col-lg-4 col-sm-4" data-scrollreveal="enter left after 0s over 1s" data-sr-init="true" data-sr-complete="true">
<input required="required" type="email" name="email" placeholder="Your Email" class="form-control input-box" value="">
</div>
<div class="col-lg-4 col-sm-4" data-scrollreveal="enter left after 0s over 1s" data-sr-init="true" data-sr-complete="true">
<input required="required" type="text" name="subject" placeholder="Subject" class="form-control input-box" value="">
</div>
<div class="col-lg-12 col-sm-12" data-scrollreveal="enter right after 0s over 1s" data-sr-init="true" data-sr-complete="true">
<textarea name="message" rows="12" class="form-control textarea-box" placeholder="Your Message"></textarea>
</div>
<button class="btn btn-primary custom-button red-btn" type="submit" data-scrollreveal="enter left after 0s over 1s" data-sr-init="true" data-sr-complete="true">Send Message</button>
</form>
and here's my code in index.js :
app.post('/', function(req, res){
var mailOpts, smtpTrans;
//Setup Nodemailer transport, I chose gmail. Create an application-specific password to avoid problems.
smtpTrans = nodemailer.createTransport('SMTP', {
service: 'Gmail',
auth: {
user: "me#gmail.ca",
pass: "application-specific-password"
}
});
//Mail options
mailOpts = {
from: req.body.name + ' <' + req.body.email + '>', //grab form data from the request body object
to: 'me#gmail.ca',
subject: req.body.subject,
text: req.body.message
};
smtpTrans.sendMail(mailOpts, function (error, response) {
//Email not sent
if (error) {
console.log("Failed");
}
//Yay!! Email sent
else {
console.log("Succes");
}
});
});
But when I try and press the button "Send Message", it just open the page Not Found 404. I don't understand why. I never used node.js before, I'm using it because the guy I'm working with wanted to use it... So I really have no clue.
There's also "app.js", shall I write this code there instead? I'm kinda lost, we're trying to merge 3 wordpress themes in one and we need to convert everything (because wordpress is php...) and I've been trying to implement the contact form for 2 weeks... and it seems like nothing wants to work.
Anyone has an idea? Thanks a lot.
Here I added the app.js :
var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var nodemailer = require('nodemailer');
//var knob = require('jQuery-Knob');
var index = require('./routes/index');
var prices = require('./routes/prices');
var projects_startup = require('./routes/projects_startup');
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'hbs');
// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
//app.use(knob);
app.use('/', index);
app.use('/prices', prices);
app.use('/projects_startup', projects_startup);
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// error handlers
// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: err
});
});
}
// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
res.status(err.status || 500);
res.render('error', {
message: err.message,
error: {}
});
});
module.exports = app;
Thanks again.
OK, I see your app.js file, everything looks good there, the problem could be when you are posting your form, the browser is expecting a POST page at '/', so you should render a success page, or you can just redirect to the original GET page. You should be able to add a line to your success page.
smtpTrans.sendMail(mailOpts, function (error, response) {
//Email not sent
if (error) {
console.log("Failed");
}
//Yay!! Email sent
else {
console.log("Succes");
res.render('successPage')
//or you can do res.redirect('/')
}
});
I am working through Ethan Brown's book "Web Development with Node and Express" and it has been going well until I got to enabling csrf the multipart/form-data upload on the photo upload. I downloaded the full book code from Github, https://github.com/EthanRBrown/web-development-with-node-and-express and that does the same thing, works until csrf is enabled then it errors with:
Error: invalid csrf token
here are the bits of code I think are relevant, /meadowlark.js starting at line 100
app.use(require('cookie-parser')(credentials.cookieSecret));
app.use(require('express-session')({ store: sessionStore,
secret: credentials.cookieSecret,
name: credentials.cookieName,
saveUninitialized: true,
resave: true }));
app.use(express.static(__dirname + '/public'));
app.use(require('body-parser')());
// cross-site request forgery protection
app.use(require('csurf')());
app.use(function(req, res, next){
res.locals._csrfToken = req.csrfToken();
next();
});
// database configuration
var mongoose = require('mongoose');
var options = {
server: {
socketOptions: { keepAlive: 1 }
}
};
Then in /handlers/contest.js
var path = require('path'),
fs = require('fs'),
formidable = require('formidable');
// make sure data directory exists
var dataDir = path.normalize(path.join(__dirname, '..', 'data'));
var vacationPhotoDir = path.join(dataDir, 'vacation-photo');
fs.existsSync(dataDir) || fs.mkdirSync(dataDir);
fs.existsSync(vacationPhotoDir) || fs.mkdirSync(vacationPhotoDir);
exports.vacationPhoto = function(req, res){
var now = new Date();
res.render('contest/vacation-photo', { year: now.getFullYear(), month: now.getMonth() });
};
function saveContestEntry(contestName, email, year, month, photoPath){
// TODO...this will come later
}
exports.vacationPhotoProcessPost = function(req, res){
var form = new formidable.IncomingForm();
form.parse(req, function(err, fields, files){
if(err) return res.redirect(303, '/error');
if(err) {
res.session.flash = {
type: 'danger',
intro: 'Oops!',
message: 'There was an error processing your submission. ' +
'Pelase try again.',
};
return res.redirect(303, '/contest/vacation-photo');
}
var photo = files.photo;
var dir = vacationPhotoDir + '/' + Date.now();
var path = dir + '/' + photo.name;
fs.mkdirSync(dir);
fs.renameSync(photo.path, dir + '/' + photo.name);
saveContestEntry('vacation-photo', fields.email,
req.params.year, req.params.month, path);
req.session.flash = {
type: 'success',
intro: 'Good luck!',
message: 'You have been entered into the contest.',
};
return res.redirect(303, '/contest/vacation-photo/entries');
});
};
exports.vacationPhotoEntries = function(req, res){
res.render('contest/vacation-photo/entries');
};
and the views/contest/vacation-photo.handlebars
<form class="form-horizontal" role="form"
enctype="multipart/form-data" method="POST"
action="/contest/vacation-photo/{{year}}/{{month}}">
<input type="hidden" name="_csrf" value="{{_csrfToken}}">
<div class="form-group">
<label for="fieldName" class="col-sm-2 control-label">Name</label>
<div class="col-sm-4">
<input type="text" class="form-control"
id="fieldName" name="name">
</div>
</div>
<div class="form-group">
<label for="fieldEmail" class="col-sm-2 control-label">Email</label>
<div class="col-sm-4">
<input type="email" class="form-control" required
id="fieldName" name="email">
</div>
</div>
<div class="form-group">
<label for="fieldPhoto" class="col-sm-2 control-label">Vacation photo</label>
<div class="col-sm-4">
<input type="file" class="form-control" required accept="image/*"
id="fieldPhoto" data-url="/upload" name="photo">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-4">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</div>
</form>
What is the proper way to make csrf work?
Thanks,
On vacation-photo GET request, you should send csrf token like below.
exports.vacationPhotoEntries = function(req, res){
res.render('contest/vacation-photo/entries', { _csrfToken: req.csrfToken()});
};
You can also catch csrf token error in your default error handler like below.
// error handler
app.use(function (err, req, res, next) {
if (err.code !== 'EBADCSRFTOKEN') return next(err)
// handle CSRF token errors here
res.status(403)
res.send('session has expired or form tampered with')
})
For more info, please check this link.
Append csrf token as query string to action Url..
It works!
<form class="form-horizontal" role="form" enctype="multipart/form-data" method="POST"
action="/contest/vacation-photo/{{year}}/{{month}}?_csrf={{_csrfToken}}">
</form>