Unable to update MongoDB from edit profile page - node.js

I am trying to update my particular user database on edit profile page.But I don't know where I am going wrong in it.
{{!--editProfile.hbs--}}
<link rel="stylesheet" href="myprofile.css">
<title>Edit Profile Page</title>
<body>
<div class="container">
<h1>Edit Profile</h1>
<hr>
<div class="row">
<!-- left column -->
<div class="col-md-3">
<div class="text-center">
<img src="//placehold.it/100" class="avatar img-circle" alt="avatar">
<h6>Upload a different photo...</h6>
<input type="file" class="form-control">
</div>
</div>
<!-- edit form column -->
<div class="col-md-9 personal-info">
<h3>Personal info:</h3>
<form class="form-horizontal" role="form" action="/addDB" method="POST">
<div class="form-group">
<label class="col-lg-3 control-label" for="username">Username:</label>
<div class="col-lg-8">
<input class="form-control " type="text" id="username" name="username"placeholder="Username">
</div>
</div>
<div class="form-group">
<label class="col-lg-3 control-label">Email:</label>
<div class="col-lg-8">
<input class="form-control " type="text" placeholder="Email" name="email">
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label">Password:</label>
<div class="col-md-8">
<input class="form-control " type="password" placeholder="Password"name="password">
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label" for="phone">Phone:</label>
<div class="col-md-8">
<input class="form-control " type="text" id="phone" placeholder="Phone"name="phone">
</div>
</div>
<div class="form-group">
<label class="col-md-3 control-label"></label>
<div class="col-md-8">
button class="btn btn-primary" type="submit">Save Changes</button>
</div>
</div>
</form>
</div>
</div>
</div>
<hr>
</body>
</html>
//index.js
var express=require('express');
var app=express();
var session=require('express-session');
var mongoClient=require("mongodb").MongoClient;
var db;
mongoClient.connect("mongodb://localhost:27017",function(err,client){
if (err) throw err;
db=client.db("myDBS");
});
app.use(
session({secret: "Express session secret"}));
app.use(express.urlencoded({ extended:false}));
app.set('view engine', 'hbs');
app.use(express.static(__dirname + '/public'));
app.get("/", function(req, res){
res.sendFile(__dirname + "/login.html");});
//For Inserting new User in DB
app.get('/addS',function(req,res){
res.render('addNewUsers');
});
app.post("/add",function(req,res){
db.collection("users").insert(req.body);
console.log("Insert successfully");
res.render("myprofile");
});
//for updating DB
app.post('/addDB', function(req, res, next) {
var data = {
username: req.body.username,
email: req.body.email,
password: req.body.password,
phone:req.body.phone
};
// var id = req.body.id;
mongoClient.connect("mongodb://localhost:27017", function(err, db) {
db.collection('users').updateOne({$set: data}, function(err, result) {
console.log('User updated');
db.close();
});
});
});
app.get("/edit",function(req,res){
res.render("editProfile");
});
app.get("/dmyprofile",function(req,res){
res.render(307,"/myprofile");
});
app.post("/myprofile",function(req,res){
db.collection("users").find().toArray(function(err,result){
if (err) throw err;
for(var i=0;i<result.length;i++){
if(req.body.email==result[i].email &&
req.body.password==result[i].password)
{
req.session.loggedIn=true;
}
}
res.redirect("/user");
});
});
app.get("/user",function(req,res){
if(req.session.loggedIn==true){
res.render("myprofile");
}else{
res.redirect("/");
}
});
app.get("/logout",function(req,res){
req.session.destroy();
res.redirect("/");
});
app.listen(3355,function(){
console.log("Listening on 3355");
});
when I am clicking on save changes it is showing me db.collection not a function. Though my insert route is working fine but update part is not working.
All other routes are working fine. But this update part is throwing error.

The problem here is the way you are connecting to MongoDB.
To have direct access to the collections after connecting to Mongo you must have the database name in the connection string, like in the code below:
mongoClient.connect("mongodb://localhost:27017/MyDBS", function(err, db) {
db.collection('users').updateOne({$set: data});
});
The other way to get access to the collections is connecting to Mongo and choosing the which database to use right after, like you did upper in your code:
mongoClient.connect("mongodb://localhost:27017",function(err,client){
if (err) throw err;
db=client.db("myDBS");
db.collection('users').updateOne({$set: data});
});

Related

node.js POST empty req.body

