String Functions are not working in Multer - node.js

While I tried to rename uploaded image with date, an error is being thrown and it shows "Cannot read property 'isLoggedIn' of undefined".
I would be happy if anyone could solve the problem. Thanks in advance
I think from Multer an error is thrown and it goes to error handling middleware.
here is my app.js
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const csrf = require('csurf');
const flash = require('connect-flash');
const multer = require('multer');
const errorController = require('./controllers/error');
const User = require('./models/user');
const MONGODB_URI = 'mongodb+srv://axxxxn:xxxxxx#cluster0-sm6lw.mongodb.net/sxhxoxxxp';
const app = express();
const store = new MongoDBStore({
uri: MONGODB_URI,
collection: 'sessions'
});
const csrfProtection = csrf();
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'images');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname );
}
});
app.set('view engine', 'ejs');
app.set('views', 'views');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(multer({ storage: fileStorage }).single('image'));
app.use(express.static(path.join(__dirname, 'public')));
app.use(
session({
secret: 'my secret',
resave: false,
saveUninitialized: false,
store: store
})
);
app.use(csrfProtection);
app.use(flash());
app.use((req, res, next) => {
res.locals.isAuthenticated = req.session.isLoggedIn;
res.locals.csrfToken = req.csrfToken();
next();
});
app.use((req, res, next) => {
//throw new Error('Sync Dummy');
if (!req.session.user) {
return next();
}
User.findById(req.session.user._id)
.then(user => {
//throw new Error('Dummy');
if(!user){
return next()
}
req.user = user;
next();
})
.catch(err => {
next(new Error(err));
});
});
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.get('/500', errorController.get500);
app.use(errorController.get404);
app.use((error, req, res, next) => {
res.status(404).render('500', {
pageTitle: 'Error 500',
path: '/500',
isAuthenticated: req.session.isLoggedIn
});
});
mongoose
.connect(MONGODB_URI)
.then(result => {
app.listen(3000);
console.log('connected');
})
.catch(err => {
console.log(err);
});

I had this problem on windows: new Date().toISOString() gives a 'zulu' date, something like
2020-08-13T10:01:36.688Z. But : is not a valid character in windows filenames. This worked for me:
const dateStr = new Date().toISOString().replace(/:/g, '-');
cb(null, dateStr + '-' + file.originalname);  

I think this problem is related to Windows, maybe Windows will be angry if you try to put ":" inside fileName so instead of "toIsoString" you can use "toDateString" like this:
cb(null, new Date().toDateString().replace(/\s/g, '_') + '_' + new Date().toTimeString().replace(/[\s:]/g, '_') + file.originalname);
By the way, this is more readable for the user and contains all the information (date and time)
Finally, make sure to replace '\\' to '/' inside file.path when you add imageUrl to db like:
{
...,
imageUrl: req.file.path.replace('\\', '/'),
...
}

Related

nodejs flash message disappears from request

