What's the "right" way to add Google Web Auth to Svelte/Sapper? - google-authentication

Giving Svelte/Sapper a look and am curious what the right way to add something like Google Sign-In for Websites to my app.
I have everything working from the example code they give you from the site above, but I've done it by adding the onsuccess "onSignIn" function to the template.html file which doesn't seem like the right way to do this.
Inside src/routes/template.html
<script src="https://apis.google.com/js/platform.js" async defer></script>
<script>
function onSignIn(googleUser) {
var profile = googleUser.getBasicProfile();
console.log("ID: " + profile.getId());
}
</script>
Inside src/components/Nav.svelte
<div class="g-signin2" data-onsuccess="onSignIn" data-theme="dark"></div>
The code above works fine because onSignIn has access to window, but it seems like I should be able to add this to the Nav component where the button itself lives. Is there a preferred way to handle something like this?

If anyone is looking for something similar, I found this git repo that I was able to get started and modify to suit my needs github.com/beyonk-adventures/svelte-social-auth.

Related

hello.js not in AngularJS web app not working on iPhones and Blackberry Z10s

I have a login system that works for most people (on Chrome, Android devices, IE8, Firefox, etc), but it seems not to work for people with Z10s or iPhone 5s. I don't have access to these devices so it's difficult to test, so I wanted to ask whether I was setting up everything properly.
It's an AngularJS app, using hello.js for OAuth, and bootstrap-social and font-awesome for the sign in buttons.
To insert hello into Angular, in app.js I include:
var app = angular
.module('myapp', [
'ui.bootstrap',
'ui.router',
'hello',
])
...
.run([..., 'hello', ..., function(..., hello, ...) {
...
hello.init(...);
...
}]);
...
var helloApp = angular.module('hello', []);
helloApp.factory('hello', function() {
return window.hello; // Assumes hello has been loaded
});
Then, in my loginCtrl, I inject it with
angular.module('myapp').controller('loginCtrl', [..., 'hello', ...,
function(..., hello, $location, ...) {
...
$scope.doLogin = function(network) {
console.log('Calling hello ' + network);
hello.login(network);
};
...
}]);
And in my view, I have
<button id="facebookLogin" class="btn btn-social btn-facebook" ng-click="doLogin('facebook')">
<span class="fa fa-facebook pull-left"></span> <span>Sign in with Facebook</span>
</button>
<button id="googleLogin" class="btn btn-social btn-google-plus" ng-click="doLogin('google')">
<span class="fa fa-google-plus pull-left"></span> <span>Sign in with Google</span>
</button>
Yesterday I was using onclick="hello.login('facebook')", and I suspected that was breaking on certain devices because I shouldn't be using onclick and hello wasn't in scope, so that's why I changed it to ngClick and calling a function in scope. The specific effect of onclick on the users who had errors was to redirect the user to the default/catch-all route without accessing the server at all (I listen for hello events and call the server, so this suggests it wasn't calling hello at all.)
But still, I ask the people who are having issues to re-try (after refreshing obviously), and now they say the button simply does nothing.
Other buttons on the site work. In fact, to get to this page, they use a <button> that uses ui-router to get to this page.
I'm going to continue to search, but I just wanted to ask if I seemed to be hooking hello.js into AngularJS properly, and not making any other beginner mistakes.
I believe the problem is that iPhones and Z10s were blocking hello.js's popup OAuth authentication, but I couldn't just switch it to use page.
When I tried, Facebook returns me to my redirect_url with the fragment
#access_token=....&expires_in=4264&state={%22client_id%22%3A%22164986300332415%22%2C%22network%22%3A%22facebook%22%2C%22display%22%3A%22page%22%2C%22callback%22%3A%22_hellojs_3ojn1yy8%22%2C%22state%22%3A%22%22%2C%22oauth_proxy%22%3A%22https%3A%2F%2Fauth-server.herokuapp.com%2Fproxy%22%2C%22scope%22%3A%22basic%22%2C%22oauth%22%3A{%22version%22%3A2%2C%22auth%22%3A%22https%3A%2F%2Fwww.facebook.com%2Fdialog%2Foauth%2F%22}}
it's ugly, but the point is it starts with a hash tag. So, while hello.js can normally read this, it couldn't in this case because Angular would mangle the address immediately. I'm not sure if this is because I specify to use hash-bangs instead of hash's, but it was.
And I couldn't send this to a PHP script or anything because the fragment after the hashtag would never make it to the PHP script.
So, my solution was to point the redirect_url at an independent page that has hello.js on it, but no Angular. It saves stuff to window.sessionStorage and redirects the user back to the login page, where hello.js passes the user through.
I'm not very confident in this ugly approach yet, so I put a browser sniffer to only do it for iPhones (and use popup for everyone else), I may remove this check in the future (because it's sketchy)
#matt it uses localstorage, not sessionstorage.
Use popup for all, and define a redirect_uri page with just hello.js In it. I dont know why you might think thats sounds wrong. All the demos do it this way. It also gives you a chance to display a nifty loading screen.
Sorry about the ugly fragment. It communcates a lot of state parameters which is used for the oauth proxy... most endpoints like facebook dont need it, so I might refactor that to make it a little less daunting.

