PUT does not update Mysql thru REST api / JWT - javascript

I am trying to make an update request using Jwt (Tokens) and Node.Js with a backend in mysql.
It just tells me in Postman that the record has been updated, i try to see where the update took place and i could not find a thing. Nothing updated.
My code is looking thus :
app.put('/api/v1/logistics/update_profile', async function (req, res, next) {
try {
if (
!req.headers.authorization ||
!req.headers.authorization.startsWith('Bearer ') ||
!req.headers.authorization.split(' ')[1]
) {
return res.status(422).json({ message: 'Please Provide Token!' });
}
const theToken = req.headers.authorization.split(' ')[1];
const decoded = jwt.verify(theToken, 'fasta-logistics');
var fullname = req.body.fullname;
var email = req.body.email;
var state = req.body.state;
var city = req.body.city;
var phone_num = req.body.phone_num;
var company_type = req.body.company_type;
var company_name = req.body.company_name;
var company_regnum = req.body.company_regnum;
var l_licensenumber = req.body.l_licensenumber;
var company_address = req.body.company_address;
dbConn.query(
'UPDATE XXXXXx SET fullname =? , email =?, state=?, city=?, phone_num=?, company_type=?, company_name =?, company_regnum =?, l_licensenumber =?, company_address =? where id =?',
[
fullname,
email,
state,
city,
phone_num,
company_type,
company_name,
company_regnum,
l_licensenumber,
company_address,
decoded.id,
],
function (error, results, fields) {
if (error) throw error;
return res.send({
error: false,
data: results,
message: 'User Updated Successfully',
});
}
);
} catch (err) {
next(err);
}
});
Why does it tell me the records has been updated and nothing happens? Please I need guidance here of some sort.

return res.json({ error: false, data: results, message: 'User Updated Successfully' }); should work.

To be honest, I don't know how the "dbConn.query" works, but I guess you misspelled the arguments order or something like that. I can suggest you to use ORMs instead (at least query builders like knex), because they have declarative and more readable code, huge doc and community and issues like this doesn't exist in there.

Related

Mongoose findOneAndUpdate doesn't find (or update) in Node

I'm trying to add user input (url's) to a database with Mongoose but also checking if the added data already exists. Instead it seems to be creating a new model every time.
This shows the res.json(input) on screen, not the test json
var mongo = require('mongodb');
var mongoose = require('mongoose');
var cors = require('cors');
// Basic Configuration
var port = process.env.PORT || 3000;
process.env.DB_URI="omg it's my secret url"
// Connect to DB.
mongoose.connect(process.env.DB_URI, { useNewUrlParser: true, useUnifiedTopology: true }).
catch(error => handleError(error));
mongoose.connection.on('error', err => {
console.log(err);
});
app.use(cors());
//First we create a schema and Model in MongoDB.
const urlSchema = new mongoose.Schema({
original_url: String,
short_url: Number
});
const urlModel = mongoose.model('urlModel', urlSchema);
app.post(/PATH, function(req, res, done) {
//Now we check if the input-url was actually valid.
if(!/(^https:\/\/)/.test(req.body.url)){
res.json({error: "Invalid url"});
}
//If it's valid we will start creating a model in the DB.
else {
var userUrl = req.body.url;
var urlNumber = 0;
var input = new urlModel({
original_url: userUrl
});
//Now we check if the url was already added to the database and return a new or updated item.
urlSchema.pre('save', function (next) {
var query = {'original_url': userUrl };
urlModel.findOneAndUpdate(query, userUrl, {upsert: true}, function(err, doc) {
if (err) return res.send(500, {error: err});
res.json({'test': 'test'});
});
});
res.json(input);
urlNumber++;
input.save(function(err, data) {
if (err) return console.log(err);
done(null, data);
});
};
});
As you can see I also have a problem updating the number that I want to attach to the url in the database, since I re-assign 0 to urlNumber at the beginning of the call. Must be because it's late but I can't seem to find a way to update that number correctly. I tried two variables and checking them against each other and an if(urlNumber > 0), but that's a problem I'm still solving. Seems so simple..
Anyway the question here is: why doesn't findOneAndUpdate seem to update? The returned res.json(input) shows a new '_id' every time, which tells me it does actually create new models every run.
Example returns
#1
{
_id: eksdjh3948wryeids293ren12;
original_url: "https://www.correct.com"
short_url: 0
}
#2
{
_id: eksdjh3948wryeids293ren13; // (<----- NEW NUMBER)
original_url: "https://www.correct.com"
short_url: 0
}
Your pre('save' function(next) {}) hook isn't calling next()
Turns out the .pre hook doesn't work with findOneAndUpdate! If I just remove that, the code now works as expected.

Variable value updation gives value change to null