I am trying to post a flash message after authenticating but for some reason the req.flash() loses its value after a redirect.
The code starts when the user asks for a GET on '/'. Here's the code:
const express = require('express');
const session = require('express-session');
const cookie = require('cookie');
const methodOverride = require('method-override')
const passport = require('passport');
const localStrategy = require ('passport-local').Strategy;
const bcrypt = require('bcryptjs');
const cookieParser = require('cookie-parser');
const flash = require('express-flash');
const fs = require('fs');
const config = require('./config.js');
const db = require('./db.js');
const log = require('./logger.js');
const crypto = require('crypto');
var app = express();
const server = require('http').createServer(app);
const build_version = fs.readFileSync("minorBuild.txt").toString();
process.on('UnhandledPromiseRejectionWarning', function(err) {
log.error({ section: "UnhandledPromiseRejectionWarningr", err: err, uid: '1', orgId: '1' });
});
app.set('port', 3000);
app.set('views', __dirname + '/views');
app.set('view engine', 'ejs');
app.use(cookieParser(config.cookieSecret));
app.use(flash());
app.use(express.urlencoded({extended: false}));
app.use(express.json());
app.use(session({ name: 'sid',
secret: config.sessionSecret,
cookie: { maxAge: config.sessionCookieMaxAge, domain: 'localhost:3000' },
resave: true,
saveUninitialized: true
}));
app.use(passport.initialize());
app.use(passport.session());
app.use(express.static('public'));
app.use(methodOverride('_method'))
app.get('/', function(req, res, next) {
if (req.isAuthenticated()) {
res.redirect('/dashboard');
} else {
res.render('index', { messages: req.flash("error") });
})
}
});
Once the user POSTS username and password, the data is sent to this function:
app.post('/login', function(req, res, next){
passport.authenticate('local', function(err, user, info){
var redirectUrl = '/';
if (!user) {
req.flash('error', info.messages);
return res.redirect('/');
}
if (req.session.redirectUrl) {
redirectUrl = req.session.redirectUrl;
req.session.redirectUrl = null;
}
req.logIn(user, function(err){
if (err) {
return next(err);
}
});
res.redirect(redirectUrl);
})(req, res, next);
});
The data is authenticated here and the message is set on incorrect auth:
async function authenticateUser (email, password, done) {
await db.getParticipantByEmail(email)
.then(async (getEmailResult) => {
if (getEmailResult === undefined) {
return done(null, false, { messages: "Incorrect Username and/or Password" });
}
});
}
Using the debugger I see the message come back to /login in the info.messages. In this line in the '/login' function:
if (!user) {
req.flash('error', info.messages); //I see the message show up here
return res.redirect('/');
}
After the redirect to '/' req.flash('error') is empty.
res.render('index', { messages: req.flash("error") }); //req.flash("error") is empty here
I have no idea why this is. What am I missing?

Not being able to connect to mongoDB

I am trying to connect my app to MongoDB but i get the following error as i run my app:
DepracationWarning: current URL string parser is deprecated, and will be removed in a future version. To use the new parser, pass option { useNewUrlParser: true } to MongoClient.connect.
[MONGODB DRIVER] Warning: Current Server Discover and Monitoring engine is deprecated, and will be removed in a future version. To use the new Server Discover and Monitoring engine, pass option { useUnifiedTopology: true } to MongoClient constructor
I know both above are just warnings but they are stopping my app and no letting me run it.
This is how i am setting the connection to mongodb in app.js:
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const csrf = require('csurf');
const flash = require('connect-flash');
const multer = require('multer');
const errorController = require('./controllers/error');
const User = require('./models/user');
const MONGODB_URI =
'mongodb+srv://mateoghidini:<PASSWORD>#cluster0.9dernor.mongodb.net/test';
const app = express();
const store = new MongoDBStore({
uri: MONGODB_URI,
collection: 'sessions'
});
const csrfProtection = csrf();
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'images');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
}
};
app.set('view engine', 'ejs');
app.set('views', 'views');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(
multer({ storage: fileStorage, fileFilter: fileFilter }).single('image')
);
app.use(express.static(path.join(__dirname, 'public')));
app.use('/images', express.static(path.join(__dirname, 'images')));
app.use(
session({
secret: 'my secret',
resave: false,
saveUninitialized: false,
store: store
})
);
app.use(csrfProtection);
app.use(flash());
app.use((req, res, next) => {
res.locals.isAuthenticated = req.session.isLoggedIn;
res.locals.csrfToken = req.csrfToken();
next();
});
app.use((req, res, next) => {
// throw new Error('Sync Dummy');
if (!req.session.user) {
return next();
}
User.findById(req.session.user._id)
.then(user => {
if (!user) {
return next();
}
req.user = user;
next();
})
.catch(err => {
next(new Error(err));
});
});
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.get('/500', errorController.get500);
app.use(errorController.get404);
app.use((error, req, res, next) => {
// res.status(error.httpStatusCode).render(...);
// res.redirect('/500');
res.status(500).render('500', {
pageTitle: 'Error!',
path: '/500',
isAuthenticated: req.session.isLoggedIn
});
});
mongoose
.connect(MONGODB_URI)
.then(result => {
app.listen(3000);
})
.catch(err => {
console.log(err);
});
Is any of the packages that i am requiring above deprecated? Or should i include new lines of code that i am missing?
I remember having similar issue, so first of all make sure your mongoose version is above 5.7.1, if it is you can pass the options objects suggested from your warning message to your connect function like so:
mongoose
.connect(MONGODB_URI, {useNewUrlParser: true, useUnifiedTopology: true})
.then(result => {
app.listen(3000);
})
.catch(err => {
console.log(err);
});

