Parse custom webhook: can I query my tables? - javascript

In a Parse custom webhook, which is of the form:
app.post('/receiveSMS', function(req, res) {
Where receiveSMS is hooked up to the Twilio api and this method is properly called (I have logs to prove it), but I'm trying to query on my tables within this method and it doesn't seem to be working.
Is this allowed, or is there anything special I need to do to make this work?
var contactObj = Parse.Object.extend("Contact");
var contactQuery = new Parse.Query(contactObj);
console.log(req.body.From);
contactQuery.each(function(contact) {
and the body of the each call never gets called.
Is this allowed, and if so, what am I doing wrong here?
Update -- The entirety of the webhook code block is:
app.post('/receiveSMS', function(req, res) {
console.log('receive SMS');
console.log(req.body.Body);
res.send('Success');
if(req.body.Body.toLowerCase() == "in" || req.body.Body.toLowerCase() == "out") {
twilio.sendSMS({
From: "(xxx) xxx-xxxx",
To: req.body.From,
Body: "It's been noted, and notifications have been sent. Check us out!"
}, {
success: function(httpResponse) {
console.log(httpResponse);
response.success("SMS Sent!");
},
error: function(httpResponse) {
console.error(httpResponse);
response.error("Uh OH, something went wrong");
}
});
if(req.body.Body.toLowerCase() == "in") {
console.log("in was received");
// eventQuery
var contactObj = Parse.Object.extend("Contact");
var contactQuery = new Parse.Query(contactObj);
console.log(req.body.From);
// contactQuery.equalTo("phone", req.body.From);
contactQuery.first({
success: function(contact) {
console.log("found contact");
console.log(contact);
}, error: function(error) {
alert("Error: " + error.code + " " + error.message);
}
});
}
}
});
This code is called and the logs "console.log('receive SMS')" and the like are all called, except for what is inside the query's first call.

Queries on tables is fine, but you can't use the each() function, as that is restricted to only work in background jobs.
You'll have to use find() or first() or get() depending on your needs.
UPDATE
OK, after seeing your full code I have some ideas as to why it isn't working. First off you're sending res.send("Success"); before you're finished, I'm not positive but I think this causes it to stop running the rest of your code (haven't checked, could be wrong).
Also you're doing multiple async operations without chaining them so the contactQuery.first() will run before the twilio.sendSMS() is finished.
Inside twilio.sendSMS() you're calling response.success() / response.error(). These are for cloud methods, not web hooks, so I expect these would be throwing errors server-side (check the logs on the Dashboard).
Inside contactQuery.first() you are using alert() which isn't supported in cloud code.
I'm not sure if those mistakes will be caught early and throw errors or if they'll raise run-time exceptions, but they should be fixed, your code re-deployed and try again. Then report any errors in the server logs.

Yes, it's allowed, I'm using the same web hooks.
My guess is that you probably have defined security restriction on your Contact class that prevent the query to fetch anything. What's the security setting on this class ?
You can either try to relax the constrains, or login as a dummy user, and execute the query (approach that I chose).
cheers
-A

Related

SignalR error when invoking method on the server from JavaScript client

I have a C# server running my hub class, which contains only 1 method in there, which is as follows,
public class HothHub : Hub
{
public async Task AddSingleUserGroup(string name)
{
await Groups.AddToGroupAsync(Context.ConnectionId, name);
}
}
I also have a JavaScript client, which connects to the hub via the following code,
var connection;
async function signalRStart() {
connection = new signalR.HubConnectionBuilder()
.withUrl("https://somesignalrurl.com/hothhub", { withCredentials: false })
.withAutomaticReconnect()
.configureLogging(signalR.LogLevel.Information)
.build();
connection.on("hothHubToHothUpdate", () => {
console.log("Called by the server!");
});
connection.onreconnecting(error => {
console.log("Connection lost due to error " + error + ". Reconnecting.");
});
// Start the connection.
await start();
}
async function start() {
try {
await connection.start();
connection.invoke("addSingleUserGroup", "someUniqueUserName");
} catch (err) {
console.log(err);
setTimeout(start, 5000);
}
};
Now when the client initiates the connections and run start() on itself, this part seems to run fine. A connection to the signalR hub is made successfully. The problem I'm having is when connection.invoke("addSingleUserGroup", "someUniqueUserName"); is run although the error does not happen all the time. On first run, the method at the server end is hit successfully however, it looks like subsequent calls to it fail and this is the error returned in the client,
Uncaught (in promise) Error: Failed to invoke 'addSingleUserGroup' due to an error on the server. HubException: Method does not exist.
at _callbacks.<computed> (signalr.js:1252:36)
at HubConnection._processIncomingData (signalr.js:1364:33)
at HubConnection.connection.onreceive (signalr.js:985:52)
at webSocket.onmessage (signalr.js:2236:30)
I've read a few articles on here but most seemed to be related to the client calling the wrong method name having used a capital letter at the start of the method name when invoking it and some having mentioned issues with the method expecting 1 type parameter and receiving another type although in my instance here its hard to think how the server would not treat the incoming parameter as a string, which is what is being passed in. Has anyone got any ideas on what could be wrong here or what I could try?
Thanks!
Unfortunately I dont have an actual answer for this but after deploying the solution to my Azure App Service, the release version does not produce the error. It seems the error only persisted when in debug mode but like I said I'am not sure why.

Is there a way to mock a property on a request object

I have a Javascript REST api endpoint defined using swagger. In my controller, I am logging the IP address from the incoming request.
This is functioning just fine but now I am trying to add Jest tests for coverage and each time I run my test I am getting an error thrown
module.exports.execute = async function execute (req, res) {
try {
log.info("Start processing request from client IP="+req.connection.remoteAddress);
... do some stuff
log.info("Finished processing request from client IP="+req.connection.remoteAddress);
} catch(err) {
log.error("Error caught in Address controller =>" + err.message);
utils.writeJson(res, err.message, 500);
}
};
When I execute my tests, I am getting Error caught in controller =>Cannot read property 'remoteAddress' of undefined
When I comment out the lines that call req.connection.remoteAddress, all is good and I get coverage but not for those 2 lines.
I am guessing the issue is that the req.connection.remoteAddress is a property and not a function.
Is there a way I can mock the response from this call to return a statis string like 1.1.1.1 ?
Any help is appreciated
After thinking about the question in the first comment from #Will Alexander, I added this (second line) and now all is good. Thank you Will
let mockReq = _.set({},'swagger.params.entity.value', JSON.stringify({ fail: false}));
mockReq.connection = _.set({},'remoteAddress', '1.1.1.1');

Node http.ClientRequest does not fire "error" event

I have the following javascript node.js code:
var options = {
host: "x.y.z"
,path: "/api/abc/"
,method: "GET"
};
var req = http.request(options);
req.on('response' , function(data) {
console.log("response: ",data.statusCode);
done();
});
req.on('error' , function() {
console.log("error");
done();
});
req.end();
I can't get the error event when an actual HTTP request error occurs. What am I missing ?
Preliminary findings: It would appear that the failure case "no response from server" (e.g. due to network issue) does not fire any event. So, the workaround is to create a 'timer' and trap this condition by yourself.
Try using an if / else statement instead of two independent functions.
if(response you want && response.statusCode = 200){
//logic
} else {
//console.log("error")
}
You should create your own Timeout function inside the request. In fact, I believe that after a lot of time (maybe a minute?) the request would fail. But, if you require something more earlier, you can check this thread that asks for the same thing:
How to set a timeout on a http.request() in Node?

Account.createUser call back is not working in meteorjs

I am developing an app with meteor js. I have created one meteor method for creating user. It's showing me following error:-
Accounts.createUser with callback not supported on the server yet.
here is my meteor method
how can i add callback in account.createUser?
Meteor.startup(function () {
Meteor.methods({
postForm:function(doc){
var result = Accounts.createUser({
username: doc.username,
password: doc.password,
email: doc.emails,
profile: {
lastname: doc.lastname,
contact:doc.phoneNumber,
bdat:doc.bod,
address:doc.address
}
},function(){
console.log('hello');
});
}
});
});
The "yet" in that error message is likely a mistake on the author's part. According to the documentation:
On the server, [Accounts.createUser] returns the newly created user id.
This means that on the server-side, Accounts.createUser is essentially blocking: it waits for the user to be created, and then returns its newly generated id. So "the callback", in that case, is basically anything that follows your createUser statement. You get one value, the user's _id, which you can use to retrieve the inserted user with Meteor.users.find(). And you can catch thrown exceptions if you want to cover errors.
But as David Weldon said, you could basically do that using Accounts.createUser() on the client, which takes a callback. I guess it makes sense if you want to do something server-specific in the "callback" of that creation, but one may also argue that you could do a server method call just for that. (though it would call the server twice in that case, once for the creation, and once for the callback logic)
I received exactly the same error message including the word "yet." My complete error message: Exception while invoking method Error: Accounts.createUser with callback not supported on the server yet. Translate that error message as
Hey, Developer, you big dummy, your method call doesn't handle both
response and error via callbacks, yet. Please fix your code.
The issue for me was two fold. Like you, I did not adequately account for callback error and response. What that means is, if there is an error somewhere else in the chain of calls, that error WON'T get passed back to you, so you have no idea what's wrong. Fix the call back code first.
Meteor.methods({
postForm:function(doc){
try {
var result = Accounts.createUser({
username: doc.username,
password: doc.password,
email: doc.emails,
profile: {
lastname: doc.lastname,
contact:doc.phoneNumber,
bdat:doc.bod,
address:doc.address
}
});
if(result){
// are you using roles?
// Roles.addUsersToRoles(result, doc.roles);
return result;
}
}
catch(err){
return err;
}
}
});
Hopefully this will 'fix' the callback not supported error message. And at that time you should be able to see what is really causing your troubles. In my case it was a faulty Accounts.validateNewUser((user) routine that I had copied from a tutorial and forgotten to update to match my data.
Oh, almost forgot... here's sample code to call the method from the client.
Meteor.call('postForm', newUser, function(error, response) {
if (error) {
console.log('postForm: Error: ', error);
}
if (response) {
console.log('postForm: Response: ', response);
}
});
Good luck with this. Info offered here in case anybody gets the "yet" error!

Save success not working with parse.com object

I have been messing around trying to save data from a web form and cannot get the standard validation to return. Thinking this is some sort of async problem that I am just not getting. Saving objects with the parse.com api is built off of backbone.js, so it is pretty similar to that. For some reason I can save my data to my database no problems, but when I try to introduce some sort of validation it gets messed up. Looking for some info on how to properly get a success validation back from the server. Right now it hits error every time, and seems to kill the server from saving data.
Below is the code that executes on submit. I have shown the three ways I have tried saving data.
$("#f1").submit(function(event) {
var NewRes = Parse.Object.extend("Customer");
var newRes = new NewRes();
newRes.set("FirstName", "Ricky");
newRes.set("LastName", "Bobby");
//works every time, but I have no return validating it
newRes.save();
//saving with callback options, doesn't save anything to the database and hits error message
newRes.save(null, {
wait: true,
success: function(newRes, response) {
alert("success" + response.message);
},
error: function(newRes, response) {
alert("errorcode: " + response.code + " Message: " + response.message);
}
});
//saving with promises, doesn't save anything and hits error message
newRes.save().then(function(response) {
alert("success");
}, function(error) {
alert("error");
});
});
Here are the results of the error message given below:
errorcode: 100 Message: XMLHttpRequest failed: {"statusText":"","status":0,"response":"","responseType":"","responseXML":null,"responseText":"","upload":{"ontimeout":null,"onprogress":null,"onloadstart":null,"onloadend":null,"onload":null,"onerror":null,"onabort":null},"withCredentials":false,"readyState":4,"timeout":0,"ontimeout":null,"onprogress":null,"onloadstart":null,"onloadend":null,"onload":null,"onerror":null,"onabort":null}
The reason none of this was working is because the form.submit() function was finishing before any of the parse.com asynchronous functions were complete. In order to prevent this I used the preventdefault method to stop the form from submitting. Then I used location.reload() to refresh the page after my parse.com requests have either finished successful or failed.
$("#f1").submit(function(event) {
event.preventDefault();
var NewRes = Parse.Object.extend("Customer");
var newRes = new NewRes();
newRes.set("FirstName", "Ricky");
newRes.set("LastName", "Bobby");
//saving with promises
newRes.save().then(function(response) {
alert("success");
location.reload(); //refreshes the form
}).catch(function(error) {
alert("error");
location.reload();
});
});

Categories

Resources