I have an application that is connected to this route. This route is to update the user personal detail, I don't get any errors in the process but for some reason what ever I put the input, the value on the mongodb is changed to null.
app.post('/updateUserDetails', verifyToken, function(req, res){
jwt.verify(req.token, 'secretkey', (err, authData) => {
if(err) {
res.sendStatus(403);
} else {
var userID = authData._id,
newFirstName = req.firstName;
// lastName = req.lastName,
// age = req.age,
// gender = req.gender,
// phoneNumber = req.body.phoneNumber;
console.log(err);
user.update({_id: userID}, {firstName: newFirstName}, function(err, updatedUser){
if(err){
console.log("error updating user firstName");
res.json({msg:"error updating user firstName"});
}else{
console.log("user firstName has been updated");
res.json({msg:"user firstName has been updated", firstName: newFirstName});
}
},function(err){
console.error(err);
});
}
});
});
Console.log your req see exactly what you are sending, you can also use the debugger to understand what is being sent and received at any point.
console req.firstname and check what will print. try req.body.firstName, your route is post call

how to properly send the response code from Node.js API

I have a simple node-based API, which needs to parse some JSON, save some data into Postgres, and then, send the appropriate response code (like http 201).
My code looks like this:
router.route('/customer')
.post(function(req, res) {
Customers = req.body;
var numberOfCustomers = Customers.length;
for(var i = 0; i < Customers.length; i++){
Customer = Customers[i];
console.log(Customer.Name + " " + Customer.Address);
var date = moment(new Date()).unix();
client.query(
'INSERT into customer (name, address, date_modified) VALUES($1, $2, $3) RETURNING id',
[Customer.Name, Customer.Address, date],
function(err, result) {
if (err) {
console.log(err);
status = 1;
} else {
console.log('row inserted with id: ' + result.rows[0].id);
if(numberOfCustomers === i) {
res.status(201).send({ message: "created" });
}
}
});
}
})
I'm getting this error:
_
http_outgoing.js:344
throw new Error('Can\'t set headers after they are sent.');
^
Error: Can't set headers after they are sent.
at ServerResponse.OutgoingMessage.setHeader (_http_outgoing.js:344:11)
I need to account for the fact, that I'm performing my Postgres insert multiple times within a loop, so I can not send my response headers after just the first insert is done.
What is the most appropriate place within my 'POST' handler to put my res.status(201).send({ message: "created" });
?
Architectural decisions aside (for example, you might want a separate module that acts as an HTTP adapter to handle logic for sending response codes as opposed to doing it inside of your route controller), you can use promises to wait for all the inserts to finish and then send a single response code. For example, something like this:
var Promise = require('bluebird');
var query = Promise.promisify(client.query);
router.route('/customer')
.post(function(req, res) {
// all your logic, and then
return Promise.all(Customers.map(function() {
return query(sql, [Customer.Name, Customer.Address, date]);
})
.then(function() {
res.status(201).send({ message: 'Created' });
});
});
Check out the the bluebird docs for the API used in this example.
I'm unfamiliar with Postgres's API, but the concept should be similar: you need to wait for all the requests to your DB to be resolved first.
As stated above: Yes, async helpers such as Promises and async are beneficial for such matters. However, I do believe the 'best' way to solve this problem is to only use a single query. Instead of only performing one insert per query, batch them all up in to a single query like so:
INSERT into customer (name, address, date_modified)
VALUES
($1, $2, $3),
($4, $5, $6),
($7, $8, $9),
...
RETURNING id'
Suggestion
router.route('/customer').post(function(req, res) {
//Fetch customers
var customers = req.body;
//Store parameters and query inserts for db-query.
var params = [];
var inserts = [];
//For each customer
// - Add parameters for query
// - Build insert string
customers.forEach(function(customer){
inserts.push(
[
"($",
params.push(customer.Name),
", $",
params.push(customer.Address),
", ",
NOW(), //unnecessary to generate timestamp in js
")",
].join('')
)
});
//Build query
var query = 'INSERT into customer (name, address, date_modified) VALUES '+ inserts +' RETURNING id';
//Query database in a more simple fashion.
client.query(query, params, function(err, result) {
if (err) {
console.log(err);
status = 1;
} else {
res.status(201).send({ message: "created" });
});
}
})
If you're using ES6 you are able to simplify the string build operations by using string templating.
customers.forEach(function(customer){
var query = `($${params.push(customer.Name)}, $${params.push(customer.Address)}, NOW())`
inserts.push(query);
});
//and
var query = `
INSERT into customer (name, address, date_modified)
VALUES ${inserts}
RETURNING id
`;
The proper way be to do, I would also recommend you look into Async or lodash lib.
router.route('/customer')
.post(function(req, res) {
var Customers = req.body,
numberOfCustomers = Customers.length;
for(var i = 0; i < Customers.length; i++){
var Customer = Customers[i];
console.log(Customer.Name + " " + Customer.Address);
var date = moment(new Date()).unix(),
sql = 'INSERT into customer (name, address, date_modified) VALUES($1, $2, $3) RETURNING id';
client.query(sql, [Customer.Name, Customer.Address, date],
function(err, result) {
if (err) {
console.log(err);
res.status(500).json({message: "Server Error", err: err});
} else {
console.log('row inserted with id: ' + result.rows[0].id);
if (numberOfCustomers === i) {
res.status(201).send({ message: "Created" });
}
}
});
}
})

How to determine which session I'm on for OAuth reauthentication in Meteor?

I've written my own custom authentication to work with our corporate OAuth solution. This results in an OAuth access and refresh token being sent to me. I can then store these tokens in the user collection of the Meteor database but when I want to perform reauthentication I need to be able to find the right session to be able to locate which OAuth token I should use for refreshing it, if required. Since the user can login from multiple devices, this complicates matters.
This is the code I use to store the tokens and send result on the server-side:
var userId = null;
var user = Meteor.users.findOne({username: userName});
if (!user) {
userId = Meteor.users.insert({username: userName});
} else {
userId = user._id;
}
logger.info("User logged in: " + userId);
var initToken = Accounts._generateStampedLoginToken();
var token = Accounts._hashStampedToken(initToken);
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
// Need way to bind oath.loginTokens with Meteor resume token
Meteor.users.update(userId,
{$push: {'services.oauth.loginTokens': token}}
);
var rslt = {
userId: userId
};
return(rslt);
And this is the resulting record in the DB:
"services" : {
"oauth" : {
"loginTokens" : [
{
"when" : ISODate("2014-06-17T17:51:24.635Z"),
"hashedToken" : "ErcosEo9rD+IuT3EyFb3DFS8Bf0enwLzkCIf/nP1JFE=",
"accessToken" : "bhafr3WBDS67EmZ9hFE20af83BJRPFQQS8NGpMlSH6NHVCOiTeTuTJ",
"refreshToken" : "enOAFkBcxB88FlATUh2m0E5NLLG0y8AojyIH5gItnJXdU6",
"ttl" : 3600
}
]
},
"resume" : {
"loginTokens" : [
{
"when" : ISODate("2014-06-17T17:51:24.637Z"),
"hashedToken" : "uhRZpGdBHnAVKvgBEm7oSWsdflOGRI2YrR9Q21iqjzp+Xc="
}
]
}
},
"username" : "lous"
As you can see from what's above, I need to key off of one of the token values to find the right oauth information to do a possible refresh. On the client side I then do what's shown below, but the problem is that the token returned in validateResult is not the same token that is being stored in the DB, so I have no way to track which session is mine.
Template.login.events({
'submit #login-form': function(e,t) {
e.preventDefault();
var id = t.find('#login-id').value,
password = t.find('#login-password').value;
var req = {id: id, password: password};
Accounts.callLoginMethod({
methodArguments: [req],
validateResult: function (result) {
var token = result.token;
window.localStorage.setItem('token', token);
subscribeToRequests();
$.mobile.changePage('#landingPage', {transition: 'slidefade'});
},
userCallback: function(error) {
if (error) {
console.log("Error: " + error.message);
alert("Login Failure");
}
}
});
return false;
}
});
Why would the token not be the same? Any recommendations on how to address this? Then once I do have the token stored client side, does Meteor provide an out-of-the-box way to test the token's validity? Here's the findUser method I'm using to attempt to do that:
Meteor.methods({
findUser: function(token) {
var user = null;
var hashedToken = Accounts._hashLoginToken(token);
if (this.userId) {
//TODO need user object to include token to do TTL check and reauth if necessary
user = Meteor.users.findOne({_id:this.userId});
var result = refreshUser(user);
if (result.err) {
throw { name: 'System Error', message: 'The following error occurred: ' + result.err
};
}
} else {
throw { name: 'System Error', message: 'No userId available. Please try again.'
};
}
return user;
}
});
In your findUser method, you can call Accounts._getLoginToken(this.connection.id) to get the current login token for the connection. You can then look up the OAuth access token associated with this value.
As for your original question of why result.token on the client is different from what's in the database: I think you're comparing the unhashed token (result.token) to the hashed token stored in the database. If that's the case, you can pass result.token to the server and pass it through Accounts._hashLoginToken before looking it up in the database.
Does that make sense?
Here's how I ended up aligning my OAuth tokens with the Meteor session token.
I created the following Meteor.methods on the server-side and my client just calls the updateToken in the validateResult of my Accounts.callLoginMethod so my oauth tokens can be found by the method #emily describes in her answer.
It calls reauthenticateUser whenever the app starts up or is refreshed and finally, it calls logoutUser when the user logs our or the session timeout expires.
updateToken: function() {
// Update oauth hash token with correct hashed token
var user = Meteor.users.findOne({'_id': this.userId});
var hashedToken = Accounts._getLoginToken(this.connection.id);
// Get last element for OAuth array (safely presuming the last one is the last oauth from current call stack) and update hashedToken
var oauthObj = _.last(user.services.oauth.loginTokens);
Meteor.users.update({'services.oauth.loginTokens': {$elemMatch: {hashedToken: oauthObj.hashedToken}}}, {$set: {'services.oauth.loginTokens.$.hashedToken': hashedToken}});
},
reauthenticateUser: function() {
var user = null;
if (this.userId) {
var hashedToken = Accounts._getLoginToken(this.connection.id);
user = Meteor.users.findOne({$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]});
// Get specific oauthTokens (keep in mind multiples per client)
var oauthTokens = _.findWhere(user.services.oauth.loginTokens, {'hashedToken': hashedToken});
var result = refreshUser(this.userId, user.username, oauthTokens);
if (result.err) {
throw { name: 'System Error', message: 'The following error occurred: ' + result.err
};
}
} else {
throw { name: 'System Error', message: 'No userId available. Please try again.'
};
}
return user;
},
logoutUser: function() {
var hashedToken = Accounts._getLoginToken(this.connection.id);
// Remove orphaned Oauth tokens
Meteor.users.update(
{$and: [{'_id': this.userId}, {'services.oauth.loginTokens': {$elemMatch: {hashedToken: hashedToken}}}]},
{$pull: {'services.oauth.loginTokens': {'hashedToken':hashedToken}
}});
return true;
}
Once I had this in place, it was easy for me to update the oauth tokens once they were refreshed or to remove them once the user logged out.
I'm not meteorJS developer, but I'll try to suggest the resolution of problem.
install meteor-cookies using npm install meteor-cookies.
and then:
var initToken = Cookie.get('initToken');
if(!initToken) {
initToken = Accounts._generateStampedLoginToken();
Cookie.set('initToken', initToken, {days: 30});
}
var token = Accounts._hashStampedToken(initToken);
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
OR:
var token = Cookie.get('token');
if(!token) {
var initToken = Accounts._generateStampedLoginToken();
token = Accounts._hashStampedToken(initToken);
Cookie.set('token', token, {days: 30});
}
token.accessToken = result.data.access_token;
token.refreshToken = result.data.refresh_token;
token.ttl = result.data.expires_in;
maybe there are errors in my additions but I think You've understood the trick. (:

