Google oAuth Google Fit - javascript

I'm trying to implement Google Fit, in a school project.
I am using the documentation released by Google but it does not work.
I am getting 403 bad request error
Is it possible because I am using XAMPP to try to connect, it gives me an error?
I have entered the request domains on the Google project.
Can you help me?
Also I have a question:
Does it cost to use Google Fit Api rest?
Thanks everyone for your answers
var CLIENT_SECRET;
var CLIENT_ID;
$.post('healthDataFunc.php', { functionname: 'get_app_credentials' }, function(data){
var result = JSON.parse(data);
if (result){
CLIENT_SECRET = result[0];
CLIENT_ID = result[1];
}
});
var CLIENT_REDIRECT = "https://localdefault.com:4433";
//End-Configuration
var SCOPES_FITNESS = 'https://www.googleapis.com/auth/fitness.activity.read+https://www.googleapis.com/auth/fitness.body.read+https://www.googleapis.com/auth/fitness.location.read+https://www.googleapis.com/auth/fitness.blood_pressure.read+https://www.googleapis.com/auth/fitness.sleep.read';
var GoogleAuth;
/*
Initial request for Google authentication code
Opens google auth window
returns Google Auth token
*/
function requestGoogleoAuthCode() {
// Load the API's client and auth2 modules.
// Call the initClient function after the modules load.
gapi.load('client:auth2', initClient);
console.log(gapi);
}
function initClient() {
// In practice, your app can retrieve one or more discovery documents.
var discoveryUrl = "https://www.googleapis.com/discovery/v1/apis/drive/v3/rest";
// Initialize the gapi.client object, which app uses to make API requests.
// Get API key and client ID from API Console.
// 'scope' field specifies space-delimited list of access scopes.
gapi.client.init({
'apiKey': CLIENT_SECRET,
'clientId': CLIENT_ID,
'discoveryDocs': [discoveryUrl],
'scope': SCOPES_FITNESS
}).then(function () {
GoogleAuth = gapi.auth2.getAuthInstance();
// Listen for sign-in state changes.
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
var user = GoogleAuth.currentUser.get();
GoogleAuth.signIn();
console.log("test--------->", GoogleAuth, user);
});
}
/*
Uses Google Auth code to get Access Token and Refresh Token
returns object with access token, refresh token and access token expiration
*/
function getAccessToken(google_auth_code) {
var retVal = null;
jQuery.ajax({
url: "https://www.googleapis.com/oauth2/v3/token?code=" + google_auth_code + "&redirect_uri=" + CLIENT_REDIRECT + "&client_id=" + CLIENT_ID + "&client_secret=" + CLIENT_SECRET + "&scope=&grant_type=authorization_code",
type: "post",
success: function (result) {
console.log("Got Access Token And Refresh Token");
retVal = result;
console.log(result);
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("Error during getAccessToken");
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
retVal = null;
},
async: false
});
return retVal;
}
/*
Uses Refresh token to obtain new access token
returns new access token with expiration
*/
function refreshAccessToken(refresh_token) {
var retVal = null;
jQuery.ajax({
url: "https://www.googleapis.com/oauth2/v3/token?client_secret=" + CLIENT_SECRET + "&grant_type=refresh_token&refresh_token=" + refresh_token + "&client_id=" + CLIENT_ID,
type: "post",
success: function (result) {
console.log("Refreshed Access Token");
retVal = result;
},
error: function (jqXHR, textStatus, errorThrown) {
console.log("Error during refreshAccessToken");
console.log(jqXHR);
console.log(textStatus);
console.log(errorThrown);
retVal = null;
},
async: false
});
return retVal;
}
function revokeAccess(accessToken) {
GoogleAuth.disconnect();
}
var isAuthorized;
var currentApiRequest;
/**
* Store the request details. Then check to determine whether the user
* has authorized the application.
* - If the user has granted access, make the API request.
* - If the user has not granted access, initiate the sign-in flow.
*/
function sendAuthorizedApiRequest(requestDetails) {
currentApiRequest = requestDetails;
if (isAuthorized) {
// Make API request
// gapi.client.request(requestDetails)
// Reset currentApiRequest variable.
currentApiRequest = {};
} else {
GoogleAuth.signIn();
}
}
/**
* Listener called when user completes auth flow. If the currentApiRequest
* variable is set, then the user was prompted to authorize the application
* before the request executed. In that case, proceed with that API request.
*/
function updateSigninStatus(isSignedIn) {
if (isSignedIn) {
isAuthorized = true;
if (currentApiRequest) {
sendAuthorizedApiRequest(currentApiRequest);
}
} else {
isAuthorized = false;
}
}