TypeError: Cannot read properties of undefined (reading 'isLoggedIn')

In my app i was able to register a user and log in with that user but when i submit the form to add a product i have the following error and my app crashes
TypeError: Cannot read properties of undefined (reading 'isLoggedIn')
This is my app.js:
const path = require('path');
const express = require('express');
const bodyParser = require('body-parser');
const mongoose = require('mongoose');
const session = require('express-session');
const MongoDBStore = require('connect-mongodb-session')(session);
const csrf = require('csurf');
const flash = require('connect-flash');
const multer = require('multer');
const errorController = require('./controllers/error');
const User = require('./models/user');
const MONGODB_URI =
'mongodb+srv://mateoghidini:<PASSWORD>#cluster0.9dernor.mongodb.net/test';
const app = express();
const store = new MongoDBStore({
uri: MONGODB_URI,
collection: 'sessions'
});
const csrfProtection = csrf();
const fileStorage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, 'images');
},
filename: (req, file, cb) => {
cb(null, new Date().toISOString() + '-' + file.originalname);
}
});
const fileFilter = (req, file, cb) => {
if (
file.mimetype === 'image/png' ||
file.mimetype === 'image/jpg' ||
file.mimetype === 'image/jpeg'
) {
cb(null, true);
} else {
cb(null, false);
}
};
app.set('view engine', 'ejs');
app.set('views', 'views');
const adminRoutes = require('./routes/admin');
const shopRoutes = require('./routes/shop');
const authRoutes = require('./routes/auth');
app.use(bodyParser.urlencoded({ extended: false }));
app.use(
multer({ storage: fileStorage, fileFilter: fileFilter }).single('image')
);
app.use(express.static(path.join(__dirname, 'public')));
app.use('/images', express.static(path.join(__dirname, 'images')));
app.use(
session({
secret: 'my secret',
resave: false,
saveUninitialized: false,
store: store
})
);
app.use(csrfProtection);
app.use(flash());
app.use((req, res, next) => {
res.locals.isAuthenticated = req.session.isLoggedIn;
res.locals.csrfToken = req.csrfToken();
next();
});
app.use((req, res, next) => {
// throw new Error('Sync Dummy');
if (!req.session.user) {
return next();
}
User.findById(req.session.user._id)
.then(user => {
if (!user) {
return next();
}
req.user = user;
next();
})
.catch(err => {
next(new Error(err));
});
});
app.use('/admin', adminRoutes);
app.use(shopRoutes);
app.use(authRoutes);
app.get('/500', errorController.get500);
app.use(errorController.get404);
app.use((error, req, res, next) => {
// res.status(error.httpStatusCode).render(...);
// res.redirect('/500');
res.status(500).render('500', {
pageTitle: 'Error!',
path: '/500',
isAuthenticated: req.session.isLoggedIn
});
});
mongoose
.connect(MONGODB_URI, {useNewUrlParser: true, useUnifiedTopology: true})
.then(result => {
app.listen(3000);
})
.catch(err => {
console.log(err);
});
So i read in other questions that it might be an issue of file pathing but i don´t know exactly what is that is breaking my app. Does it has anything to do with file pathing or just an authentication error which seems odd due that i was able to log in with an existing user.

TypeError: Cannot set properties of undefined (setting 'nombre')

