I have an app where users can create an account and update their information after creation. I am able to save the updated document to the database when users input new information on the edit page, however, when I redirect them to the user panel, the old information is still being displayed. I believe that it has something to do with the session that gets created on login because the updated information only shows once the user logs out and logs back in.
This is my edit page:
<%- include('partials/header') %>
<% if(user.firstName.endsWith("s")) { %>
<h1 class="dashboard-title"><%=user.firstName + "' Account"%></h1>
<% } else { %>
<h1 class="dashboard-title"><%=user.firstName + "'s Account"%></h1>
<% } %>
<!-- Action Buttons -->
<div class="container">
<div class="row justify-content-center">
<div class="col-md-3">
<a href="/logout" class="dashboard-btn">
<h5>Logout <i class="fas fa-door-open"></i></h5>
</a>
</div>
<div class="col-md-3">
<a href="/edit" class="dashboard-btn">
<h5>Edit <i class="fas fa-edit"></i></h5>
</a>
</div>
</div>
</div>
<br>
<!-- Information -->
<div class="container">
<form class="" action="/edit" method="post">
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="firstName">First Name:</label>
<div class="form-group col-md-7">
<input name="firstName" class="form-control" type="text" value="<%=user.firstName%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="lastName">Last Name:</label>
<div class="form-group col-md-7">
<input name="lastName" class="form-control" type="text" value="<%=user.lastName%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="email">Email:</label>
<div class="form-group col-md-7">
<input name="email" class="form-control" type="text" value="<%=user.username%>" readonly>
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="phone">Phone:</label>
<div class="form-group col-md-7">
<input name="phone" class="form-control" type="text" value="<%=user.phoneNumber%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="address">Address:</label>
<div class="form-group col-md-7">
<input name="address" class="form-control" type="text" value="<%=user.personalInfo.address%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="coverage">Coverage:</label>
<div class="form-group col-md-7">
<input name="coverage" class="form-control" type="text" value="<%=user.coverage%>" >
</div>
</div>
<br>
<div class="row justify-content-center">
<label class="col-form-label col-md-1" for="paymentPlan">Payment:</label>
<div class="form-group col-md-7">
<input name="paymentPlan" class="form-control" type="text" value="<%=user.paymentPlan%>">
</div>
</div>
<br>
<button class="btn register-btn" type="submit">Submit Changes</button>
</form>
</div>
<%- include('partials/footer') %>
And app.js to handle the post requests to edit route:
app.get("/user-panel", function(req, res) {
if(req.isAuthenticated()) {
res.render("user-panel", {
user: req.user
});
} else {
res.redirect('/login');
}
});
app.get("/edit", function(req, res) {
if(req.isAuthenticated()) {
res.render("edit", {
user: req.user
});
} else {
res.redirect("/login");
}
});
app.post("/edit", function(req, res) {
const email = req.user.username;
const firstName = req.body.firstName;
const lastName = req.body.lastName;
const phone = req.body.phone;
User.findOne({username: email}, function(err, foundUser) {
if(err) {
console.log(err);
} else {
if (foundUser) {
foundUser.firstName = firstName;
foundUser.save();
res.redirect("/user-panel");
}
}
});
});
Any ideas on how I can get the server to respond with the updated info without having to log out the user?
I want to touch on a few things.
to answer your question, you need to query the database again upon redirect. like so:
you need to pass the email value back to the original user-panel function:
res.redirect("/user-panel?username=" + email);
then, you have to query the database again, like so:
app.get("/user-panel", authCheck, function(req, res) {
let email = req.query.email
User.findOne({username: email}, function(err, foundUser) {
if(err) {
console.log(err);
} else {
if (foundUser) {
foundUser.firstName = firstName;
foundUser.save();
res.render("user-panel", {
user: req.user
});
}
}
});
});
You should try not to use authentication logic within each function, rather have it as a seperate function and import it as middleware. Makes it cleaner. I've rewritten it for you.
function authCheck(req, res, next) {
if(req.isAuthenticated()) {
next()
} else {
res.redirect('/login');
}
}
now within any new function you create (within this file), you can just use the function authCheck() as middleware:
app.get('/', authCheck, (req, res) => {
Related
I am just stuck in a problem and also don't know whether the question is correct or not.
I am working on a node express js, using ejs templating engine.
I have created certain endpoints (say login(POST) endpoint) which are generic endpoints.
Now I want to create a new application which uses should use these endpoints and render the view according to the result of these endpoints.
Lets say I have a generic endpoint for login
router.post('/user/login', function (req, res) {
var userLoginId = req.body.username;
var currentPassword = req.body.password;
UserLogin.findOne({userLoginId: userLoginId, currentPassword: currentPassword}, function (err, usr) {
if (err) {
console.log('Error in User login');
console.log(err);
res.status(500).type('application/problem+json').send();
} else {
if (!usr) {
console.log('Please enter valid username and password');
res.status(404).type('application/problem+json').send();
} else {
res.type('application/json').status(200).send(usr);
}
}
});
});
And I am using this login.ejs file
<div class="container panel panel-primary">
<h2 class="h2 text-center">Login</h2>
<form class="form-horizontal" name="loginForm" method="post" action="/user/login">
<div class="form-group">
<label for="username" class="col-sm-offset-2 col-sm-2 control-label">UserName</label>
<div class="col-sm-4">
<input type="text" name="username" class="form-control" id="username" placeholder="username">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-offset-2 col-sm-2 control-label">Password</label>
<div class="col-sm-4">
<input type="password" name="password" class="form-control" id="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-4">
<button type="submit" class="btn btn-primary btn-">Sign in</button>
</div>
</div>
</form>
</div>
Now I want to use this code and want to login to the system.
If the user login is successful I want to redirect to dashboard page else same login page.
On executing this code the api returns me the JSON response and from this response how can I decide to whether to redirect on dashboard page or login page.
Please help if more input is needed please put a comment.
I would instead of doing a form request to login, do a AJAX request to login and then use something like jQuery to do the AJAX request and response. Alternatively you could do something like the following.
router.get('/login', function(req, res){
res.render('login', {});
})
router.post('/login', function (req, res) {
var userLoginId = req.body.username;
var currentPassword = req.body.password;
UserLogin.findOne({userLoginId: userLoginId, currentPassword: currentPassword}, function (err, usr) {
if (err) {
console.log('Error in User login');
console.log(err);
// res.status(500).type('application/problem+json').send();
res.status(500).render('login', { error : 'Error finding password'})
} else {
if (!usr) {
console.log('Please enter valid username and password');
// res.status(404).type('application/problem+json').send();
res.status(404).render('login', { error : 'Please enter valid username and password'})
} else {
res.redirect('/dashboard');
}
}
});
});
For the login.ejs file i would conditionally render the error.
<!DOCTYPE html>
<html>
<body>
<div class="container panel panel-primary">
<h2 class="h2 text-center">Login</h2>
<%if (locals.error) { %>
<%= error %>
<% } %>
<form class="form-horizontal" name="loginForm" method="post" action="/user/login">
<div class="form-group">
<label for="username" class="col-sm-offset-2 col-sm-2 control-label">UserName</label>
<div class="col-sm-4">
<input type="text" name="username" class="form-control" id="username" placeholder="username">
</div>
</div>
<div class="form-group">
<label for="password" class="col-sm-offset-2 col-sm-2 control-label">Password</label>
<div class="col-sm-4">
<input type="password" name="password" class="form-control" id="password" placeholder="Password">
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-4 col-sm-4">
<button type="submit" class="btn btn-primary btn-">Sign in</button>
</div>
</div>
</form>
</div>
</body>
</html>
Ok so in my app I am trying to allow image uploading using multer. My app is built using node.js and my database is using mongodb. When I create an account and select an image for the avatar image, it creates the account but automatically uses the no-image.png file I have setup in case someone doesn't select an image. Here is the code... Any help will be awesome.
// handle signup logic
router.post("/register", function(req, res) {
upload(req, res, function(err) {
if(err){
req.flash("error", err.message);
return res.redirect("/register");
}
var newUser = new User({
username: req.body.username,
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
bio: req.body.bio
});
if(typeof req.file !== "undefined") {
newUser.avatar = '/uploads/userImg/' + req.file.filename;
} else {
newUser.avatar = '/uploads/userImg/no-image.png';
}
console.log(newUser);
if(req.body.adminCode === process.env.ADMINCODE) {
newUser.isAdmin = true;
}
if(req.body.answer !== process.env.SECRET){
req.flash("error", "answer the question");
return res.redirect("back");
} else {
User.register(newUser, req.body.password, function(err, user){
if(err){
return res.render("register", {error: err.message});
}
passport.authenticate("local")(req, res, function(){
req.flash("success", "Welcome to Let's Camp " + user.username);
res.redirect("/campgrounds");
});
});
}
});
});
var multer = require("multer");
var storage = multer.diskStorage({
destination: function(req, file, callback) {
callback(null, './public/uploads/userImg');
},
filename: function(req, file, callback) {
callback(null, Date.now() + file.originalname);
}
});
var upload = multer({ storage : storage}).single('image');
<% include ./partials/header %>
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<form action="/register" method="post">
<h1 class="text-center">Sign Up</h1>
</div>
<div class="row">
<div class="col-xs-4 col-xs-offset-2">
<div class="form-group">
<label for="firstName">First Name</label>
<input id="firstName" class="form-control" type="text" name="firstName" placeholder="First Name*" required>
</div>
</div>
<div class="col-xs-4 col-xs-offset-0">
<div class="form-group">
<label for="lastName">Last Name</label>
<input id="lastName" class="form-control" type="text" name="lastName" placeholder="Last Name*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-4 col-xs-offset-2">
<div class="form-group">
<label for="email">Email</label>
<input id="email" class="form-control" type="email" name="email" placeholder="Email*" required>
</div>
</div>
<div class="col-xs-4 col-xs-offset-0">
<div class="form-group">
<label for="avatar">Avatar Image URL</label>
<input id="avatar" class="form-control" type="file" name="avatar">
</div>
</div>
</div>
<div class="row">
<div class="col-xs-4 col-xs-offset-2">
<div class="form-group">
<label for="username">Username</label>
<input id="username" class="form-control" type="text" name="username" placeholder="Username*" required>
</div>
</div>
<div class="col-xs-4 col-xs-offset-0">
<div class="form-group">
<label for="password">Password</label>
<input id="password" class="form-control" type="password" name="password" placeholder="Password*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="bio">Bio</label>
<textarea id="bio" class="form-control" type="bio" name="bio" rows="5" placeholder="Write a short description of yourself and what you enjoy about camping."></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-4 col-xs-offset-2">
<div class="form-group">
<label for="adminCode">Admin Code</label>
<input id="adminCode" class="form-control" type="text" name="adminCode" placeholder="Admin Code">
</div>
</div>
<div class="col-xs-4 col-xs-offset-0">
<div class="form-group">
<label for="number">Enter: I Love Camping</label>
<input id="number" class="form-control" type="text" name="answer" placeholder="Answer*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-xs-8 col-xs-offset-2">
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Sign Up!</button>
</div>
Go Back
</form>
</div>
</div>
<div class="row">
<div class="col-xs-12">
<p class="text-center"><strong>*</strong> indicates a required field.</p>
</div>
</div>
</div>
<% include ./partials/footer %>
If I use enctype="multipart/form-data" I get an error for some reason but if I leave it off it completes but the image still doesnt upload. Just reverts to the no-image.png
If You want to post file You've to use entype="multipart/form-data":
<form action="/register" method="post" enctype="multipart/form-data">
If You've other problems so fix that problem.
from documentation :
.single(fieldname)
Accept a single file with the name fieldname. The single file will be stored in req.file.
So create upload method like this and call it in Your router:
var uploadAvatar = multer({ storage : storage}).single('avatar');
or rename Your input file name="image" :
<input id="avatar" class="form-control" type="file" name="image">
Ok so I am trying to implement Google Recaptcha into my register page for my app. Everything on the front end seems to work as far as it loads the page and when I click "I am not a robot" it asks me to verify images and then... when I click submit, It tells me to "Please select captcha" and it redirects me back to the register page. Thats how I have the code setup if someone doesn't select the captcha checkmark but I cannot figure out why it won't continue and create the user. Here is the code...
// handle signup logic
router.post("/register", function(req, res) {
if(req.body.captcha === undefined || req.body.captcha === "" || req.body.captcha === null){
req.flash("error", "Please select captcha");
return res.redirect("/register");
}
// secret key
var secretKey = process.env.CAPTCHA;
// Verify URL
var verifyURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${req.body.captcha}&remoteip=${req.connection.remoteAddress}`;
// Make request to Verify URL
request(verifyURL, (err, response, body) => {
// if not successful
if(body.success !== undefined && !body.success){
req.flash("error", "Captcha Failed");
return res.redirect("/register");
}
// if successful
upload(req, res, function(err) {
if(err){
console.log(err.message);
req.flash("error", err.message);
return res.redirect("/register");
}
var newUser = new User({
username: req.body.username,
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
bio: req.body.bio
});
if(typeof req.file !== "undefined") {
newUser.avatar = '/uploads/userImg/' + req.file.filename;
} else {
newUser.avatar = '/uploads/userImg/no-image.png';
}
console.log(newUser);
if(req.body.adminCode === process.env.ADMINCODE) {
newUser.isAdmin = true;
}
if(req.body.answer !== process.env.SECRET){
req.flash("error", "answer the question");
return res.redirect("back");
} else {
User.register(newUser, req.body.password, function(err, user){
if(err){
console.log(err.message);
return res.render("register", {error: err.message});
}
passport.authenticate("local")(req, res, function(){
req.flash("success", "Welcome to Let's Camp " + user.username);
res.redirect("/campgrounds");
});
});
}
});
});
});
<% include ./partials/header %>
<div class="row">
<div class="col-md-8 col-md-offset-2">
<form id="register" action="/register" method="post" enctype="multipart/form-data">
<h1 class="text-center">Sign Up</h1>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="firstName">First Name</label>
<input id="firstName" class="form-control" type="text" id="firstName" name="firstName" placeholder="First Name*" required>
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="lastName">Last Name</label>
<input id="lastName" class="form-control" type="text" id="lastName" name="lastName" placeholder="Last Name*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="email">Email</label>
<input id="email" class="form-control" type="email" id="email" name="email" placeholder="Email*" required>
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="avatar">Avatar Image URL</label>
<input id="avatar" class="form-control" type="file" name="avatar">
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="username">Username</label>
<input id="username" class="form-control" type="text" id="username" name="username" placeholder="Username*" required>
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="password">Password</label>
<input id="password" class="form-control" type="password" id="password" name="password" placeholder="Password*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="bio">Bio</label>
<textarea id="bio" class="form-control" type="bio" name="bio" rows="5" placeholder="Write a short description of yourself and what you enjoy about camping."></textarea>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="adminCode">Admin Code</label>
<input id="adminCode" class="form-control" type="text" name="adminCode" placeholder="Admin Code">
</div>
</div>
<div class="col-md-4 col-md-offset-0 col-xs-8 col-xs-offset-2">
<div class="form-group">
<label for="number">Enter: Answer</label>
<input id="number" class="form-control" type="text" id="answer" name="answer" placeholder="Answer*" required>
</div>
</div>
</div>
<div class="row">
<div class="col-md-4 col-md-offset-4">
<div class="g-recaptcha form-group" data-sitekey="6LduxzsUAAAAAAoten8FA_zg12PjA3QfSjF5vFvY"></div>
</div>
</div>
<div class="row">
<div class="col-md-8 col-md-offset-2 col-xs-8 col-xs-offset-2">
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Sign Up!</button>
</div>
Go Back
</form>
</div>
</div>
<div class="row">
<div class="col-md-12 col-xs-8 col-xs-offset-2">
<p class="text-center"><strong>*</strong> indicates a required field.</p>
</div>
</div>
</div>
<% include ./partials/footer %>
It's not req.body.captcha
Seems like You've not read tutorial correctly.
From this tutorial is see such example:
app.post('/submit',function(req,res){
// g-recaptcha-response is the key that browser will generate upon form submit.
// if its blank or null means user has not selected the captcha, so return the error.
if(req.body['g-recaptcha-response'] === undefined || req.body['g-recaptcha-response'] === '' || req.body['g-recaptcha-response'] === null) {
// not passed validation
}
And from this file is see such code at line 52 :
if(req.body && req.body['g-recaptcha-response']) response = req.body['g-recaptcha-response'];
Both of them proves that "invisible" field is accessible under req.body['g-recaptcha-response']
HERE IS THE FIX:
this:
const captcha = req.body['g-recaptcha-response'];
if(!captcha){
req.flash("error", "Please select captcha");
return res.redirect("/register");
}
and this:
// Verify URL
var verifyURL = `https://www.google.com/recaptcha/api/siteverify?secret=${secretKey}&response=${captcha}&remoteip=${req.connection.remoteAddress}`;
or just create simple middleware catchReCaptcha and attach to router:
// middleware that catches g-recaptcha-response and puts in req.body.captcha
const catchReCaptcha = (req, res, next) => {
if(req.body && req.body['g-recaptcha-response']) {
req.body.captcha = req.body['g-recaptcha-response'];
}
next();
};
// attached middleware to register route
router.post("/register", catchReCaptcha, (req, res) => {
but keep in mind You'll have conflicts of parsing multipart/form-data since upload method responsible also for parsing body of request for that content-type.
my problem is that whenever a new client is created, all the values are null in the database except the id, the name, responsable and the logo. i dont think i did a programmation mistake, so i think it is a case of callbacks race but i cant found the solution.
P.S : the problem occure only if i select and send an image file to be uploaded, in the other case, the client values are stored correctly.
P.S 2 : the problem occure in my remote server only, in local environnement all is ok !
Than you very much !
UPDATE : i included the code for my create.ejs view
This is the code of the store method in my ClientService :
store: function(req, done) {
var name = req.param('name'),
town = req.param('town'),
adress = req.param('adress'),
postalCode = req.param('postalCode'),
telephone = req.param('telephone'),
email = req.param('email'),
fax = req.param('fax'),
responsable = req.param('responsable'),
website = req.param('website'),
activity = req.param('activity');
comments = req.param('comments');
Client.create({
name: name,
town: town,
adress: adress,
postalCode: postalCode,
telephone: telephone,
fax: fax,
responsable: responsable,
website: website,
activity: activity,
email: email,
comments: comments
}).exec(function(err, client) {
if (err) console.log(err);
req.file('logo').upload(
{
dirname: sails.config.appPath + sails.config.params.logos
},
function(err, logo) {
if (err) return done(err, null);
if (logo.length !== 0) {
client.logo = require('path').basename(logo[0].fd);
} else {
client.logo = 'default.png';
}
client.save(function(err) {
return done(null, client);
});
}
);
});
}
And this is the code for the EJS view :
<div class="portlet-body form">
<!-- BEGIN FORM-->
<form action="store" method="POST" class="form-horizontal" enctype="multipart/form-data">
<div class="form-body">
<div class="row">
<div class="col-md-6">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="name">
<label for="form_control_1">Nom du Client</label>
<i class="fa fa-institution"></i>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="activity">
<label for="form_control_1">Activité</label>
<i class="icon-star"></i>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="responsable">
<label for="form_control_1">Responsable</label>
<i class="icon-user"></i>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group" style="margin-left:15px;">
<div class="form-photo-label-form" >
<i class="icon-picture icon-create"></i>
<label for="form_control_1" class="form-photo-create" >Photo </label>
</div>
<br>
<div class="fileinput fileinput-new" data-provides="fileinput">
<span class="btn green btn-file">
<span class="fileinput-new"> Selectionner Fichier </span>
<span class="fileinput-exists"> Changer </span>
<input type="file" name="logo"> </span>
<span class="fileinput-filename"> </span>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="email">
<label for="form_control_1">Email</label>
<i class="fa fa-inbox"></i>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="adress">
<label for="form_control_1">Adresse</label>
<i class="icon-home"></i>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-6">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="postalCode">
<label for="form_control_1">Code postale</label>
<i class="fa fa-send"></i>
</div>
</div>
</div>
<div class="col-md-6">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="town">
<label for="form_control_1">Ville</label>
<i class=" fa fa-map"></i>
</div>
</div>
</div>
<!--/span-->
</div>
<div class="row">
<div class="col-md-6">
<div class="row">
<div class="col-md-12">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<textarea class="form-control" rows="3" style="height: 192px; resize:none " name="comments"></textarea>
<label for="form_control_1">Commentaire</label>
<i class=" fa fa-edit"></i>
</div>
</div>
</div>
</div>
</div>
<div class="col-md-6">
<div class="row">
<div class="col-md-12">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="telephone">
<label for="form_control_1">Telephone</label>
<i class="icon-screen-smartphone"></i>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="fax">
<label for="form_control_1">Fax</label>
<i class="fa fa-fax"></i>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="form-group form-md-line-input has-success form-md-floating-label form-create">
<div class="input-icon">
<input type="text" class="form-control" name="website">
<label for="form_control_1">Site Internet</label>
<i class=" fa fa-internet-explorer"></i>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="form-actions right">
<button type="button" class="btn default">Annuler</button>
<button type="submit" class="btn green"><i class="fa fa-check"></i> Enregistrer</button>
</div>
</form>
Nothing mysterious (:
Your problem is that You use req.param instead of req.body
And Your code is simply should look like this:
const path = require('path'); // somewhere in same module at the top
store: (req, done) => {
Client
.create(req.body)
.exec((err, client) => {
if(err) {
// no need to go further
// if You cannot create database record
return done(err);
}
const dirname = path.join(sails.config.appPath, sails.config.params.logos); // safely concatenates paths based on OS
req
.file('logo')
.upload({dirname}, (err, logo) => {
if (err) {
// we created record (client)
// but could not save the file
// it should not be a stopper
console.error(err);
}
client.logo = (logo) ? path.basename(logo[0].fd) : 'default.png';
client.save((err) => {
if(err) {
// just log the error and continue
console.error(err);
}
done(null, client);
});
});
});
}
P.S. When You pass req.body (or any other) object to Client.create don't worry about object contents, just define field constrains in You model file, ODM (or ORM) will just handle validation automatically based on constraints and will prevent from creating null valued fields
Example:
module.exports = {
attributes: {
name: {
// it requires field name:
// to be defined (required: true),
// to be string (type),
// to have at least 2 symbols,
// to not exceed 100 symbols
type: 'string',
required: true,
minLength: 2,
maxLength: 100
},
email: {
// it requires field email:
// to be defined (required: true),
// to be email (type),
// to be unique among documents, records, rows
type: 'email',
required: true,
unique: true
},
... and so on ...
}
}
More about validation here
Thanks everybody. I solved the problem by putting the file input at the end the form. Like you suggested, the values after the file input were reset after the upload of the file
EDIT Project repo
I am using a boiler plate and have logged the issue with the creator but was hoping for help sooner. My issue is that when I go to change plans it tells me to please add a card before choosing a plan. The code for the page is as follows:
The form:
`<form {% if !user.stripe.last4 %}id="cardForm"{% endif %}
action="/user/plan" method="POST" class="form-horizontal">
<div class="form-group">
<label for="plan" class="col-sm-3 control-label">Plan</label>
<div class="col-sm-4">
{% for plan in plans %}
<div class="radio">
<label>
<input type="radio" {% if user.stripe.plan == loop.key
%}checked{% endif %} name="plan" value="{{loop.key}}" data-toggle="radio">
<span>{{plan.name}} - ${{plan.price}}</span>
</label>
</div>
{% endfor %}
</div>
</div>
{% if !user.stripe.last4 %}
<div id="cardWrapper">
<div class="form-group">
<label class="col-sm-3 control-label">Test Card Info</label>
<div class="col-sm-7">
<div class="form-control-static">4242424242424242, 11/19, 123 - additional test info</div>
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Card Number</label>
<div class="col-sm-4">
<input id="card-num" type="text" class="form-control">
</div>
</div>
<div class="form-group">
<label class="col-sm-3 control-label">Card Details</label>
<div class="col-sm-4">
<div class="row">
<div class="col-xs-4">
<input id="card-month" type="text" size="2" maxlength="2"
class="form-control" placeholder="MM">
</div>
<div class="col-xs-4">
<input id="card-year" type="text" size="2" maxlength="2"
class="form-control" placeholder="YY">
</div>
<div class="col-xs-4">
<input id="card-cvc" type="text" size="3" maxlength="3"
class="form-control" placeholder="CVC">
</div>
</div>
</div>
</div>
<div class="form-group">
<div class="col-sm-6">
<div id="cardFormError" class="alert alert-danger hidden"
role="alert">
<p>{{error}}</p>
</div>
</div>
</div>
</div>
{% endif %}
<div class="form-group">
<div class="col-sm-offset-3 col-sm-4">
<button type="submit" class="btn btn-primary">Update Plan</button>
</div>
</div>
</form>`
Calls the route /user/plan
app.post('/user/plan',
setRedirect({auth: '/', success: '/billing', failure: '/billing'}),
isAuthenticated,
users.postPlan);
users.postPlan is the issue I think:
exports.postPlan = function(req, res, next){
var plan = req.body.plan;
var stripeToken = null;
if(plan){
plan = plan.toLowerCase();
}
if(req.user.stripe.plan == plan){
req.flash('info', {msg: 'The selected plan is the same as the current plan.'});
return res.redirect(req.redirect.success);
}
if(req.body.stripeToken){
stripeToken = req.body.stripeToken;
}
if(!req.user.stripe.last4 && !req.body.stripeToken){
req.flash('errors', {msg: 'Please add a card to your account before choosing a plan.'});
return res.redirect(req.redirect.failure);
}
User.findById(req.user.id, function(err, user) {
if (err) return next(err);
user.setPlan(plan, stripeToken, function (err) {
var msg;
if (err) {
if(err.code && err.code == 'card_declined'){
msg = 'Your card was declined. Please provide a valid card.';
} else if(err && err.message) {
msg = err.message;
} else {
msg = 'An unexpected error occurred.';
}
req.flash('errors', { msg: msg});
return res.redirect(req.redirect.failure);
}
req.flash('success', { msg: 'Plan has been updated.' });
res.redirect(req.redirect.success);
});
});
};
This is the code I think that somewhere is messed up. If there appear to be more I can include let me know. I am not sure which section of code the issue lays in but I think it is the users.postPlan but I don't know enough about node to tell.
I'd be tempted to confirm that user.stripe.last4 has something in it; that seems to be why it's routing you to the card form.