MongoDB update upon button click - javascript

Within my view, I am directing the user from '/dashboard' to '/upvote'
Within my routes, I have:
app.get('/upvote', function(req, res) {
user = req.user
user.score += 1;
user.save();
res.redirect('/dashboard');
});
This is just an example, trying to grasp how to use this for a different purpose at a later stage.
How do I correctly update my users 'score' attribute to increment every time there's a GET command for '/upvote/' ?

You need to find the given user in your request; req.user is just an object and not a mongoose model. If you have the ID of the document, you can use findById. If you don't you'll need to use a find query on another field.
// Users is the mongoose model
Users.findById(id, function (err, user) {
if (err) return handleError(err);
user.score += 1;
user.save(function(err) {
if (err) return handleError(err);
res.send(user); // Or redirect, basically finish request.
});
});
Second of all - I wouldn't necessarily do a redirect. You could stay on the same page and simply have the command refresh the user model.

If you separately modify and then save your user document, you can lose votes during concurrent requests.
Instead, use update with the $inc operator to make the upvote atomic:
app.get('/upvote', function(req, res) {
User.update({_id: req.user._id}, {$inc: {score: 1}}, function(err, count) {
res.redirect('/dashboard');
});
});
BTW, you should consider using a POST or PUT request instead of a GET as GET requests shouldn't change data.

Related

How can I get a value from the JWT header into a variable in nodejs?

