Edit: Thanks for your help everyone. I ended up completely rewriting the code using async await to be more readable. The issue no longer persists.
I've been getting the following error when I try to view my site's ecommerce cart at /cart:
Example app listening on port 8080
/mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongodb/lib/utils.js:132
throw err;
^
Error [ERR_HTTP_HEADERS_SENT]: Cannot set headers after they are sent to the client
at validateHeader (_http_outgoing.js:500:11)
at ServerResponse.setHeader (_http_outgoing.js:507:3)
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/controllers/cart.js:99:9
at Function.<anonymous> (/mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/lib/model.js:3928:16)
at parallel (/mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/lib/model.js:2078:12)
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/node_modules/async/internal/parallel.js:35:9
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/node_modules/async/internal/once.js:12:16
at iteratorCallback (/mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/node_modules/async/eachOf.js:52:13)
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/node_modules/async/internal/onlyOnce.js:12:16
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/node_modules/async/internal/parallel.js:32:13
at apply (/mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/lodash/_apply.js:15:25)
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/lodash/_overRest.js:32:12
at callbackWrapper (/mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/lib/model.js:2047:11)
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/lib/model.js:3928:16
at model.$__save.error (/mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/mongoose/lib/model.js:343:7)
at /mnt/c/Users/Gernene/Documents/Programming/journal-supplies-co/node_modules/kareem/index.js:297:21
This error seems to be caused by the lines:
Cart.create({token: token, discount: null}, function(err, cart) {
if (err || !cart) throw err;
res.setHeader('Set-Cookie', cookie.serialize("cart_token", token, {
path: "/",
maxAge: 60 * 60 * 24 * 7 // 1 week
}));
After looking at some similar issues, I am fairly sure the lines above are comming into conflict with these:
res.render("cart/index", {
cartItems: cartItems,
products: products,
cartCount: cartCount,
discount: discount
});
However, I'm not sure how to fix this issue and could be wrong.
Here's my full cart code:
module.exports = function(app){
// Dependencies and imported functions
const async = require('async');
const ObjectId = require('mongoose').Types.ObjectId;
const validate = require('../modules/validate');
const paypal = require('paypal-rest-sdk');
const cookie = require('cookie');
const path = require('path');
const appDir = path.dirname(require.main.filename);
const cartMod = require("../modules/cart");
const cartCount = cartMod.itemCount;
const crypto = require("crypto");
// DB
const Cart = require('../models/carts');
const CartItem = require('../models/cart_items');
const Discount = require('../models/discounts');
const Product = require('../models/products');
paypal.configure({
"host" : "api.sandbox.paypal.com",
"port" : "",
'mode': 'sandbox', //sandbox or live
'client_id': process.env.JSC_PAYPAL_CLIENT_ID,
'client_secret': process.env.JSC_PAYPAL_CLIENT_SECRET
});
const payPalPayment = (items, total) => {
return {
"intent": "sale",
"payer": {
"payment_method": "paypal"
},
"redirect_urls": {
"return_url": appDir + "/success",
"cancel_url": appDir + "/cancel"
},
"transactions": [{
"item_list": { "items": items },
"amount": {
"currency": "USD",
"total": total
},
"description": "This is the payment description."
}]
};
};
const createPayPalPayment = (payment, req, res) => {
paypal.payment.create(payment, function(err, payment) {
if (err) {
throw err;
} else {
if(payment.payer.payment_method === 'paypal') {
req.paymentId = payment.id;
var redirectUrl;
for(var i = 0; i < payment.links.length; i++) {
var link = payment.links[i];
if (link.method === 'REDIRECT') {
redirectUrl = link.href;
}
}
res.redirect(redirectUrl);
}
}
});
};
const displayCartItems = (res, cartId, cartCount, discount) => {
CartItem.find({cart: cartId}, function(err, cartItems) {
if (err) return next(err);
var products = [];
async.eachSeries(cartItems,
function(cartItem, next) {
Product.findById(cartItem.product, function(err, product) {
if (err) throw err;
products.push(product);
return next();
});
},
function(err) {
if (err) res.status(400).send("Could not display cart items");
res.render("cart/index", {
cartItems: cartItems,
products: products,
cartCount: cartCount,
discount: discount
});
}
);
});
};
const createCart = (req, res, next) => {
var token = crypto.randomBytes(20).toString("hex");
Cart.create({token: token, discount: null}, function(err, cart) {
if (err || !cart) throw err;
res.setHeader('Set-Cookie', cookie.serialize("cart_token", token, {
path: "/",
maxAge: 60 * 60 * 24 * 7 // 1 week
}));
return next();
});
};
const checkCart = (req, res, next) => {
var token = req.cookies["cart_token"];
if (!token) {
createCart(res, res, next);
} else {
Cart.find({token: token}, function(err, cart) {
if (err || !cart) createCart(res, res, next);
return next();
});
}
};
const addCartItem = (cartId, productId, quantity) => {
CartItem.findOne(
{'product': productId, "cart": cartId},
function(err, item) {
if (err || !item) {
CartItem.create({
cart: cartId,
product: productId,
quantity: quantity
});
} else {
var newQuantity = item.quantity + parseInt(quantity);
CartItem.update(
{'_id': item._id},
{quantity: newQuantity},
function(err, item) {});
}
}
);
};
const updateCartItem = (res, id, quantity) => {
CartItem.findById(id, function(err, item) {
if (err || !item) throw err;
CartItem.update({_id: id}, {quantity: quantity}, function(err, item) {
res.send("Successfully updated cart item quantity.");
});
});
};
const deleteCartItem = (res, id) => {
CartItem.findById(id, function(err, item) {
if (err || !item) throw err;
CartItem.remove({_id: id}, function(err, item) {
res.send("Successfully deleted cart item.");
});
});
};
const cartIndex = (req, res, cartCount) => {
var token = req.cookies["cart_token"];
Cart.findOne({token: token}, function(err, cart) {
if (err || !cart) throw err;
if (cart.discount) {
Discount.findById(cart.discount, function(err, discount) {
if (err || !discount) throw err;
displayCartItems(res, cart._id, discount.percent, cartCount);
});
} else {
displayCartItems(res, cart._id, 0, cartCount);
}
});
};
app.get("/discount", function (req, res) {
cartCount(req, res, function(req, res, cartCount) {
res.render("discount/index", {cartCount: cartCount});
});
});
app.post("/discount", checkCart, function (req, res) {
var code = req.body["code"];
Discount.findOne({code: code}, function(err, discount) {
if (err || !discount) {
cartCount(req, res, function(req, res, cartCount) {
res.render("discount/index", {err: true, cartCount: cartCount});
});
} else {
var cartToken = req.cookies["cart_token"];
Cart.findOne({token: cartToken}, function(err, cart) {
if (err || !cart) throw err;
Cart.update(
{_id: cart._id},
{discount: discount._id},
function(err, cart) {
cartCount(req, res, function(req, res, cartCount) {
res.render("discount/index", {err: false, cartCount: cartCount});
});
}
);
});
}
});
});
app.get('/cart', checkCart, function (req, res, next) {
cartCount(req, res, cartIndex);
});
app.post('/cart', checkCart, function (req, res, next) {
var token = req.cookies["cart_token"];
Cart.findOne({token: token}, function(err, cart) {
if (err || !cart) return next(err);
CartItem.find({cart: cart._id}, function(err, cartItems) {
if (err) return next(err);
var purchases = [];
var total = 0;
async.eachSeries(cartItems,
function(cartItem, next) {
Product.findById(cartItem.product, function(err, product) {
if (err) {
res.status(400).send("Could not find products");
} else {
var purchase = {};
purchase["name"] = product.name;
purchase["sku"] = product.name;
purchase["price"] = product.price;
purchase["currency"] = "USD";
purchase["quantity"] = cartItem.quantity;
purchases.push(purchase);
total += product.price * cartItem.quantity;
}
return next();
});
},
function(err) {
if (err) {
res.status(400).send("Could not display cart items");
} else {
if (cart.discount) {
Discount.findById(cart.discount, function(err, discount) {
if (err || !discount) throw err;
var discountItem = {};
discountItem["name"] = "Discount";
discountItem["sku"] = "Discount";
discountItem["price"] = -1 * (total * discount.percent / 100);
discountItem["currency"] = "USD";
discountItem["quantity"] = 1;
purchases.push(discountItem);
total += discountItem.price;
var payment = payPalPayment(purchases, total);
createPayPalPayment(payment, req, res);
});
} else {
var payment = payPalPayment(purchases, total);
createPayPalPayment(payment, req, res);
}
}
}
);
});
});
});
app.post('/cart/confirm', checkCart, function (req, res, next) {
var cartToken = req.cookies["cart_token"];
Cart.find({token: cartToken}, function(err, cart) {
if (err || !cart) return next(err);
else {
CartItem.find({cart: cart._id}, function(err, cartItems) {
if (err) return next(err);
var products = [];
async.eachSeries(cartItems,
function(cartItem, next) {
Product.findById(cartItem.product, function(err, product) {
if (err) {
res.status(400).send("Could not find products");
} else {
products.push(product);
}
return next();
});
},
function(err) {
if (err) {
res.status(400).send("Could not display cart items");
} else {
executePayPalPayment(req);
res.render("cart/index", {
cartItems: cartItems,
products: products
});
}
}
);
});
}
});
});
app.post('/cart/add/:id', checkCart, function (req, res, next) {
var cartToken = req.cookies["cart_token"];
var productId = req.params.id;
var quantity = validate.sanitize(req.body[`quantity`]);
if (validate.isInt(quantity)) {
Product.findById(productId, function(err, product) {
if (err || !product) throw err;
Cart.findOne({token: cartToken}, function(err, cart) {
if (err || !cart) throw err;
addCartItem(cart._id, product._id, quantity);
res.send("Product added!")
});
});
}
});
app.post('/cart/update/:id', checkCart, function (req, res, next) {
var id = req.params.id;
var quantity = req.body["quantity"];
if (!validate.isInt(quantity)) throw err;
else if (quantity < 1) {
deleteCartItem(res, id);
} else {
updateCartItem(res, id, quantity);
}
});
app.post('/cart/delete/:id', checkCart, function (req, res, next) {
var id = req.params.id;
deleteCartItem(res, id);
});
}
const createCart = (req, res, next) => {
var token = crypto.randomBytes(20).toString("hex");
Cart.create({token: token, discount: null}, function(err, cart) {
if (err || !cart) throw err;
res.setHeader('Set-Cookie', cookie.serialize("cart_token", token, {
path: "/",
maxAge: 60 * 60 * 24 * 7 // 1 week
}));
return next();
});
};
const cartIndex = (req, res, cartCount) => {
var token = req.cookies["cart_token"];
Cart.findOne({token: token}, function(err, cart) {
if (err || !cart) throw err;
if (cart.discount) {
Discount.findById(cart.discount, function(err, discount) {
if (err || !discount) throw err;
displayCartItems(res, cart._id, discount.percent, cartCount);
});
} else {
displayCartItems(res, cart._id, 0, cartCount);
}
});
};
app.get('/cart', checkCart, function (req, res, next) {
cartCount(req, res, cartIndex);
});
}
Essentially, I'm trying to check if the user has any cookies which could identify their cart and create a new cookie/cart if not. Also, I call cartCount to display the number of cart items at the top of each page.
I really appreciate any help! Please let me know if you need more information!
Edit:
Full app.js:
// Dependencies
const express = require("express");
const app = express();
const bodyParser = require("body-parser");
const cookieParser = require("cookie-parser");
const mongoose = require("mongoose");
const path = require("path");
const pug = require("pug");
const session = require("express-session");
const validate = require("./modules/validate");
const cartMod = require("./modules/cart");
const cartCount = cartMod.itemCount;
const port = process.env.PORT || 8080;
// DB
const mongoURI = 'mongodb://localhost/db';
mongoose.connect(process.env.MONGODB_URI || mongoURI);
const db = mongoose.connection;
db.on("error", console.error.bind(console, "connection error:"));
db.once("open", function() {
// Connected!
});
app.set('trust proxy', 1)
app.set("views", __dirname + "/views");
app.set("view engine", "pug");
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(__dirname + "/assets"));
app.use(session({
secret: process.env.JSC_SESSIONS_SECRET,
resave: true,
saveUninitialized: false
}));
// Routes
require("./controllers/cart")(app);
require("./controllers/categories")(app);
require("./controllers/discount")(app);
require("./controllers/nav_pages")(app);
require("./controllers/pages")(app);
require("./controllers/products")(app);
require("./controllers/users")(app);
app.use(function(req, res, next) {
res.status(404);
// respond with html page
if (req.accepts('html')) {
cartCount(req, res, function(req, res, cartCount) {
res.render("errors/404", { cartCount: cartCount, url: req.url });
return;
});
}
});
app.listen(port, function() {
console.log("Example app listening on port " + port)
});
Add return if err or cart not exist in checkCart:
if (err || !cart) return createCart(res, res, next);
return next();
This error usually means that you called res.send() or res.end() or any of the methods that send a response to the frontend. These methods can only be called once, and after calling them you're expected not to interact with the response anymore (for example, you can't call res.setHeader if before that you called res.render.
This code:
async.eachSeries(cartItems,
function(cartItem, next) {
Product.findById(cartItem.product, function(err, product) {
if (err) throw err;
products.push(product);
return next();
});
},
function(err) {
if (err) res.status(400).send("Could not display cart items");
res.render("cart/index", {
cartItems: cartItems,
products: products,
cartCount: cartCount,
discount: discount
});
}
);
If there's an error (and res.render is fired), then you should not send information to the client anymore (because you already did). It looks like it failed for one of the cart items but you still keep interacting with the res object.
To fix the issue, avoid calling res after you've sent data to the client.
Related
Hello I am creating login-register system in my project, actually I made it in many of my previous projects but this time I am getting an error, for which I've seen many posts related to this but none of them worked for me.
I got some issues on "verifySignUp.js" that
"TypeError: Cannot read property 'username' of undefined"
on last 'undefined' of line 'username: req.body.username'
and This is my postman data push
{
"username":"deayhrovv",
"email":"deayhrovv#gmail.com",
"password":"123456",
"roles":["user","moderater"]
}
this is my server.js
var express = require("express");
var bodyParser = require("body-parser");
var cors = require("cors");
var dbConfig = require("./app/config/db.config");
var db = require("./app/models");
var Role = db.role;
var app = express();
// routes
require('./app/routes/auth.routes')(app);
require('./app/routes/user.routes')(app);
var corsOptions = {
origin: "http://localhost:8080"
};
db.mongoose
.connect(`mongodb://${dbConfig.HOST}:${dbConfig.PORT}/${dbConfig.DB}`, {
useNewUrlParser: true,
useUnifiedTopology: true
})
.then(() => {
console.log("Successfully connect to MongoDB.");
initial();
})
.catch(err => {
console.error("Connection error", err);
process.exit();
});
function initial() {
Role.estimatedDocumentCount((err, count) => {
if (!err && count === 0) {
new Role({
name: "user"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'user' to roles collection");
});
new Role({
name: "moderator"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'moderator' to roles collection");
});
new Role({
name: "admin"
}).save(err => {
if (err) {
console.log("error", err);
}
console.log("added 'admin' to roles collection");
});
}
});
}
app.use(cors(corsOptions));
// parse requests of content-type - application/json
app.use(bodyParser.json())
// parse requests of content-type - application/x-www-form-urlencoded
app.use(bodyParser.urlencoded({ extended: false }))
// simple route
app.get("/", (req, res) => {
res.json({ message: "Welcome to Canteen Food Order APIs application ."});
});
// set port, listen for requests
const PORT = process.env.PORT || 8080;
app.listen(PORT, () => {
console.log(`Server is running on url ${corsOptions.origin}.`);
});
This is my middlewares
const { verifySignUp } = require("../middlewares");
const controller = require("../controllers/auth.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"x-access-token, Origin, Content-Type, Accept"
);
next();
});
app.post(
"/api/auth/signup",
[
verifySignUp.checkDuplicateUsernameOrEmail,
verifySignUp.checkRolesExisted
],
controller.signup
);
app.post("/api/auth/signin", controller.signin);
};
This is my verifySignUp.js
const db = require("../models");
const ROLES = db.ROLES;
const User = db.user;
checkDuplicateUsernameOrEmail = (req, res, next) => {
User.findOne()
// Username
User.findOne({
username: req.body.username
}).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (user) {
res.status(400).send({ message: "Failed! Username is already in use!" });
return;
}
// Email
User.findOne({
email: req.body.email
}).exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (user) {
res.status(400).send({ message: "Failed! Email is already in use!" });
return;
}
next();
});
});
};
checkRolesExisted = (req, res, next) => {
if (req.body.roles) {
for (let i = 0; i < req.body.roles.length; i++) {
if (!ROLES.includes(req.body.roles[i])) {
res.status(400).send({
message: `Failed! Role ${req.body.roles[i]} does not exist!`
});
return;
}
}
}
next();
};
const verifySignUp = {
checkDuplicateUsernameOrEmail,
checkRolesExisted
};
module.exports = verifySignUp;
Incase of GET request, you need to access the parameters using req.query instead of req.body. So, modify the simple route to following
app.get("/", (req, res) => {
Username = req.query.username
res.json({ message: "Welcome to Canteen Food Order APIs application ." + Username });
});
I am using Syncfusion Scheduler in my MEAN-stack application. This is the code for handling getting / inserting / editing the appointments:
MongoClient.connect(url, function (err, db) {
if (err) throw err;
var dbo = db.db("meanstacknew");
app.use(function (req, res, next) {
res.header("Access-Control-Allow-Origin", "*");
res.header("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept");
next();
});
app.post("/GetData", (req, res) => {
var user = req.user;
const token = req.get("authorization");
dbo.collection('ScheduleData').find({}).toArray((err, cus) => {
res.send(cus);
console.log(token);
});
});
app.post("/BatchData", (req, res) => {
console.log(req.body);
var eventData = [];
if (req.body.action == "insert" || (req.body.action == "batch" && req.body.added.length > 0)) {
(req.body.action == "insert") ? eventData.push(req.body.value) : eventData = req.body.added;
for (var i = 0; i < eventData.length; i++) {
var sdate = new Date(eventData[i].StartTime);
var edate = new Date(eventData[i].EndTime);
eventData[i].StartTime = (new Date(+sdate - (sdate.getTimezoneOffset() * 60000)));
eventData[i].EndTime = (new Date(+edate - (edate.getTimezoneOffset() * 60000)));
eventData[i].CreatedBy = //here I want to send the email to the database
dbo.collection('ScheduleData').insertOne(eventData[i]);
}
}
if (req.body.action == "update" || (req.body.action == "batch" && req.body.changed.length > 0)) {
(req.body.action == "update") ? eventData.push(req.body.value) : eventData = req.body.changed;
for (var i = 0; i < eventData.length; i++) {
delete eventData[i]._id;
var sdate = new Date(eventData[i].StartTime);
var edate = new Date(eventData[i].EndTime);
eventData[i].StartTime = (new Date(+sdate - (sdate.getTimezoneOffset() * 60000)));
eventData[i].EndTime = (new Date(+edate - (edate.getTimezoneOffset() * 60000)));
dbo.collection('ScheduleData').updateOne({ "Id": eventData[i].Id }, { $set: eventData[i] });
}
}
if (req.body.action == "remove" || (req.body.action == "batch" && req.body.deleted.length > 0)) {
(req.body.action == "remove") ? eventData.push({ Id: req.body.key }) : eventData = req.body.deleted;
for (var i = 0; i < eventData.length; i++) {
dbo.collection('ScheduleData').deleteOne({ "Id": eventData[i].Id });
}
}
res.send(req.body);
});
I am calling those endpoints in my schedule.component.ts:
private dataManager: DataManager = new DataManager({
url: 'http://localhost:8000/GetData',
crudUrl: 'http://localhost:8000/BatchData',
adaptor: new UrlAdaptor,
crossDomain: true
});
I am using the JWT token for user authorization at the moment, for example, this is my /profile endpoint:
router.get('/profile', authRequired, (req, res) => {
User.findOne({_id: req.decoded.userId}).select('username email').exec((err, user) =>{
if(err){
res.json({success: false, message: err});
} else {
if(!user){
res.json({success: false, message: 'User not found'});
} else {
res.json({success: true, user: user})
}
}
});
});
How can I access the users email to set the 'createdBy' field in the appointment?
If I console.log the token this way I just get undefined
This is the authRequired function in middleware.js file:
function authRequired(req, res, next) {
const token = req.get("authorization");
if (!token) {
res.json({ success: false, message: "No token provided" });
} else {
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
res.json({ success: false, message: "Token is invalid" + err });
} else {
req.decoded = decoded;
next();
}
});
}
}
module.exports = {
authRequired: authRequired
};
You are not running authRequired middleware on the POST /GetData route so the token is not extracted. Make sure you are also sending the token in the POST.
Update the route as you do in router.get('/profile', authRequired, (req, res) => { so you can get the decoded token.
app.post("/GetData", authRequired, (req, res) => {
var user = req.decoded; //decoded
...
});
i export all the secret Api and password and cloudinary credentials to heroku using heroku config:set what syntax do i use now to replace process.env that i was using in development since i am not using .env file in the production. i am looking for syntax to replace the process.env
here is my code:
//----------------------------------------------------------------------------//
//--------------------------Dependencies For Route----------------------------//
//----------------------------------------------------------------------------//
var express = require("express");
var router = express.Router();
var Campground = require("../models/campground");
var middleware = require("../middleware");
var NodeGeocoder = require('node-geocoder');
var multer = require('multer');
var async = require("async");
//Node Geocoder API Configuration
var options = {
provider: 'google',
httpAdapter: 'https',
apiKey: process.env.GEOCODER_API_KEY,
formatter: null
};
var geocoder = NodeGeocoder(options);
//Multer Storage
var storage = multer.diskStorage({
filename: function(req, file, callback) {
callback(null, Date.now() + file.originalname);
}
});
//Multer Filter
var imageFilter = function (req, file, cb) {
// accept image files only
if (!file.originalname.match(/\.(jpg|jpeg|png|gif)$/i)) {
return cb(new Error('Only image files are allowed!'), false);
}
cb(null, true);
};
//Storing Image + Filter
var upload = multer({ storage: storage, fileFilter: imageFilter});
//Cloudinary Configuration
var cloudinary = require('cloudinary');
cloudinary.config({
cloud_name: 'dnposhqpc',
api_key: process.env.CLOUDINARY_API_KEY,
api_secret: process.env.CLOUDINARY_API_SECRET
});
// INDEX - SHOW ALL CAMPGROUNDS
router .get("/", function(req, res){
var perPage = 8;
var pageQuery = parseInt(req.query.page);
var pageNumber = pageQuery ? pageQuery : 1;
var noMatch = null;
if (req.query.search) {
const regex = new RegExp(escapeRegex(req.query.search), 'gi');
// GET ALL CAMPGROUNDS FROM THE DB
Campground.find({"name": regex}, function(err, allCampgrounds){
if(err || !allCampgrounds){
console.log(err);
req.flash("error", "Something went wrong!");
} else {
if(allCampgrounds.length < 1){
noMatch = "No campground match that query, please try again.";
}
res.render("campgrounds/index", {campgrounds:allCampgrounds, page: 'campgrounds', noMatch: noMatch});
}
});
} else {
Campground.find({}).skip((perPage * pageNumber) - perPage).limit(perPage).exec( function(err, allCampgrounds){
Campground.count().exec(function (err, count) {
if(err) {
console.log(err);
} else {
res.render("campgrounds/index", {campgrounds:allCampgrounds, page: 'campgrounds', noMatch: noMatch,
campgrounds: allCampgrounds,
current: pageNumber,
pages: Math.ceil(count / perPage)
});
}
});
})
}
});
//----------------------------------------------------------------//
//-----------------CREATE NEW CAMPGROUNDS -----------//
//----------------------------------------------------------------//
//CREATE - ADD NEW CAMPGROUND TO DB
router.post("/", middleware.isLoggedIn, upload.single('image'), function(req, res){
// local variables
// Request The Name
var name = req.body.name;
// Request The Image
var image = req.body.image;
var imageId = req.body.imageId;
// Request The descriptions
var desc = req.body.descriptions;
// Request The Price
var price = req.body.price;
// Request The Author's ID + Username
var author = {
id: req.user._id,
username: req.user.username
};
//Location Code - Geocode Package
geocoder.geocode(req.body.location, function (err, data ) {
//Error Handling For Autocomplete API Requests
//Error handling provided by google docs -https://developers.google.com/places/web-service/autocomplete
if (err || data.status === 'ZERO_RESULTS') {
req.flash('error', 'Invalid address, try typing a new address');
return res.redirect('back');
}
//Error handling provided by google docs -https://developers.google.com/places/web-service/autocomplete
if (err || data.status === 'REQUEST_DENIED') {
req.flash('error', 'Something Is Wrong Your Request Was Denied');
return res.redirect('back');
}
// Error handling provided by google docs -https://developers.google.com/places/web-service/autocomplete
if (err || data.status === 'OVER_QUERY_LIMIT') {
req.flash('error', 'All Requests Used Up');
return res.redirect('back');
}
//Credit To Ian For Fixing The Geocode Problem - https://www.udemy.com/the-web-developer-bootcamp/learn/v4/questions/2788856
var lat = data[0].latitude;
var lng = data[0].longitude;
var location = data[0].formattedAddress;
//Reference: Zarko And Ian Helped Impliment the Image Upload - https://github.com/nax3t/image_upload_example
cloudinary.uploader.upload(req.file.path, function (result) {
//image variable needs to be here so the image can be stored and uploaded to cloudinary
image = result.secure_url;
imageId= result.public_id;
//Captures All Objects And Stores Them
var newCampground = {name: name, image: image, description: desc, price: price, author:author, location: location, lat: lat, lng: lng, imageId: imageId};
// Create a new campground and save to DB
Campground.create(newCampground, function(err, newlyCreated){
if(err || !newlyCreated){
//Logs Error
req.flash('error', err.message);
return res.redirect('back');
} else {
//redirect back to campgrounds page
//Logs Error
console.log(newlyCreated);
//Flash Message
req.flash("success", "Campground Added Successfully");
//Redirects Back To Featured Campgrounds Page
res.redirect("/campgrounds");
}
});
});
});
});
// NEW - SHOW FORM TO CREATE NEW CAMPGROUND
router.get("/new", middleware.isLoggedIn, function(req, res) {
res.render("campgrounds/new");
});
// SHOW - SHOW ONLY ONE CAMPGROUND FROM THE DB
router.get("/:id", function(req, res) {
// find campround with the Provided id
Campground.findById(req.params.id).populate("comment").exec(function(err, foundcampground){
if(err || !foundcampground){
console.log(err);
req.flash("error", "Sorry, that campground does not exist!");
res.redirect("back"); // you need to redirect the user in case there isn't anything found by the provided id
} else {
console.log(foundcampground);
// render the show template
res.render("campgrounds/show", {campground: foundcampground});
}
});
});
// EDIT CAMPGROUND ROUTE
router.get("/:id/edit", middleware.checkCampgroundOwnership, function(req, res) {
Campground.findById(req.params.id, function(err, foundcampground){
if(err || !foundcampground){
console.log(err);
req.flash("error", "campground not found");
return res.redirect("back");
}
res.render("campgrounds/edit", {campground: foundcampground});
});
});
//----------------------------------------------------------------//
//-----------------Update CAMPGROUNDS -----------//
//----------------------------------------------------------------//
// UPDATE CAMPGROUND ROUTE
router.put("/:id", middleware.checkCampgroundOwnership, upload.single('image'), function(req, res, next){
async.waterfall([
function(done) {
geocoder.geocode(req.body.campground.location, function (err, data) {
if (err || !data.length) {
req.flash('error', 'Invalid address');
return res.redirect('back');
}
done(null, data);
});
},
function(data, done) {
// handle image uploading
Campground.findById(req.params.id, function(err, foundCampground) {
if(err || !foundCampground) {
console.log(err);
req.flash("error", err.message);
return res.redirect("back");
} else {
done(null, foundCampground, data);
}
});
},
function(foundCampground, data, done) {
if(req.file) {
cloudinary.v2.uploader.destroy(foundCampground.imageId, function(err, result) {
if(err) {
req.flash("error", err.message);
return res.redirect("back");
} else {
done(null, foundCampground, data);
}
});
} else {
done(null, foundCampground, data);
}
},
function(foundCampground, data, done) {
// if new image uploaded, destroy the old one
if(req.file) {
cloudinary.uploader.upload(req.file.path, function(result) {
req.body.campground.imageId = result.public_id;
req.body.campground.image = result.secure_url;
done(null, foundCampground, data);
});
} else {
done(null, foundCampground, data);
}
},
function(foundCampground, data) {
// update
// var newCampground = {name: req.name, price: price, image: image, imageId: imageId, description: desc, author:author, location: location, lat: lat, lng: lng};
req.body.campground.lat = data[0].latitude;
req.body.campground.lng = data[0].longitude;
req.body.campground.location = data[0].formattedAddress;
Campground.findByIdAndUpdate(req.params.id, req.body.campground, function(err, campground){
if(err){
req.flash("error", err.message);
res.redirect("back");
} else {
req.flash("success","Successfully Updated!");
res.redirect("/campgrounds/" + campground._id);
}
});
}
], function(err) {
if (err) return next(err);
res.redirect('/campgrounds');
});
});
// DESTORY CAMPGROUND ROUTE
router.delete("/:id", middleware.checkCampgroundOwnership, function(req, res) {
Campground.findByIdAndRemove(req.params.id, function(err, foundcampground){
if(err || !foundcampground){
req.flash("error", "Something went wrong!");
res.redirect("/campgrouns");
} else {
req.flash("success", "You have successfully deleted a campground");
res.redirect("/campgrounds");
}
});
})
// Middleware
function escapeRegex(text) {
return text.replace(/[-[\]{}()*+?.,\\^$|#\s]/g, "\\$&");
};
module.exports = router;
Thanks for your assistance
You use the same syntax.
For example, if I did:
heroku config:set EXAMPLE_NAME=sainteverest
then I can do the following:
console.log(process.env.EXAMPLE_NAME)
// sainteverest
this is a part of my model
router.get('/subscription', function (req, res, next) {
var membership = require('../controllers/membership.js');
var jData = membership.getAll(req, res);
res.render('subscription', { title: 'Subscription', data : jData });
});
this is a part of my controller.js
var db = require('../db.js');
module.exports = {
//home: function (req, res, next) {
// res.send('home page');
//},
insert: function (req, res) {
var body = req.body; //_.pick(req.body, 'description', 'completed');
db.membership.create(body).then(function (membership) {
res.json(membership.toJSON());
}, function (e) {
res.status(500).json(e);
});
},
updateById: function (req, res, next) {
//var Id = parseInt(req.params.id, 10);
var body = req.body;
db.membership.update(body, { where: { id: parseInt(_.propertyOf(body)('id'), 10) } }).then(function (membership) {
if (!!membership) {
res.json(membership.toJSON());
} else {
res.status(404).send();
}
}, function (e) {
res.status(500).json(e);
});
},
deleteById: function (req, res, next) {
//var Id = parseInt(req.params.id, 10);
var body = req.body;
db.membership.destroy({ where: { id: parseInt(_.propertyOf(body)('id'), 10) } }).then(function (membership) {
if (!!membership) {
console.log('The Row with the Id : ' + _.propertyOf(body)('id') + ' deleted successfully!');
} else {
res.status(404).send();
}
}, function (e) {
res.status(500).json(e);
});
},
deleteAll: function (req, res, next) {
db.membership.truncate().then(function () {
console.log('All rows deleted successfully!');
}, function (e) {
res.status(500).json(e);
});
},
getById: function (req, res) {
var Id = parseInt(req.params.id, 10);
db.membership.findById(Id).then(function (membership) {
if (!!membership) {
console.log('\n\nMEMBERSHIP : ' + JSON.stringify(membership.toJSON()));
res.json(membership.toJSON());
//return membership.toJSON();
} else {
res.status(404).send();
}
}, function (e) {
res.status(500).send();
});
},
getAll: function (req, res) {
var where = {};
db.membership.findAll({
where: where
}).then(function (membership) {
res.json(membership.toJSON());
}, function (e) {
res.status(500).send();
});
}
};
i am trying to get aal data in my model data comes perfectly so no issue in controller
but res.render function data could not be passed to jade.
according to me res.render function call before jdata variable filled.
any solution about it tell me.
thanks in advance
You can't send the response two times, if you send the res in the controller you can't send it again in the model, you should use a callback:
Controller:
getAll: function(cb) {
var where = {};
db.membership.findAll({
where: where
}).then(function(membership) {
cb({
data: membership.toJSON()
});
}, function(e) {
cb({
error: e
});
});
}
Model:
router.get('/subscription', function (req, res, next) {
var membership = require('../controllers/membership.js');
var jData = membership.getAll(function (cb) {
if (cb.error) res.status(400).send();
res.render('subscription', { title: 'Subscription', data : cb.data });
});
});
I have no experience with NodJs. I am trying to run app.js file from command prompt using node command and i am getting this error
D:\Imports\sparkleshare-dashboard\node_modules\connect-redis\lib\connect-redis.j
s:96
RedisStore.prototype.__proto__ = Store.prototype;
^
TypeError: Cannot read property 'prototype' of undefined
at module.exports (D:\Imports\sparkleshare-dashboard\node_modules\connect-re
dis\lib\connect-redis.js:96:41)
at Object.<anonymous> (D:\Imports\sparkleshare-dashboard\app.js:12:42)
at Module._compile (module.js:456:26)
at Object.Module._extensions..js (module.js:474:10)
at Module.load (module.js:356:32)
at Function.Module._load (module.js:312:12)
at Function.Module.runMain (module.js:497:10)
at startup (node.js:119:16)
at node.js:902:3
here is my app.js file
/**
* Module dependencies.
*/
var express = require('express');
var querystring = require('querystring');
var i18n = require("i18n");
var config = require('./config');
var errors = require('./error');
var utils = require('./utils');
var RedisStore = require('connect-redis')(express);
var redis = require('redis'), redisClient = redis.createClient();
var app = null;
if (config.https.enabled) {
var fs = require("fs");
var privateKey = fs.readFileSync(config.https.key);
var certificate = fs.readFileSync(config.https.cert);
app = module.exports = express.createServer({ key: privateKey, cert: certificate });
} else {
app = module.exports = express.createServer();
}
var session = express.session({ secret: config.sessionSecret, store: new RedisStore() });
i18n.configure({
locales: ['en', 'cs', 'de', 'el']
});
// Configuration
app.configure(function(){
var lf = utils.getLoggingFormat();
if (lf) {
app.use(express.logger(lf));
}
app.set('views', __dirname + '/views');
app.set('view engine', 'jade');
app.set('basepath', config.basepath);
app.use(function(req, res, next) {
if ('x-forwarded-proto' in req.headers && req.headers['x-forwarded-proto'] == 'https') {
req.connection.encrypted = true;
}
next();
});
app.use(express.bodyParser());
app.use(express.methodOverride());
app.use(express.cookieParser());
app.use(express.compiler({ src: __dirname + '/public', enable: ['sass'] }));
app.use(express.static(__dirname + '/public'));
app.use(i18n.init);
app.use(app.router);
});
var FolderProvider = require('./folderProvider').FolderProvider;
var folderProvider = new FolderProvider(config.folders);
var DeviceProvider = require('./deviceProvider').DeviceProvider;
var deviceProvider = new DeviceProvider(redisClient);
var UserProvider = require('./userProvider').UserProvider;
var userProvider = new UserProvider(redisClient, deviceProvider);
var LinkCodeProvider = require('./linkCodeProvider').LinkCodeProvider;
var linkCodeProvider = new LinkCodeProvider();
var middleware = require('./middleware');
middleware.setup(userProvider, deviceProvider, folderProvider, linkCodeProvider);
app.configure('development', function(){
app.use(express.errorHandler({ dumpExceptions: true, showStack: true }));
});
app.configure('production', function(){
app.use(errors.errorHandler);
app.use(express.errorHandler());
});
function auth(login, pass, next) {
userProvider.findByLogin(login, function(error, user) {
if (!user) {
return next(new Error('Invalid login'));
}
if (user.checkPassword(pass)) {
return next(null, user);
} else {
return next(new Error('Invalid login'));
}
});
}
// Dynamic helpers
app.dynamicHelpers({
messages: require('express-messages'),
user: function(req, res) {
return req.currentUser;
},
basepath: function() {
return this.set('basepath');
}
});
app.helpers({
convertSize: function(bytes) {
var unit = 0;
while (unit < 3 && bytes >= 1024) {
unit++;
bytes /= 1024;
}
return (Math.round(bytes * 100, 2) / 100).toString() + " " + ["", "Ki", "Mi", "Gi"][unit] + "B";
},
__i: i18n.__,
__n: i18n.__n
});
// Routes
app.all(/^(?!\/api\/).+/, function(req, res, next) {
session(req, res, next);
});
require('./api')(app, deviceProvider, folderProvider, middleware);
app.get('/', function(req, res){
res.redirect('/login');
});
app.get('/logout', function(req, res){
req.session.destroy(function(){
res.redirect('home');
});
});
app.get('/login', function(req, res){
userProvider.getUserCount(function(error, count) {
if (count < 1) {
res.redirect('/createFirstUser');
} else {
if (req.session.user) {
res.redirect('/folder');
} else {
res.render('login');
}
}
});
});
app.get('/createFirstUser', middleware.userDbEmpty, function(req, res) {
res.render('createFirstUser', { formval: {} });
});
app.post('/createFirstUser', middleware.userDbEmpty, function(req, res) {
var reRenderForm = function() {
res.render('createFirstUser', {
formval: req.body
});
};
if (!req.body.passwd1) {
req.flash('error', i18n.__('Password could not be empty'));
return reRenderForm();
}
if (req.body.passwd1 != req.body.passwd2) {
req.flash('error', i18n.__('Passwords must match'));
return reRenderForm();
}
userProvider.createNew(req.body.login, req.body.realname, req.body.passwd1, true, [], function(error, user) {
if (error) {
req.flash('error', error);
reRenderForm();
} else {
res.redirect('/login');
}
});
});
app.post('/login', function(req, res){
auth(req.body.login, req.body.password, function(error, user) {
if (error) {
req.flash('error', error);
res.render('login');
} else {
if (user) {
req.session.regenerate(function(){
req.session.user = user;
res.redirect('back');
});
} else {
req.flash('error', error);
res.render('login');
}
}
});
});
app.get('/changeProfile', middleware.isLogged, function(req, res) {
res.render('changeProfile', {
formval: req.currentUser
});
});
app.post('/changeProfile', middleware.isLogged, function(req, res, next) {
var reRenderForm = function() {
res.render('changeProfile', {
formval: req.body
});
};
var updatePassword = false;
if (req.body.new1) {
if (req.body.new1 != req.body.new2) {
req.flash('error', i18n.__('Passwords must match'));
return reRenderForm();
}
updatePassword = true;
}
var user = req.currentUser;
if (updatePassword) {
user.setPassword(req.body.new1);
req.flash('info', i18n.__('Password updated'));
}
user.name = req.body.name;
userProvider.updateUser(user, function(error) {
req.flash('info', i18n.__('Profile updated'));
res.redirect('back');
});
});
app.get('/manageUsers', [middleware.isLogged, middleware.isAdmin], function(req, res, next) {
userProvider.findAll(function(error, u) {
if (error) { return next(error); }
res.render('manageUsers', {
users: u
});
});
});
app.get('/modifyUser/:uid', [middleware.isLogged, middleware.isAdmin, middleware.loadUser], function(req, res, next) {
folderProvider.findAll(function(error, folders) {
if (error) { return next(error); }
res.render('modifyUser', {
u: req.loadedUser,
folders: folders
});
});
});
app.post('/modifyUser/:uid', [middleware.isLogged, middleware.isAdmin, middleware.loadUser], function(req, res, next) {
folderProvider.findAll(function(error, folders) {
if (error) { return next(error); }
var u = req.loadedUser;
u.name = req.body.name;
u.admin = req.body.admin == 't' ? true : false;
u.acl = req.body.acl ? req.body.acl : [];
userProvider.updateUser(u, function(error) {
req.flash('info', i18n.__('User updated'));
res.redirect('back');
});
});
});
app.get('/deleteUser/:uid', [middleware.isLogged, middleware.isAdmin, middleware.loadUser], function(req, res, next) {
res.render('deleteUser', {
u: req.loadedUser
});
});
app.post('/deleteUser/:uid', [middleware.isLogged, middleware.isAdmin, middleware.loadUser], function(req, res, next) {
var reRenderForm = function() {
res.render('deleteUser', {
u: req.body
});
};
var u = req.loadedUser;
userProvider.deleteUser(u.uid, function(error) {
if (error) {
req.flash('error', error.message);
reRenderForm();
} else {
req.flash('info', i18n.__('User deleted'));
res.redirect('/manageUsers');
}
});
});
app.get('/createUser', [middleware.isLogged, middleware.isAdmin], function(req, res) {
res.render('createUser', { formval: {} });
});
app.post('/createUser', [middleware.isLogged, middleware.isAdmin], function(req, res) {
var reRenderForm = function() {
res.render('createUser', {
formval: req.body
});
};
if (!req.body.passwd1) {
req.flash('error', i18n.__('Password could not be empty'));
return reRenderForm();
}
if (req.body.passwd1 != req.body.passwd2) {
req.flash('error', i18n.__('Passwords must match'));
return reRenderForm();
}
userProvider.createNew(req.body.login, req.body.realname, req.body.passwd1, req.body.admin == 't', [], function(error, user) {
if (error) {
req.flash('error', error);
reRenderForm();
} else {
req.flash('info', i18n.__('User created'));
res.redirect('/manageUsers');
}
});
});
app.get('/publicFolder/:folderId', function(req, res, next) {
folderProvider.findById(req.params.folderId, function(error, folder) {
if (!folder.pub) {
next(new errors.Permission('This is not a public folder'));
} else {
var filename = req.param('name');
if (!filename) {
filename = 'file';
}
res.attachment(filename);
folder.getRawData(req,
function(error, data) {
if (error) { return next(error); }
res.write(data);
},
function(error, data) {
if (error) { return next(error); }
res.end();
}
);
}
});
});
app.get('/recentchanges/:folderId?', middleware.isLogged, middleware.checkFolderAcl, function(req, res, next) {
folderProvider.findById(req.params.folderId, function(error, folder) {
if (error) { return next(error); }
folder.getRecentChanges(req, function(error, data) {
if (error) { return next(error); }
res.render('recentchanges', {
data: data,
folder: folder
});
});
});
});
app.get('/folder/:folderId?', middleware.isLogged, middleware.checkFolderAcl, function(req, res, next) {
if (!req.params.folderId) {
folderProvider.findAll(function(error, folders){
if (error) { return next(error); }
utils.aclFilterFolderList(folders, req.currentUser);
res.render('folders', {
folders: folders
});
});
} else {
folderProvider.findById(req.params.folderId, function(error, folder) {
if (error) { return next(error); }
if (req.param('type') == 'file') {
var filename = req.param('name');
if (!filename) {
filename = 'file';
}
res.attachment(filename);
folder.getRawData(req,
function(error, data) {
if (error) { return next(error); }
res.write(data);
},
function(error, data) {
if (error) { return next(error); }
res.end();
}
);
} else {
folder.getItems(req, function(error, list) {
if (error) { return next(error); }
var curPath = req.param('path');
var parUrl = null;
if (curPath) {
var parPath = curPath.split('/');
parPath.pop();
parPath = parPath.join('/');
parUrl = querystring.stringify({
path: parPath
});
}
res.render('folder', {
folder: folder,
tree: list,
path: curPath,
parUrl: parUrl
});
});
}
});
}
});
app.get('/download/:folderId', middleware.isLogged, middleware.checkFolderAcl, function(req, res, next) {
folderProvider.findById(req.params.folderId, function(error, folder) {
if (error) { return next(error); }
var headersSent = false;
var maybeSentHeaders = function() {
if (headersSent) {
return;
}
headersSent = true;
var filename = 'archive';
var path = req.param('path');
if (path && path != '') {
filename += '-' + path.replace(/[^\w\d-]/, '_');
}
filename += '-' + req.params.folderId.substring(0, 8) + '.zip';
res.writeHead(200, {
'Content-Type': 'application/zip',
'Content-Disposition': 'attachment; filename="' + filename + '"'
});
};
folder.createArchive(req, function(error, data) {
if (error) { return next(error); }
maybeSentHeaders();
res.write(data);
},
function(error, data) {
if (error) { return next(error); }
maybeSentHeaders();
res.end();
}
);
});
});
app.get('/linkedDevices', middleware.isLogged, function(req, res, next) {
if (req.currentUser.admin) {
deviceProvider.findAll(function(error, devices) {
if (error) { return next(error); }
r = function(logins) {
res.render('linkedDevices', {
devices: devices,
logins: logins
});
};
var logins = {};
userProvider.findAll(function(error, users) {
var count = users.length;
if (count === 0) {
r(logins);
}
users.forEach(function(user) {
logins[user.uid] = user.login;
if (--count === 0) {
r(logins);
}
});
});
});
} else {
deviceProvider.findByUserId(req.currentUser.uid, function(error, devices) {
if (error) { return next(error); }
res.render('linkedDevices', {
devices: devices
});
});
}
});
app.get('/linkDevice', middleware.isLogged, function(req, res) {
var schema = config.https.enabled ? 'https' : 'http';
var url = schema + '://' + req.header('host');
if (config.externalUrl) {
url = config.externalUrl;
}
res.render('linkDevice', {
url: url
});
});
app.get('/unlinkDevice/:did', [middleware.isLogged, middleware.loadDevice, middleware.owningDevice], function(req, res, next) {
res.render('unlinkDevice', {
d: req.loadedDevice
});
});
app.post('/unlinkDevice/:did', [middleware.isLogged, middleware.loadDevice, middleware.owningDevice], function(req, res, next) {
var d = req.loadedDevice;
deviceProvider.unlinkDevice(d.id, function(error) {
if (error) {
req.flash('error', error.message);
res.render('unlinkDevice', {
d: req.loadedDevice
});
} else {
req.flash('info', i18n.__('Device unlinked'));
res.redirect('/linkedDevices');
}
});
});
app.get('/modifyDevice/:did', [middleware.isLogged, middleware.loadDevice, middleware.owningDevice], function(req, res, next) {
res.render('modifyDevice', {
d: req.loadedDevice
});
});
app.post('/modifyDevice/:did', [middleware.isLogged, middleware.loadDevice, middleware.owningDevice], function(req, res, next) {
var d = req.loadedDevice;
d.name = req.body.name;
deviceProvider.updateDevice(d, function(error) {
req.flash('info', i18n.__('Device updated'));
res.redirect('back');
});
});
app.get('/getLinkCode', middleware.isLogged, function(req, res) {
var code = linkCodeProvider.getNewCode(req.currentUser.uid);
var schema = config.https.enabled ? 'https' : 'http';
code.url = schema + '://' + req.header('host');
if (config.externalUrl) {
code.url = config.externalUrl;
}
res.contentType('application/json');
res.send(code);
});
// always keep this as last route
app.get('/stylesheets', function(req, res, next) {
next();
});
app.get('*', function(req, res, next){
next(new errors.NotFound(req.url));
});
function runApp() {
app.listen(config.listen.port, config.listen.host, function() {
console.log("SparkleShare Dashboard listening on port %d in %s mode", app.address().port, app.settings.env);
});
if (config.fanout.enabled) {
var fanout = require('./fanout/fanout');
fanout.listen(config.fanout.port, config.fanout.host, function() {
console.log("SparkleShare Fanout listening on port %d", config.fanout.port);
});
}
}
// upgrade database
require('./upgrade').upgrade(redisClient, runApp);
Fixed: I changed my code to:
var session = require('express-session')
, RedisStore = require('connect-redis')(session);