Extract data from form and add to database using Mongoose - node.js

I want to simply display usernames and age on the webpage using Express Node.js and Mongoose/
The view should get updated on the left while the form is at the right. Refer this image.
Below is my users.js (/users route) followed by html of the form.
Bodyparser has been included in app.js of this application.
On clicking submit, 404 not found is thrown.
Refer this error image
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.render('userview');
});
router.post('#', function(req, res, next) {
//User is the model created in app.js of this project
var newUser = userModel({
name:req.body.name,
age: req.body.age
});
console.log(newUser);
// save the user
newUser.save(function(err) {
if (err) throw err;
console.log('User created!');
});
});
module.exports = router;
<form method="post">
Name:
<input type="text" name="name"><br><br>
Age:
<input type="number" name="age"><br><br>
<input type="submit" value="Submit">
</form>
Here is my 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 index = require('./routes/index');
var users = require('./routes/users');
var applist = require('./routes/applist');
var mongoose=require('mongoose');
var app = express();
//set database connection
mongoose.connect('mongodb://localhost:27017/users');
mongoose.connection.on('error',function(){
console.log('MongoDB Connection Error. Please make sure that MongoDB is running');
process.exit(1);
});
mongoose.connection.once('open',function(callback){
console.log('Connected to Database');
});
var userSchema = new mongoose.Schema({
name:{type:String,uppercase:true},
age:Number
},{collection:'userlist'});
//make model
var userModel = mongoose.model('userModel',userSchema);
app.get('/users', function(req, res, next) {
userModel.find({},function(err,userModel){
res.render('userview',{userlist:userModel});
})
});
module.exports = userModel;
// 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 }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
// 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 handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
userModel is present in app.js

On the view change
name = "fullname" to name="name"
userview
<form method="post">
Name <input type="text" name="name"><br><br>
Age<input type="number" name="age"><br><br>
<input type="submit" value="Submit">
</form>

First of all, to use req.body you need to use body-parser or busboy, connect-busboy, multiparty, connect-multiparty, formidable, multer etc. - see:
https://github.com/expressjs/body-parser
Also, what is this route supposed to be:
router.post('#', function(req, res, next) {
This character is not valid in the URL path amd needs to be URL-encoded on the client side to work. Are you sure that this is the route your need?
If you are thinking about the fragment part of the URL (as in http://host/path#fragment) then it is not sent during the HTTP request at all. See:
https://en.wikipedia.org/wiki/Fragment_identifier

Related

Node.js & Express Form Submit returns 404

I'm trying to make a simple file upload system but everytime I submit my uploaded file I get a 404 error. I've tried various different names and paths but all of them fail instantly. When I press submit, the browser tries to redirect to /upload then returns the 404 error. I'm new to node.js so it may as well be very simple to solve but I couldn't find it.
I've tried 2 different modules, formidable and express-fileupload. Both return the same error.
./views/test2.ejs
<html>
<head>
</head>
<body>
<form action="/upload" method="post" enctype="multipart/form-data">
<input type="file" name="filetoupload"><br>
<input type="submit">
</form>
</body>
./routes/test2.js
var express = require('express');
var router = express.Router();
var http = require('http');
var formidable = require('formidable');
router.get('/', function (req, res, next) {
res.render('test2');
res.sendFile(__dirname + '/test2.ejs');
});
router.post('/upload', function (req, res, next) {
var form = new formidable.IncomingForm();
form.parse(req);
form.on('fileBegin', function (name, file) {
file.path = __dirname + '/uploads/' + file.name;
});
form.on('file', function (name, file) {
console.log('Uploaded ' + file.name);
});
res.sendFile(__dirname + '/test2.ejs');
});
module.exports = router;
./app.js
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var expressValidator = require('express-validator');
var flash = require('connect-flash');
var session = require('express-session');
var passport = require('passport');
var LocalStrategy = require('passport-local').Strategy;
var mongo = require('mongodb');
var mongoose = require('mongoose');
mongoose.connect("REDACTED", function(err,db){
if(!err){
console.log("Connected");
}
});
var index = require('./routes/index');
var users = require('./routes/users');
var login = require('./routes/login');
var form = require('./routes/form');
var buttonrelay = require('./routes/buttonrelay');
var tesekkurler = require('./routes/tesekkurler');
var test = require('./routes/test');
var test2 = require('./routes/test2');
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 }));
app.use(cookieParser());
//app.use(expressLayout);
// Set Static Folder
app.use(express.static(path.join(__dirname, 'public')));
app.use(expressValidator());
// Express Session
app.use(session({
secret: REDACTED,
saveUninitialized: true,
resave: true
}));
app.use('/', index);
app.use('/users', users);
app.use('/login', login);
app.use('/form', form);
app.use('/buttonrelay', buttonrelay);
app.use('/tesekkurler', tesekkurler);
app.use('/test', test);
app.use('/test2', test2);
// 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 handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
module.exports = app;
you used app.use('/test2', test2); for the /upload routing
So form action should be "/test2/upload"

