I'm trying to run the following Google Api example:
<:html:>
<:body:>
<:div id='content':>
<:h1:>Events<:/h1:>
<:ul id='events':><:/ul:>
<:/div:>
<:a href='#' id='authorize-button' onclick='handleAuthClick();':>Login<:/a:>
<:script:>
var clientId = redacted;
var apiKey = redacted;
var scopes = 'https://www.googleapis.com/auth/calendar';
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
checkAuth();
}
function checkAuth() {
gapi.auth.authorize({client_id: clientId, scope: scopes, immediate: true},
handleAuthResult);
}
function handleAuthResult(authResult) {
var authorizeButton = document.getElementById('authorize-button');
if (authResult) {
authorizeButton.style.visibility = 'hidden';
makeApiCall();
} else {
authorizeButton.style.visibility = '';
authorizeButton.onclick = handleAuthClick;
}
}
function handleAuthClick(event) {
gapi.auth.authorize(
{client_id: clientId, scope: scopes, immediate: false},
handleAuthResult);
return false;
}
function makeApiCall() {
gapi.client.load('calendar', 'v3', function() {
var request = gapi.client.calendar.events.list({
'calendarId': 'primary'
});
request.execute(function(resp) {
for (var i = 0; i <: resp.items.length; i++) {
var li = document.createElement('li');
li.appendChild(document.createTextNode(resp.items[i].summary));
document.getElementById('events').appendChild(li);
}
});
});
}
<:/script:>
<:script src="https://apis.google.com/js/client.js?onload=handleClientLoad":><:/script:>
<:/body:>
<:/html:>
Whenever I run the file I get two errors:
gapi.client object is null or undefined
window.sessionStorage.length object is null or undefined
For the last error it gives this url as the source:
https://apis.google.com//scs/apps-static//js/k=oz.gapi.nl.4xKjGS6fluU.O/m=client/am=QQ/rt=j/d=1/rs=AItRSTMdnq2AHV2okN-h3tZllkPQibG86w/cb=gapi.loaded_0
I'm running IE8, does anyone have an idea what's wrong?
function handleClientLoad() {
gapi.client.setApiKey(apiKey);
window.setTimeout(checkAuth,1);
checkAuth();
}
You're calling checkAuth() twice. Maybe the setTimeout() is necessary for a valid response?
I have noticed that the same example (like hello world) from official documentation page here
is declaring to use variables:
// The Browser API key obtained from the Google Developers Console.
var developerKey = 'xxxxxxxYYYYYYYY-12345678';
// The Client ID obtained from the Google Developers Console. Replace with your own Client ID.
var clientId = "1234567890-abcdefghijklmnopqrstuvwxyz.apps.googleusercontent.com"
// Scope to use to access user's photos.
var scope = ['https://www.googleapis.com/auth/photos'];
but developerKey variable if browser API key is used returns error that API is inaccessible and when creating server key and using it instead everything works fine.
Related
I'm in the process of writing code that is to look for files stored in box.com under a certain user, grab certain data about those files and put the data in a Google Sheet. I have my script to the point where it authenticates at Box but on the redirect THEcallback function is not found.
What I get as an error:
Script function not found: callback
My redirect URL in the box config is:
https://script.google.com/macros/d/{MY-GOOGLE-APP-ID}/usercallback
Code as follows:
var CLIENT_ID = 'MY-CLIENT-ID';
var CLIENT_SECRET = 'MY-CLIENT-SECRET';
function run() {
console.log('function run()');
var service = getService();
if (service.hasAccess()) {
console.log('service.hasAccess TRUE');
var url = 'https://api.box.com/2.0/folders/0';
var response = UrlFetchApp.fetch(url, {
headers: {
Authorization: 'Bearer ' + service.getAccessToken()
}
});
var result = JSON.parse(response.getContentText());
console.log(JSON.stringify(result, null, 2));
} else {
console.log('service.hasAccess FALSE');
showSidebar();
}
}
/**
* Reset the authorization state, so that it can be re-tested.
*/
function reset() {
var service = getService();
service.reset();
}
/**
* Configures the service.
*/
function getService() {
console.log('function getService()');
return OAuth2.createService('Box')
// Set the endpoint URLs.
.setAuthorizationBaseUrl('https://account.box.com/api/oauth2/authorize')
.setTokenUrl('https://api.box.com/oauth2/token')
// Set the client ID and secret.
.setClientId(CLIENT_ID)
.setClientSecret(CLIENT_SECRET)
// Set the name of the callback function that should be invoked to
// complete the OAuth flow.
.setCallbackFunction('usercallback')
// Set the property store where authorized tokens should be persisted.
.setPropertyStore(PropertiesService.getUserProperties())
// Set additional headers required
.setParam('state', ScriptApp.newStateToken().createToken());
}
/**
* Handles the OAuth callback.
*/
function usercallback(request) {
console.log('function usercallback()');
var service = getService();
var authorized = service.handleCallback(request);
if (authorized) {
console.log('authorized TRUE');
return HtmlService.createHtmlOutput('Success!');
} else {
console.log('authorized FALSE');
return HtmlService.createHtmlOutput('Denied');
}
}
function logRedirectUri() {
var service = getService();
Logger.log(service.getRedirectUri());
}
function showSidebar() {
console.log('function showSidebar()');
var service = getService();
if (!service.hasAccess()) {
console.log('service.hasAccess FALSE');
var authorizationUrl = service.getAuthorizationUrl();
var template = HtmlService.createTemplate(
'Authorize. ' +
'Reopen the sidebar when the authorization is complete.');
template.authorizationUrl = authorizationUrl;
var page = template.evaluate();
SpreadsheetApp.getUi().showSidebar(page);
} else {
console.log('service.hasAccess TRUE');
// ...
}
}
Thanks to this page - https://ctrlq.org/code/20088-box-api-google-script I was able to determine what was ultimately wrong in my script.
When I removed .setParam('state', ScriptApp.newStateToken().createToken());
from function getService() it started working and I was able to pull the data I was expecting.
I'm using the javascript api for Google Auth 2.0 . I'm running into the problem where the users email is not showing up, even though I request with https://www.googleapis.com/auth/userinfo.email .
My code looks like this:
gapi.auth.authorize({
client_id : 'xxxxxxxxxx.apps.googleusercontent.com',
scope : ['https://www.googleapis.com/auth/plus.me', 'https://www.googleapis.com/auth/userinfo.email', 'https://www.googleapis.com/auth/userinfo.profile'],
immediate : false
}, function(result) {
if (result != null) {
gapi.client.load('plus', 'v1', function() {
var request = gapi.client.plus.people.get({
'userId' : 'me'
});
request.execute(function(resp) {
console.log(resp);
});
});
}
});
What am I missing to get the user's email?
While the userinfo.email role gives you access to the information, the plus v1 client doesn't provide it. You will need to make an additional call to a different endpoint to get the info.
You will need the oauth2 v2 endpoint, which you can request with gapi.client.load('oauth2', 'v2', callback). The endpoint itself that you want is gapi.client.oauth2.userinfo.get(). This is untested, but the code might look something like:
gapi.client.load('oath2','v2',function(){
gapi.client.oauth2.userinfo.get().execute(function(resp){
console.log(resp);
});
});
See How can I get the user's email address in google apps? and Why can't I retrieve the users email from Google Plus API after getting permission for some related questions and https://developers.google.com/accounts/docs/OAuth2 for more details from the official doc.
Here's how I did it:
function tryAuth() {
var clientId = CLIENT_ID;
var configString = {
client_id: clientId,
scope: SCOPE,
immediate: 'false'
};
gapi.auth.authorize(configString, handleAuthResult);
}
Where SCOPE = 'https://www.googleapis.com/auth/fusiontables email';
Replace https://www.googleapis.com/auth/fusiontables scope with your scope but keep ' email' .
function handleAuthResult(authResult) {
if (authResult && !authResult.error) {
var access_token = authResult.access_token;
alert('Successfully logged in.' + access_token);
tryGetEmail(access_token);
}
And then
function tryGetEmail(access_token) {
var xmlHttp = new XMLHttpRequest();
xmlHttp.open("GET", 'https://www.googleapis.com/oauth2/v1/userinfo?access_token=' + access_token, false );
xmlHttp.send( null );
if(xmlHttp.status == 200) {
var strJSON = xmlHttp.responseText;
var objJSON = eval("(function(){return " + strJSON + ";})()");
email = objJSON.email;
alert('got email ' + email);
}
}
The userinfo endpoint and oauth2 v2 are being deprecated. The older answers are for the old system. All the details for migration are here:
https://developers.google.com/+/api/auth-migration#email
In short: put 'email' instead of 'h ttps://www.googleapis.com/auth/userinfo.email' for your scope, and the G+ email will be included as the first entry of the 'emails' property in the 'person' object you're fetching. There's also apparently an option described in the link to pull it out of the ID token, referenced in the link above.
Full example
I have problem with my phantom Js code, as you see below, I have code to test my friend web server (make with node Js). Actually, it seem simple and perfectly runs.
var page = require('webpage').create();
var address = "http://localhost:3333";
// Route "console.log()" calls from within the Page context to the
// main Phantom context (i.e. current "this")
page.onConsoleMessage = function(msg) {
console.log("Console.log: ", msg);
};
page.onAlert = function(msg) {
console.log("Alert:", msg);
};
page.open(address, function (s) {
page.evaluate(function () {
function click(el){
var ev = document.createEvent("MouseEvent");
ev.initMouseEvent(
"click",
true /* bubble */,
true /* cancelable */,
window, null,
0, 0, 0, 0, /* coordinates */
false, false, false, false, /* modifier keys */
0 /*left*/, null
);
el.dispatchEvent(ev);
}
document.getElementById('username').value = 'MyName';
document.getElementById('password').value = 'MyWord';
click(document.querySelector('input[type=submit]'));
});
page.onNavigationRequested = function() {
// console.log("Moved", JSON.stringify(arguments))
// to check whether send or not
page.render("printscreen" + ".png");
};
setTimeout(function(){
page.render("nextprintscreen" + ".png");
phantom.exit();
}, 3000);
});
BUT
when I declare
var userName = 'MyName';
var passWord = 'MyWord';
then place it below
var address = "http://localhost:3333";
and exchange
document.getElementById('username').value = 'MyName';
document.getElementById('password').value = 'MyWord';
with
document.getElementById('username').value = userName;
document.getElementById('password').value = passWord;
it return invalid username or password from my friend web server. Can you help me how to figure it out and why it happen. It's my first 'javascript world' code.
I already read this question and another variation then a suggestion
but it's just make me more confuse.
Thanks,
Ahmad
The problem is that page.evaluate() is sandboxed, and so has no access to the variables of your phantom script.
Since PhantomJS 1.6, JSON-serializable arguments can be passed to the page.evaluate().
The arguments and the return value to the evaluate function must be a simple primitive object. However, an object can be serialized via JSON.
You can change your code to this :
page.evaluate(function (login, pwd) {
...
document.getElementById('username').value = login;
document.getElementById('password').value = pwd;
...
}, userName , passWord );
I am writing a Javascript SDK to interact with a web service. I am using jQuery to do my AJAX calls.
When an AJAX call fails, I have registered an event handler for the ajaxError that gets called at the top of my .js file. My problem, and I don't understand why, is that when it gets called I have no way of accessing class member variables for my Akamanda.Client.
I tried adding another method for Akamanda.Client as .prototype.logError, which got called by the jQuery Ajax handler, but even then a test for (this.logging) failed as well.
How can I access class member variables from jQuery callbacks? What am I failing to understand here? Akamanda.Client.logging is undefined from the ajaxError callback.
My code for the SDK:
$(document).ajaxError(function(event, jqxhr, settings, exception) {
// more robust error handling for different conditions
if (Akamanda.Client.logging) {
console.log('FAILED: ' + settings.type + ' ' + settings.url + ' => ' + exception);
}
});
Akamanda.Client = function(options) {
this.URL = options.URL || 'http://m-test.akamanda.com';
this.baseURL = this.URL + '/api/' + Akamanda.API_VERSION;
this.feedsURI = '/websyndication/feed/';
// who is the client? (iphone/android/web)
this.clientName = options.clientName;
// For development: Logging and buildcurl IS ON, for production: OFF
//this.logging = options.logging || true;
this.logging = true;
// called when a user is not authorised (Disabled)
// this.logoutCallback = options.logoutCallback || null;
}
Akamanda.Client.prototype.getFeeds = function(callback){
var feeds = [];
$.getJSON(this.baseURL + this.feedsURI, function(data) {
$.each(data, function(index, feed) {
feeds[index] = {
name: feed.name,
title: feed.title,
link: feed.link
};
})
callback(feeds);
});//.error(function(err) { (disabled at the moment in favour of ajaxError event)
// console.log('Error: ' + err.error);
// });
}
My code for the client (in another JS source file):
var options = { logging: true };
myAPI = new Akamanda.Client(options);
var feeds = [];
var articles = [];
function getFeeds()
{
myAPI.getFeeds(function(AkamandaFeeds) {
feeds = AkamandaFeeds;
showFeeds();
});
}
As far as I can see from the code you posted, you are never instantiating an object of type Akamanda.Client.
var Client = new Akamanda.Client();
or
var Akamanda.Client = {};
Akamanda.Client.logging = ....
JSBin Example: http://jsbin.com/ajidig/1/edit
Ok, here a little example(real code but very simplified):
//we wrap our code in a self invoking function so that we don't pollute the global namespace, see http://stackoverflow.com/questions/6715805/self-invoking-functions-javascript for further details
(function(){
//create your object that holds all your function, that are different ways to do this
var Akamanda = {};
//a private function
function ErrorHandler(clientObj) {
this.clientObj = clientObj;
//do whatever with clientObj
this.log = function(){..}
}
//private constructor for clientobj
function Client(options){
..
}
Akamanda.Client = function(){
var newClient = new Client({..});
//setup
Akamanda.ErrorLogging = new ErrorHandler(newClient);
return newClient;
}
//bind our service to the window object to make it accesible
window.Akamanda = Akamanda;
})()
//client
var myAPI = Akamanda.Client();
Akamanda.ErrorLogging.log();
I hope this basic examples helps. If you need to know more about Javascript Patterns, I can recommend this book http://jsninja.com/ by John Resig, the creator of jQuery.
Depending on what you want to do, there's also a lot of frameworks like http://backbonejs.org/ that help with this kind of stuff.
I'm trying to do a implementation of the google login on our website. I have read the documentation and setup a application on the apis console.
I prefer that the signup dialogue is shown in a popup and after the users logins in and accepts the permissions that I would get an javascript callback. This the api also supports according to the documentation. So I build the below with help of the documentation ;-)
This first part is to load the google client script async and the init the script with the correct clientid and apikey.
$gp = new googlePlus('#Trustpilot.Web.Social.Google.ClientID', '#Trustpilot.Web.Social.Google.ApiKey');
(function () {
var po = document.createElement('script'); po.type = 'text/javascript'; po.async = true;
po.src = 'https://apis.google.com/js/client.js?onload=googlePlusClientLoad';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(po, s);
})();
The next part it the part that uses the google client api. handleClientLoad() is called when the client.js is loaded. The method checks if the use is authenticated. If the user is, the idea is that I want to login the user.
If the user is not already authenticated there will be a button and when clicking handleAuthClick() is called, it basic does the same as handleClientLoad() but there will be an popup where the user most login (with google account) and accept permissions. After login handleAuthResult() is called which logins the user.
function googlePlus(clientId, apiKey) {
this.clientId = clientId;
this.apiKey = apiKey;
this.scopes = 'https://www.googleapis.com/auth/plus.me https://www.googleapis.com/auth/userinfo.email';
/// This method is called when the javascript is loaded async
this.handleClientLoad = function() {
gapi.client.setApiKey(this.apiKey);
window.setTimeout(this.authorize(true), 1);
};
this.handleAuthResult = function (authResult) {
console.log(authResult);
if (authResult && !authResult.error) {
var token = gapi.auth.getToken();
console.log(token);
}
else if (authResult && authResult.error) {
alert(authResult.error);
}
};
this.handleAuthClick = function(event) {
this.authorize(false);
return false;
};
this.makeApiCall = function() {
gapi.client.load('plus', 'v1', function () {
var request = gapi.client.plus.people.get({
'userId': 'me'
});
request.execute(function (resp) {
console.log(resp);
});
});
};
this.authorize = function (immediate) {
gapi.auth.authorize({ client_id: this.clientId, scope: this.scopes, immediate: immediate }, this.handleAuthResult());
//gapi.auth.authorize({ client_id: this.clientId, scope: this.scopes, immediate: immediate }, this.handleAuthResult());
};
}
var googlePlusClientLoad = function() {
$gp.handleClientLoad();
};
So now to the problem:
When handleClientLoad is called the user is never authenticated even
if the user already has autehnticated.
If the user uses handleAuthClick() the popup shows and login, permissions and
callback to handleAuthResult() work. But the parameter authResult is
always nothing (should be something accouring to the documentation).
If I try multiple times without reloading the page I can sometimes
get the makeApiCall() and gapi.auth.getToken() to work and get the information I need.
There are two issues in your code :
The API key is not required, you can remove it. You get the user token through OAuth2 and that is enough.
In authorize(), the handleAuthResult method is not correctly called, remove the parenthesis at the end of the function name. You do not want to execute the function, just pass its reference. Here's what the authorize method must look like :
gapi.auth.authorize({ client_id: this.clientId, scope: this.scopes, immediate: immediate }, this.handleAuthResult);
Note the difference in parenthesis.