I'm having trouble when I store data to MySQL database. I get a return in console blank.like this {}
here's route code :::app.post('/create', employeeController.create);
this is my controller code
exports.create = function(req, res) {
console.log((req.body));
const new_employee = new Employee(req.body);
//handles null error
if(req.body.constructor === Object && Object.keys(req.body).length === 0){
res.status(400).send({ error:true, message: 'Please provide all required field' });
}else{
Employee.create(new_employee, function(err, employee) {
if (err)
res.send(err);
res.json({error:false,message:"Employee added successfully!",data:employee});
});
}
};
this is my model code:
var db = require('../database');
//Employee object create
var Employee = function(employee){
this.name = employee.name;
this.email = employee.email;
this.position = employee.position;
};
Employee.create = function (newEmp, result) {
db.query("INSERT INTO employee set ?", newEmp, function (err, res) {
if(err) {
console.log("error: ", err);
result(err, null);
}
else{
console.log(res.insertId);
result(null, res.insertId);
}
});
};
module.exports= Employee;
my view code:
<form action="/create" enctype="multipart/form-data" method="POST">
<div class="row">
<div class="col-md-6">
<label>Name</label>
<input name="name" type="text" class="form-control" required>
</div>
<div class="col-md-6">
<label>Email</label>
<input name="email" type="email" class="form-control" required>
</div>
</div>
<div class="row">
<div class="col-md-6">
<label for="exampleFormControlTextarea1" class="form-label">Position</label>
<input name="position" type="text" class="form-control" required>
</div>
</div>
<button type="submit" class="btn btn-primary">Save</button>
<button type="submit" class="btn btn-primary">Cancel</button>
<br><br>
</form>
Im getting {} in log it means req.body is getting blank.
i have tried in app.js
app.use(bodyParser.json());
app.use(express.urlencoded({limit: '100mb',extended: false }));
but it's not working
Add app.use(bodyParser.urlencoded({ extended: false })) before your app.use(bodyParser.json());, and remove app.use(express.urlencoded({limit: '100mb',extended: false }));.
app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json());
Then remove enctype="multipart/form-data" in the form. Because your form only have text input, so you could remove it. And bodyParser doesn't support multipart/form-data.

Why am I getting a 400 bad request error when submitting a form that I added inputs to?