Related

How to resolve 403 error with Service Account and Google Drive API

I'm trying to write a client-side JS script that will fetch images from my gDrive to display on a website using a service account. I created the service account and added and enabled the google Drive API for the project. But when I run the script, I'm getting a 403 error: Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. I think it has to do with permissions or scopes maybe? I've looked at several other stack overflows and can't seem to figure it out.
Getting a 403 - Forbidden for Google Service Account
Google Drive service account returns 403 usageLimits
Some of them mention adding roles or scopes, but I can't figure out how to add them or which ones I need to add. Is a GSuite account mandatory? It sounds like I would need to go into the GSuite admin console to add the scopes? I would like to not have to sign up for an account, as it's not free. Any help would be appreciated. My code looks like the following:
function gDrive() {
function init(callback) {
authorizeClient(getJWT()).then(function(token) {
loadClient(token, callback);
});
}
/* Retrieve a signed JWT */
function getJWT() {
// Prepare header, payload, and key
let oHeader = {
"alg": "RS256",
"typ": "JWT"
};
let sHeader = JSON.stringify(oHeader);
let oPayload = {
"iss": "SERVICE ACCOUNT EMAIL",
"sub": "SERVICE ACCOUNT EMAIL",
"aud": "https://www.googleapis.com/oauth2/v3/token",
"iat": KJUR.jws.IntDate.getNow(),
"exp": KJUR.jws.IntDate.get("now + 1hour"),
"scope": "https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.appdata https://www.googleapis.com/auth/drive.file https://www.googleapis.com/auth/drive.metadata https://www.googleapis.com/auth/drive.metadata.readonly https://www.googleapis.com/auth/drive.photos.readonly https://www.googleapis.com/auth/drive.readonly"
};
let sPayload = JSON.stringify(oPayload);
let privKey = "-----BEGIN PRIVATE KEY-----BLAH BLAH BLAH\n-----END PRIVATE KEY-----\n";
// Sign JWT
return signedJWS = KJUR.jws.JWS.sign(null, sHeader, sPayload, privKey);
}
/* Http POST to Google Auth api */
function authorizeClient(JWS) {
// Request access token
const url = "https://www.googleapis.com/oauth2/v3/token";
let encodedData = "";
let encodedDataPairs = [];
encodedDataPairs.push(encodeURIComponent("grant_type") + '=' + encodeURIComponent("urn:ietf:params:oauth:grant-type:jwt-bearer"));
encodedDataPairs.push(encodeURIComponent("assertion") + '=' + encodeURIComponent(JWS));
encodedData = encodedDataPairs.join('&').replace(/%20/g, '+');
const params = {
headers: {"content-type":"application/x-www-form-urlencoded"},
body: encodedData,
method: "POST"
};
return fetch(url, params).then(accessTokenSucces).then(returnToken).catch(accessTokenFailed);
}
function accessTokenSucces(data) {
console.log("Retrieved access token");
return data.json();
}
function returnToken(resp) {
return resp.access_token;
}
function accessTokenFailed(error) {
console.log("Requesting access token failed: " + error);
}
function loadClient(accessToken, callback) {
gapi.load('client', function() {
console.log("loading client");
gapi.client.setToken(accessToken);
console.log("set access token");
return gapi.client.load("https://content.googleapis.com/discovery/v1/apis/drive/v3/rest").then(clientLoadSuccessful).then(callback).catch(clientLoadFailed);
})
}
function clientLoadSuccessful() {
console.log("Client loaded");
return Promise.resolve();
}
function clientLoadFailed(error) {
console.log("Loading Client failed: " + error);
return Promise.reject();
}
function fetchAllImages(fileName, chapter, callback) {
console.log("fetching images");
let initialRequest = gapi.client.drive.files.list({"q": "mimeType contains \"image\" and name contains '"
+ fileName + "_ch" + chapter + "'"});
retrievePageOfFiles(initialRequest, [], fileName, chapter);
function retrievePageOfFiles(request, result) {
request.execute(function(resp) {
result = result.concat(resp.files);
let nextPageToken = resp.nextPageToken;
if (nextPageToken) {
request = gapi.client.drive.files.list({
"pageToken": nextPageToken,
"q": "mimeType contains \"image\" and name contains '" + fileName + "_ch" + chapter + "'"
});
retrievePageOfFiles(request, result);
} else {
console.log("Images retrieved");
callback(result);
}
}).catch(function(err) {
console.log("Could not retrieve images: " + err);
});
}
}
return {
init: init,
fetchAllImages: fetchAllImages
};
}
gDrive().init(runApp);
function runApp() {
console.log("Running App");
gDrive().fetchAllImages("FILENAME", "1", imageCallback);
}
function imageCallback(data) {
console.log("Images Retrieved!");
console.log(data);
}
When your script is run, the error of Daily Limit for Unauthenticated Use Exceeded. Continued use requires signup. occurs.
You want to remove this error.
If my understanding is correct, how about this modification? I think that the access token retrieved with your script can be used. So please modify your script as follows.
From:
gapi.client.setToken(accessToken);
To:
gapi.client.setToken({access_token: accessToken});
Reference:
gapi.client.setToken(tokenObject)
If this was not the direct solution of your issue, I apologize.