I am making an API server where I can login and see some information. Whenever I log in I get a JWT token which contains my username. I want to store this username in a variable whenever I want to use it. This is the code I use to verify my token when I want to enter certain webpages.
import jwt from "jsonwebtoken";
function authenticateToken(req, res, next) {
const authHeader = req.header("access-token");
if (!authHeader) return res.sendStatus(401);
jwt.verify(authHeader, process.env.ACCESS_TOKEN_SECRET, (err, user) => {
if (err) return res.sendStatus(403);
req.user = user;
next();
});
}
export default authenticateToken;
It checks if the header contains a JWT token. If so it verifies it. Then at the bottom the user gets retrieved, but I dont know how to get this value.
On my routes I secure them like this:
router.get("/", authenticateToken, getData);
within the getData method im displaying data from a mysql database. I want to add a check to see if my username is equal to the data in getData (since you can only see certain data).
In getData i get my data like this:
connection.query(
"SELECT * FROM data WHERE userid = ?", [user.username],
(err, rows) =>
On the [user.username] spot I want to retrieve the username within the JWT token. I want to do this using a method, but I cant seem to get it. How can I get my username?
You could try to change your code a little bit to pass the request to the getData function, as you store the authenticated user within the request.
Try something like this:
router.get("/", authenticateToken, async (req, res) => {
getData(req);
});

passport.js logs in one specific user, even though other user's username/password has been entered

I have the following code to authenticate users. When a username/password is not correct, passport.js doesn't allow to login which is as expected.
But when username/password is correct, passport.js always logs in one specific user regardless of the fact that another user's credentials have been entered. I wonder if anybody knows what might be the cause.
function authenticationMiddleware(){
return function(req,res,next){
console.log('req.isAuthenticated(): '+req.isAuthenticated())
if(req.isAuthenticated()){
return next()
}
res.redirect('/')
}
}
app.get('/profile', authenticationMiddleware(), (req, res) => {
res.render('profile.ejs',{
user: req.user
});
})
Console logs indicate that passport.js serializes the user whose credentials have been entered, however it always de-serializes one specific user regardless of entered credentials. I thought maybe my serializing and de-serializing methods are incorrect, but I couldn't find anything wrong with them:
passport.serializeUser(function(user, done) {
console.log('serializing user.username: '+user.username)
//return user by id (automatically generated id by CouchDB is _id)
done(null, user._id);
});
//
passport.deserializeUser(function(id, done) {
UserFindByID(id, function(err, user) {
console.log('deserializing user.username: '+user.username)
done(err, user);
});
});
UPDATE
There was a mistake in my UserFindByID function. I corrected the mistake and now the code works as expected.
Did you check that the id passed is correct? print it out before the UserFindByID. Maybe that function returns a wrong value

Express send information to user with a page

I have the following code
var user = function(req,res,next) {
db.findOne({ username: req.params.uid }, function (err, docs) {
//error handaling
if(err){console.log(err)}
//check if user is real
if(docs === null){
res.end('404 user not found');
}else{
//IMPORTANT PART res.sendFile(__dirname + '/frontend/user.html');
}
});
}
app.get('/user/:uid',user);
Don't worry about the database stuff.
I want to know how to get req.params.uid sent to the client side and how to get it from there.
Thanks so much.
If your user is configured correctly every request will have a user:
var user = function(req,res) {
db.User.findOne({ _id: req.user._id }, function (err, docs) {
//error handaling
if(err){console.log(err)}
//check if user is real
if(docs === null){
res.end('404 user not found');
}else{
res.json(docs)
}
});
and then your api endpoint is just '/user/
In your client just make a GET request to this endpoint (maybe using AJAX) and your response will be any user that makes that given request.
Note: You don't need to pass in next unless you are defining middleware.
This is just a more complete answer based on my comment.
If you want to store a string of information about the user with each request they make, then you want to use cookies.
When the user first makes a request to the page, you would set the cookie via the res.cookie. So, in your code, the final if statement would look something like:
if(docs === null) {
res.end('404 user not found');
} else {
res.cookie('uid', req.params.uid, { httpOnly: true });
//IMPORTANT PART res.sendFile(__dirname + '/frontend/user.html');
}
Then, in the next request, and futures requests before the cookie expires, you can access it using:
req.cookies.uid
However, you need the cookie-parser middleware somewhere in your app beforehand:
var cookieParser = require('cookie-parser');
app.use(cookieParser());
If you need to access the value of uid on the clientside, you could either use a template, or set the httpOnly value to false when setting it using res.cookie. Then you could access the cookie using document.cookies.
Check out this W3Schools page for accessing cookies on the clientside.

Regarding efficiency of passport.js module "deserializeUser" in node.js

So I was looking into the document regarding passport.js module serialize users to keep logged in users in session. (A little above the Username & Password parts). I'm using mongodb, with mongoose
passport.deserializeUser(function(id, done) {
console.log("this code is used again! ");
User.findById(id, function(err, user) {
done(err, user);
});
});
I test these code in example they gave. So it looks that this piece of code is executed every time when the logged-in user refresh a page.
Say there are 100,000 users and there are 10 pages in this entire application, it means there will be 1 million look-ups, just to maintain in session status for every one. Doesn't this sounds too inefficient? Does most application do this kind database search?
Or am I making mistaking understand it?
There's nothing stopping you from using a cache or similar approach. One of them could be https://www.npmjs.com/package/cache-manager but do shop for more!
Alternatively, if you don't really need to know all the user information all the time you can serialize/deserialize the user id only and load the user record on demand. In your instance just pass through function:
passport.deserializeUser(function(id, done) {
console.log("this code is used again! ");
done(null, id);
});
If that's not enough you could deserialize to an object like this:
passport.deserializeUser(function(id, done) {
console.log("this code is used again! ");
done(null, {id: id, user: function(done){
User.findById(id, function(err, user) {
done(err, user);
});
}});
});

Sending multiple mail in Nodejs

A web app I'm building will send out invoices to clients every third month. This will be a scheduled event that is run in the middle of the night, but under development I have put this code into a route so I can test it.
In short i want the code to do the following.
QUery all unsent invoices from DB.
Make a call to Mandrill for each invoice (In this call I'm also invoking a function creating a Mandrill message object from the invoice).
For every message Mandrill send, Update the DB invoice sent: true.
When all invoices are sent, make a final callback in the async.waterfall
The code below works. but i have some concerns regarding the _.each.
invoices.post('/invoices/send/', function(req, res, next) {
async.waterfall([
// Query all unsent invoices
function(callback) {
db.invoices.find({sent: false}).toArray(callback);
},
// Send all unsent invoices
function(invoices, callback) {
if (invoices.length === 0) {
var err = new Error('There are no unsent invoices');
err.status = 400;
return next(err); //Quick escape if there are no matching invoice to process
}
// Make a call to Mandrill transactional email service for every invoice.
_.each(invoices, function(invoice) {
mandrillClient.messages.sendTemplate({template_name: "planpal-invoice", template_content: null, message: mandrillClient.createInvoiceMessage(invoice)}, function(sendResult) {
console.log(sendResult);
db.invoices.updateById(invoice._id, {$set: {sent: true}}, function(err, saveResult) {
console.log(saveResult);
});
}, function(err) {
return next(err);
});
});
callback(null, 'done');
}
],
function(err, result) {
if (err) {
return next(err);
}
res.json(result);
});
});
I'm thinking I should use async.eachLimit instead.... but I dont know how to write it.
I have no idea what i should set the limit to, but I guess several parallel request would be better than running all mandrill request in serie like above, am I wrong? EDIT _.each run the callbacks in parallel. The difference from a async.each is that I dont get a "final callback"
Conclusion: Should i use a async.eachLimit above? If Yes, what is a good limit value?
I think you can use the https://github.com/caolan/async#each function.
it will execute the queries in parallel too

Categories