Facebook apps in Python and Pylons part 2

This article is a followup to my previous post, Facebook apps in Python and Pylons part 1. I’m going to talk a little more about what is interesting about Facebook apps and how they work in practice. At the end, I provide a little code sample and a convenience decorator to save you some hassle.

Why write a Facebook app?

facebook logo

Even if you are pretty familiar with using Facebook, you would be easily forgiven if you didn’t fully understand what the capabilities of a Facebook application are, and how the flow works. Facebook applications essentially offer you:

  • The ability to put your own content on a user’s profile.
  • The ability to update a user’s news feed.

While there are a bunch more things you can do with your Facebook application – as described on the official “Anatomy of a Facebook application” page on developers.facebook.com, those two things are likely the most interesting to you.

How do I add content to the user’s profile and to their news feed?

This is the next question! Obviously, the basic answer is “by writing a Facebook app, stupid!”. Of course, you’re looking for a little bit more than just that. The first step is for the user to add your application. I’m about to drop a whole load of Facebook API jargon – specialised terms are highlighted in bold – the user can do this by visiting your canvas URL. You generate the canvas page from your callback URL, and include some FBML to give it an add to profile button. Once the person adds your application, Facebook will redirect them to your post add URL. From the post add hook, you can use the Facebook API to call setFBML to add content to their profile page, and publishUserAction to add stuff to their feed.

Its pretty trivial – but there is an additional caveat. Before you can do anything useful in a Facebook app, you must have a valid Facebook session. Basically, you want most of your entry points to only be loaded if a user has a logged in session, and if they don’t, you want them to be redirected to the login page. This ends up being a fair bit of boiler-plate code. I have written this method decorator to normalise the boiler-plate code into a single place, such that your Pylons controller methods will be handed a valid PyFacebook API object (from the PyFacebook library – see part 1). Here is an extremely basic code skeleton for a Facebook app in Pylons using my decocorator and PyFacebook:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
def require_login(f):
    ''' This decorator first checks to see
       if the user is authenticated.
       If not, it redirects them
       in the appropriate fashion to the
       log in page.  If they are authenticated,
       it sets up the PyFacebook Facebook
       object and passes it down to our wrapped method. '''
    def redirect(fb, url):
        if fb.in_canvas:
            log.info("doing fbml redirect 302")
            return '<fb:redirect url="%s" />' %(url, )
        else:
            log.info("sending a 302")
            response.status_int = 302
            response.headers['location'] = url
            return 'Moved temporarily'
    api_key = config['pyfacebook.apikey']
    secret_key = config['pyfacebook.secret']
    appid = config['pyfacebook.appid']
    auth_token = request.params.get('auth_token', None)
    fb = Facebook(api_key, secret_key, app_name='myapp',
             callback_path='/myapp/callback',
             auth_token=auth_token)
    if not fb.check_session(request) or not auth_token:
        log.info("got an unauthenticated session request")
        return lambda a: redirect(fb, fb.get_login_url())
    return lambda a: f(a, fb=fb)
 
class FacebookController(BaseController):
 
    def index(self):
        return 'Hello World'
 
    @require_login
    def post_add(self, fb=None):
        fb.auth.getSession()
        log.info("got a valid session from user %s", fb.uid)
        fb.profile.setFBML('<fb:wide></fb:wide>')
 
    @require_login
    def callback(self, fb=None):
        c.uid = fb.uid
        return render('/canvas.fbml')

Hopefully that is enough to get you started. I’ll be writing more about this subject so stay tuned. If you have any specific questions, feel free to post a comment!

3 comments to Facebook apps in Python and Pylons part 2

  • Buchibabu

    Hi,

    I have used the exact code you have provided above. But i am getting too many redirections always.

    Can you please help me to fix this problem?

    Regards,
    Buchibabu

  • Buchibabu

    Here is the code i used.

    from facebook import Facebook
    log = logging.getLogger(__name__)

    def require_login(f):
    def redirect(fb, url):
    if not fb.check_session(request) and not auth_token:
    log.info(“doing fbml redirect 302″)
    return ” %(url, )
    else:
    log.info(“sending a 302″)
    response.status_int = 302
    response.headers['location'] = url
    return ‘Moved temporarily’
    api_key = ‘7ef4078c35827840efcb74021862d987′
    secret_key = ‘4478c27c72b200639026a01166b3e2c1′
    appid = ‘119751057792′
    auth_token = request.params.get(‘auth_token’, None)

    fb = Facebook(api_key, secret_key, auth_token, app_name=’SamyuthaCalendar’,
    callback_path=’/samyuthacalendar/callback’,)

    if request.method == ‘POST’:
    fb_params = fb.validate_signature(request.POST)
    else:
    fb_params = fb.validate_signature(request.GET)

    if not fb.check_session(request) or not auth_token:
    log.info(“got an unauthenticated session request”)
    return lambda a: redirect(fb, fb.get_login_url())
    return lambda a: f(a, fb=fb)

    class MyCalendarController(BaseController):
    @require_login
    def index(self,fb):
    # Return a rendered template
    m = request.params.get(‘m’)
    y = request.params.get(‘y’)

  • I replaced the “if not fb.check_session(request)…” line with:

    if not fb.check_session(request):
    if not fb.auth_token:

    I don’t know why that works and the other doesn’t – perhaps there’s something lazy going on as it evaluates the ‘or’.

Leave a Reply

 

 

 

You can use these HTML tags

<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong> <pre lang="" line="" escaped="">