How to manage API permissions? javascript

I've written some client-side app and tried to test it. How it turned out only I can use it. Anyone else will get such error.
{
"error": {
"errors": [
{
"domain": "global",
"reason": "forbidden",
"message": "Forbidden"
}
],
"code": 403,
"message": "Forbidden"
}
}
What does it mean? How to solve this?
There is my code. There i'm getting Email, name, surname and user photo. I want to get the number of youtube channel subscribers and work with youtube later. For example I want to rate some videos directly from the site.
function resultFindUserByEmail()
{
if (ajaxRet['isUserFinded'])
{
cf_JSON.clear();
cf_JSON.addItem( 'email',email );
var jsonstr = cf_JSON.make();
ajax_post('doyoutubelogin','loginres','index.php',jsonstr,c_dologin);
}else{
gapi.client.init({
discoveryDocs: ["https://www.googleapis.com/discovery/v1/apis/people/v1/rest"],
clientId: OAUTH2_CLIENT_ID,
scope: OAUTH2_SCOPES
}).then(function () {
var request = gapi.client.people.people.get({
'resourceName': 'people/me'
}).then(function(response) {
var parsedResponse = JSON.parse(response.body).names;
surname = parsedResponse[0].familyName;
name = parsedResponse[0].givenName;
photo = JSON.parse(response.body).photos[0].url;
addYoutubeUser();
});
});
}
}
function addYoutubeUser() {
cf_JSON.clear();
cf_JSON.addItem( 'Email',email );
cf_JSON.addItem( 'Firstname',name );
cf_JSON.addItem( 'Lastname',surname );
cf_JSON.addItem( 'Image',photo );
var jsonstr = cf_JSON.make();
ajax_post('addyoutubeuser','loginres','index.php',jsonstr,c_dologin);
}
var API_KEY = '<Key removed for posting>';
var API_KEY1='<Key removed for posting>';
var OAUTH2_CLIENT_ID = '<Key removed for posting>';
var OAUTH2_CLIENT_ID1 = '<Key removed for posting>';
var OAUTH2_SCOPES = 'https://www.googleapis.com/auth/youtube.force-ssl';
var DISCOVERY_DOCS = ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"];
var GoogleAuth;
function handleClientLoad() {
// Load the API's client and auth2 modules.
// Call the initClient function after the modules load.
gapi.load('client:auth2', initClient);
}
function initClient() {
// Retrieve the discovery document for version 3 of YouTube Data API.
// In practice, your app can retrieve one or more discovery documents.
var discoveryUrl = 'https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest';
// Initialize the gapi.client object, which app uses to make API requests.
// Get API key and client ID from API Console.
// 'scope' field specifies space-delimited list of access scopes.
gapi.client.init({
'apiKey': API_KEY,
'discoveryDocs': [discoveryUrl,"https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"],
'clientId': OAUTH2_CLIENT_ID,
'scope': OAUTH2_SCOPES
}).then(function () {
GoogleAuth = gapi.auth2.getAuthInstance();
//GoogleAuth.grant(OAUTH2_SCOPES);
// Listen for sign-in state changes.
GoogleAuth.isSignedIn.listen(updateSigninStatus);
// Handle initial sign-in state. (Determine if user is already signed in.)
var user = GoogleAuth.currentUser.get();
setSigninStatus();
// Call handleAuthClick function when user clicks on
// "Sign In/Authorize" button.
$('#sign-in-or-out-button').click(function() {
handleAuthClick();
});
$('#revoke-access-button').click(function() {
revokeAccess();
});
});
}
function handleAuthClick() {
if (GoogleAuth.isSignedIn.get()) {
// User is authorized and has clicked 'Sign out' button.
GoogleAuth.signOut();
} else {
// User is not signed in. Start Google auth flow.
GoogleAuth.signIn();
}
}
function revokeAccess() {
GoogleAuth.disconnect();
}
function setSigninStatus(isSignedIn) {
var user = GoogleAuth.currentUser.get();
var isAuthorized = user.hasGrantedScopes(OAUTH2_SCOPES);
if (isAuthorized) {
$('#sign-in-or-out-button').html('Sign out');
$('#revoke-access-button').css('display', 'inline-block');
$('#auth-status').html('You are currently signed in and have granted ' +
'access to this app.');
//// get gmail Email
gapi.client.init({
'apiKey': API_KEY,
'discoveryDocs': ["https://www.googleapis.com/discovery/v1/apis/gmail/v1/rest"],
'clientId': OAUTH2_CLIENT_ID,
'scope': OAUTH2_SCOPES
}).then(function () {
var request = gapi.client.gmail.users.getProfile({
'userId': 'me'
}).then(function(response) {
email = JSON.parse(response.body).emailAddress;
cf_JSON.clear();
cf_JSON.addItem( 'email',email );
var jsonstr = cf_JSON.make();
tryFindUserByEmail(jsonstr);
});
});
// try to find email
} else {
$('#sign-in-or-out-button').html('Вход через Youtube');
$('#revoke-access-button').css('display', 'none');
$('#auth-status').html('You have not authorized this app or you are ' +
'signed out.');
}
}
function updateSigninStatus(isSignedIn) {
setSigninStatus();
}
How to manage permissions:
When you authenticate a user you are given access to that users account data and only that user. So if you are trying to access data on someone else's account they are not going to have permissions to access it and you are going to get the 403 forbidden error.
Without seeing your code its hard to know what you are doing, but I can guess.
You are using Oauth2 to authenticate users.
You are trying to access something with a hard coded id belonging to your personal account which the user does not have access.
How to fix it will depend on what it is you are trying to do.
You need to check some authentication in the API url like
username , ipaddress , token etc.
Based on the parameter you can control the permission on your API request.for example
http://some/thing?username="testuser"&ipaddress="323.2323.232.32"
You can find the parameters value using the function below
function getParameterByName(name, url) {
if (!url) url = window.location.href;
name = name.replace(/[\[\]]/g, "\\$&");
var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
results = regex.exec(url);
if (!results) return null;
if (!results[2]) return '';
return decodeURIComponent(results[2].replace(/\+/g, " "));
}
And then make you check and implement your error and redirection for specific users.
I guess it will help full for you , Thanks !