How to create an update function on nodejs/mongodb?

Hi I am currently new to nodejs and mongodb what I want to do is make a function to update my win,lose,draw record from my userschema.
My Schema:
UserSchema = new mongoose.Schema({
username:'string',
password:'string',
email:'string',
//Change Made
win:{ type: Number, default: 0 },
lose:{ type: Number, default: 0 },
draw:{ type: Number, default: 0 }
});
My Function for updating:
//Update scores
app.post("/user/updateScores", function (req, res) {
var user = new User({
username:req.body.username,
win:req.body.win,
lose:req.body.lose,
draw:req.body.draw
});
Users.findOne({ username : req.params.username }, function(error, user) {
if (error || !user) {
res.send({ error: error });
} else {
user.update(function (err, user) {
if (err) res.json(err)
req.session.loggedIn = true;
res.redirect('/user/' + user.username);
});
}
});
});
The problem is when I try updating, when I try updating via my html file. It does not update anything and just stays the same (the values win,lose,draw the default value is 0 so when I logout and login again the values of the win,lose,draw record is still zero). I thoroughly checked if the problem was the html and javascript functions that I have made but this is not the case so I think that the problem is the update function I have made. Any of you guys have an idea where I went wrong? Thanks!
Assuming your post is being called correctly from the client, you'll need to be careful about variable and parameter names, as the scope right now is that you're saving an exact duplicate of the user object that was just fetched via findOne.
You had user declared as a variable of the post callback, and then again within the findOne. The inner variable user will take precedence.
app.post("/user/updateScores", function (req, res) {
var username = req.body.username;
Users.findOne({ username : username }, function(error, user) {
if (error || !user) {
res.send({ error: error });
} else {
// update the user object found using findOne
user.win = req.body.win;
user.lose = req.body.lose;
user.draw = req.body.draw;
// now update it in MongoDB
user.update(function (err, user) {
if (err) res.json(err) {
req.session.loggedIn = true;
}
res.redirect('/user/' + user.username);
});
}
});
});

Categories

Resources