Background: I have a node/express based web application that is basically a rating/database site for campgrounds. You can view the current working version here: https://radiant-eyrie-76078.herokuapp.com and the github here: https://github.com/HashSlingSlash/YelpCamp. I've just completed attempting to add user profiles by updating the signup form to include more information and adding a show page for each user. Now whenever I click the signup button (or send a post request to /register using postman) I get a 400 Bad Request error. If I then go to the home page I can sign in as the user that I attempted to register so the user is getting registered despite the bad request error. I have tried clearing my cache and browsing history and using other browsers, but it still won't work. I even tried removing all the changes I made to the form to make it just username and password again and it still did not work. I have tried fixing this and debugging for hours and I cannot understand what could be happening.
Here is my register page:
<%- include("./partials/header") %>
<div class="row">
<h1 class="login-header">Sign Up</h1>
<div class="login-form">
<form action="/register" method="POST">
<div class="form-group">
<label for="username">Username</label>
<input class="form-control" type="text" name="newUser[username]" placeholder="username" id="username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input class="form-control" type="password" name="password" placeholder="password" id="password">
</div>
<div class="form-group">
<label for="firstName">First Name</label>
<input class="form-control" type="text" name="newUser[firstName]" placeholder="First Name" id="firstName">
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input class="form-control" type="text" name="newUser[lastName]" placeholder="Last Name" id="lastName">
</div>
<div class="form-group">
<label for="email">Email</label>
<input class="form-control" type="email" name="newUser[email]" placeholder="email#mail.com" id="email">
</div>
<div class="form-group">
<label for="avatar">Avatar</label>
<input class="form-control" type="text" name="newUser[avatar]" placeholder="avatar url" id="avatar">
</div>
<div class="form-group">
<label for="admin">Admin Key (Enter admin key here if you've been given one)</label>
<input class="form-control" type="text" name="adminKey" placeholder="********" id="admin">
</div>
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Sign Up!</button>
</div>
</form>
Go Back
</div>
</div>
<%- include("./partials/footer") %>
Here are my index routes:
const express = require("express");
const router = express.Router();
const passport = require("passport");
const User = require("../models/user");
const Campground = require("../models/campground");
//root route
router.get("/", (req, res) =>{
res.render("landing");
});
//show register form
router.get("/register", (req, res) =>{
res.render("register", {page: "register"});
});
//handle sign up logic
router.post("/register", (req, res) =>{
const newUser = new User(req.body.newUser);
if(req.body.adminKey === "secret"){
newUser.isAdmin = true;
}
User.register(newUser, req.body.password, (err, user) =>{
if(err){
return res.render("register", {"error": err.message});
}
passport.authenticate("local")(req, res, () =>{
req.flash("success", "Welcome to YelpCamp " + user.username);
res.redirect("/campgrounds");
});
});
});
//login form
router.get("/login", (req, res) =>{
res.render("login", {page: "login"});
});
//login logic
router.post("/login",
passport.authenticate("local",
{
failureRedirect: "/login",
failureFlash: true
}), (req, res) =>{
req.flash("success", "Welcome back " + req.user.username);
res.redirect("/campgrounds");
});
//logout
router.get("/logout", (req, res) =>{
req.logOut();
req.flash("success", "Logged you out!");
res.redirect("/campgrounds");
});
//user profile
router.get("/user/:id", (req, res) =>{
User.findById(req.params.id, (err, foundUser) =>{
if(err){
req.flash("error", "Something went wrong");
return res.redirect("back");
}
Campground.find().where("author.id").equals(foundUser._id).exec((err, campgrounds) =>{
if(err){
req.flash("error", "Something went wrong");
return res.redirect("back");
}
res.render("users/show", {user: foundUser, campgrounds: campgrounds});
});
});
});
module.exports = router;
Here is my User schema:
const mongoose = require("mongoose");
const passportLocalMongoose = require("passport-local-mongoose");
const UserSchema = new mongoose.Schema({
username: String,
password: String,
firstName: String,
lastName: String,
email: String,
avatar: String,
isAdmin: {type: Boolean, default: false}
});
UserSchema.plugin(passportLocalMongoose);
module.exports = mongoose.model("User", UserSchema);
I've tried fixing this for hours and would appreciate any help!
I finally figured out the issue. I had to change the name attribute on the form inputs to just username, password, email, etc. I believe passport local mongoose expects to receive the data according to those key value pairs specifically, although I am unsure as to the exact reason why this is necessary since I end up giving the data as an object either way. In case anyone wants to see it here is my updated and working code:
Register form:
<%- include("./partials/header") %>
<div class="row">
<h1 class="login-header">Sign Up</h1>
<div class="login-form">
<form action="/register" method="POST">
<div class="form-group">
<label for="username">Username</label>
<input class="form-control" type="text" name="username" placeholder="username" id="username">
</div>
<div class="form-group">
<label for="password">Password</label>
<input class="form-control" type="password" name="password" placeholder="password" id="password">
</div>
<div class="form-group">
<label for="firstName">First Name</label>
<input class="form-control" type="text" name="firstName" placeholder="First Name" id="firstName">
</div>
<div class="form-group">
<label for="lastName">Last Name</label>
<input class="form-control" type="text" name="lastName" placeholder="Last Name" id="lastName">
</div>
<div class="form-group">
<label for="email">Email</label>
<input class="form-control" type="email" name="email" placeholder="email#mail.com" id="email">
</div>
<div class="form-group">
<label for="avatar">Avatar</label>
<input class="form-control" type="text" name="avatar" placeholder="avatar url" id="avatar">
</div>
<div class="form-group">
<label for="admin">Admin Key (Enter admin key here if you've been given one)</label>
<input class="form-control" type="text" name="adminKey" placeholder="********" id="admin">
</div>
<div class="form-group">
<button class="btn btn-lg btn-primary btn-block">Sign Up!</button>
</div>
</form>
Go Back
</div>
</div>
<%- include("./partials/footer") %>
Route:
//handle sign up logic
router.post("/register", (req, res) =>{
const newUser = new User({
username: req.body.username,
firstName: req.body.firstName,
lastName: req.body.lastName,
email: req.body.email,
avatar: req.body.avatar
});
if(req.body.adminKey === "secret"){
newUser.isAdmin = true;
}
User.register(newUser, req.body.password, (err, user) =>{
if(err){
return res.render("register", {"error": err.message});
}
passport.authenticate("local")(req, res, () =>{
req.flash("success", "Welcome to YelpCamp " + user.username);
res.redirect("/campgrounds");
});
});
});

Mail not sent by node mailer

I am trying to send mail when we click the mail icon of respective id. But I am not able to send the mail.
First I click the icon, it redirects to another ejs file for sending email and then the email is sent from there. Here the mail is not sent so can anyone please help?
Thank you
mail.ejs
<form action="/send-email" method="POST">
<div class="col-md-12">
<div class="form-group">
<input type="text" class="form-control" placeholder="To" name="to">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="From" name="from" id="from">
</div>
<div class="form-group">
<input type="text" class="form-control" placeholder="Subject" name="subject" id="subject">
</div>
<div class="form-group">
<textarea class="form-control" id="content" rows="4"></textarea>
</div>
<button type="submit" class="btn btn-primary" id="">Send</button>
</div>
</form>
Controller.js
router.get('/donation/mail/:emailid', function (req, res, next) {
res.render('mail', {email: req.query.emailid});
})
router.post('/send-email', function (req, res) {
var transport = nodemailer.createTransport(smtpTransport({
service: "gmail",
port:425,
auth: {
// should be replaced with real sender's account
user: 'xxxx#gmail.com',
pass: 'gmailpassword'
}
}));
var mailOptions = {
// should be replaced with real recipient's account
from:'xxxxx#gmail.com',
to : req.param.email,
subject : req.body.subject,
text : req.body.text
};
transport.sendMail(mailOptions, function(error, info) {
if (error) {
return console.log(error);
}
console.log('Message sent: ' + info.response);
});
res.redirect("/donation");
});
I have allowed my gmail account to access non secure app

how to submit a form on the same post in the same page

So i am trying to submit a form on the same post (kinda like the comments on facebook or youtube where on a post you have a field you populate the field and submit then you are redirected to the same page but the post has a comment or in my case a tag added).
Schema
Tag schema
var mongoose = require("mongoose");
var tagSchema = new mongoose.Schema({
tagDescription: String
});
module.exports = mongoose.model("Tag", tagSchema);
Note Schema
var mongoose = require("mongoose");
var noteSchema = new mongoose.Schema({
title: String,
body: String,
category: String,
created: { type: Date, default: Date.now },
tags: [
{
type: mongoose.Schema.Types.ObjectId,
ref: "Tag"
}
]
});
module.exports = mongoose.model("note", noteSchema);
So I tried the following code but whenever i submit a tag the tags are added only to the first post, and if I remove findOne and replace it with find a cannot read property of push of undefined occurs.
this is the index.ejs page
<div class="card-body">
<h2 class="card-title"><%= note.title %></h2>
<div class="card-text-center">
<p><%= note.category %></p>
<p><%= note.body.substring(0,20)%>...</p>
<% note.tags.forEach(function(tag){ %>
<p><%= tag.tagDescription %></p>
<% }) %>
<div class="float-right card-footer">
<small><%= note.created.toDateString() %></small>
</div>
<p>Read More</p>
<form action="/" method="post">
<input class="col-md-2 form-control" type="text" name="tag[tagDescription]" placeholder="Tag" />
<button class="btn btn-primary">Submit</button>
</form>
Routes
app.post("/", function (req, res) {
Note.findOne({}, function (err, note) {
if (err) {
console.log(err);
res.redirect("/notes");
} else {
Tag.create(req.body.tag, function (err, tag) {
if (err) {
console.log(err);
} else {
note.tags.push(tag);
note.save();
res.redirect("/notes");
}
});
}
});
});
app.get("/notes", function (req, res) {
Note.find({}).populate("tags").exec(function (err, notes) {
if (err) {
console.log(err);
} else {
res.render("index", { notes: notes/*, tags: i */});
//console.log(i);
}
});
});
app.get("/notes/new", function (req, res) {
res.render("new");
})
app.post("/notes", function (req, res) {
Note.create(req.body.note, function (err, newNote) {
if (err) {
console.log(err);
} else {
res.redirect("/notes");
}
});
});
form submit for new note/post
<form action="/notes" method="post">
<div class="form-group">
<label>Title</label>
<input class="form-control" type="text" name="note[title]" placeholder="Title" />
</div>
<div class="form-group">
<label>Category</label>
<input class="form-control" type="text" name="note[category]" placeholder="Category" />
</div>
<div class="form-group">
<label>Note content</label>
<textarea class="form-control" name="note[body]" placeholder="Add a new Note..."></textarea>
</div>
<div class="form=group">
<button class="btn btn-primary btn-large btn-block">Submit</button>
</div>
</form>
When posting a tag, the route needs to know which note the tag belongs to. Instead of using findOne(), I would prefer the original solution that you were using by routing to notes/:id/tag and call
Note.findById(req.params.id, ...);
If you insist on posting to '/' as your route, you could pass the noteId as a parameter
<form action="/?noteId=<%= note.id %>" method="post">
and then catch it on your route
Note.findById(req.body.noteId, ...);
The trade offs for using nested resources in REST are discussed well here.
index
<% note.tags.forEach(function(tag){ %>
<div class="badge">
<div class="badge badge-pill badge-info">
<form action="/notes/<%= note._id %>/tags?_method=DELETE" method="post" style="display: inline">
<button class="btn btn-sm">x</button>
</form>
<%= tag.tagDescription %>
</div>
</div>
<% }) %>
<p>Read More</p>
<div class="float-right card-footer">
<small><%= note.created.toDateString() %></small>
</div>
<form action="/notes/<%= note.id %>/tags" method="post">
<input class="col-md-2 form-control" type="text" name="tag[tagDescription]" placeholder="Tag" />
<button class="btn btn-primary">Add Tag</button>
</form>
routes
app.post("/notes/:id/tags", function (req, res) {
Note.findById(req.params.id, function (err, note) {
if (err) {
res.redirect("/notes");
}
else {
Tag.create(req.body.tag, function (err, tag) {
if (err) {
console.log(err);
}
else {
note.tags.push(tag);
note.save();
res.redirect("/notes");
}
});
}
});
});
Note.find({}).populate("tags").exec(function (err, notes) {
if (err) {
console.log(err);
} else {
res.render("index", { notes: notes });
}
});

Updating a user record in Passport + MongoDB

I'm trying to update a user record in passport via a POST request. I've had a look at various tutorials and a previous answer to a similar question. I've implemented the following code:
var User = require("../models/user");
router.get("/settings/profile/:id", isLoggedIn, function(req,res){
res.render("profile/profilesettings", {
User: req.user
});
});
router.post("/settings/profile/:id", isLoggedIn, function(req,res){
User.update({_id: req.session.passport.user.id}, {
email: req.body.email,
imageUrl: req.body.imageUrl,
bio: req.body.bio
}, function (err){
console.log(err);
});
res.render("profile/profilesettings", {
User: req.user
});
})
This is the form that executes the update function.
<form class="form-horizontal" action="/settings/profile/<%= currentUser._id %>" method="POST">
<div class="form-group">
<label class="control-label col-sm-2" for="username">Username:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="username" name="username" placeholder="username" value="<%= currentUser.username %>" disabled>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="email">Email:</label>
<div class="col-sm-10">
<input type="text" class="form-control" id="email" name="email" placeholder="email" value="<%= currentUser.email %>">
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="profileimage">Upload Image:</label>
<div class="col-sm-10">
<div class="input-group">
<span class="input-group-btn">
<span class="btn btn-default btn-file">
Browse.. <input type="file" id="profileimage">
</span>
</span>
<input type="text" class="form-control" id="profileimage" name="profileimage" placeholder="Profile Pic">
</div>
</div>
</div>
<div class="form-group">
<label class="control-label col-sm-2" for="bio">Bio:</label>
<div class="col-sm-10">
<textarea class="form-control" rows="5" id="bio" name="bio" placeholder="Tell us about yourself!"><%= currentUser.bio %></textarea>
</div>
</div>
<div class="form-group">
<div class="col-sm-offset-2 col-sm-10">
<button class="btn btn-lg btn-primary">Save Changes</button>
</div>
</div>
</form>
I also have the following isLoggedIn middleware:
function isLoggedIn(req, res, next) {
if (req.isAuthenticated()) {
return next();
}
res.redirect("/login");
}
The application runs, but when I click 'Save Changes' a null result is returned and nothing is updated.
It's because you response to request before your document gets updated. You should move your response(res.render(...) inside update callback:
User.update({_id: req.session.passport.user.id}, {
email: req.body.email,
imageUrl: req.body.imageUrl,
bio: req.body.bio
}, function (err){
if (err) console.log(err);
res.render("profile/profilesettings", {
User: req.user
});
});
1) req.user._id and req.session.passport.user both are same. You can use req.user._id instead.
2) Most of my passport applications doesn't have req.session.passport.user.id, while req.session.passport.user itself is an id.
3) Try nesting inside the callbacks
router.post("/settings/profile/:id", isLoggedIn, function(req, res, next){
User.update({ id: req.session.passport.user }, {
email: req.body.email,
imageUrl: req.body.imageUrl,
bio: req.body.bio
}, function(err, user) {
if (err) return next(err);
User.findById(req.user._id, function(err, user) {
if (err) return next(err);
return res.render('profile/profilesettings', {
user:user
});
});
});
});

Resources