Save session parameters in cookies

I've got a simple Backbone.js app which uses json-server as a backend. I have a function to log in, that finds a user from the collection, but I don't get how will I save my session. I thought about storing a parameter in cookies that later will be checked on every redirect. Here is my model:
var User = Backbone.Model.extend({
defaults: {
login: '',
password: '',
authToken: ''
}
});
And here is my collection:
var UserCollection = Backbone.Collection.extend({
url: 'http://localhost:3000/users',
// creates a random token
setToken: function () {
var rand = function () {
return Math.random().toString(36).substr(2)
}
var token = rand() + rand();
this.set({authToken: token});
}
});
And this is the view with login function
var LoginView = Backbone.View.extend({
initialize: function () {
this.collection = new UserCollection();
// template
}
// render function omitted
signIn: function () {
var login = $('#login').val();
var password = $('#password').val();
/**
finds a user within with the values from input fields
inside the collection
*/
if (login && password) {
this.collection.fetch({
data: {
login: login,
password: password
}
});
}
}
});
This function returns me an array with one object that is my requested model. All that I need is to use my setToken method and to save this model's authToken in cookie so that I could use it elsewhere in app, but I don't actually get how to do that.
Using a model to handle authentication would make more sense than a collection. Keep the model's responsibility simple and scoped to one thing. A model to handle the authentication, then a model to handle calls to other object which needs to be authenticated, not both at once.
I personally based authentication on Backbone-session's model.
// Using CommonJS
var Session = require('backbone-session');
// Extend from Session to implement your API's behaviour
var Account = Session.extend({
urlRoot: 'http://localhost:3000/users',
signIn: function(opt) {
opt = opt || {};
opt.data = _.extend({}, {
login: opt.login,
password: opt.password
}, opt.data);
return this.fetch(opt);
},
signOut: function(opt) { /** handle logout */ },
getAuthStatus: function() { /** handle refetching if needed */ }
});
Which I expose as a service to my application. In this session module, I override Backbone.Sync to ensure auth for each following calls to the API for any models or collection.
var mySession = new Account();
Backbone.sync = (function(syncFn) {
return function(method, model, options) {
options = options || {};
var beforeSend = options.beforeSend,
error = options.error;
// Add auth headers
options.beforeSend = function(xhr) {
xhr.setRequestHeader('Authorization', "Bearer " + mySession.get('authToken'));
if (beforeSend) return beforeSend.apply(this, arguments);
};
// handle unauthorized error (401)
options.error = function(xhr, textStatus, errorThrown) {
if (error) error.call(options.context, xhr, textStatus, errorThrown);
if (xhr.status === 401) {
mySession.signOut();
}
};
return syncFn.apply(this, arguments);
};
})(Backbone.sync);
Backbone-session's model uses the local storage as a backend. Its own sync method is overriden to use the local storage instead of the default sync behavior.
sync: function(method, model, options) {
options = options || {};
var url = model.options.url || model.url;
var key = _.isFunction(url) ? url() : '' + url;
var response;
switch (method) {
case 'create':
case 'update':
var data = model.toJSON();
var text = JSON.stringify(data);
response = localStorage.setItem(key, text);
break;
case 'delete':
response = localStorage.removeItem(key);
break;
case 'read':
response = JSON.parse(localStorage.getItem(key));
break;
}
if (_.isFunction(options.success)) {
options.success(response);
}
return Backbone.$.Deferred()
.resolve(response)
.promise();
},
Why the local storage?
You could use this implementation and change it minimally to use cookies instead.
The local storage was a better option for me since my API is on another domain and uses CORS to enable public access. Safari has limitation on cookies.
Safari also blocks cookies from sites that haven't been visited
directly. You can see in the security settings. It's default setting
is Accept cookies: "Only from sites I visit".