Universal Analytics clientID

Recently we upgraded to universal analytics which appears to all be working. I have been trying to capture the clientID to a js variable via the following code:
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', 'UA-REMOVED', 'xxxx.xxx');
ga('require', 'linkid', 'linkid.js');
ga('send', 'pageview');
ga(function(tracker) {
var clientId = tracker.get('clientId');
});
</script>
To prove the variable clientID is being captured I try and write it to the page using the following code:
<script>
document.write(clientId);
</script>
Which writes nothing to the page.
I have browsed this site and others but can not figure what i am missing. I feel like i'm overlooking something blindingly obvious. Any help much appreciated.
Ultimately i will be writing the variable to a form field to process offline steps occuring in a 3rd party system.
In your code, the variable clientId is declared inside a function. Hence, 'clientId' does not have a global scope. Its value is not accessible outside of the function. Need to assign the value from tracker.get('clientId') to a global variable if you need to use it later. See http://learn.jquery.com/javascript-101/scope/
Calling the following does work on my page:
ga(function(tracker) { alert(tracker.get('clientId'));})
I am doing exactly the same thing as you but instead of writing it to a page, I am alerting it. Maybe document.write is not working for you as expected?
If the code you posted is same as the one you are using, The reason it is not working is because document.write runs before the callback is called. remember that everything that you pass into ga() is asynchronous.

Fetch and display Google Doc body within html page

Is it possible to retrieve the content of a Google Doc and display it within a div in an html page? If so, what's the right way to implement the "MAGIC" in the stripped-down example below?
<html>
<head>
</head>
<body>
<div>
<MAGIC>
Script or link that retrieves and displays the body of a Google Doc.
</MAGIC>
</div>
</body>
</html>
In the above, you can assume
The html is served by Google Drive Hosting.
The reference to the Google Doc is static.
There is no need to edit the Doc from within the public html page (i.e it's read-only in that context).
I've read through the Apps Script documentation and it looks as though something might be possible with some combination of Document Service and Content Service. For instance, Document Service has getBody() and copy() methods, but it's not clear whether the objects returned by these calls can be rendered WYSIWYG as html for insertion into an html container.
Background: I'm trying to implement a safe easy-to-use CMS for a small nonprofit. I've prototyped a website framework that's hosted
on Google Drive. So far it looks promising, but changes require being able to edit the html. We have a number of people who can create content in a word-processor-like environment but only couple including myself
who can cope with HTML/CSS/JQuery/AppsScript.
If I could concentrate on the overall framework and let the others update the content for
events, etc., that would be a huge win. Basically, I'd be very happy if they were able to edit the Google Doc and then manually reload the web page to see the result.
I realize there are many approaches for CMS, but for now, I'm interested in exploring a pure Google Docs/Google Drive solution.
I've settled on publishing the content docs and including the iframe embed code supplied by Google to implement the "MAGIC" from my original question, e.g
<iframe class="cmsframe" src="https://docs.google.com/document/d/1rhkuAB3IIu5Hq0tEtA4E_Qy_-sJMMnb33WBMlAEqlJU/pub?embedded=true"></iframe>
The class tag is added manually so I can control the iframe size with CSS.
You can get the raw html content of a google doc with a call to the drive API using urlFetch, here is how it works
var id = 'Doc-Very-Long-ID-Here';
var url = 'https://docs.google.com/feeds/';
var doc = UrlFetchApp.fetch(url+'download/documents/Export?exportFormat=html&format=html&id='+id,
googleOAuth_('docs',url)).getContentText();
// the variable doc is the HTML content that you can use
function googleOAuth_(name,scope) {
var oAuthConfig = UrlFetchApp.addOAuthService(name);
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:name, oAuthUseToken:"always"};
}
There is also a library by Romain Vialard available here it is called DocsListExtended and provides a whole bunch of nice extensions.
EDIT : Following your EDIT:
You can't use it just like that, to render an HTML content in a webapp use html service, example below with your complete code and working example:
function doGet() {
var id = '1el3DpTp1sukDjzlKXh8plf0Zj-qm0drI7KbytroVrNU';
var url = 'https://docs.google.com/feeds/';
var doc = UrlFetchApp.fetch(url+'download/documents/Export?exportFormat=html&format=html&id='+id, googleOAuth_('docs',url)).getContentText();
return HtmlService.createHtmlOutput(doc);
}
// the variable doc is the HTML content that you can use
function googleOAuth_(name,scope) {
var oAuthConfig = UrlFetchApp.addOAuthService(name);
oAuthConfig.setRequestTokenUrl("https://www.google.com/accounts/OAuthGetRequestToken?scope="+scope);
oAuthConfig.setAuthorizationUrl("https://www.google.com/accounts/OAuthAuthorizeToken");
oAuthConfig.setAccessTokenUrl("https://www.google.com/accounts/OAuthGetAccessToken");
oAuthConfig.setConsumerKey('anonymous');
oAuthConfig.setConsumerSecret('anonymous');
return {oAuthServiceName:name, oAuthUseToken:"always"};
}

Google Search autocomplete API?

