I try to use req.session.user in node.js to control the connection on my application. It's working on my local environnement but when I put my app on glitch the req.session.user is undefined.
I try to use req.session.user in node.js to control the connection on my application. It's working on my local environnement but when I put my app on glitch in my auth function the req.session.user is undefined. I initialized it in the "app.post('/api/login'..." and when I call auth function it's disapear.
Here my server.js :
const express = require('express');
const path = require('path');
let bodyParser = require('body-parser');
const mongoose = require('mongoose');
const User = require('./model/user');
const bcrypt = require('bcryptjs');
const session = require("express-session");
const Reservation = require('./model/reservation');
const Resource = require('./model/resource');
const rateLimit = require("express-rate-limit");
/*const routes = require('./routes');
const auth = require('./auth');*/
require('dotenv').config();
mongoose.connect(process.env.MONGODB_URI, {
useNewUrlParser: true,
useUnifiedTopology: true
});
const app = express();
//app.use(routes);
app.use(session({
secret: 'top secret',
resave: false,
saveUninitialized: true
}));
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static(path.join(__dirname, 'views')));
app.set('views', path.join(__dirname , 'views'));
app.engine('html', require('ejs').renderFile);
app.set('view engine', 'html');
app.use(bodyParser.json());
function auth(req, res, next) {
if (req?.session?.user) {
return next();
}
else {
return res.sendStatus(401);
}
}
app.get('/', function(req, res) {
if(req?.session?.user){
res.redirect("/home");
}
else{
res.redirect("/login");
}
});
app.get('/login', function(req, res) {
res.render(path.join(__dirname, 'views', 'login.html'));
});
app.get('/register', function(req, res) {
res.render(path.join(__dirname, 'views', 'register.html'));
});
app.get('/home', auth, async (req, res) => {
const resources = await Resource.find();
res.render(path.join(__dirname, 'views', 'home.ejs'), {user: req.session.user.username, isAdmin: req.session.user.isAdmin, resources });
});
app.get('/calendar', auth, async function(req, res) {
const reservations = await Reservation.find();
res.render(path.join(__dirname, 'views', 'calendar.ejs'), {user: req.session.user.username, isAdmin: req.session.user.isAdmin, reservations});
});
app.get('/reservations', auth, async function(req, res) {
const reservations = await Reservation.find({user : req.session.user.username});
return res.render(path.join(__dirname, 'views','reservations.ejs'), {user: req.session.user.username, isAdmin: req.session.user.isAdmin, reservations});
});
app.get('/addReservation', auth, async function(req, res) {
const resources = await Resource.find();
res.render(path.join(__dirname, 'views', 'addReservation.ejs'), {user: req.session.user.username, isAdmin: req.session.user.isAdmin, resources});
});
app.get('/admin', auth, async function(req, res) {
if(req.session.user.isAdmin){
const resources = await Resource.find();
res.render(path.join(__dirname, 'views', 'admin.ejs'), {user: req.session.user.username, isAdmin: req.session.user.isAdmin, resources});
}
});
app.post('/api/login', async (req, res) => {
const { username, password } = req.body
const user = await User.findOne({ username }).lean()
if (!user) {
return res.render(path.join(__dirname, 'views', 'error.ejs'), {error : "Incorrect username or password", redirect : "/login"});
} else if (await bcrypt.compare(password, user.password)){
req.session.user = {username : username, isAdmin : user.isAdmin};
res.redirect("/home");
}
else {
return res.render(path.join(__dirname, 'views', 'error.ejs'), {error : "Incorrect username or password", redirect : "/login"});
}
});
app.post('/logout', function(req, res) {
req.session.destroy();
res.redirect("/login");
});
const registerLimiter = rateLimit({
windowMs: 15 * 60 * 1000, // 15 minutes
max: 10000, // limit each IP to 100 requests per windowMs
message: "Too many registration attempts. Please try again later."
});
app.use("/api/register", registerLimiter);
app.post('/api/register', async (req, res) => {
const { username, password: plainTextPassword } = req.body
if (!username || typeof username !== 'string') {
return res.json({ status: 'error', error: "Nom d'utilisateur invalide" });
}
if (!plainTextPassword || typeof plainTextPassword !== 'string') {
return res.json({ status: 'error', error: 'Mot de passe invalide' });
}
if (plainTextPassword.length < 4) {
return res.json({
status: 'error',
error: 'Le mot de passe doit contenir au moins 4 caractères'
})
}
const duplicate = await User.findOne({username});
if(duplicate){
return res.json({ status: 'error', error: "Nom d'utilisateur indisponible" });
}else{
const password = await bcrypt.hash(plainTextPassword, 10);
const user = new User({ username, password, isAdmin : false });
await user.save();
req.session.user = {username : username, isAdmin : false};
res.json({ status: 'ok' });
console.log('Utilisateur créé : ', req.session.user);
}
});
app.post('/api/reservations', auth, async (req, res) => {
try {
const {resourceId, dateDebut, dateFin, user} = req.body;
let conflicts = [];
if (dateDebut > dateFin) {
return res.render(path.join(__dirname, 'views', 'error.ejs'), {error : "La date de début doit être antérieure à la date de fin", redirect : "/addReservation"});
}
// check for conflicts with existing reservations
for (let i = 0; i < resourceId.length; i++) {
const existingReservation = await Reservation.findOne({
resourceId: resourceId[i],
$or: [
{$and: [{dateDebut: {$gte: dateDebut}}, {dateDebut: {$lte: dateFin}}]},
{$and: [{dateFin: {$gte: dateDebut}}, {dateFin: {$lte: dateFin}}]},
{$and: [{dateDebut: {$lte: dateDebut}}, {dateFin: {$gte: dateFin}}]}
]
});
if (existingReservation) {
conflicts.push(resourceId[i]);
}
}
if (conflicts.length > 0) {
const error = {
status: 'Conflit de réservation',
message: `Votre réservation n'a pas pu aboutir car une autre réservation est déjà en cours pour la(les) ressource(s) : "${conflicts}" durant cette plage horaire.`
};
return res.render(path.join(__dirname, 'views', 'conflict.ejs'), {error});
}
// create new reservation
for (let i = 0; i < resourceId.length; i++) {
const reservation = new Reservation({
resourceId: resourceId[i],
dateDebut,
dateFin,
user
});
await reservation.save();
const resource = await Resource.findOne({ name: resourceId[i] });
await resource.save();
}
} catch (error) {
console.log(error);
return res.render(path.join(__dirname, 'views','error.ejs'),
{error : "La création de la réservation a échoué. Veuillez réessayer ultérieurement.", redirect: "/reservations"});
}
return res.redirect("/reservations");
});
app.post('/api/reservations/delete', auth, async (req, res) => {
try {
const deletedReservation = await Reservation.findByIdAndDelete(req.body.id);
if (!deletedReservation) {
return res.status(404).render(path.join(__dirname, 'views', 'error.ejs'), {error : "Réservation introuvable", redirect: "/reservations"});
}
return res.redirect("/reservations");
} catch (err) {
return res.status(500).render(path.join(__dirname, 'views', 'error.ejs'),
{error : "Erreur lors de la suppression de la réservation", redirect: "/reservations"});
}
});
app.post('/api/resources', auth, async (req, res) => {
try {
const duplicate = await Resource.findOne({
name: req.body.name
});
if (duplicate) {
return res.render(path.join(__dirname, 'views', 'error.ejs'), {error : "Ressource déjà existante", redirect: "/admin"});
}
const name = req.body.name;
const resource = new Resource({name});
await resource.save();
console.log('Ressource créée : ', resource);
return res.redirect("/admin");
} catch (error) {
return res.render(path.join(__dirname, 'views', 'error.ejs'),
{error : "La création de la ressource a échoué. Veuillez réessayer ultérieurement.", redirect: "/admin"});
}
});
app.listen(process.env.PORT, () => {
console.log('Server up at ' + process.env.PORT);
})
If anyone could help me...
Thanks a lot for your help
Related
this login form have some problem in it whenever I register and then login with credentials, it always show that my credentials are wrong.
this is auth.js code from controller
const mysql = require("mysql");
const jwt = require('jsonwebtoken');
const bcrypt = require('bcryptjs');
const { promisify } = require('util');
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
exports.login = async (req, res) => {
try {
const { email, password } = req.body;
if( !email || !password ) {
return res.status(400).render('login', {
message: 'Please provide an email and password'
})
}
db.query('SELECT * FROM users WHERE email = ?', [email], async (error, results) => {
console.log(results);
if( !results || !(await bcrypt.compare(password, results[0].password)) ) {
res.status(401).render('login', {
message: 'Email or Password is incorrect'
})
} else {
const id = results[0].id;
const token = jwt.sign({ id }, process.env.JWT_SECRET, {
expiresIn: process.env.JWT_EXPIRES_IN
});
console.log("The token is: " + token);
const cookieOptions = {
expires: new Date(
Date.now() + process.env.JWT_COOKIE_EXPIRES * 24 * 60 * 60 * 1000
),
httpOnly: true
}
res.cookie('jwt', token, cookieOptions );
res.status(200).redirect("/");
}
})
} catch (error) {
console.log(error);
}
}
exports.register = (req, res) => {
console.log(req.body);
const { name, email, password, passwordConfirm } = req.body;
db.query('SELECT email FROM users WHERE email = ?', [email], async (error, results) => {
if(error) {
console.log(error);
}
if( results.length > 0 ) {
return res.render('register', {
message: 'That email is already in use'
})
} else if( password !== passwordConfirm ) {
return res.render('register', {
message: 'Passwords do not match'
});
}
let hashedPassword = await bcrypt.hash(password, 8);
console.log(hashedPassword);
db.query('INSERT INTO users SET ?', {name: name, email: email, password: hashedPassword }, (error, results) => {
if(error) {
console.log(error);
} else {
console.log(results);
return res.render('register', {
message: 'User registered'
});
}
})
});
}
exports.isLoggedIn = async (req, res, next) => {
// console.log(req.cookies);
if( req.cookies.jwt) {
try {
//1) verify the token
const decoded = await promisify(jwt.verify)(req.cookies.jwt,
process.env.JWT_SECRET
);
console.log(decoded);
//2) Check if the user still exists
db.query('SELECT * FROM users WHERE id = ?', [decoded.id], (error, result) => {
console.log(result);
if(!result) {
return next();
}
req.user = result[0];
console.log("user is")
console.log(req.user);
return next();
});
} catch (error) {
console.log(error);
return next();
}
} else {
next();
}
}
exports.logout = async (req, res) => {
res.cookie('jwt', 'logout', {
expires: new Date(Date.now() + 2*1000),
httpOnly: true
});
res.status(200).redirect('/');
}
and this is app.js
const express = require("express");
const path = require('path');
const mysql = require("mysql");
const dotenv = require('dotenv');
const cookieParser = require('cookie-parser');
dotenv.config({ path: './.env'});
const app = express();
const db = mysql.createConnection({
host: process.env.DATABASE_HOST,
user: process.env.DATABASE_USER,
password: process.env.DATABASE_PASSWORD,
database: process.env.DATABASE
});
const publicDirectory = path.join(__dirname, './public');
app.use(express.static(publicDirectory));
// Parse URL-encoded bodies (as sent by HTML forms)
app.use(express.urlencoded({ extended: false }));
// Parse JSON bodies (as sent by API clients)
app.use(express.json());
app.use(cookieParser());
app.set('view engine', 'hbs');
db.connect( (error) => {
if(error) {
console.log(error)
} else {
console.log("MYSQL Connected...")
}
})
//Define Routes
app.use('/', require('./routes/pages'));
app.use('/auth', require('./routes/auth'));
app.listen(5001, () => {
console.log("Server started on Port 5001");
})
When entered right credentials
enter image description here
whenever i enter credential whether right or wrong it shows this only.
please help me, i am stuck here
I am not sure but I think the problem is in controller/auth.js code and i tried to change the login code in that
Replace question mark with ${email}
'SELECT * FROM users WHERE email =${email}'
I have made an authentication with jwt api in node.js/express and i run it on heroku.
When a user logged in, server create a cookie via cookie-parser and send it to the client.
Below is the code from server.js
const express = require('express');
const jwt = require('jsonwebtoken');
const cookieParser = require('cookie-parser');
const cors = require('cors');
const path = require('path');
const bcrypt = require('bcrypt');
const PORT = process.env.PORT || 3000;
const serveStatic = require('serve-static');
require('dotenv').config();
const mongoose = require('mongoose');
const { User, Posts } = require(path.join(__dirname, './model.js'));
const mongoString = process.env.DATABASE_URL;
const JWT_SECRET = process.env.JWT_SECRET;
const { verifyToken, checkUser } = require(path.join(__dirname, './auth.js'));
const app = express();
//Middlewares
app.use(
cors({
credentials: true,
origin: true,
})
);
app.use(express.json());
app.use(cookieParser());
//Connect to Database
mongoose.connect(mongoString);
const db = mongoose.connection;
db.on('error', (err) => {
console.log(err);
});
db.once('connected', () => {
console.log('----Database Connected----\n');
});
//functions
const maxAge = 3 * 24 * 60 * 60;
const createToken = (id) => {
return jwt.sign({ id }, JWT_SECRET, {
expiresIn: maxAge,
});
};
// AUTH ROUTES
app.get('*', checkUser);
app.get('/', checkUser, (req, res) => {
res.json({ status: 'success' });
});
app.post('/api/register', async (req, res) => {
const salt = await bcrypt.genSalt();
try {
const user = await User.create(
new User({
username: req.body.username,
email: req.body.email,
city: req.body.city,
password: await bcrypt.hash(req.body.password, salt),
})
);
const token = createToken(user._id);
res.cookie('jwt', token, {
maxAge: maxAge * 1000,
secure: true,
});
res.status(201).json(user);
console.log(user);
} catch (err) {
console.log(err);
res.json(err);
}
});
app.post('/api/login', async (req, res) => {
try {
const { email, password } = req.body;
const user = await User.findOne({ email }).lean();
if (!user) {
return res.send({
status: 'error',
error: 'Invalid email',
});
}
if (await bcrypt.compare(password, user.password)) {
const token = createToken(user._id);
res.cookie('jwt', token, { secure: true, maxAge: maxAge * 1000 });
res.status(200).send({ status: 'ok', token: token });
console.log(user._id + ' logged in successfully');
return;
}
return res.send({ status: 'error', error: 'Invalid password' });
} catch (err) {
console.log(err);
}
});
app.get('/api/home', verifyToken, (req, res) => {
res.send(res.locals.user);
});
app.get('/api/logout', (req, res) => {
try {
res.cookie('jwt', '', { maxAge: 1 });
res.status(200).send({ status: 'ok' });
} catch (err) {
res.send(err);
}
});
//POSTS ROUTES
app.post('/api/posts', verifyToken, checkUser, async (req, res) => {
try {
const post = await Posts.create(
new Posts({
postBody: req.body.postBody,
city: req.body.city,
author: res.locals.user.id,
})
);
res.status(200).json(post);
console.log('====New Post=====');
} catch (err) {
res.status(400).send({ message: err.message });
}
});
app.get('/api/posts', verifyToken, async (req, res) => {
try {
const data = await Posts.find();
res.send({ user: res.locals.user, data: data });
} catch (err) {
res.json({ message: err.message });
}
});
app.get('/api/posts/:city', verifyToken, async (req, res) => {
try {
const data = await Posts.find({ city: req.params.city });
res.json(data);
res.send(res.locals.user);
} catch (err) {
res.json({ message: err.message });
}
});
//run server
app.listen(PORT, () => {
console.log(`Server running on ${PORT}...\n`);
});
Now, for front-end i use Vue.js that its running on Firebase.
Here is the script part of Login.Vue
<script>
/* eslint-disable */
import axios from 'axios';
export default {
name: 'Login',
data() {
return {
email: '',
password: '',
error: '',
};
},
methods: {
async onSubmit() {
if (!this.email || this.password.length < 6) {
this.error = 'vale kati';
return;
}
await axios
.post(
'https://thelostpet.herokuapp.com/api/login',
{
email: this.email,
password: this.password,
},
{ withCredentials: true }
)
.then((res) => {
console.log(res.data.token);
if (res.data.status == 'error') {
this.error = res.data.error;
}
if (res.data.status == 'ok') {
this.$router.push('/home');
}
})
.catch((err) => {
console.log(err);
});
},
},
};
</script>
When I try to login from Login.vue, that its ruuning on Firebase, the browser doesn't save the cookie that it created from the api.
BUT when I make a post request on https://thelostpet.herokuapp.com/api/login from postman, the cookie is saved on postman.
Thank you!
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 });
});
When signing in with postman everything works fine. But when i am doing an axios request i get 404 error and directly after 204 error. When i render my vue.js page i get "cannot get api/auth/signin. Also I get a message somewhere that says user not found.
What i have tried:
Frontend: I tried with adding headers to my axios request. I console logged the data and it seems perfectly fine.
Backend: Changed deprecated body parsers.
Frontend Code:
Auth store
import axios from "axios";
const state = {
token: "",
users: [],
};
const getters = {};
const actions = {
async signIn(_, payload) {
const response = await axios.post(
"http://localhost:3000/api/auth/signin",
{ payload },
{
headers: {
"Content-Type": "application/json",
},
}
);
console.log(response.data);
console.log(response.headers);
console.log(response.status);
},
};
const mutations = {};
export default {
state,
getters,
actions,
mutations,
};
This is my backend:
Controller
//signin
exports.signin = (req, res) => {
User.findOne({
username: req.body.username,
})
.populate("roles", "-__v")
.exec((err, user) => {
if (err) {
res.status(500).send({ message: err });
return;
}
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
var passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({
accessToken: null,
message: "Invalid Password!",
});
}
var token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
var authorities = [];
for (let i = 0; i < user.roles.length; i++) {
authorities.push("ROLE_" + user.roles[i].name.toUpperCase());
}
res.status(200).send({
id: user._id,
username: user.username,
email: user.email,
roles: authorities,
accessToken: token,
});
});
};
Route
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);
And my server
const express = require("express");
const bodyParser = require("body-parser");
const cors = require("cors");
const jwt = require("jsonwebtoken");
const mongoose = require("mongoose");
const Quote = require("./models/Quote");
const quoteRoute = require("./routes/quoteRoute");
const quoteController = require("../Maxico/controllers/quoteController");
const config = require("./config/config");
const verifySignup = require("./middlewares/verifySignUp");
const Role = require("./models/Role");
const app = express();
//Import routes
//const authRoute = require("./routes/auth");
var corsOptions = {
origin: "http://localhost:8080/?#/",
};
app.use(cors(corsOptions));
app.use(express.urlencoded({ extended: true }));
app.use(express.json()); //
const db = require("./models/Quote");
mongoose
.connect(
"url",
{
useNewUrlParser: true,
useUnifiedTopology: true,
useFindAndModify: false,
}
)
.then(() => {
console.log("Connected to the database!");
})
.catch((err) => {
console.log("Cannot connect to the database!", err);
process.exit();
});
app.use(express.json());
app.get("/", (req, res) => {
res.send("Welcome to homepage");
});
app.use("/quote", quoteRoute);
require("./routes/authRoute")(app);
//require("./routes/userRoute")(app);
// initial roles
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");
});
new Role({
name: "superadmin",
}).save((err) => {
if (err) {
console.log("error", err);
}
console.log("added 'superadmin' to roles collection");
});
}
});
// set port, listen for requests
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`Server is running on port ${PORT}.`);
});
In my network tab the request pay load got sent like this:
{payload: {username: "jon", password: "password"}}
payload: {username: "jon", password: "password"}
But my postman only accepts this:
{username: "jon", password: "password"}
So in my action i sent like this:
const actions = {
async signIn(_, payload) {
console.log(payload);
const response = await axios.post(
"http://localhost:3000/api/auth/signin",
payload,
{
headers: {
"Content-Type": "application/json",
},
}
);
console.log(payload);
console.log(response.data);
console.log(response.headers);
console.log(response.status);
},
};
Hello everyone i am in a problem, may be you can help me.
So basically i have created two collection in mongoose, one for user details when they sign Up or login and other for Recipe they post.
I also want to save the each recipe a user post in the user collection (like populate property of mongoose). like if user1 post a recipe1 then it should save in the recipe collection and also in the user data who posted this.
I tried to use Populate method for this as shown in the code below but when ever i post some recipe it stored in recipe collection only and the "posts" key in the users collection is always empty. I want to save the recipe in the "posts" key of the users collection also.
Please Guide me how to do this.
require('dotenv').config()
const express = require("express");
const bodyParser = require("body-parser");
const ejs = require("ejs");
const requestObj = require("request");
const https = require("https");
const multer = require("multer");
const path = require("path");
const mongoose = require('mongoose');
const session = require('express-session');
const passport = require("passport");
const passportLocalMongoose = require("passport-local-mongoose");
const findOrCreate = require('mongoose-findorcreate');
const app = express();
const GoogleStrategy = require('passport-google-oauth20').Strategy;
app.set("view engine", "ejs");
app.use(bodyParser.urlencoded({
extended: true
}));
app.use(express.static("public"));
app.use(session({
secret: "This is my secret",
resave: false,
saveUninitialized: false
}));
app.use(passport.initialize());
app.use(passport.session());
// Mongoose connection
mongoose.connect("mongodb://localhost:27017/recipeUsers", {
useNewUrlParser: true,
useUnifiedTopology: true
});
mongoose.set('useCreateIndex', true);
//mongoose schema
const userSchema = new mongoose.Schema({
username: String,
password: String,
googleId: String,
name: String,
posts: [{
type: mongoose.Schema.Types.ObjectId,
ref: 'Recipe'
}]
});
const recipeSchema = new mongoose.Schema({
genre: String,
name: String,
description: String,
ingredients: [{
type: String
}],
method: [{
type: String
}],
imageName: String,
author: {
type: mongoose.Schema.Types.ObjectId,
ref: 'User'
}
});
userSchema.plugin(passportLocalMongoose);
userSchema.plugin(findOrCreate);
// model
const Recipe = mongoose.model("Recipe", recipeSchema);
const User = mongoose.model("User", userSchema);
module.exports = {
User,
Recipe,
}
passport.use(User.createStrategy());
passport.serializeUser(function(user, done) {
done(null, user.id);
});
passport.deserializeUser(function(id, done) {
User.findById(id, function(err, user) {
done(err, user);
});
});
passport.use(new GoogleStrategy({
clientID: process.env.CLIENT_ID,
clientSecret: process.env.CLIENT_SECRET,
callbackURL: "http://localhost:5000/auth/google/index",
userProfileURL: "https://www.googleapis.com/oauth2/v3/userinfo"
},
function(accessToken, refreshToken, profile, cb) {
// console.log(profile);
User.findOrCreate({
googleId: profile.id,
name: profile.displayName
}, function(err, user) {
return cb(err, user);
});
}
));
var storage = multer.diskStorage({
destination: (req, file, cb) => {
cb(null, "public/img/uploads")
},
filename: (req, file, cb) => {
cb(null, file.fieldname + '-' + Date.now() + path.extname(file.originalname));
}
});
var upload = multer({
storage: storage,
limits: {
fileSize: 5 * 1024 * 1024
}
});
app.use((req, res, next) => {
res.locals.isAuthenticated = req.isAuthenticated();
if (req.isAuthenticated()) {
currentUser = req.user.name;
}
next();
});
app.get("/", function(req, res) {
res.render("index");
});
app.get("/index", (req, res) => {
res.render('index');
});
app.get("/about", function(req, res) {
res.render("about");
});
app.route("/search")
.get(function(req, res) {
res.render("search");
})
.post(function(req, res) {
const searchRecipe = req.body.recipeName;
Recipe.findOne({
name: searchRecipe
}, (err, foundRecipe) => {
if (err) {
res.send(err);
} else {
if (foundRecipe) {
res.render("recipe", {
dishName: foundRecipe.name,
descrip: foundRecipe.description,
genre: foundRecipe.genre,
ingredients: foundRecipe.ingredients,
steps: foundRecipe.method,
author: foundRecipe.author,
dishImage: foundRecipe.imageName
});
} else {
res.redirect("/Failure");
}
}
});
});
app.get("/Failure", function(req, res) {
res.render("Failure");
});
app.route("/post")
.get(function(req, res) {
if (req.isAuthenticated()) {
res.render("post", {
message: ""
});
} else {
res.redirect("/login");
}
})
.post(upload.single('dishImage'), function(req, res, next) {
const dishType = req.body.recipeGenre;
const description = req.body.description;
const dishName = req.body.dishName;
const ingredient = req.body.ingredients;
const step = req.body.steps;
// const authorName = req.body.author;
// const url = "https://polar-oasis-10822.herokuapp.com/recipes";
const file = req.file;
if (!file) {
const error = new Error("Please upload a image");
error.httpStatusCode = 400;
return next(error);
}
// console.log(req.user);
const dish = new Recipe({
genre: dishType,
name: dishName,
description: description,
ingredients: ingredient,
method: step,
imageName: file.filename,
});
dish.save((err) => {
if (err) {
res.send(err);
} else {
User.findOne({
_id: req.user._id
})
.populate('posts').exec((err, posts) => {
console.log("Populated User " + posts);
})
res.render("post", {
message: "Your Recipe is successfully posted."
});
}
});
});
app.get("/menu", function(req, res) {
res.render("menu");
});
app.get('/auth/google',
passport.authenticate('google', {
scope: ["profile"]
})
);
app.get('/auth/google/index', passport.authenticate('google', {
failureRedirect: '/login'
}), function(req, res) {
// Successful authentication, redirect home.
res.redirect('/');
});
app.get("/logout", (req, res) => {
req.logout();
res.redirect('/');
});
app.route("/signup")
.get((req, res) => {
res.render("signup");
})
.post((req, res) => {
User.register({
username: req.body.username,
name: req.body.name,
}, req.body.password, (err, user) => {
if (err) {
console.log(err);
res.redirect("/signup");
} else {
passport.authenticate("local")(req, res, () => {
res.redirect('/');
});
}
});
})
app.route("/login")
.get((req, res) => {
res.render("login");
})
.post((req, res) => {
const user = new User({
username: req.body.username,
password: req.body.password
});
req.login(user, (err) => {
if (err) {
console.log(err);
} else {
passport.authenticate("local")(req, res, () => {
res.redirect("/");
});
}
});
})
app.listen(process.env.PORT || 5000, function() {
console.log("server is running on port 5000");
});
I believe your problem is here:
dish.save((err) => {
if (err) {
res.send(err);
} else {
User.findOne({
_id: req.user._id
})
.populate('posts').exec((err, posts) => {
console.log("Populated User " + posts);
})
res.render("post", {
message: "Your Recipe is successfully posted."
});
}
});
});
You are using populate as a function that changes the dataset elements, but it is just a trick for printing results from different collection, in the roots, they are different; if you want them to be in the same document, you must use subdocuments. populate does not change document paths.
Assuming I have not typed anything wrong, that you must correct yourself or let me know, this should solve your problem; just use populate to print the documents our as one, not to save.
app
.route("/post")
.get(function(req, res) {
if (req.isAuthenticated()) {
res.render("post", {
message: ""
});
} else {
res.redirect("/login");
}
})
.post(upload.single("dishImage"), function(req, res, next) {
const dishType = req.body.recipeGenre;
const description = req.body.description;
const dishName = req.body.dishName;
const ingredient = req.body.ingredients;
const step = req.body.steps;
const username = req.body.author; //make sure this information is passed to req.body
// const url = "https://polar-oasis-10822.herokuapp.com/recipes";
const file = req.file;
if (!file) {
const error = new Error("Please upload a image");
error.httpStatusCode = 400;
return next(error);
}
// console.log(req.user);
const dish = new Recipe({
genre: dishType,
name: dishName,
description: description,
ingredients: ingredient,
method: step,
imageName: file.filename
});
dish.save(err => {
if (err) {
res.send(err);
} else {
User.findOne({
_id: req.user._id
}).then(user => {//I have changed just here! I have eliminated the populate call
user.posts.push(dish._id);
user.save().then(() => {
console.log("okay");
});
});
res.render("post", {
message: "Your Recipe is successfully posted."
});
}
});
});
Since your code is big, I may have missed something, please, let me know if I have misunderstood what you wanted.
References
https://mongoosejs.com/docs/populate.html#refs-to-children