Javascript gmail api code for sending email not working

1.Used the code from this link: Sending email from gmail api not received but shown in sent folder
2. I'm using domino server locally with Domino Designer 9
3. Making sure that I'm able to authorize with Gmail api with my google client id (logout from gmail, run the code which is asking me login again)
The modified version of the above code is not working.
What is wrong in my code or setup.
Here is full code.
// Your Client ID can be retrieved from your project in the Google
// Developer Console, https://console.developers.google.com
// function assignval(cl,sc){
// var CLIENT_ID = '261056497849-8kj87m3pjmqko8iot7kpdee2htmaf29a.apps.googleusercontent.com';
// var CLIENT_ID = cl;
//var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly'];
// var SCOPES = sc;
// }
var CLIENT_ID = '204856067483-0ib90ohcb1itdvho93cf33pc8g83t4lp.apps.googleusercontent.com';
var SCOPES = ['https://www.googleapis.com/auth/gmail.readonly','https://mail.google.com/','https://www.googleapis.com/auth/gmail.modify','https://www.googleapis.com/auth/gmail.compose','https://www.googleapis.com/auth/gmail.send'];
/**
* Check if current user has authorized this application.
*/
function auth() {
var config = {
'client_id': CLIENT_ID,
'scope': SCOPES
};
gapi.auth.authorize(config, function() {
console.log('login complete');
console.log(gapi.auth.getToken());
});
}
function checkAuth() {
gapi.auth.authorize(
{
'client_id': CLIENT_ID,
'scope': SCOPES.join(' '),
'immediate': true
}, handleAuthResult);
}
/**
* Handle response from authorization server.
*
* #param {Object} authResult Authorization result.
*/
function handleAuthResult(authResult) {
var authorizeDiv = document.getElementById('authorize-div');
if (authResult && !authResult.error) {
// Hide auth UI, then load client library.
authorizeDiv.style.display = 'none';
loadGmailApi();
} else {
// Show auth UI, allowing the user to initiate authorization by
// clicking authorize button.
authorizeDiv.style.display = 'inline';
}
}
/**
* Initiate auth flow in response to user clicking authorize button.
*
* #param {Event} event Button click event.
*/
function handleAuthClick(event) {
gapi.auth.authorize(
{client_id: CLIENT_ID, scope: SCOPES, immediate: false},
handleAuthResult);
return false;
}
/**
* Load Gmail API client library. List labels once client library
* is loaded.
*/
function loadGmailApi() {
gapi.client.load('gmail', 'v1',send());
}
function sendMessage(email, callback) {
//auth();
gapi.client.load('gmail', 'v1',function(){
var base64EncodedEmail = btoa(email).replace(/\//g,'_').replace(/\+/g,'-');
alert("Message sending" + base64EncodedEmail);
var request = gapi.client.gmail.users.messages.send({
'userId': 'me',
'message': {
'raw': base64EncodedEmail
}
});
request.execute(callback);
});
}
function send() {
var to = 'mohan_gangan#yahoo.com',
subject = 'Gmail API sendmessage test',
content = 'send a Gmail using domino server'
var email ="From: 'me'\r\n"+
"To: "+ to +"\r\n"+
"Subject: "+subject+"\r\n"+
"\r\n"+
content;
alert("Message sent to Gamil API");
sendMessage(email, function (response) {
//console.log("Handed to Gmail API for sending");
{console.log(response)}
});
alert("Message sent");
}

Retrieve customer email from ID contained in webhook in Parse.com

I have an App using Parse.com as a backend and an external site that acts as my payment gateway. Upon receiving the customer/subscription webhook data from Stripe I wish to lookup the users email so I can then run a Cloud Code function and change their user status to 'paid'
My webhook receiver is:
Parse.Cloud.define("update_user", function(request, response) {
var data = request.params["data"]
var customer = data.object.customer;
response.success'Working' + request);
});
And I am able to get an email back from stripe from the customer ID using:
Parse.Cloud.define("pay", function(request, response) {
Stripe.initialize(STRIPE_SECRET_KEY);
console.log(JSON.stringify(request.params));
Stripe.Customers.retrieve(
customerId, {
success:function(results) {
console.log(results["email"]);
// alert(results["email"]);
response.success(results);
},
error:function(error) {
response.error("Error:" +error);
}
}
);
});
I need help turning this into a complete function that is run on receipt of every webhook from Stripe. I am also struggling with options for fallback if this does not work for whatever reason.
EDIT
Taking parts of the first answer and I now have:
Parse.Cloud.define("update_user", function(request, response) {
Stripe.initialize(STRIPE_SECRET_KEY);
var data = request.params["data"]
var customerId = data.object.customer;
get_stripe_customer(customerId, 100).then(function(stripeResponse) {
response.success(stripeResponse);
}, function(error) {
response.error(error);
});
});
function get_stripe_customer (customerId) {
Stripe.initialize(STRIPE_SECRET_KEY);
return Stripe.Customers.retrieve(
customerId, {
success:function(results) {
console.log(results["email"]);
},
error:function(error) {
}
}
);
};
My knowledge is really falling down on the Promise side of things and also the callback (success:, error, request response) etc further reading would be appreciated.
This is now working
Out of interest I did this:
Parse.Cloud.define("update_user", function(request, response) {
var data = request.params["data"]
var customerId = data.object.customer;
get_stripe_customer(customerId, 100).then(function(stripeResponse) {
return set_user_status(username, stripeResponse);
}).then(function(username) {
response.success(username);
}, function(error) {
response.error(error);
});
});
function get_stripe_customer (customerId) {
Stripe.initialize(STRIPE_SECRET_KEY);
return Stripe.Customers.retrieve(
customerId, {
success:function(results) {
// console.log(results["email"]);
},
error:function(error) {
}
}
);
};
function set_user_status(stripeResponse) {
Parse.Cloud.useMasterKey();
var emailquery = new Parse.Query(Parse.User);
emailquery.equalTo("username", stripeResponse['email']); // find all the women
return emailquery.first({
success: function(results) {
alert('running set_user_status success');
var user = results;
user.set("tier", "paid");
user.save();
},
error:function(error) {
console.log('error finding user');
}
});
};
open to improvements...
EDIT - I (#danh) cleaned it up a bit. A few notes:
used promises throughout. much easier to read and handle errors
get_stripe_customer requires only one param (that 100 was my idea to charge $100)
set_user_status appears to need only user email as param, which apparently is in the stripeResponse
set_user_status returns a promise to save the user. that will be fulfilled with the user object, not the username
be sure you're clear on how to identify the user. stripe apparently provides email address, but in your user query (in set_user_status) you compare email to "username". some systems set username == email. make sure yours does or change that query.
Parse.Cloud.define("update_user", function(request, response) {
var data = request.params["data"]
var customerId = data.object.customer;
get_stripe_customer(customerId).then(function(stripeResponse) {
var email = stripeResponse.email;
return set_user_status(email);
}).then(function(user) {
response.success(user);
}, function(error) {
response.error(error);
});
});
function get_stripe_customer(customerId) {
Stripe.initialize(STRIPE_SECRET_KEY);
return Stripe.Customers.retrieve(customerId).then(function(results) {
// console.log(results["email"]);
return results;
});
};
function set_user_status(email) {
Parse.Cloud.useMasterKey();
var emailquery = new Parse.Query(Parse.User);
emailquery.equalTo("username", email); // find all the women
return emailquery.first().then(function(user) {
user.set("tier", "paid");
return user.save();
}, function(error) {
console.log('error finding user ' + error.message);
return error;
});
}
Did a quick skim of the docs pertaining to stripe, and it looks like the steps are: (1) make a stripe REST-api call from your client side to get a token, (2) pass that token to a cloud function, (3) call stripe from the parse cloud to finish paying. I understand that you'd like to include a (4) fourth step wherein the transaction is recorded in the data for the paying user.
From the client (assuming a JS client):
var token = // we've retrieved this from Stripe's REST api
Parse.Cloud.run("pay", { stripeToken: token }).then(function(result) {
// success
}, function(error) {
// error
});
On the server:
Parse.Cloud.define("pay", function(request, response) {
var user = request.user;
var stripeToken = request.params.stripeToken;
payStripeWithToken(stripeToken, 100).then(function(stripeResponse) {
return updateUserWithStripeResult(user, stripeResponse);
}).then(function(user) {
response.success(user);
}, function(error) {
response.error(error);
});
});
Now we need only to build promise-returning functions called payStripeWithToken and updateUserWithStripeResult.
// return a promise to pay stripe per their api
function payStripeWithToken(stripeToken, dollarAmt) {
Stripe.initialize(STRIPE_SECRET_KEY); // didn't see this in the docs, borrowed from your code
return Stripe.Charges.create({
amount: dollarAmt * 10, // expressed in cents
currency: "usd",
card: stripeToken //the token id should be sent from the client
});
// caller does the success/error handling
}
// return a promise to update user with stripeResponse
function updateUserWithStripeResult(user, stripeResponse) {
var transactionId = // dig this out of the stripeResponse if you need it
user.set("paid", true);
user.set("transactionId", transactionId);
return user.save();
}

Categories