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.
Related
My project was working fine till last week and now all of a sudden my post requests are not working . i tried all methods and read other questions of stack overflow but was unable to fix the issue . can some one please help me?
Issue : req.body is undefined and also whenever i try upload a file "cannot read property path of undefined" is the error.
i'm using express middle ware to parse the request body . i also have my form enctype to multipart/form-data..
Code snippet is below :
require('dotenv').config()
const express = require('express');
const app = express();
const router = express.Router();
const session = require('express-session');
const fs = require(`fs`);
const mysql = require(`mysql-await`);
const path = require('path');
app.set('view engine', 'ejs');
app.set('views', path.join(__dirname, 'views'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(express.json())
app.use(express.urlencoded({ extended: true }))
const multer = require('multer');
const {storage} = require('../cloudinary');
const upload = multer({storage});
const con = mysql.createConnection({
host: "localhost",
user: "root",
password: "Sujanya#1978",
database: "dept"
});
con.connect((err) => {
if (!err) {
console.log("Connected");
}
else {
console.log(err)
}
})
router.get('/naaccircular',(req,res)=>{
(async () => {
let results = await con.awaitQuery('select* from dept.naaccircular;');
res.render('Naac_circular',{Egs : results})
})();
})
router.get('/naaccriteria',(req,res)=>{
(async () => {
flet results = await con.awaitQuery('select* from dept.naaccriteria;');
res.render('Naac_criteria_files',{Fgs : results})
})();
})
router.post('/naacaddcircular',upload.single('circularfile'),(req,res) => {
console.log(req.body);
const n = req.body.circularname;
const d = req.body.circulardate;
const l = req.file.path;
con.connect(function(err){
var records = [n,d,l];
con.query("insert into dept.naaccircular (cirname,cirlink,cirdate)
VALUES (?,?,?)", [n,l,d] , function (err, result, fields){
if (err) throw err;
})
});
console.log(n);
console.log(l);
console.log(d);
res.redirect('/naaccircular');
})
module.exports = router;
style="margin-top:80px; background-color: white;">
<form action="/naacaddcircular" method="POST" class="row g-3 form-container" enctype="multipart/form-data">
<h3 style="text-align: center;">Naac Circular</h3>
<div class="mb-3">
<label for="ii" class="form-label">Name</label>
<input id="ii" name="circularname" class="form-control" type="text" placeholder="Default input"
aria-label="default input example">
</div>
<div class="mb-3">
<label for="jj" class="form-label">Date</label>
<input id="jj" name="circulardate" class="form-control" type="date">
</div>
<div class="input-group mb-2">
<input type="file" class="form-control" name="circularfile"id="inputGroupFile04" aria-describedby="inputGroupFileAddon04"
aria-label="Upload">
<!--<button class="btn btn-outline-secondary" type="button" id="inputGroupFileAddon04">Button</button>-->
</div>
<button type="submit"
class="btn btn-primary position-relative start-50 botttom-0 translate-middle-x">Upload</button>
</form>
</div> ```
The problem is with cloudinary module. I have rectified it, there are no errors in the post method.
Once upload.single() function is removed from the router.post() function I'm able to get the req.body(),
const express = require("express");
const handlebars = require("express-handlebars");
const mongoose = require("mongoose");
const bodyParser = require("body-parser");
const path = require("path");
const app = express();
const port = 3000;
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: true }));
app.engine(".hbs", handlebars({ defaultLayout: "main", extname: ".hbs" }));
app.set("view engine", ".hbs");
app.use(express.static(path.join(__dirname, "public")));
app.use(express.urlencoded({ extended: false }));
app.use(express.json());
mongoose.Promise = global.Promise;
mongoose.connect(
"mongodb://usresa:passcode#mongodb-rukshi-shard-00-00.nerbj.gcp.mongodb.net:27017,mongodb-rukshi-shard-00-01.nerbj.gcp.mongodb.net:27017,mongodb-rukshi-shard-00-02.nerbj.gcp.mongodb.net:27017/db_name?ssl=true&replicaSet=atlas-dxrzem-shard-0&authSource=admin&retryWrites=true&w=majority",
{ useNewUrlParser: true, useUnifiedTopology: true }
);
const nameSchema = new mongoose.Schema({
name: String,
naquantityme: String,
description: String,
});
const User = mongoose.model("User", nameSchema);
app.get("/", (req, res) => {
res.render("login", { layout: "loginlayout" });
});
app.get("/home", (req, res) => {
res.render("dashboard", { layout: "main" });
});
app.use("/AddProduct", (req, res) => {
res.render("AddProduct", { layout: "main" });
});
app.post("/addproductform", (req, res) => {
var myData = new User(req.body);
myData
.save()
.then((item) => {
res.send("Product saved to database");
})
.catch((err) => {`enter code here`
res.status(400).send("Unable to save to database");
});`enter code here
});
app.listen(port, () => {
console.log("Server listening on port " + port);
});
///// Front End
<form id="form_validation" method="post" action="/addproductform">
<div class="form-group form-float">
<input type="text" class="form-control" placeholder="Product Name" name="name"
required>
</div>
<div class="form-group form-float">
<input type="text" class="form-control" placeholder="Quantity" name="quantity"
required>
</div>
{{!-- <div class="form-group">
<div class="radio inlineblock m-r-20">
<input type="radio" name="gender" id="male" class="with-gap" value="option1">
<label for="male">Male</label>
</div>
<div class="radio inlineblock">
<input type="radio" name="gender" id="Female" class="with-gap" value="option2"
checked="">
<label for="Female">Female</label>
</div>
</div> --}}
<div class="form-group form-float">
<textarea name="description" cols="30" rows="5" placeholder="Description"
class="form-control no-resize" required></textarea>
</div>
{{!-- <div class="form-group">
<div class="checkbox">
<input id="checkbox" type="checkbox">
<label for="checkbox">I have read and accept the terms</label>
</div>
</div> --}}
<button class="btn btn-raised btn-primary waves-effect" id="submitDetails"
name="submitDetails" type="submit">SUBMIT</button>
</form>
This is appjs code. Rest I have AddProduct in views folder.
The default setting for accesing the view is from views folder.
This addproduct form is not submitting the datat to database.
How do we change the route of different views
This addproduct form is not submitting the datat to database.
This addproduct form is not submitting the datat to database.
This addproduct form is not submitting the datat to database.
I have a simple CRUD app in Node.js/Express. It's an order intake form to post data to a MongoDB collection.
I cannot for the life of me see why this POST (CREATE) route is not succeeding. I’ve been troubleshooting this all morning. My other routes run just fine as validated with my console.logs.
Here is my orders route file (/routes/orders.js):
var express = require("express");
var router = express.Router();
var Order = require("../models/order.js");
// Load Keys ===================================================================
const keys = require('../config/keys');
// INDEX ROUTE - show all orders
router.get("/", isLoggedIn, function(req, res){
// Get all orders from DB
Order.find({}, function(err, allOrders){
if(err){
console.log(err);
} else {
res.render("orders", {orders:allOrders});
//Test to see if this returns the number of records in the collection
console.log("There are currently " + allOrders.length + " orders.");
}
});
});
// CREATE ROUTE - add new order to the DB
router.post("/", isLoggedIn, function(req, res){
// get data from form and add to newOrder object
var date = req.body.date;
var territory = req.body.territory;
var principal = req.body.principal;
var customer = req.body.customer;
var representative = req.body.representative;
var amount = req.body.amount;
var newOrder = {date: date, territory: territory, principal: principal, customer: customer, representative: representative, amount: amount};
// Create a new order and save to DB
Order.create(newOrder, function (err, newlyCreated){
if(err){
console.log(err);
} else {
//redirect back to orders page
res.redirect("/");
console.log("New order created (orders route file).");
}
});
});
// NEW ROUTE - show form to create new customer
router.get("/new", isLoggedIn, function(req, res){
res.render("new.ejs");
console.log("This is coming from the order route js file.");
});
This is my new.ejs template file with the form:
<div class="container container-new py-5">
<div class = "row">
<div class="col-lg-12 orders-title">
<h2>New Order</h2>
</div>
</div>
<div class="row">
<div class="col-md-10 mx-auto">
<form action="/orders" method="POST">
<div class="form-group row">
<div class="col-sm-3">
<label for="inputDate">Date</label>
<input type="text" class="form-control" id='datetimepicker' name="date">
</div>
<div class="col-sm-3">
<label for="inputTerritory">Territory</label>
<select id="selectTerr" class="form-control" name="territory">
<option>Choose a territory</option>
</select>
</div>
<div class="col-sm-6">
<label for="inputPrincipal">Principal</label>
<select id="selectPrin" class="form-control" name="principal">
<option>Choose a principal</option>
</select>
</div>
</div>
<div class="form-group row">
<div class="col-sm-5">
<label for="inputCustomer">Customer</label>
<select id="selectCust" class="form-control" name="customer">
<option>Choose a customer</option>
</select>
</div>
<div class="col-sm-4">
<label for="inputRepresentative">Sales Rep</label>
<select id="selectRep" class="form-control" name="representative">
<option>Choose a rep</option>
</select>
</div>
<div class="col-sm-3">
<label for="inputState">Total</label>
<input type="text" class="form-control" id="inputTotal" name="amount">
</div>
</div>
<div class="form-group new-buttons">
<button type="button" class="btn btn-cancel btn-default btn-primary px-4">Clear</button>
<button type="button" class="btn btn-submit btn-default btn-primary px-4">Submit</button>
</div>
</form>
</div>
</div>
<div class = "row row-back">
<div class="col-lg-12 orders-title">
Back to Main
</div>
</div>
</div>
app.js:
var express = require("express"),
app = express(),
bodyParser = require("body-parser"),
mongoose = require("mongoose"),
passport = require("passport"),
LocalStrategy = require("passport-local"),
passportLocalMongoose = require("passport-local-mongoose"),
methodOverride = require("method-override"),
seedDB = require("./seeds");
// seedDB();
// Requiring Routes ============================================================
var ordersRoutes = require("./routes/orders"),
indexRoutes = require("./routes/index");
// Load Keys ===================================================================
const keys = require('./config/keys');
// Map global promises
mongoose.Promise = global.Promise;
// Mongoose Connect ============================================================
mongoose.connect(keys.mongoURI, {
useMongoClient: true
})
.then(() => console.log('MongoDB Connected'))
.catch(err => console.log(err));
//==============================================================================
app.use(express.static('public'));
app.use(bodyParser.urlencoded({extended: true}));
app.set('view engine', 'ejs');
app.set('views', __dirname + '/views');
app.use(methodOverride("_method"));
app.use(indexRoutes);
app.use("/orders", ordersRoutes);
const port = process.env.PORT || 5000;
app.listen(port, () => console.log(`server started on port ${port}`));
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>
<% })} %>
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>