Add variable to a URL (node, express) - node.js

I'm using node and express. What I want to do is to do is make a mix of res.render and res.redirect.
Thing is, res.render can only receive a .ejs file and data, and redirect will go to a specific URL. What I need to do is go to a specific URL (e.g. /reviews/new/:id), render a .ejs file and give some data to it.
This is my code. I can't use session or cookies for this project.
This are the routes, user enters to edit a review of some show. If it is a new review, the id of the show is in the URL, if the user is editing one, the ID of the review is on the URL. Either way, if something fails, I have to append something to this URL and send data.
router.get('/new/:id', controller.newReview);
router.post('/store', controller.checkBeforeStoringReview);
router.get('/edit/:id', controller.editReview);
router.post('/update', controller.checkBeforeUpdatingReview);
This is the function to check auth before updating.
checkBeforeUpdatingReview: function(req, res) { // auth before updating review (can't use session or cookies)
console.log(req.body)
DB
.User
.findOne(
{
where : {
email: req.body.email,
},
}
)
.then (function (results) {
if (results[0] != '') {
if (bcrypt.compareSync(req.body.password, results.password)) {
return module.exports.updateReview(req, res, results)
} else { // same as catch
return res.render('reviews/edit/', { // i'm missing the ID (which i have in req.params.id) at the end of the route
id : req.params.id,
errors : "Incorrect username or password",
email : req.body.email,
});
}
}
})
.catch (function (error) {
console.log(error)
return res.render('reviews/edit/', { // i'm missing the ID (which i have in req.params.id) at the end of the route
id : req.params.id,
errors : "An unexpected error happened",
email : req.body.email,
});
})
},
If everything's ok, as seen above, it goes directly to this function
updateReview: function(req, res, results) { // update review
console.log(req.body)
DB
.Review
.update(req.body,
{
where : {
id: req.body.review_id,
}
}
)
.then(function (results) {
return res.redirect('/series/detail/' + req.body.series_id)
})
.catch (error => {
return res.send(error)
})
},
TL;DR: If auth fails, should go back to the review url and send the data that was sent so that the user does not lose it.
So that's it, if I could use sessions/cookies I think I would be able to go back to the last route, but I can't for this.
Thanks in advance!

Related

NodeJS cannot import custom module although it exists

