How do I embed a Facebook Feed in the new Google Sites (using Apps Script)? - facebook

I've read that you can make a Google Apps Script that shows a Facebook Feed, and then embed this in a Google Site, but I can't find any more information on how to do it and I can't figure it out myself.
When I try to make an Apps Script web app with a Facebook feed I get errors like:
Uncaught DOMException: Failed to set the 'domain' property on 'Document': Assignment is forbidden for sandboxed iframes.
This is from copying the "Facebook Javascript SDK" and "Page Feed" from Facebook Developers into an HTML file and deploying it as a web app. I gather it has something to do with how Apps Script sandboxes your code but I don't know what I have to do here.
For that matter, even if I try to make a simpler Apps Script with some static HTML, when I try to embed it from Drive into the site I get an error "Some of the selected items could not be embedded".

The New Google Sites doesn't support Google Apps Script.
Related question: Google App Scripts For New Google Sites Release

The new Google Sites does now support embedding apps script (make sure to deploy the apps script as a web app, set the right permissions, and use the /exec url and not your /dev one to embed).
I found I couldn't use the facebook SDK for videos because of the sandboxing. I used an iframe solution instead for videos, but maybe you could try something like this for the feed (I'm assuming you've registered your app in fb so you can get generate tokens):
In apps script, create a .gs file and an html file, roughly along the lines below (I haven't actually worked with returning feeds, so check the returned data structure and adjust accordingly)
//**feed.gs**
function doGet(e) {
return HtmlService
.createTemplateFromFile('my-html-file')
.evaluate();
}
function getToken() { //use your fb app info here (and make sure this script is protected / runs as you
var url = 'https://graph.facebook.com'
+ '/oauth/access_token'
+ '?client_id=0000000000000000'
+ '&client_secret=0x0x0x0x0x0x0x0x0x0x0x0x'
+ '&grant_type=client_credentials';
var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
var json = response.getContentText();
var jsondata = JSON.parse(json);
return jsondata.access_token;
}
function getFeed() {
var url = 'https://graph.facebook.com'
+ '/your-page/feed'
+ '?access_token=' + encodeURIComponent(getToken());
var response = UrlFetchApp.fetch(url, {'muteHttpExceptions': true});
var json = response.getContentText();
var jsondata = JSON.parse(json);
//Logger.log(jsondata); //check this and adjust following for loop and html showFeed function accordingly
var posts = {};
for (var i in jsondata) {
posts[i] = {"post":jsondata[i].message};
}
return posts;
}
<!--**my-html-file.html**-->
<!DOCTYPE html>
<html>
<head>
<base target="_top">
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<script>
// The code in this function runs when the page is loaded (asynchronous).
$(function() {
google.script.run
.withSuccessHandler(showFeed)
.withFailureHandler(onFailure)
.getFeed(); //this function is back in .gs file and must return an array or object which gets auto-passed to the showFeed function below
});
function showFeed(posts) { //parameter name must match array or object returned by getFeed in gs file
var html = '';
for (var p in posts) {
html += '<p>' + posts[p].post + '</p>'; //instead of a string, you can build an array for speed
}
$('#feed').empty().append(html); //if you used an array for the html, you'd split it here
}
function onFailure(error) {
$('#feed').empty().append("Unable to retrieve feed: " + error.message); ;
}
</script>
</head>
<body>
<div id="feed">
Loading...
</div>
</body>
</html>

Related

Powershell webinvoke with Google Script webapp

Is there a way to web invoke from PowerShell connection to web app created in google app script ?
When im running the request on normal sites I will receive back information containing Forms[], Images[], InputFields[] etc. However when I'm trying to run the same request on a https://script.google.com/a/macros/ web app all those fields are blank and i can only see a variable called el linking to field called sandboxFrame.
The app is a simple upload site to one of my google folders, everything is working when I'm in browser. I'm trying to automate the process through PowerShell script
HTML file
<!DOCTYPE html>
<html>
<body>
<input name="file" id="files" type="file" multiple>
<input type='button' value='Upload' onclick='getFiles()'>
</body>
<script>
function getFiles() {
const f = document.getElementById('files');
[...f.files].forEach((file, i) => {
const fr = new FileReader();
fr.onload = (e) => {
const data = e.target.result.split(",");
const obj = {fileName: f.files[i].name, mimeType: data[0].match(/:(\w.+);/)[1], data: data[1]};
google.script.run.withSuccessHandler((id) => {
console.log(id);
}).saveFile(obj);
}
fr.readAsDataURL(file);
});
}
</script>
</html>
GS script
function saveFile(obj) {
var folder = DriveApp.getFolderById('1w586veZcOZN_NnB90jaTZ12DF-jP005u');
var blob = Utilities.newBlob(Utilities.base64Decode(obj.data), obj.mimeType, obj.fileName);
return folder.createFile(blob).getId();
}
You would need to take advantage of the doPost function.
I assume you already know about the doGet function, but there is another function that you can use as part of a web app called doPost. This allows you to post data using something like the following from powershell:
Invoke-WebRequest https://script.google.com/a/macros/[SCRIPTID]?[QUERYSTRING] -Method POST
Where the [QUERYSTRING] is something like:
name=bartosz&stack=BartoszWolas&reputation=1000
Then within the doPost on the web app side you would write a function like this:
function doPost(e) {
const name = e.parameter.name; // bartosz
const stackAlias = e.parameter.stack; // BartoszWolas
const reputation = e.parameter.reputation; // 1000
}
Reference
web app

Prevent flutter web cuts off the url path #

My flutter web site is redirected from another site with the format like this:
http://example.com/#id_token=abc
I'd like to read the info in #id_token=abc in initState like this
#override
void initState() {
super.initState();
var url = html.window.location.href;
if (url.contains('id_token=')) {
// read data
}
}
But the flutter site is reloaded & cut off #id_token part automatically (the same for localhost when debugging) before it goes to initState, the new url is
http://example.com/#/
It makes my code can't read the id_token info correctly
It looks weird, how can I prevent this happen?
P/s: it works well with the url paramter format like http://example.com?id_token=abc but I can't control other site to support this format
I can't find any solution on flutter side. So I solve my problem by using a blank page and use javascript to read data from #id_token=abc and then navigates to flutter home page with parameter like this index.html?id_token=abc
Here is the page content:
<body>
<script>
document.addEventListener('DOMContentLoaded', function() {
console.log('document is ready');
var url = window.location.href;
console.log(url);
if(url.indexOf('#id_token=') != -1){
var idToken = url.split('#id_token=')[1];
console.log('idToken ' + idToken);
window.location.replace("index.html?id_token=" + idToken);
}else {
console.log('there is no id token');
}
});
</script>
</body>
<div class="center-screen">Waiting...</div>

Unexpected behavior for Facebook Sharing [duplicate]

This question already has an answer here:
Facebook ignoring OG image on first share
(1 answer)
Closed 6 years ago.
First of all hi and thanks in advance to anyone who can help with this because I've been going crazy over this for weeks now.
So I've got a website which lists gif taken from my mobile application (which are then stored on AWS and my visitors ( I haven't found a use for me to have users) can share these gifs on facebook using the facebook sdk.
The problem appears when I try sharing an image for the first time
This is what the share dialog shows the first time I click on my sharing button:
http://i.stack.imgur.com/lNVNF.png
and then I close and reclick the same button and now it works:
http://i.stack.imgur.com/YsDUm.png
Now I've been trying to find a way to make this work on the first sharing attempt but to no avail.
I am using meteor in combination with biasport:facebook-sdk and Amazon S3 for the hosting of my files.
Edit here is the code used:
FRONT SIDE
HTML
<div class="facebook share">
<img src="/gallery/fb.png">
</div>
Javascript
Template.*templateName*.events({
'click .facebook': function(e){
e.preventDefault();
e.stopPropagation();
// this is in a modal so I store the data I need
// (events have photos which in turn contain a url to the gif
var url = Session.get('event').photos[Session.get("id")].url;
FB.ui({
method: 'share',
href: url
});
}
SERVER SIDE
JAVASCRIPT
if(Meteor.isClient) {
window.fbAsyncInit = function() {
FB.init({
appId : 'APP_ID',
status : true,
xfbml : true,
version : 'v2.5'
});
};
}
Edit: I found a manual solution using exec future and curl
so first I added a call to a meteor method on the share that updates the facebook crawler
JAVASCRIPT
Template.*templateName*.events({
'click .facebook': function(e){
e.preventDefault();
e.stopPropagation();
// this is in a modal so I store the data I need
// (events have photos which in turn contain a url to the gif
var url = Session.get('event').photos[Session.get("id")].url;
Meteor.call('updateCrawler', url, function(){
FB.ui({
method: 'share',
href: url
});
});
}
Then I defined my meteor method as such
JAVASCRIPT
Meteor.methods({
updateCrawler: function(url){
var future = new Future();
cmd = 'curl -X POST -F "id=' + url + '" -F "scrape=true" -F "access_token={my_access_token}" "https://graph.facebook.com"';
exec(cmd, function(error){
if (error){
console.log(error);
}
future.return();
});
future.wait();
}
});
it's ugly but since I'd have to wait for the crawler to update and it works I'll leave this here for future use for someone maybe
Edit2:
I did not use og tags at all since I was simply sharing a url to aws directly and not a url to my website
I worked around this problem by calling the Facebook API direct from the server to make it scrape the og data by requesting info on the page. First time round it doesn't have the image cached but second time it does so this workaround does the initial call before sharing.
Use an access token for your facebook app and call the below in an ajax call and await the response before opening share dialog. Replace Google address with your own uri encoded address https://graph.facebook.com/v2.5/?id=http%3A%2F%2Fwww.google.co.uk&access_token=xxxxx
EDIT:
As per comments, here is my server side method for calling this which I use when posts etc are inserted to make the initial call and prompt a scrape from fb:
var getTheOGInfo = function (link)
{
if (!link || link.slice(0, 4).toLowerCase() != "http"){
throw new Meteor.Error("og-info-bad-url", "Function requires an unencoded fully qualified url");
return false;
}
var url = "https://graph.facebook.com/v2.5/{{{{id}}}}?access_token={{{{token}}}}&fields=og_object{id,description,title,type,updated_time,url,image},id,share";
var token = Meteor.settings.private.fb.token;
if (!token){
throw new Meteor.Error("og-info-no-token", "Function requires a facebook token in Meteor.settings.private.fb.token");
return false;
}
var link_id = encodeURIComponent(link);
url = url.replace('{{{{token}}}}', token).replace('{{{{id}}}}', link_id);
var result = HTTP.get(url, {timeout:1000});
return result;
}
Or for your purposes you may not want anything that might be blocking so you could change the last two lines to be aynchronous:
var result = HTTP.get(url, {timeout:1000});
return result;
//Replace with non blocking
HTTP.get(url, {timeout:1000}, function(err, result){console.log('something asynchronous', err, result);});
return true;

Image request blocking FB.getLoginStatus

Facebook's Javascript SDK has a method called getLoginStatus that stalls (and never fires the callback passed into it) while an image request on the page also stalls (i.e. the browser doesn't receive a 200 or 404 for a very long time.)
If you wait an extremely long time and the browser (?) finally closes out the attempt to fetch the image, the SDK continues on its merry way.
What might be going on, and is there a way to prevent it? It's awfully inconvenient when a user can't sign in or sign up just because of an image request.
Blocking (HTML):
<img src="..." />
Non-Blocking (with CSS):
#someDiv {
background-image: url(...) no-repeat;
width: xxx;
height: xxx;
}
Non-Blocking (with JS):
var img = new Image();
img.onload = function () {
document.getElementById('someDiv').appendChild(img);
};
img.src = "...";
Try with solution number 2 or 3 - there are also many preloader plugins for JavaScripts making it easier for you to load a lot of images asynchronously, for example: http://thinkpixellab.com/pxloader/
Another solution would be to load smaller images first and load the hires ones asynchronously.
When you use the initialization code from the Facebook SDK website, by default it wants to wait for the page to be fully loaded be for running certain events, like the fbAsyncInit function.
I'm not sure of an "officially supported" way to bypass this, but you could load the Javascript source yourself and call the routines outright (i.e. not in the async wrapper).
This is a barebones example that stalled like you mentioned using the Facebook SDK initialization procedure but works fine with this workaround.
<html>
<head>
<title>This is a test</title>
<script src="http://connect.facebook.net/fr_FR/sdk.js"></script>
<script language="javascript">
<!--
var loggedIn = false;
var authenticated = false;
FB.init({
appId : '{your app ID here}',
xfbml : true,
version : 'v2.0'
});
FB.getLoginStatus(function(response) {
if (response.status === 'connected') {
// the user is logged in and has authenticated your
// app, and response.authResponse supplies
// the user's ID, a valid access token, a signed
// request, and the time the access token
// and signed request each expire
var uid = response.authResponse.userID;
var accessToken = response.authResponse.accessToken;
loggedIn = true;
authenticated = true;
} else if (response.status === 'not_authorized') {
// the user is logged in to Facebook,
// but has not authenticated your app
loggedIn = true;
} else {
// the user isn't logged in to Facebook.
}
});
function testLogin()
{
alert("Logged in: " + loggedIn + "\nAuthenticated: " + authenticated);
}
// -->
</script>
</head>
<body>
Testing!
<button onclick="testLogin()">Test login?</button>
<img src="http://deelay.me/5000/ http://example.com/image.gif">
</body>
</html>
I'm not sure how this will affect integration with your site, but I can't imagine it would be a problem. If anything I suppose it's worth a shot!
Do you have any adblockers setup? I had a similar problem with a different API and Adblock Pro was causing some issues.

display my feeds from facebook on my webpage with javascript api?

Im trying to get all the feed from my facebook page whit the javascript api.
Does anybody have a working example?
I have tryed but I cant get it right, I can get photos from albums, but I cant get the feeds and I dont know what Im doing wrong.
Any input really appreciated. Thanks!
I have this code:
Edit
OK, I have the code inside the init code like below and it doesnt work, it is not executing the code and I get no errors:
<script>
window.fbAsyncInit = function() {
FB.init({
appId : '<%=facebookAppId%>', // App ID
channelUrl : 'www.mypage.se/channel.html', // Channel File
status : true, // check login status
cookie : true, // enable cookies to allow the server to access the session
xfbml : true, // parse XFBML
oauth : true
});
// get the wall - feed
var page_id = '<%=facebookPageId%>';
FB.api('/' + page_id, {fields: 'access_token'}, function(resp2) {
if(resp2.access_token) {
alert(resp2.access_token);
FB.api('/page id/feed?access_token='+resp2.access_token, function(response) {
var ul = document.getElementById('feed');
for (var i=0, l=response.data.length; i<l; i++) {
var
feed = response.data[i],
li = document.createElement('li'),
a = document.createElement('a');
a.innerHTML = feed.message;
a.href = feed.link;
li.appendChild(a);
ul.appendChild(li);
}
});
}
});
};//end window.fbAsyncInit
// Load the SDK Asynchronously
(function(d){
var js, id = 'facebook-jssdk', ref = d.getElementsByTagName('script')[0];
if (d.getElementById(id)) {return;}
js = d.createElement('script'); js.id = id; js.async = true;
js.src = "//connect.facebook.net/en_US/all.js";
ref.parentNode.insertBefore(js, ref);
}(document));
</script>
So why can I have for example:
FB.api('/facebook id', function(response) {
alert('Your name is ' + response.name);
});
inside the init code and not the other code?
I would still need some structure help writing the callbacks out on the page so it looks good as it does on facebook.
I like to write out "message, picture, link, name" and maybe something else?
As I test to get the messages in this example and some of the callback is displayed as "undefined" on the page? Does that mean that the message doesnt have a value when I get it?
If so how can I not write out emty values - undefined ones?
Thanks!
UPDATE:
If I use this code then it reads the feed, but only if Im logged in to Facebook?
Im starting to get confused, since I think that the above code should work:
I first ask for the access token in the first call, and when I get the access token, then using it in the second call, what Im I doing wrong?
FB.api('/my userid or pageid/feed?access_token=the acces token that I get from the Graph API Explorer', {limit:5} , function(response){
if (response && response.data && response.data.length){
alert(response.message);
var ul = document.getElementById('feed');
for (var j=0; j<response.data.length; j++){
var feed = response.data[j],
li = document.createElement('li'),
a = document.createElement('a');
a.innerHTML = feed.message;
a.href = feed.link;
li.appendChild(a);
ul.appendChild(li);
}
}
});
I get a couple of undefined responses, how can I not write them out on the page?
How can I get the above code to work even if the user that visit the webpage is not logged in to facebook?
I make other calls that gets the photos of an album with no problem displaying them on the webpage, I dont understand why this is different?
If I want to set this up for a customer(when its finished) what are the steps I need to take? Getting a bit confused... :-)
I would like to get the message, picture, likes etc with the call
and display it like it is on the feed-wall, any suggestions here?
Ok, finally I got it working :-)
I got the right acces token and now I can display the feeds.
I got the right token here:
https://graph.facebook.com/oauth/access_token?client_id=myapp_id&client_secret=myapp_secret&grant_type=client_credentials
And now I can use the below code both for getting user feeds and page feeds, just changing the page_id!
var page_id = '<%=facebookPageId%>';
var pageaccessToken='xxxxxxxxxxxxxxxxxxxxxxxxxx';
FB.api('/' + page_id + '/feed?access_token='+ pageaccessToken, {limit:5} , function(response){
if (response && response.data && response.data.length){
var ul = document.getElementById('pagefeed');
for (var j=0; j<response.data.length; j++){
var feed = response.data[j],
li = document.createElement('li'),
a = document.createElement('a');
a.innerHTML = feed.message;
a.href = feed.link;
li.appendChild(a);
ul.appendChild(li);
}
}
});
Ok, now it works, but I get the undefined in the response?
What is causing this, is it because it is a empty value that I get in the response?
What can I do so it is not displayed on the page?
I don't understand what it is you're trying to do, I have the feeling though that you took the wrong path..
Let's start with the fact that you don't need any special permission or a page access token to query for the page feed, it's public and so all you need (quoted from the docs) is: "any valid access_token or user access_token".
Which means that if a user authorized your application, you then acquired an access token for him and can get any page feed.
For example try the southpark page feed in the Graph API Explorer.
Another issue is that asking the user for the "manage_pages" permission and then asking the graph api for the access token of your own app would not work. When a user grants your app to manage his pages that's exactly what you get, the permissions to his pages, and so this request for example: /southpark?feilds=access_token won't get you the token since you are not the admin of this page (even if you grant the app with the "manage_pages" permission).
Last thing is the use of window.onload, which in your situation just does not address the problem.
You don't want to execute that code when the window is loaded but when the facebook sdk is loaded and intialized. That's why facebook tells you to use the fbAsyncInit event.
The code you had before the window.onload is the correct form, what exactly do you mean when you say "it didn't work"? Did you get any errors? It did not get executed?
Edit
From what I understand you want to display the content of a facebook Page feed in your website.
As I already told you, all you need in order to get the feed of a page is an active access token ("any valid access_token or user access_token").
If you follow the Authentication doc, the App Login section you'll see that you can issue an access token for your facebook app. With that token you can then get the feed of ANY PAGE you want on the server side.