nodejs sessions after refresh a page

This is simple login form. I have validated a email, if email is not valid it gives an error( no problem here). After refreshing that page instead of showing login form it also shows error along with login form on that page.
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 hbs = require('express-handlebars');
var expressValidator = require('express-validator');
var expressSession = require('express-session');
var routes = require('./routes/index');
var app = express();
// view engine setup
//app.engine('hbs', hbs({extname: 'ejs'}));
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');
//app.set('views', path.join(__dirname, 'views'));
//app.set('view engine', 'hbs');
// 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 }));
app.use(expressValidator());
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(expressSession({secret: 'max', saveUninitialized: false, resave: false}));
app.use('/', routes);
// 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;
index.js file
var express = require('express');
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res, next) {
console.log(req.session);
res.render('student_login', { success: req.session.success, errors: req.session.errors });
req.session.errors = null;
console.log(req.session);
});
router.get('/submit', function(req, res, next) {
req.check('e', 'Invalid email address').isEmail();
//req.check('p', 'Password is invalid').isLength({min: 4}).equals(req.body.confirmPassword);
var errors = req.validationErrors();
if (errors) {
console.log(req.session);
req.session.errors = errors;
req.session.success = false;
console.log(req.session);
} else {
console.log(req.session);
req.session.success = true;
console.log(req.session);
}
res.redirect('/');
});
module.exports = router;
student_login.ejs
<!DOCTYPE html>
<html >
<% if(success ){ %>
<h1>validation succesful</h1>
<% }
else{ %>
<ul>
<% if(errors) {%>
<h1> errors </h1>
<% } %>
</ul>
<h1>Login</h1>
<form action="/submit" method="get">
<input type="text" name="e" placeholder="Email" required="required" > <br>
<input type="password" name="p" placeholder="Password" required="required" > <br>
<button type="submit" >Let me in.</button>
</form>
<% } %>
</html>
The problem here is that you are saving your error in the session which means it will remain in the session unless you clear it out or the session ends.
What you need here is flash messages. These are similar messages stored in the session, but they are cleared once shown to the user, so they are shown only once.
I have used the connect-flash node module before. It is easy to set up and does the job perfectly.

Express.js request.body not working

I have a simple form for login, the problem is when i press "Submit", the request.body on server side is empty.I saw that bodyParser is a fundamental part but in my case it's declared before the routes, so i think the problem is another. this is my server page App.js
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');
var index = 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', 'jade');
// 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: true }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use('/', index);
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 handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
app.listen(3000);
module.exports = app;
this is index.js
var express = require('express');
var router = express.Router();
function Login(req, res){
var mongoClient = require('mongodb').MongoClient;
mongoClient.connect('mongodb://localhost:27017/squaredDB', function(err, db) {
if(err) throw err;
db.collection('users').find({email: req.body.email}, function(err, data){
console.log(req.body);
});
});
}
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
router.post('/', function(req, res, next) {
Login(req, res);
res.render('app-home', { title: '' });
});
module.exports = router;
this is my jade template form:
form(method="post" action="/")
label Email
input(type="text" placeholder="Email")
label Password
input(type="password" placeholder="Password")
input(type="submit" value="login")
You're missing name attributes for your input fields in your template. Without those the browser won't submit them in the form.
Add a name attribute to your input field it will now be able to access the field via request like req.body.name
<form action="/", method="POST">
<input type="text" placeholder="name" name="name">
<button type="submit">Submit</button>
</form>

Nodejs and Expressjs print session out on site