Note: What you see below is the updated description of my problem, because I have been going down a rabbit hole and finding the root cause of a problem.
So, I found what's causing it (read 'OLD DESCRIPTION' below to know the context), but I have zero idea why is it being caused. So, the thing is, apparently Node cannot find the utils.getHash function (I have a separate file called utils.js which exports the getHash function), so it is never called, and execution never moves forward.
utils.js
...
const getHash = (password) => {
return crypto.createHash('sha3-512').update(password).digest('hex')
}
...
module.exports = {
getHash: getHash
}
Someone help please :(
OLD DESCRIPTION
There's a weird problem I am facing. I wrote a backend API server in ExpressJS, and one of the task it performs is user authentication. I am using MongoDB as the database, and Mongoose to connect and perform operations on it.
The problem I am facing is that the checkUserCreds function does not proceed after a point (commented in code), and Express just returns a blank JSON response.
And I say it it's weird, because I tested with the SAME code just 2 days back, it worked correctly like it should.
user.js
userSchema.statics.checkUserCreds = function (email, password) {
return new Promise((resolve, reject) => {
// Execution goes upto '$and' line, then it goes nowhere; no exceptions are raised
User.findOne({
$and: [{ email: email }, { password: utils.getHash(password) }]
}, (err, userDoc) => {
if (err) {
reject({ status: "ERROR", message: err })
} else if (userDoc) { // If valid credential
console.log(`User with email '${email}' logged in`)
resolve({ status: "OK", message: "Login successful!" })
} else { // If invalid credential
reject({ status: "ERROR", message: "Invalid credential!" })
}
})
})
}
api.js
// Route - Login (POST: email, password)
router.post("/login", (req, res) => {
// If user is already logged in, reject further login
if (req.session.email) {
res.json({ status: "ERROR", message: "Already logged in!" }).status(403).end()
} else {
// Get data from body
var form = formidable()
form.parse(req, (err, fields, files) => {
if (err) {
res.json({ status: "ERROR", message: err }).status(500).end()
} else {
// Check if credentials are valid
User.checkUserCreds(fields.email, fields.password).then((result) => {
// This portion of code isn't reached either
req.session.email = fields.email
res.json(result).status(200).end()
}).catch((err) => {
res.json(err).status(401).end()
})
}
})
}
})
Can anyone tell me why this is happening?

Sending message from express backend to vuejs frontend

Hi so it's kind of complicated for me, hope anyone can help.
Here's the situation : i have an app divided server side with node/express and front side with Vuejs,
what I'm doing in the back is creating a user here's the code :
const createUser=(req, res, next) => {
console.log("register");
let con=req.con
let { email,password } = req.body;
console.log(req.body)
con.query(
`SELECT * FROM users
WHERE email = $1`,
[email],
(err, results) => {
if (err) {
console.log(err);
res.status(404).json({error: err});
}
console.log(results);
if (results.rows.length > 0) {
//throw new error_types.InfoError("user already exists");
res.status(200).json({error: "user already exists"});
} else {
const hashedPassword = bcrypt.hashSync(password, parseInt(process.env.BCRYPT_ROUNDS));
con.query('INSERT INTO users (email,password) VALUES ($1, $2)',
[email,password],
(err, results) => {
if (err) {
next(err);
}
res.json({info: "User inseted" });
}
);
}
}
);
}
so im checking if it already exists else register it in DB,all good here.
Now in my Vuejs part i have this :
REGISTER({ commit, dispatch, rootState }, { payload }) {
const {email,password} = payload
console.log(payload)
commit('SET_STATE', {
loading: true,
})
const register = mapAuthProviders[rootState.settings.authProvider].register
register(email,password)
.then(success => {
if (success) {
notification.success({
message: "Succesful Registered",
description: "You have successfully registered!",
})
router.push('/auth/login')
commit('SET_STATE', {
loading: false,
})
}
if (!success) {
commit('SET_STATE', {
loading: false,
})
}
})
},
Now the problem happens here as the registration is done all okay but when i use the same email again for another registration it said the same message successfully registred but do not get saved to DB now what i want is the message user aleady exists that appears.
Anyone can help me please?
Edited :added axios part
export async function register(email,password) {
return axios
.post('/register', {emailpassword,})
.then(response => {
if (response) {
const { token } = response.data
if (token) {
store.set('accessToken', token)
}
return response.data
}
return false
})
.catch(err => console.log(err))
}
Without seeing the actual source code that does the HTTP request from the client, it's hard to say exactly what the error handling looks like. The most obvious culprit is this:
res.status(200).json({error: "user already exists"});
You're responding with HTTP 200 OK when an error occurs. Typically, a client implementation will treat this as success. You should signal to clients that an error has occurred - for example, respond with a "409 Conflict". Also make sure the client's fetch() call (or whatever the client uses for talking to the server) does proper error handling (checks statusCode).
The code has another issue, however - a race condition. This is a case of a TOCTTOU (Time-of-Check to Time-of-Use), where a non-zero amount of time passes between the existence check (SELECT) and the INSERT. If two users are registering for the same e-mail at the same time, they could both get a success.
You should remove the check altogether and use uniqueness constraints offered by the database instead (UNIQUE INDEX). This way, the DB guarantees there can be no duplicates and you don't have to worry about race conditions.

How to communicate from the back end to the front end in a MEAN stack application?

I'm new to the MEAN stack app and am having some trouble trying to send data from the server to the front end. However, I do have some communication going on, but this is all I can seem to do. In the server I have the json message being sent.
Server
router.route("/users/register").post((req, res) => {
registerLogin.findOne({ $or: [{ username }, { email }]}, (err, user) => {
if (err)
res.send(err);
else if (!username || !email || !password)
res.status(403).json({ registerErrRequired: "Fill out whole form." });
Front end
registerUser(username, email, password) {
const user = {
username: username,
email: email,
password: password
};
return this.http.post(`${this.uri}/users/register`, user)
.pipe(map(response => console.log(response)))
.subscribe(() => { this.router.navigate(["/users/login"]) }, (errResp) => {
errResp.error ? this.ngFlashMessageService.showFlashMessage({
messages: [errResp.error.registerErrRequired], // Where json message gets caught and shown to the browser
dismissible: true,
timeout: false,
type: 'danger'
}) : console.log("An unkown error occured.");
});
}
This works well, but I can't seem to do req/res other than using a flash message. My issue is wanting to use it in other ways than just flash messages. For example, if the user does not have a session, then I want them to navigate back to the the log in page. Here's what I tried but failed.
Server
// Middleware
const redirectLogin = ((req, res, next) => {
if (!req.session.user)
res.status(401).json({ loggedIn: false });
else
next();
});
// Route
router.route("/home").get(redirectLogin, (req, res) => {
Blog.find((err, docs) => {
if (err)
console.log(err);
else
res.json(docs);
});
});
Front end
homePage() {
// Here is where I would like to say, If session, then true, else navigate(["/users/login"])
if (loggedIn === false)
this.router.navigate(["/users/login"])
else
// Success
return this.http.get(`${this.uri}/home`);
}
The only way I found communication was through sending error flash messages, but nothing else.
What you can do is call an api to check whether the user is logged in or not in ngOnInit lifecycle hook,so every time your component loads you can check whether the session exists on backend and route accordingly.
export class App implements OnInit{
constructor(){
//called first time before the ngOnInit()
}
ngOnInit(){
//CheckLogin() is a method in your service which calls your backend api
this.http.post("your authentication url to check if session exits ",{username:username}).subscribe(data=>{
if (data["loggedIn"] === false)
this.router.navigate(["/users/login"])
})
}
}
Angular also has HTTP interceptors,you can solve this issue with jwt and http interceptors

Variable route/url param connected to Mongodb

Thanks for reading my question!
I'm making a chat-app where people can chat with each other who are born at the same date.
So the question is,
How do I change the route with an additional birthdate which is changing with every different user with different birthdates?
I already can signup/login and save the birthdate for every user.
So I need to take the birthdate from the mongoDB to put it in the url so nobody gets directed to the wrong chat.
router.get("/", chatController.getAll);
app.use('/api/v1/chat', passport.authenticate('jwt', { session: false }), apiChatRouter);
const getAll = (req,res)=>{
Message.find({},(err,docs)=>{
if(!err){
res.json({
"status":"succes",
"data":{
"chat":docs
}
});
}
});
}
fetch('http://localhost:3000/api/v1/chat/', {
//nodige headers meegeven met localstorage
'headers':{
'Authorization': 'Bearer ' + localStorage.getItem('token')
}
}).then(result => {
return result.json();
}).then(json =>{
console.log(json);
}).catch(err =>{
console.log("Unauthorized")
});
If you want to check the rest of the code:
https://github.com/abuijzen/Herexamen-Webtech3
You can use express path param please check the below example
To redirect user to other path you can user
res.redirect('/1990-03-29');
to get param from url
app.get('/api/v1/chat/:bd', function (req, res) {
// http://localhost:xx/api/v1/chat/1990-03-29
req.params // eqal { "bd": "1990-03-29" }
})
Please check routing and redirect

Can I use res.redirect and res.send simultaneously in Node.js?

I want to print user's info on the landing page after they get logged in. I am using res.redirect to redirect to landing page i.e index1.html after a user get successfully logged in.
Now I want to get user info. Here is my node.js code:
app.post('/login-feedback', function (req, res) {
dbConn.then(function(db) {
delete req.body._id; // for safety reasons
var dd = db.db("customermanagement");
dd.collection('admin').findOne({username: req.body.username, password: req.body.password}, function(err, user){
if(err) {
console.log(err);
}
else if(user){
req.session.user = user;
console.log( req.session.user.username);
res.status(200);
res.redirect('/index1.html');
}
else {
res.redirect('/login1.html');
}
});
});
});
I would love if you will tell me explicitly everything step by step.
If you want to send data to a static file, like an html file, you should use res.render :
res.render('/login1.html', {user: req.session.user.username})

Resources