I am using Pase.com with js SDK for the backend of my Dart App. This works fine apart from the parse sdk accepts an object of callback functions. In dart Im unsure how to do this, I can get single callbacks working fine. But Im completely lost here.
Normal Parse JS for registering a user
var user = new Parse.User();
user.set("username", "my name");
user.set("password", "my pass");
user.set("email", "email#example.com");
// other fields can be set just like with Parse.Object
user.set("phone", "415-392-0202");
user.signUp(null, {
success: function(user) {
// Hooray! Let them use the app now.
},
error: function(user, error) {
// Show the error message somewhere and let the user try again.
alert("Error: " + error.code + " " + error.message);
}
});
My Dart code
void registerSuccess(user) {
print("success");
}
void registerFailed(user, error){
print("fail");
}
void register(String email, String password)
{
js.scoped(() {
var parse = js.context.Parse;
var parseUser = new js.Proxy(parse.User);
parseUser.set("username", "my name");
parseUser.set("password", "my pass");
parseUser.set("email", "email#example.com");
print(parseUser.getEmail());
var callbackSuccess = new js.Callback.once(() => registerSuccess());
var callbackFailed = new js.Callback.once(() => registerFailed());
parseUser.signUp(null,{"success":callbackSuccess, "error": callbackFailed});
//parseUser.signUp();
});
}
Also the callback function needs accept vars passed back from the js.
Any help would be a appreciated, I have be spinning my wheels for 2 days on this.
Instead of :
var callbackSuccess = new js.Callback.once(() => registerSuccess());
var callbackFailed = new js.Callback.once(() => registerFailed());
parseUser.signUp(null,{"success":callbackSuccess, "error": callbackFailed});
use :
var callbackSuccess = new js.Callback.once(registerSuccess);
var callbackFailed = new js.Callback.once(registerFailed);
parseUser.signUp(null, js.map({"success":callbackSuccess, "error": callbackFailed}));
Related
Trying to follow this blog post Create a Smart Voicemail with Twilio, JavaScript and Google Calendar
When I run the code in Google Developer API Test Console, it works. However, the same parameters called within Twilio Function which runs NodeJS returns an error "ReferenceError: calendar is not defined"
I've made the Google Calendar events public and I've tried viewing it using the public URL and it works too. For someone reason calling it withing Twilio Functions is resulting in an error.
const moment = require('moment');
const { google } = require('googleapis');
exports.handler = function(context, event, callback) {
// Initialize Google Calendar API
const cal = google.calendar({
version: 'v3',
auth: context.GOOGLE_API_KEY
});
//Read Appointment Date
let apptDate = event.ValidateFieldAnswer;
var status = false;
const res = {
timeMin: moment().toISOString(),
timeMax: moment().add(10, 'minutes').toISOString(),
items: [{
id: context.GOOGLE_CALENDAR_ID
}]
};
console.log(res);
cal.freebusy.query({
resource: res
}).then((result) => {
const busy = result.data.calendars[calendar].busy;
console.log("Busy: " + busy);
if (busy.length !== 0) {
let respObj1 = {
"valid": false
};
console.log("Failed");
callback(null, respObj1);
} else {
let respObj1 = {
"valid": true
};
console.log("Success");
callback(null, respObj1);
}
}).catch(err => {
console.log('Error: checkBusy ' + err);
let respObj1 = {
"valid": false
};
callback(null, respObj1);
});
};
Have you encountered this before or is anyone able to identify the issue here?
Thanks
This line seems to be the issue:
const busy = result.data.calendars[calendar].busy;
As far as I can tell, calendar is never defined. This should work instead:
const busy = result.data.calendars[context.GOOGLE_CALENDAR_ID].busy;
It looks like this line of the code is different between the "Google Calendar FreeBusy Queries" and "Recording VoiceMails" sections of the tutorial and needs to be updated in the latter code sample.
I have an API Gateway method calling a Lambda Node.js function. The Lambda function calls SNS and posts an APNS notification to my iPhone. When I invoke the API gateway or the Lambda function in the AWS console, I get one notification as expected. I also get one notification when running the Lambda code on the command line (Grunt and Node.js). I also get one notification when running the javascript from eclipse.
However, when I POST to the API gateway, I get 2-5 notifications. Every thing looks the same. I checked the Cloudwatch logs and it seems only one request is sent each time. Anybody have any idea how to debug this?
I've had similar. For me, it was that I wasn't calling the success callback properly.
I figured it out. I had my function outside the exports.handler function:
var AWS = require('aws-sdk');
var sns = new AWS.SNS();
var myAlerter = function(){
var numSent = 0;
var callback;
var arn = "arn:aws:sns:us-west-2:45435475457:endpoint/APNS/MyAlerter/5a11c61f-1122-3344-5566-656845463";
var sendNotification = function(messageText){
var apns = {
aps : {
alert : messageText,
sound : 'default'
}
};
var message = {
"APNS" : JSON.stringify(apns)
};
message = JSON.stringify(message);
var params = {
Message: message,
MessageStructure: 'json',
TargetArn: arn
};
numSent++;
sns.publish(params, function(err, data){
if (err){
callback(err, err.stack);
}else {
var result = {
error: false,
numSent : numSent,
data: data
};
callback(false,result);
}
});
};
return {
alert : function(message, cb){
callback = cb;
sendNotification(message);
}
}
}();
exports.handler = function(event, context){
var alertedCallback = function(error, data){
if (error){
context.done(error);
} else {
context.succeed(data);
}
};
myAlerter.alert(event.message, alertedCallback);
};
Everytime I called the API Gateway and invoked my Lambda function, the numSent variable would increment. I guess putting my function inside the exports.handler ensured that my function wasn't global or something.
I tried to change the existing angularjs library to angular2 for my need. http.post method in the below code throws TypeError {} as exception. Someone please help as i am stuck on this.
login() {
return new Promise((resolve, reject) => {
if(typeof jsSHA !== "undefined") {
var signatureObj = (new OauthUtility()).createSignature("POST", this.magentoOptions.baseUrl+"/oauth/initiate", this.oauthObject, {oauth_callback: "http://localhost/callback"}, this.magentoOptions.clientSecret, null);
let headersInitiate = new Headers();
headersInitiate.append('Authorization',signatureObj.authorization_header);
headersInitiate.append('Content-Type','application/x-www-form-urlencoded');
let url = this.magentoOptions.baseUrl + "/oauth/initiate";
let callback = "oauth_callback=http://localhost/callback";
try{
this.http.post(url, callback,{headers: headersInitiate})
.subscribe(
(result) => {
console.log("i am inside");
var rParameters = (result).split("&");
.....
}
catch(Exception){
console.log(Exception)
}
You should try something like that:
var signatureObj = (new OauthUtility()).createSignature("POST",
this.magentoOptions.baseUrl+"/oauth/initiate", this.oauthObject,
{oauth_callback: "http://localhost/callback"},
this.magentoOptions.clientSecret, null); let headersInitiate = new Headers();
headersInitiate.append('Authorization',
signatureObj.authorization_header);
headersInitiate.append('Content-Type',
'application/x-www-form-urlencoded');
let url = this.magentoOptions.baseUrl + "/oauth/initiate";
let payload = ' ... ';
this.http.post(url, payload,{headers: headersInitiate})
.subscribe(
(result) => {
console.log("i am inside");
var rParameters = (result).split("&");
(...)
});
Here are the comments I would have on your code:
The second parameter of the post method should be a string corresponding to the payload not a callback. I see from your headers that you want to send url-encoded form, so you need to create it by your own
The try catch isn't necessary since executing an HTTP is asynchronous and errors can be "catched" within the second parameter (another callback) of the subscribe method.
You don't need at all a promise. For HTTP, Angular2 uses observables under the hood. They target asynchronous processing as well.
After fixing all of this, I think that you won't have error anymore...
Hope it helps you,
Thierry
I found to stuck even after proceeding with the above all steps. The complete solution is as follows.
Remove try catch block and promise as suggested by Thierry.
Use dependency injection of http inside the constructor as follows to define http.
import {Http,HTTP_PROVIDERS,Headers} from 'angular2/http';
import {Injector} from "angular2/core";
constructor() {
var injector = Injector.resolveAndCreate([HTTP_PROVIDERS]);
this.http = injector.get(Http);
}
In the below cloud code i would like to get a feedback of the saveAll function but after calling the code from my client in the parse Logs page i can only see:
I2014-10-08T15:28:32.930Z] v249: Ran cloud function acceptMeetingBis for user dyGu143Xho with:
Input: {"meetingId":"bUSTGNhOer"}
Result: Meeting accepted
Here is my cloud code:
Parse.Cloud.define("acceptMeetingBis", function(request, response) {
var userAcceptingTheMeeting = request.user;
var meetingId = request.params.meetingId;
var changedObjects = [];
var queryForMeeting = new Parse.Query("MeetingObject");
queryForMeeting.equalTo("objectId", meetingId);
queryForMeeting.first({
success: function(meeting) {
var userCreatorOfMeeting = meeting.get("user");
userAcceptingTheMeeting.increment("acceptedMeetings", +1);
changedObjects.push(userAcceptingTheMeeting);
meeting.add("participantsObjectId", userAcceptingTheMeeting.id);
if (meeting.get("participantsObjectId").length === meeting.get("meetingNumberOfPersons")) {
meeting.set("isAvailable", false);
}
changedObjects.push(meeting);
Parse.Object.saveAll(changedObjects, {
success: function(objects) {
console.log("Successfully saved objects"); //this line doesn't show up
response.success("objects saved");
},
error: function(error) {
// An error occurred while saving one of the objects.
response.error(error);
}
});
//future query and push notifications will go here
response.success("Meeting accepted");
},
error: function() {
response.error("Failed to accept the meeting");
}
});
});
I will also need to add some push and another nested query after the saveAll() but before doing/trying that i would like to know if this is the right method to use or if i have to build the code in a different way. I'm new to javascript and honestly i'm struggling to understand some concepts, like promises. Any help would be much appreciated.
Your call to
Parse.Object.saveAll
is asynchronous, and you call
response.success("Meeting accepted")
immediately after making the asynchronous call, which ends the cloud code running of the method. If you simply replace the
response.success("objects saved")
with
response.success("Meeting accepted")
you should get what you want.
I didn't see the rest of your question about promises. You should check out Parse's documentation on chaining promises, which is what you want here.
Essentially, here's what you'll want to do:
Parse.Cloud.define("acceptMeetingBis", function(request, response) {
var userAcceptingTheMeeting = request.user;
var meetingId = request.params.meetingId;
var changedObjects = [];
var meetingToAccept;
var queryForMeeting = new Parse.Query("MeetingObject");
queryForMeeting.get(meetingId).then(function(meeting) {
meetingToAccept = meeting;
var userCreatorOfMeeting = meeting.get("user");
userAcceptingTheMeeting.increment("acceptedMeetings", +1);
return userAcceptingTheMeeting.save();
}).then(function(userWhoAcceptedMeetingNowSaved) {
meetingToAccept.add("participantsObjectId", userWhoAcceptedMeetingNowSaved.id);
if (meetingToAccept.get("participantsObjectId").length === meetingToAccept.get("meetingNumberOfPersons")) {
meetingToAccept.set("isAvailable", false);
}
return meetingToAccept.save();
}).then(function(savedMeeting) {
response.success("Meeting accepted");
}, function(error) {
response.error("Failed to accept the meeting");
});
});
For each asynchronous action you want to do, perform it at the end of one of the .then functions and return the result (it returns a promise). Keep adding .then functions until you're done all the work you want to do, at which point call response.success.
Suppose I logged into my device's Facebook authentication, like system Facebook on iOS. I obtain an access token.
How can I use the access token to login to Meteor's Facebook Oauth provider?
To login with Facebook using an access token obtained by another means, like iOS Facebook SDK, define a method on the server that calls the appropriate Accounts method:
$FB = function () {
if (Meteor.isClient) {
throw new Meteor.Error(500, "Cannot run on client.");
}
var args = Array.prototype.slice.call(arguments);
if (args.length === 0) {
return;
}
var path = args[0];
var i = 1;
// Concatenate strings together in args
while (_.isString(args[i])) {
path = path + "/" + args[i];
i++;
}
if (_.isUndefined(path)) {
throw new Meteor.Error(500, 'No Facebook API path provided.');
}
var FB = Meteor.npmRequire('fb');
var fbResponse = Meteor.sync(function (done) {
FB.napi.apply(FB, [path].concat(args.splice(i)).concat([done]));
});
if (fbResponse.error !== null) {
console.error(fbResponse.error.stack);
throw new Meteor.Error(500, "Facebook API error.", {error: fbResponse.error, request: args});
}
return fbResponse.result;
};
Meteor.methods({
/**
* Login to Meteor with a Facebook access token
* #param accessToken Your Facebook access token
* #returns {*}
*/
facebookLoginWithAccessToken: function (accessToken) {
check(accessToken, String);
var serviceData = {
accessToken: accessToken
};
// Confirm that your accessToken is you
try {
var tokenInfo = $FB('debug_token', {
input_token: accessToken,
access_token: Meteor.settings.facebook.appId + '|' + Meteor.settings.facebook.secret
});
} catch (e) {
throw new Meteor.Error(500, 'Facebook login failed. An API error occurred.');
}
if (!tokenInfo.data.is_valid) {
throw new Meteor.Error(503, 'This access token is not valid.');
}
if (tokenInfo.data.app_id !== Meteor.settings.facebook.appId) {
throw new Meteor.Error(503, 'This token is not for this app.');
}
// Force the user id to be the access token's user id
serviceData.id = tokenInfo.data.user_id;
// Returns a token you can use to login
var loginResult = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, {});
// Login the user
this.setUserId(loginResult.userId);
// Return the token and the user id
return loginResult;
}
}
This code depends on the meteorhacks:npm package. You should call meteor add meteorhacks:npm and have a package.json file with the Facebook node API: { "fb": "0.7.0" }.
If you use demeteorizer to deploy your app, you will have to edit the output package.json and set the scrumptious dependency from "0.0.1" to "0.0.0".
On the client, call the method with the appropriate parameters, and you're logged in!
In Meteor 0.8+, the result of Accounts.updateOrCreateUserFromExternalService has changed to an object containing {userId: ...} and furthermore, no longer has the stamped token.
You can get the accessToken in the Meteor.user() data at Meteor.user().services.facebook.accessToken (be aware this can only be accessed on the server side as the services field is not exposed to the client.
So when a user logs in with facebook on your meteor site these fields would be populated with the user's facebook data. If you check your meteor user's database with mongo or some other gui tool you could see all the fields which you have access to.
Building on DrPangloss' most excellent answer above, combining it with this awesome post: http://meteorhacks.com/extending-meteor-accounts.html
You'll run into some issues using ObjectiveDDP in trying to get the client persist the login. Include the header:
#import "MeteorClient+Private.h"
And manually set the required internals. Soon I'll make a meteorite package and an extension to MyMeteor (https://github.com/premosystems/MyMeteor) but for now it's manual.
loginRequest: {"accessToken":"XXXXXb3Qh6sBADEKeEkzWL2ItDon4bMl5B8WLHZCb3qfL11NR4HKo4TXZAgfXcySav5Y8mavDqZAhZCZCnDDzVbdNmaBAlVZAGENayvuyStkTYHQ554fLadKNz32Dym4wbILisPNLZBjDyZAlfSSgksZCsQFxGPlovaiOjrAFXwBYGFFZAMypT9D4qcZC6kdGH2Xb9V1yHm4h6ugXXXXXX","fbData":{"link":"https://www.facebook.com/app_scoped_user_id/10152179306019999/","id":"10152179306019999","first_name":"users' first name","name":"user's Full Name","gender":"male","last_name":"user's last name","email":"users#email.com","locale":"en_US","timezone":-5,"updated_time":"2014-01-11T23:41:29+0000","verified":true}}
Meteor.startup(
function(){
Accounts.registerLoginHandler(function(loginRequest) {
//there are multiple login handlers in meteor.
//a login request go through all these handlers to find it's login hander
//so in our login handler, we only consider login requests which has admin field
console.log('loginRequest: ' + JSON.stringify(loginRequest));
if(loginRequest.fbData == undefined) {
return undefined;
}
//our authentication logic :)
if(loginRequest.accessToken == undefined) {
return null;
} else {
// TODO: Verfiy that the token from facebook is valid...
// https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow/v2.0#checktoken
// graph.facebook.com/debug_token? input_token={token-to-inspect}&access_token={app-token-or-admin-token}
}
//we create a user if not exists, and get the userId
var email = loginRequest.fbData.email || "-" + id + "#facebook.com";
var serviceData = {
id: loginRequest.fbData.id,
accessToken: loginRequest.accessToken,
email: email
};
var options = {
profile: {
name: loginRequest.fbData.name
}
};
var user = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, options);
console.log('Logged in from facebook: ' + user.userId);
//send loggedin user's user id
return {
userId: user.userId
}
});
}
);
This answer could be improved further as we can now directly debug the token from a REST http request using futures. Credit still goes to #DoctorPangloss for the principal steps necessary.
//Roughly like this - I removed it from a try/catch
var future = new Future();
var serviceData = {
accessToken: accessToken,
email: email
};
var input = Meteor.settings.private.facebook.id + '|' + Meteor.settings.private.facebook.secret
var url = "https://graph.facebook.com/debug_token?input_token=" + accessToken + "&access_token=" + input
HTTP.call( 'GET', url, function( error, response ) {
if (error) {
future.throw(new Meteor.Error(503, 'A error validating your login has occured.'));
}
var info = response.data.data
if (!info.is_valid) {
future.throw(new Meteor.Error(503, 'This access token is not valid.'));
}
if (info.app_id !== Meteor.settings.private.facebook.id) {
future.throw(new Meteor.Error(503, 'This token is not for this app.'));
}
// Force the user id to be the access token's user id
serviceData.id = info.user_id;
// Returns a token you can use to login
var user = Accounts.updateOrCreateUserFromExternalService('facebook', serviceData, {});
if(!user.userId){
future.throw(new Meteor.Error(500, "Failed to create user"));
}
//Add email & user details if necessary
Meteor.users.update(user.userId, { $set : { fname : fname, lname : lname }})
Accounts.addEmail(user.userId, email)
//Generate your own access token!
var token = Accounts._generateStampedLoginToken()
Accounts._insertLoginToken(user.userId, token);
// Return the token and the user id
future.return({
'x-user-id' : user.userId,
'x-auth-token' : token.token
})
});
return future.wait();
Use this instead of the JS lib suggested by #DoctorPangloss. Follow the same principles he suggested but this avoids the need to integrate an additional library