Hello i am trying to do a simple log in system without(password) in nodejs and expressjs, using sessions. My problem is that when I try to print the log in name on to the next page it dosent come out.
login html:
<form method="post">
<label for="">UserName:</label>
<input type="text" name="username" placeholder="Enter username" >
<input type="Submit" value="Submit">
</form>
main.html:
<h3> Welcome: <%= user %> </h3>
index.js:
var express = require('express');
var jokes = require('../model/jokes');
var session = require("express-session")
var router = express.Router();
/* GET home page. */
router.get('/', function(req, res) {
res.render('main', { title: 'Express', user: session.loggedin });
})
router.get('/login',function(req,res){
res.render('login');
})
router.get('/joke', function(req,res){
res.render('randomJoke',{ jokesObj : jokes.getRandomJoke()});
})
router.get('/allJokes', function(req,res){
res.render('Jokes',{ jokesObj1: jokes.allJokes});
})
router.get('/addNewJoke', function(req,res){
res.render('addJokes');
})
router.post('/storeJoke', function(req,res){
var funJoke = req.body;
var jsonJoke = JSON.stringify(funJoke);
jokes.addJoke(jsonJoke);
res.redirect('/addNewJoke');
})
module.exports = router;
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 session = require("express-session");
var routes = require('./routes/index');
var users = require('./routes/users');
var app = express();
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 }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({secret:'secret_3162735',saveUninitialized:true, resave: true}));
app.use('/', routes);
app.use('/users', users);
app.use(function (req,res,next) {
var usernameLogged = req.session.loggedin;
var inputName = req.body.username;
if(usernameLogged){
return next();.
}else if(inputName){
usernameLogged = inputName;
session.userName = req.body.username;
return res.redirect("/");
}else{
req.url = "/login";
return next();
}
});
// error handlers
// catch 404 and forward to error handler
app.use(function(req, res, next) {
var err = new Error('Not Found');
err.status = 404;
next(err);
});
// 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;
So in main.html i cant se the user, i tried to print the session(usernameLogged) out in my main.html does not work.
As far as I can see it looks like your using middleware in a way it's not really supposed to be used. Middleware in Express is normally used to do an action for every (or a sub-section) of requests e.g logging, setting custom headers and so on, you can read more about Express-middleware from the documentation.
You need to have a route to respond to POST requests (which your login form should send):
Firstly, your login template needs to send the form input to /login like so:
<form method="post" action="/login">
<label for="">UserName:</label>
<input type="text" name="username" placeholder="Enter username" >
<input type="Submit" value="Submit">
</form>
To display the form you have a route like so to simply render the login template:
router.get('/login', function(req, res) {
// Show the login form
res.render('login');
})
Finally, you should have a route to accept the user-input from the form. As the form sends a POST request, you need to use router.post:
router.post('/login', function(req, res) {
if (req.session.loggedin) {
// User is already logged in, send them to the main page
return res.redirect('/')
}
else if (req.body.username) {
// User is not logged in, set the username for the user's session
req.session.userName = req.body.username;
// Then redirect to the main page
return res.redirect('/')
}
else {
// No username was entered
res.send('Please enter a username')
}
})
And finally,
You then should be safe to delete your middleware (the app.use section) of your app.js file.
Edit:
A user correctly spotted that questions (and answers) were using session rather than using req.session - Session refers to the express-session module, whereas req.session refers to the user's session.
So your '/' route should look like this:
res.render('main', { title: 'Express', user: req.session.loggedin });
If you want to show if the user is logged in or not.
Or you can do the following to show the current user's username.
res.render('main', { title: 'Express', user: req.session.userName });

Trouble with Express 4 and CSRF Token posting