Does Google provide API access to autocomplete for search like on the actual site? I have not been able to find anything.
I would like to use Google's autocomplete logic for web search on my own site which relies on Google's search API.
The new url is:
http://suggestqueries.google.com/complete/search?client=firefox&q=YOURQUERY
the client part is required; I did't test other clients.
[EDIT]
If you want the callback use this:
http://suggestqueries.google.com/complete/search?client=chrome&q=YOURQUERY&callback=callback
As #Quandary found out; the callback does not work with client "firefox".
[EDIT2]
As indicated by # user2067021 this api will stop working as of 10-08-2015: Update on the Autocomplete API
First, go to google, click Settings (bottom right corner), change Search Settings to "never show instant results. That way, you'll get regular autocomplete instead of a full page of instant results.
After your settings are saved, go back to the Google main home page. Open your browser's developer tools and go to the Network tab. If you're in Firefox, you might have to reload the page.
Type a letter in the search box. A new line should appear in the Network window you just opened. That line is showing where the autocomplete data came from. Copy that url. It should look something like this:
https://www.google.com/complete/search?client=hp&hl=en&sugexp=msedr&gs_rn=62&gs_ri=hp&cp=1&gs_id=9c&q=a&xhr=t&callback=hello
You'll notice your search term right after the part that says q=.
Add &callback=myAmazingFunction to the end of the url. You may replace myAmazingFunction with whatever you want to name your function that will handle the data.
Here's an example of the code required to show the autocomplete data for the search term "a".
<div id="output"></div>
<script>
/* this function shows the raw data */
function myAmazingFunction(data){
document.getElementById('output').innerHTML = data;
}
</script>
<script src="https://www.google.com/complete/search?client=hp&hl=en&sugexp=msedr&gs_rn=62&gs_ri=hp&cp=1&gs_id=9c&q=a&xhr=t&callback=hello&callback=myAmazingFunction"></script>
Now that you know how to get the data, the next step is to automatically change that last script (the one with the autocomplete url). The basic procedure is: each time the user types something in the search box (onkeyup) replace the search term (q=whatever) in the url, and then append to the body a script with that url. Remove the previous script so that the body doesn't get cluttered.
For more info, see http://simplestepscode.com/autocomplete-data-tutorial/
Most of the above mentioned methods works for me, specifically the following serves my purpose.
http://suggestqueries.google.com/complete/search?client=firefox&q=YOURQUERY
Being a newbie in web programming, I'm not much aware of the "Callback" functionality and the format of the file returned by query. I'm little aware of AJAX and JSON.
Could someone provide more details about the format of file returned by the query.
Thanks.
Hi I don't know if this answer is relevant for you anymore or not but google returns JSON data through following get request (although this isn't an official API but many toolbars are using this API so there's no reason why google might discontinue it):
http://google.com/complete/search?q=<Your keywords here>&hl=en
You should use AutocompleteService and pass that text box value into the service.getPlacePredictions function. It send the data in callback function.
let service = new google.maps.places.AutocompleteService();
let displaySuggestions = function(predictions, status) {
}
service.getPlacePredictions({
input: value
}, displaySuggestions);
Base: https://developers.google.com/maps/documentation/javascript/reference/places-autocomplete-service#AutocompleteService.getPlacePredictions
example: https://dzone.com/articles/implement-and-optimize-autocomplete-with-google-pl
I'm using (( Edrra.com )) API that have google search and suggestions that works with both GET & POST:
Google suggestions:
https://edrra.com/v1/api.php?c=google&f=suggest&k=YOUR_API_KEY&v=YOUR_SEARCH
Google search:
https://edrra.com/v1/api.php?c=google&f=search&k=YOUR_API_KEY&v=YOUR_SEARCH
and more...
What are you trying to use an auto-complete for? More information would help narrow it down.
As far as I know, google does not provide one, but they do exist like jQuery UI's auto-complete.
EDIT:
If you are using their custom search API view here for autocomplete.

sfEasyGMapPlugin won't show the Google Map

I've just started to use the sfEasyGMapPlugin, in my Symfony website. So I've followed the samples and created a basic map, to check if it works.
In the action :
$this->gMap = new GMap();
$this->gMap->setCenter(50.637551,3.062725);
And in the template :
<?php use_helper('Javascript','GMap') ?>
<?php include_map($gMap,array('width'=>'700px','height'=>'400px')); ?>
<!-- Javascript included at the bottom of the page -->
<?php include_map_javascript($gMap); ?>
I've signed up some api keys for my domains like http://localhost or http://127.0.0.1 and defined them in my app.yml.
Now, when I go to the page, the canvas shows up with it's control buttons, but the map do not shows up (there is only a grey background).
There is no error, everything seems to be configured fine. I can center the map on a point, like in the action above, but it do nothing.
I've tried to use the html code given by Google with my api keys and it works fine. So I really don't understand.
Am I doing it wrong ?
Regards,
Timothée Martin.
I got my answer...
You must define the center AND the zoom level with :
$this->gMap->setCenter(latitude, longitude);
$this->gMap->setZoom(level);
After that, the map shows up normally.
Hope it helps...