I am trying to write a function that add or edit some fields on a User object.
The problem come when I try to save the user, if I use user.save, the Promise is rejected with error 206 UserCannotBeAlteredWithoutSessionError.
However, if I get the session id (and documentation about that is scarce), the promise never get resolve, nor rejected. The app seems to just jump to the callback.
My function:
function update(user, callback) {
let query = new Parse.Query(Parse.User);
query.equalTo("username", user.email);
query.find().then(
(users) => {
if(users.length === 0) {
callback('Non existent user');
} else {
let user = users[0];
// user.set('some', 'thing');
console.log('save');
user.save(/*{
sessionToken: user.getSessionToken()
}*/).then(
(test) => {
console.log('OK - ' + test);
callback();
}, (err) => {
console.log('ERR- ' + require('util').inspect(err));
// console.log(callback.toString());
callback(error.message);
}
);
}
},
(error) => {
callback(error.message);
}
);
}
Called with:
var async = require('async'),
baas = require('./baas.js');
async.waterfall([
(callback) => {
callback(null, {
email: 'user#test.com',
password: 'password'
});
},
(user, callback) => {
console.log('connect');
baas.connect(() => { //Initialize the connection to Parse, and declare use of masterKey
callback(null, user);
});
},
(user, callback) => {
console.log('update');
baas.update(user, (err) => {
callback(err);
});
}
], (err) => {
console.log('Error: ' + err);
});
The logs become:
Without session token:
connect
update
save
ERR- ParseError { code: 206, message: 'cannot modify user sA20iPbC1i' }
With session token:
connect
update
save
I do not understand how it is possible that the promise just callback without printing anything, nor why no error are raised anywhere.
Edit:
Following #user866762 advice, I tried to replace the query with Parse.User.logIn and use the resulting User object.
While this solution give me a sessionToken, the end result is the same, parse crash if I don t provide the session token, or give me a error if I do.
According to the Parse Dev guide:
...you are not able to invoke any of the save or delete methods unless the Parse.User was obtained using an authenticated method, like logIn or signUp.
You might also try becoming the user before saving, but I have my doubts that will work.
When you're "get[ting] the session id" my guess is that you're really breaking something. Either Parse is having a heart attack at you asking for the session token, or when you're passing it in save you're causing something there to explode.
Related
I want to make a javascript code that does a metamask transaction and redirects the user to another page after the transation is completed. How easy this may sound, I can not figure it out.
My current code lets the user complete the transaction, but it does not redirect the user to another page. Instead, it gives this error: "MetaMask - RPC Error: invalid argument 0: json: cannot unmarshal non-string into Go value of type common.Hash"
I have looked it up, but I could not find any possible fix for my problem.
This is my code:
try {
// send the transaction
ethereum.send({
method: 'eth_sendTransaction',
params: [
{
to: contractAddress,
from: userAddress,
value: amt
},
],
}, (error, transactionHash) => {
if (error) {
console.error(error);
} else {
// check the status of the transaction using the transaction hash
ethereum.request({
method: 'eth_getTransactionReceipt',
params: [transactionHash],
}).then((receipt) => {
// check if the transaction was successful
if (receipt.status === '0x1') {
console.log(`Transaction was successful`);
// redirect to another page
window.location.href = "page.php";
} else {
console.log(`Transaction failed`);
}
}).catch((error) => {
// This is the line of code the error is assigned to:
console.error(error);
});
}
});
} catch (error) {
console.error(error);
}
});
} else {
document.getElementById("bericht").innerHTML = "Install Metamask before you continue";
return;
}
I have tried looking the error up on internet, but nothing significant showed up. Could anyone help? Thank you in advance!
Am try to implement and learn async await functions in my login example, but I don't know if is the best, elegant and clean code. I have doubs meanly in catch errors, and if I need implement in a best way the const and functional programing. Can share your opinions?
app.post('/', async (req, res) => {
try {
const { email } = req.body.email; // destructuring
const usuarioEncontrado = await Usuario.findOne({email: email});
// Validate user exist
if (!usuarioEncontrado) { // when not exist return null
throw res.status(404).json({error: 'El usuario no existe'});
}
// validate user pass
if (!bcrypt.compareSync(req.body.password, usuarioEncontrado.password)) {
throw res.status(404).json({error: 'No match'});
}
const token = jwt.sign( // generate token
{
usuario: usuarioEncontrado
},
SEED,
{
expiresIn: (60 * 60)
}
);
res.status(200).json({ // send response
token: token,
usuario: usuarioEncontrado
});
} catch (e) { // send error
res.status(404).json(e);
}
}
THANKS
Your code shows a couple problems:
You're attempting to send double responses. First you do throw res.status(404).json(...). Then, you catch that exception and do res.status(404).json(e) again. That's not right. If you're going to send the response, then just return, don't throw. Or, just throw the exception without sending a response and send the actual error response from the catch handler.
Also, throw res.status(404).json({error: 'No match'}); sends the response and then throws whatever .json() returns which is probably not what you want. That won't be an error object of any kind.
I prefer to centralize the places I send an error response to one place in the request handler. That keeps you from ever attempting to send multiple responses and just makes the flow of the request handler easier to understand (in my opinion).
To do that, I just throw a custom error that may have a custom message/status associated with it and then catch all possible errors in one place. Here's one way to do that. The myError class can be used everywhere in your project, not specific to just one route. The idea is that often when you throw, you know in that context what you want the status and message to be so you set that in the custom Error object and can then use that info in the catch. The catch then has to determine whether it has your custom error or just a regular error. First, I have a reusable Error subclass that lets me throw, not only a message, but also a status value.
// reusable error class that contains a status in addition to the message
class MyError extends Error {
// this static method saves having to compare if it's a custom error object or not
// every time we use this
static sendError(res, e, status = 500) {
if (e instanceof MyError) {
e.sendError(res);
} else {
res.sendStatus(status);
}
}
constructor(msg, status = 500) {
// allow calling with or without new
if (!(this instanceof MyError)) {
return new MyError(msg, status);
}
super(msg);
this.status = status;
}
sendError(res) {
res.status(this.status).send(this.message);
}
}
And, then here's how you use that in your code and centralize the sending of the error status.
app.post('/', async (req, res) => {
try {
const { email } = req.body.email; // destructuring
const usuarioEncontrado = await Usuario.findOne({email: email});
// Validate user exist
if (!usuarioEncontrado) { // when not exist return null
throw MyError('El usuario no existe', 404);
}
// validate user pass
if (!bcrypt.compareSync(req.body.password, usuarioEncontrado.password)) {
throw MyError('No Match', 404);
}
const token = jwt.sign( // generate token
{
usuario: usuarioEncontrado
},
SEED,
{
expiresIn: (60 * 60)
}
);
res.status(200).json({ // send response
token: token,
usuario: usuarioEncontrado
});
} catch (e) { // log and send error response
// e may be either MyError or some other system generated Error
console.log(e);
MyError.sendError(res, e);
}
}
I am trying to retrieve the access token from an API (https://github.com/Axosoft/node-axosoft/)
To receive an access token we have to follow this process:
var axo = nodeAxosoft(axosoftUrl, credentials);
axo.Api.getLoginUrl(function(url) {
// open browser using authorizationUrl and get code parameter from
//redirected Url after login
var code = 'code received from redirect';
axo.Api.exchangeCodeForToken(code);
});
As I did not understood exactly how to get the code following that example nor what is the url parameter on getLoginUrl, I did it on my own.
I have a login route that redirects the user to the axosoft website for authentication and redirects the user to the /authorization-process route on my application.
On the /authorization-process I get the code returned by the login and call a function that should get the access token by calling:
axo.Api.exchangeCodeForToken(code);
Code:
var axosoft_code = req.query.code;
console.log(axosoft_code);
var token = request.exchangeAuthCodeForAccessToken(axosoft_code)
.then(function(token)
{
res.send(token);
})
The Method:
var connection = nodeAxosoft(client_url, credentials);
return new Promise(function(resolve, reject){
console.log("CODE: ", axosoft_code)
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(token){
console.log(token);
resolve(token)
})
The problem is that returns null
I had a look at the API lib api.js and found that:
https://github.com/Axosoft/node-axosoft/blob/master/lib/api.js
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
So I have two questions:
Does anyone has an Idea what am I doing wrong?
What would be necessary to code the callback function?
The method expects a callback function but I don't really know how to do it.
EDIT:
return new Promise(function(resolve, reject){
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response)
resolve(token);
}
else{
console.log("error",err)
resolve(token);
}
});
})
OR
var token = connection.Api.exchangeCodeForToken(axosoft_code, function(response,err){
if(!err){
console.log("token",response.body)
return response.body;
}
else{
console.log("error",err)
return err;
}
});
I am giving to my callback function two args (response and err), my problem is that I am falling at the else condition.
The output of err is something similar to a token though the documentation here shows that it should be like that:
{
"error" : "invalid_request",
"error_description" : "One or more parameters are missing: client_secret"
}
Another point is that the page is frozen waiting for something to happen but nothing happens.
Given that this is the input:
function exchangeCodeForToken(code, callback) {
_credentials.code = code;
_access_token = '';
_authenticateCredentails(function (err) {
if (!err) {
callback(null, _access_token);
} else {
callback(err);
}
})
}
You should format your call as:
exchangeCodeForToken(axosoft_code, function(err, response) {
if (err) {
// Deal with error
} else {
// Deal with response
}
}
Node functions often pass through error variables first so that you have to receive them, which is considered good practice.
I am attempting to send a text message when a user requests to reset their password. I would like to wait for the message to be sent to alert the user if it was successful or not. I am currently attempting to do it as follows:
async function sendResetPasswordTextMessage(req, res) {
let result = {};
let phoneNumber = req.body.phoneNumber;
if (phoneNumber === undefined) {
return sendInvalidParametersMessage(res);
}
phoneNumber = phoneNumber.toString();
const userProfile = await models.UserProfile.findOne({
where: {
phoneNumber: phoneNumber
}
});
************************** RELEVANT CODE TO ISSUE *************************
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
const sent = await AWSSNSClient.sendMessage(message, phoneNumber);
if (!sent) {
result.error = setTitleAndMessage("Error", "An error occurred");
} else {
result.success = setTitleAndMessage("Success", "Message sent");
}
}
return res.send(result);
***************************************************************************
}
In my other class AWSSNSClient, I have the following sendMessage function:
function sendMessage(message, phoneNumber) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
let sent = false;
sns.publish(params, function(err, data) {
if (err) {
console.log(err, err.stack); // an error occurred
}
else {
sent = true;
}
});
return sent;
}
I cannot figure out how to make sendMessage wait for sns.publish to return before it returns itself. I have tried making it an async method and adding await on sns.publish, but the function still returns before sent gets set to true.
I know that the messages are sending without error because I am receiving them and no console logs are printed.
Stumbled on this one via Google trying to figure this out myself today - short answer that I am now using:
You can now do this with Async/Await — and Call the AWS service (SNS for example) with a .promise() extension to tell aws-sdk to use the promise-ified version of that service function (SNS) instead of the call back based version.
The only caveat here is the containing function must ALSO be async to utilize the await syntax.
For example:
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("SNS Push Failed:");
console.log(err.stack);
return;
}
console.log('SNS push suceeded: ' + data);
return data;
}).promise();
The important part is the .promise() on the end there. Full docs on using aws-sdk in an async / promise based manner can be found here: https://docs.aws.amazon.com/sdk-for-javascript/v2/developer-guide/using-promises.html
In order to run another aws-sdk task you would similarly add await and the .promise() extension to that function (assuming that is available).
For anyone who runs into this thread and is actually looking to simply push multiple aws-sdk promises to an array and wait for that WHOLE array to finish (without regard to which promise executes first) I ended up with something like this:
let snsPromises = [] // declare array to hold promises
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn
}, async function (err, data) {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return;
}
console.log('Search push suceeded: ' + data);
return data;
}).promise();
snsPromises.push(snsResult)
await Promise.all(snsPromises)
Hope that helps someone that randomly stumbles on this via google like I did!
stackdave will that actually wait?
Necevil "Search push suceeded will get logged twice" because you're mixing calling operations by passing a callback and using promises. You should only use one method of getting the result
let snsResult = await sns.publish({
Message: snsPayload,
MessageStructure: 'json',
TargetArn: endPointArn}).promise()
will do the trick
You can simply use callbacks for that. Modify your sendMessge like this
function sendMessage(message, phoneNumber, cb) {
const params = {
Message: message,
MessageStructure: "string",
PhoneNumber: "+1" + phoneNumber
};
sns.publish(params, cb);
}
then on your main file you can supply callback like this
if (userProfile) {
const message = "Your username is:\n" + userProfile.username;
AWSSNSClient.sendMessage(message, phoneNumber, (err, data) => {
if (err) {
result.error = setTitleAndMessage("Error", "An error occurred");
}
else {
result.success = setTitleAndMessage("Success", "Message sent");
}
res.send(result);
});
}
Here the right updated API, August 2018, Necevil answer send the sms twice.
// using config.env
AWS.config.region = 'eu-west-1';
AWS.config.update({
accessKeyId: process.env.AMAZON_SMS_ID,
secretAccessKey: process.env.AMAZON_SMS_TOKEN,
});
// parameters
let params = {
Message: contentSMS, // here your sms
PhoneNumber: mobile, // here the cellphone
};
const snsResult = await sns.publish(params, async (err, data) => {
if (err) {
console.log("ERROR", err.stack);
}
console.log('SNS ok: ' , JSON.stringify (data));
});
If you're having issues with duplicate SNS messages being sent, I fixed this issue by utilizing examples from AWS:
// Load the AWS SDK for Node.js
var AWS = require('aws-sdk');
// Set region
AWS.config.update({region: 'REGION'});
// Create publish parameters
var params = {
Message: 'MESSAGE_TEXT', /* required */
TopicArn: 'TOPIC_ARN'
};
// Create promise and SNS service object
var publishTextPromise = new AWS.SNS({apiVersion: '2010-03-31'}).publish(params).promise();
// Handle promise's fulfilled/rejected states
publishTextPromise.then(
function(data) {
console.log("Message ${params.Message} send sent to the topic ${params.TopicArn}");
console.log("MessageID is " + data.MessageId);
}).catch(
function(err) {
console.error(err, err.stack);
});
By utilizing a traditional .then() I was able to squash the duplicate message bug mentioned in comments above.
You can create a async function what use the promise method
async function sendMessage(message, phoneNumber){
const params = {
Message: message,
PhoneNumber: phoneNumber
};
return new Promise((resolve, reject) => {
SNS.publish(params, (err, data) => {
if (err) {
console.log("Search Push Failed:");
console.log(err.stack);
return reject(err);
} else {
console.log('Search push suceeded:' + phoneNumber);
return resolve(data);
}
})
});
}
and then you can call
var s= await sendMessage(message,phoneNumber);
ive never used cloud code/javascript and I am trying to write some parse cloud code to find a user using a objectId passed in to the cloud function, and then update that users relation that holds friends and finally save that user.
below is the function im using:
Parse.Cloud.define("addFriendToFriendsRelation", function(request, response) {
Parse.Cloud.useMasterKey();
var fromUserObjectId = request.params.fromUserObjectId;
var acceptingUser = request.params.user;
var query = new Parse.Query(Parse.User);
// find the user the request was from using the objectId
query.get(fromUserObjectId, {
success: function(user) {
var fromUser = user
var relation = fromUser.relation("friends");
relation.add(acceptingUser);
fromUser.save({
success: function() {
response.success("Successfully saved the users relation")
},
error: function() {
response.error("Save failed");
}
});
},
error: function() {
response.error("Save failed");
}
});
});
I managed to piece this together using the Parse docs. but Im really not following it to well. Never used javascript and am finding the syntax confusing.
then im calling the function with
//fromUser is a PFUser object defined further up
[PFCloud callFunctionInBackground:#"addFriendToFriendsRelation" withParameters:#{#"fromUserObjectId" : fromUser.objectId} block:^(id object, NSError *error) {
}
however whenever this function is called I get a success/error was not called error. Though im calling response.success and response.error in the function so I dont know why that is? Can anyone lend a hand?
edit: after doing some more searching it looks like response.success and response.error should only be called once each, so I modified my function to look like this:
arse.Cloud.define("addFriendToFriendsRelation", function(request, response) {
Parse.Cloud.useMasterKey();
var fromUserId = request.params.fromUserObjectId;
console.log("fromUserId:");
console.log(fromUserId);
var acceptingUser = request.params.user;
console.log("acceptingUser:")
console.log(acceptingUser);
var query = new Parse.Query(Parse.User);
query.get(fromUserId, {
success: function(user) {
console.log("found user:");
console.log(user);
var fromUser = user;
var relation = fromUser.relation("friends");
relation.add(acceptingUser);
console.log("added accepting user to relation");
fromUser.save({
success: function() {
response.success("successfully saved user")
},
error: function() {
response.error("error saving user");
}
});
console.log("found a user");
},
error: function() {
console.log("error finding user");
}
});
});
An old question, but since it's been up-voted, maybe answering can help someone else :).
First off, there is an error in how you are saving fromUser.
fromUser.save({ success: ...
If you look at the api you can see that it should be of the form:
fromUser.save(null, { success: ...
But the larger problem that kept you from finding your bug is that errors are getting eaten 'cause you are using the old style method of dealing with async code instead of using promises.
Below, I have re-written to use promises. Note:
I always return promise generating calls (there are other options for catching errors in async code, but start with this.)
Put a .catch at the end. The .catch is effectively the same things as .then(null, response.error) but either way, it is imperative that there is final backstop to catch errors. In your code above, the error was in a success block, that was running async, so when there was an error, it failed with no one to hear it :).
Parse.Cloud.define("addFriendToFriendsRelation", (request, response) => {
const fromUserId = request.params.fromUserObjectId;
console.log("fromUserId:", fromUserId);
const acceptingUser = request.user;
console.log("acceptingUser:", acceptingUser)
new Parse.Query(Parse.User);
.get(fromUserId, { useMasterKey: true })
.then((fromUser) => {
console.log("found fromUser:", fromUser);
const relation = fromUser.relation("friends");
relation.add(acceptingUser);
console.log("added accepting user to relation");
return fromUser.save(null, { useMasterKey: true })
})
.then(response.success)
.catch(response.error);
});