I think I'm misunderstanding how the token is supposed to post. I'm just getting a 403 every time, even though it's actually attempting to pass the token.
Here's the server 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 redis = require('redis');
var session = require('express-session');
var RedisStore = require('connect-redis')(session);
var ejs = require('ejs');
var csrf = require('csurf');
var util = require('./public/javascripts/utilities');
var routes = require('./routes/index');
var users = require('./routes/users');
var login = require('./routes/login');
var loginProcess = require('./public/javascripts/login.js').loginProcess;
// var loginProcess = require('./public/javascripts/login.js')
var client = redis.createClient();
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(express.static(path.join(__dirname, '/public')));
app.use(cookieParser('secret'));
app.use(session(
{
store: new RedisStore({ host: 'localhost', port: 6379, client: client }),
secret: 'secret',
saveUninitialized: true,
resave: false
}
));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(csrf());
app.use(util.csrf);
app.use(util.authenticated);
app.use('/', routes);
app.use('/users', users);
app.use('/login',
login,
loginProcess);
// 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;
The login route is
var express = require('express');
var router = express.Router();
router.get('/', function(req, res, next) {
res.render('login', {title: 'Login'});
next();
});
Here is what I've got in var util
module.exports.csrf = function csrf(req, res, next){
res.locals.csrftoken = req.csrfToken();
next();
};
I'm also using ejs, and have this after my form method='post'
<input type="hidden" name="_csrf" value="<%= csrfToken %>>"
Whenever it returns 403, the form data is at least getting the name of the input
_csrf:
username:Test
password:>9000
But as you can see, it's blank
I also wasn't sure if the res.locals.csrftoken was being passed to the login route, so I also tried adding it directly there with a router.post, but got this error
Error: Can't set headers after they are sent.
I've gone through nearly every post concerning this I could find. I'm either not making the logical connection for what I'm missing, or am wholly misunderstanding something. Both are entirely plausible, my money is on the second one. Feel free to make any, why in the world are you doing that - that way - comments, because chances are I'm doing it out of ignorance, and those comments are good for the learning process. Thanks in advance.
edit: Removing my utility function and following correct 'csurf' docs successfully passed the csrf token to my /login view.
I'm getting closer, still wrong, but this may shed some light as to where I'm getting confused.
var express = require('express');
var router = express.Router();
/* GET login listing. */
router.get('/', function(req, res, next) {
res.render('login', {title: 'Login', csrfToken: req.csrfToken() });
});
function loginProcess(req, res, next){
console.log(req.body);
res.send(req.body.username + ' ' + req.body.password);
res.json(req.csrfToken());
next();
};
router.post('/', loginProcess);
module.exports = router;
Why would this redirect me to a 404 page?
Because I didn't remove my authentication step before testing.
Also, I know this is sending un & pw in plain text along with the csrf token and that's no bueno. I'll get to that eventually.
Something I did is attempting to set headers when submitting username and password.
Error: Can't set headers after they are sent.
I thought it was my loginProcess function, but removing next(), or adding res.end(); didn't help
function loginProcess(req, res, next){
console.log(req.body);
res.send(req.body.username + ' ' + req.body.password);
res.json(req.csrfToken());
res.end();
};
edit You can't use res.send and res.json like that because they're both technically sending, and you can't send headers+body and then send headers+body again.
The token is automatically sent so I removed res.json(req.csrfToken();
But somewhere I'm not redirecting correctly on post. I'm just getting a blank page with the username and passwords that were entered.
edit:
Hokay. So everything appears to be working properly. Here is the updated code.
login.js
var express = require('express');
var router = express.Router();
/* GET login listing. */
router.get('/', function(req, res, next) {
res.render('login', {title: 'Login', csrfToken: req.csrfToken() });
});
function loginProcess(req, res, next){
var isAuth = auth(req.body.username, req.body.password, req.session)
if (isAuth){
res.redirect('/chat');
}else{
res.redirect('/login');
}
};
router.post('/', loginProcess);
router.get('/logout', out);
module.exports = router;
app.js
var routes = require('./routes/index');
var users = require('./routes/users');
var login = require('./routes/login');
var chat = require('./routes/chat');
//var loginProcess = require('./public/javascripts/login.js').loginProcess;
var client = redis.createClient();
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(express.static(path.join(__dirname, '/public')));
app.use(cookieParser('secret'));
app.use(session(
{
secret: 'secret',
store: new RedisStore({ host: 'localhost', port: 6379, client: client }),
saveUninitialized: true,
resave: false
}
));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(csrf({ cookie: true }));
// app.use(util.csrf);
app.use(util.authenticated);
app.use('/', routes);
app.use('/users', users);
app.use('/login', login);
app.use('/chat', [util.requireAuthentication], chat);
I've still got a ton of cleanup, but it's at least functional.
Much thanks to #Swaraj Giri
What is app.use(util.csrf);? Guess you need to remove it.
From the docs of csurf,
You need to set csrf({ cookie: true }). This sets the crsf value in req.body._csrf.
Then you need to pass { csrfToken: req.csrfToken() } to the view of login page.
In login.js
router.get('/', function(req, res, next) {
res.render('login', {title: 'Login', csrfToken: req.csrfToken()});
next();
});

Resources