I have set all the routes within the same file but when I migrate them to another folder to clean the code the console throws an error, error that was not there when I had all the code in the same file.
const express = require('express')
const cookieParser = require('cookie-parser')
const session = require('express-session')
const bodyParser = require('body-parser')
const path = require('path')
const bcrypt = require('bcrypt')
const passport = require('passport');
const {Strategy} = require('passport-local')
const LocalStrategy = Strategy;
const app = express();
const usuariosDB= ['UsuariosDB']
app.set('view engine', 'ejs')
app.set('views', './views')
app.use(express.static('./public'))
app.use(cookieParser())
app.use(express.urlencoded({extended: true}))
app.use(express.json())
// app.use('/', router)
app.use(session({
secret: '123456788!"#$%&/)(',
resave: false,
saveUninitialized: false,
/* cookie:{
maxAge: 60000
} */
}))
app.get('/', (req, res)=>{
res.redirect('/login')
})
app.get('/login', (req, res)=>{
res.render('login')
})
app.get('/login-error', (req, res)=>{
res.render('login-error')
})
app.get('/index', (req, res)=>{
res.render('index', {titulo: "PRUEBAS"})
})
app.get('/registro', (req, res)=>{
res.render('registro')
})
app.get('/registro-error', (req, res)=>{
res.render('registro-error')
})
app.get('/datos', (req, res)=>{
if(req.session.nombre){
req.session.contador++
const datosUsuario = usuariosDB.find(element => {return element.nombre == req.session.nombre})
res.render('datos', {
datos: datosUsuario,
contador: req.session.contador
})
}
})
app.get('/logout', (req, res)=>{
req.session.destroy(err=>{
if(err) return res.json({error: err})
res.redirect('/login')
})
})
app.post('/registro', (req, res)=>{
const {nombre, password, direccion} = req.body
const usuario = usuariosDB.find(element => element.nombre == nombre)
if(!usuario){
usuariosDB.push({nombre,password, direccion})
console.log(usuariosDB)
res.redirect('/login')
}else{
console.log('existe')
res.redirect('/login')
}
})
app.post('/login', (req, res)=>{
const {nombre, password} = req.body
const existeUser = usuariosDB.find(element => element.nombre == nombre)
if(existeUser){
req.session.nombre = nombre
req.session.contador= 0
res.redirect('/datos')
}else{
console.log('credenciales incorrectas')
res.redirect('/login-error')
}
})
const PORT = 8080
const server = app.listen(PORT, ()=>console.log(`Listening port ${PORT}`))
server.on('error', error=>{
console.log(`error on the server ${error}`)
})
When I create routes and controller for the app is when I have the error :
TypeError: Cannot set properties of undefined (setting 'nombre')
The error line is \controller\appController.js:18:26. The migrated code is the same and I haven't modified anything, this error appears when I try to log in.
exports.getLogin = (req, res)=>{
res.render('login')
}
exports.postLogin = (req, res)=>{
const {nombre, password} = req.body;
const existeUsuario = usuariosDB.find(usuario => usuario.nombre == nombre && usuario.password == password);
console.log(existeUsuario);
if (!existeUsuario) {
console.log('credenciales incorrectas')
res.redirect('/login-error')
} else {
req.session.nombre = nombre
req.session.contador = 0
res.redirect('/datos')
}
}
exports.getRegistro = (req, res)=>{
res.render('registro')
}
exports.postRegistro = (req, res)=>{
const {nombre, password, direccion} = req.body
const usuario = usuariosDB.find(element => element.nombre == nombre)
if(!usuario){
usuariosDB.push({nombre,password, direccion})
console.log(usuariosDB)
res.redirect('/login')
}else{
console.log('existe')
res.redirect('/login')
}
}
exports.getLoginError = (req, res)=>{
res.render('login-error')
}
and the routes are
const Controller = require('../controller/appController.js')
const router = express.Router();
router
.route('/login')
.get(Controller.getLogin)
.post(Controller.postLogin)
router
.route('/login-error')
.get(Controller.getLoginError)
router
.route('/registro')
.get(Controller.getRegistro)
.post(Controller.postRegistro)
router
.route('/datos')
.get(Controller.getDatos)
router
.route('/logout')
.get(Controller.getLogout)
module.exports= router;
Hello tried looking at your code this is my option
app.post('/login', (req, res)=>{
const {nombre, password} = req.body
const existeUser = usuariosDB.find(element => element.nombre == nombre)
if(existeUser){
req.session.nombre = nombre
req.session.contador= 0
res.redirect('/datos')
}else{
console.log('credenciales incorrectas')
res.redirect('/login-error')
}
This endpoint could be throwing that error because property nombre does not exist on the session object.
So technically your suing a dot. operator on an element that does not exist on the object.
Try logging the session object and see if nombre property exists there

I cant access the req.user from passport outside of my routes folder. MERN stack redux node.js

I am trying to access the req.user that passport creates when doing a google o auth strategy. I can access the req.user in the routes file below, but when I try to access it in my userController file it is showing up as undefined.
Why is user accessible in routes file but not userController?
googleAuthRoutes.js:
const passport = require('passport');
const requireLogin = require('../middlewares/requireLogin')
const cors = require('cors');
const axios = require('axios');
const Template = require('../models/Template');
const corsOptions ={
origin: true,
credentials:true, //access-control-allow-credentials:true
optionSuccessStatus:200
}
module.exports = app => {
app.get('/auth/google',
passport.authenticate('google', {
scope: ['profile', 'email']
}));
app.get(
'/auth/google/callback',
passport.authenticate('google'),
(req, res) => {
res.redirect('/dashboard');
}
);
app.post('/templates/create', async (req, res) => {
const { template, body } = req.body
console.log(req.user)
const newTemplate = new Template({
template: template,
body: body,
_user: req.user.id
})
try {
await newTemplate.save()
return res.status(200).json({
message: "Successfully saved template"
})
} catch (err) {
return console.log(err)
}
});
app.get('/api/logout', cors(), (req, res) => {
req.logout();
res.redirect('http://localhost:3000');
});
app.get('/api/current_user', (req, res) => {
res.send(req.user);
})
}
when I call the res.send(req.user) here above it sends the user no problem
But it is undefined with the /templates/create route middleware.
the console.log(req.user) is coming back as undefined??
index.js:
const express = require('express');
const cors = require('cors')
const mongoose = require('mongoose');
const cookieSession = require('cookie-session');
const passport = require('passport');
const keys = require('./config/keys');
const bodyParser = require('body-parser')
require("dotenv").config();
require('./models/GoogleUserModel'); // the user model must be placed before this services passport// this must be ran after requiring model bcuz this needs the model. ORDER
require('./models/UserModel');
require('./services/passport');
const corsOptions ={
origin:'http://localhost:3000',
credentials: true, //access-control-allow-credentials:true
optionSuccessStatus:200
}
const app = express();
app.use(cors(corsOptions))
mongoose.connect(keys.mongoURI, {
useNewUrlParser: true,
useCreateIndex: true,
useUnifiedTopology: true
})
mongoose.connection.on('error', () => {
throw new Error (`unable to connect to database: ${keys.mongoURI}`)
});
app.use(bodyParser.json())
app.use(express.urlencoded( { extended: true }))
app.use(
cookieSession({
maxAge: 30 * 24 * 60 * 60 * 1000,
keys: [keys.cookieKey]
})
)
app.use(passport.initialize());
app.use(passport.session());
require('./routes/userRoutes')(app);
require('./routes/googleAuthRoutes')(app);
require('./routes/messageRoutes')(app);
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
res.status(401).json({"error" : err.name + ": " + err.message})
} else if (err) {
res.status(400).json({"error" : err.name + ": " + err.message})
console.log(err)
}
})
const PORT = process.env.PORT || 5000;
app.listen(PORT);
Again, Why is the req.user available in the app.get to /api/current_user but available in a post request to /templates/create?
Im trying to add the user.id to the schema when it saves so i can retrieve each template by the user.id and not show everyone everybody elses templates lol

Resources