This is a detailed example built on Facebook Python SDK example. In this example I'll take it step by step from the very beginning to login, get user data, get friends list, invite friends, and post to wall. So let's start. (also check the Ruby on Rails with Koala example)
- Download "facebook.py" from this link on GitHub.
- Add the downloaded file to your Google App Engine project.
- You can now make you own Facebook application code or re-use the current example (which I choose to do).
- Take these global variables and imports into your application (your GAE python file)
- Add this Model and Base Class that will be used to determine the user ID from cookies
- Now let's create our handler. Note that in case you wan to use your application inside Facebook frame, you will have to handle POST request too.
- Logging In and Inviting Friends
- Now let's create the template for the HTML template. Here is how it goes: If the passed "current_user" parameter is valid, it will show the content of your app and a link to a JQuery function to invite friends using Facebook Javascript SDK initialized at the bottom. Otherwise, it will show a Facebook login button.
- At this point, you should be having a working Python Google App Engine Facebook application. Next I'll go though some basic information that you may need to implement in your service. You may prefer XML, JSON, or a custom format. Anyways, here is the basic example that you may customize as you want and add more handling for special cases.
- User Profile
- Friends List
- Post Text to Wall (Arabic-friendly)
- And off course do not forget to add these handlers to the suitable URLs for your service. (side note: the /?$ sign is useful to allow URL with/out the slash)
- Download "facebook.py" from this link on GitHub.
- Add the downloaded file to your Google App Engine project.
- You can now make you own Facebook application code or re-use the current example (which I choose to do).
- Take these global variables and imports into your application (your GAE python file)
FACEBOOK_APP_ID = "123456789" #your own FB app id here FACEBOOK_APP_SECRET = "756483568435475" #your own FB app secret here INVITATION_TEXT = "I invite you to try my app. It is amazing!" import facebook import os.path import wsgiref.handlers import logging import urllib2 import hashlib from google.appengine.ext import db from google.appengine.ext import webapp from google.appengine.ext.webapp import util from google.appengine.ext.webapp import template from google.appengine.api.urlfetch import fetch import webapp2
- Add this Model and Base Class that will be used to determine the user ID from cookies
class User(db.Model): id = db.StringProperty(required=True) created = db.DateTimeProperty(auto_now_add=True) updated = db.DateTimeProperty(auto_now=True) name = db.StringProperty(required=True) profile_url = db.StringProperty(required=True) access_token = db.StringProperty(required=True) class BaseHandler(webapp.RequestHandler): """Provides access to the active Facebook user in self.current_user The property is lazy-loaded on first access, using the cookie saved by the Facebook JavaScript SDK to determine the user ID of the active user. See http://developers.facebook.com/docs/authentication/ for more information. """ @property def current_user(self): if not hasattr(self, "_current_user"): self._current_user = None cookie = facebook.get_user_from_cookie( self.request.cookies, FACEBOOK_APP_ID, FACEBOOK_APP_SECRET) if cookie: # Store a local instance of the user data so we don't need # a round-trip to Facebook on every request user = User.get_by_key_name(cookie["uid"]) if not user: graph = facebook.GraphAPI(cookie["access_token"]) profile = graph.get_object("me") user = User(key_name=str(profile["id"]), id=str(profile["id"]), name=profile["name"], profile_url=profile["link"], access_token=cookie["access_token"]) user.put() elif user.access_token != cookie["access_token"]: user.access_token = cookie["access_token"] user.put() self._current_user = user return self._current_user
- Now let's create our handler. Note that in case you wan to use your application inside Facebook frame, you will have to handle POST request too.
- Logging In and Inviting Friends
class HomeHandler(BaseHandler): def get(self): self.show_main() def post(self): self.show_main() def show_main(self): path = os.path.join(os.path.dirname(__file__), "templates/main.html") args = dict(current_user=self.current_user, facebook_app_id=FACEBOOK_APP_ID, invitation_text=INVITATION_TEXT) self.response.out.write(template.render(path, args))
- Now let's create the template for the HTML template. Here is how it goes: If the passed "current_user" parameter is valid, it will show the content of your app and a link to a JQuery function to invite friends using Facebook Javascript SDK initialized at the bottom. Otherwise, it will show a Facebook login button.
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title>Application Title</title> <script type="text/javascript" src="/js/jquery-1.8.2.min.js"></script> <script type="text/javascript"> $('#sendRequest').click(function() { FB.ui( { method : 'apprequests', message : $(this).attr('data-message') }, function (response) { // If response is null the user canceled the dialog if (response != null) { //logResponse(response); } } ); }); }); </script> </head> <body> {% if not current_user %} <div style="margin:0 auto; text-align:center;"> <fb:login-button autologoutlink="false" scope="publish_stream"></fb:login-button> </div> {% else %} <br> Welcome! Here is my application. <br> <a href="#" id="sendRequest" data-message="{{invitation_text}}"> Send Requests </a> {% endif %} <div id="fb-root"></div> <script> window.fbAsyncInit = function() { FB.init({appId: '{{ facebook_app_id }}', status: true, cookie: true, xfbml: true}); FB.Event.subscribe('{% if current_user %}auth.logout{% else %}auth.login{% endif %}', function(response) { window.location.reload(); }); }; (function() { var e = document.createElement('script'); e.type = 'text/javascript'; e.src = document.location.protocol + '//connect.facebook.net/en_US/all.js'; e.async = true; document.getElementById('fb-root').appendChild(e); }()); </script> </body> </html>
- At this point, you should be having a working Python Google App Engine Facebook application. Next I'll go though some basic information that you may need to implement in your service. You may prefer XML, JSON, or a custom format. Anyways, here is the basic example that you may customize as you want and add more handling for special cases.
- User Profile
class ProfileHandler(BaseHandler): def get(self): self.show_profile() def post(self): self.show_profile() def show_profile(self): profile = '' current_user = self.current_user if current_user: graph = facebook.GraphAPI(current_user.access_token) profile = profile = graph.get_object("me") path = os.path.join(os.path.dirname(__file__), "templates/profile.html") args = dict(current_user=current_user, facebook_app_id=FACEBOOK_APP_ID, profile=profile) self.response.out.write(template.render(path, args))
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title></title> </head> <body> {% if current_user %} {% if profile %} {{profile}} {% endif %} {% endif %} </body> </html>
- Friends List
class FriendsHandler(BaseHandler): def get(self): self.show_friends() def post(self): self.show_friends() def show_friends(self): friends_list = [] current_user = self.current_user if current_user: graph = facebook.GraphAPI(current_user.access_token) friends_list = graph.get_connections("me", "friends")['data'] path = os.path.join(os.path.dirname(__file__), "templates/friends.html") args = dict(current_user=current_user, facebook_app_id=FACEBOOK_APP_ID, friends_list=friends_list) self.response.out.write(template.render(path, args))
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> <title></title> </head> <body> {% if current_user %} {% if friends_list %} {{friends_list}} {% else %} {% endif %} {% else %} {% endif %} </body> </html>
- Post Text to Wall (Arabic-friendly)
class PostTextHandler(BaseHandler): def post(self): text = self.request.get('text') if text: text = text.encode('utf-8') # for non-english text current_user = self.current_user if current_user: graph = facebook.GraphAPI(current_user.access_token) graph.put_object("me", "feed", message=text) self.response.out.write('yes') # just a feedback reponse else: self.response.out.write('no') # just a feedback reponse else: self.response.out.write('no') # just a feedback reponse
- And off course do not forget to add these handlers to the suitable URLs for your service. (side note: the /?$ sign is useful to allow URL with/out the slash)
app = webapp2.WSGIApplication([ ('/', HomeHandler), ('/profile/?$', ProfileHandler), ('/friends/?$', FriendsHandler), ('/posttext/?$', PostTextHandler)])
great tutorial thank a lot !
ReplyDeletebut when i've already login the Facebook icon still shown.
ReplyDeletePlease note that I pass a "current_user" variable to the html template. Then in the template I use:
Delete{% if not current_user %}
{% endif %}
So I'f I'm logged in, there will be a valid "current_user: variable, so the condition will be false and the button should not appear. Please make sure your variable is valid.
Or you may make a different template or different condition as another solution.
how to access email of user,It shows null when i run this code for email.
ReplyDeleteThanks! This helped a lot. I had only one problem when adding the #rsendRequest jQuery click function. It had to come at the end of the HTML and could not be part of the head.
ReplyDelete