<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Chicken Scratches &#187; facebook</title>
	<atom:link href="http://www.chickenwingsw.com/scratches/category/facebook/feed" rel="self" type="application/rss+xml" />
	<link>http://www.chickenwingsw.com</link>
	<description>Developing ideas on developing.</description>
	<lastBuildDate>Thu, 01 Apr 2010 17:24:59 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Making a Facebook app (with Django) &#8211; part 3: Python &amp; FBML</title>
		<link>http://www.chickenwingsw.com/scratches/python/django-facebook-3</link>
		<comments>http://www.chickenwingsw.com/scratches/python/django-facebook-3#comments</comments>
		<pubDate>Mon, 29 Sep 2008 21:17:57 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/?p=61</guid>
		<description><![CDATA[   
      Welcome to the third part in my series of posts about creating a
      Facebook application. I am using Django as my web development
      framework, and this post will focus on some of the backend
   [...]]]></description>
			<content:encoded><![CDATA[   <p>
      Welcome to the third part in my series of posts about creating a
      Facebook application. I am using Django as my web development
      framework, and this post will focus on some of the backend
      techniques I have worked out to make this work easier. This is
      not a tutorial, but a set of tools that I have developed. This
      is a long post, with a lot of source code; I hope you find at
      least some of it useful.
    </p>
    <p>
      Keep in mind as you read this that the Facebook platform is
      still very new, and likely to change. In fact, if you're a FB
      user, you are probably aware they recently completed a major
      transition to a new profile design. This included many changes
      behind the scenes for developers, some of which are still
      playing out. I recommend keeping up with
      the <a href="http://forum.developers.facebook.com/">Facebook
      Platform Developer Forum</a> and
      the <a href="http://developers.facebook.com/news.php?tab=blog">Facebook
      Developer Blog</a>.
    </p>
    <p>
      Also, I will assume you have already read
      the <a href="http://wiki.developers.facebook.com/index.php/API">API
      Documentation</a> and the documentation
      for <a href="http://wiki.developers.facebook.com/index.php/Python">PyFacebook</a>,
      and that you know how to create a web app
      using <a href="http://www.djangoproject.com">Django</a>. If not,
      you will want to start there.
    </p>
<span id="more-61"></span>
    <p>
      PyFacebook is very useful and includes some documentation on
      getting up and running with Django. You do still need an
      understanding of how Django works and how URLs are mapped.
    </p>
    <h4>
      My goal
    </h4>
    <p>
      My goal with these code snippets and techniques is to make
      developing a Facebook app as close as possible to developing a
      regular web app. The application I am using to develop and test
      these features is <a href="http://limericks.four32one.com">The
      Limerick Book</a>. Compare that page
      to <a href="http://apps.facebook.com/limericks">The Limerick
      Book Facebook App</a>. In fact, they are the same application,
      sharing the same code. I also have developed
      a <a href="http://apps.facebook.com/playscopa">multiplayer card
      game</a> based on the traditional Italian
      game <a href="http://apps.facebook.com/playscopa">Scopa</a>. This
      is a Facebook-only application, but I wanted to be able to test
      it outside of Facebook.
    </p>
    <p>
      Ideally, we would be able to write code and templates that can
      work equally well both inside Facebook and outside.  This is
      important even if you want users to only see your application
      within Facebook, because it makes testing infinitely easier. You
      want to be able to test on your local machine before publishing
      content, and you want to be able to test things out free from
      the limitations and frequent bugginess of the Facebook platform.
    </p>
    <h4>
      First steps
    </h4>
    <p>
      Here are some simple helper functions to make life as a Facebook
      Python developer easier.
    </p>
    <p>
      I am making a conscious decision here not to package all these
      helper functions into a downloadable library. My point here
      to <i>explain</i> code, rather than just hand it out. Many of
      these things are specific to my needs, and may not fit exactly
      what you want, so some tweaking may be required. I have most of
      these functions in a file called <i>fbUtil.py</i> that I import
      from most of my Django view code (except for the template tags,
      which need to be in a specific place, per Django). Feel free to
      do the same, or to copy and paste the code for your own use, but
      I recommend reading through the code, as your needs may not be
      the same as mine.
    <p>
      <b>inFb</b> is a simple function that takes a Request object and
      returns a boolean telling whether the request is taking place
      within the context of a Facebook canvas page.
    </p>
    <pre>
<span class="keyword">def</span> <span class="function-name">inFb</span>(request):
    <span class="keyword">return</span> (request.facebook <span class="keyword">and</span>
            (request.facebook.check_session(request) <span class="keyword">or</span>
             request.facebook.in_canvas))
</pre>
    <p>
      Once we have this, we can create some more useful functions.
    </p>
    <pre class="codeSnippet">
facebookUrl = settings.FACEBOOK_URL
<span class="keyword">def</span> <span class="function-name">fbReverse</span>(view, args=<span class="py-pseudo-keyword">None</span>, kwargs=<span class="py-pseudo-keyword">None</span>):
    '''<span class="string">
    Much like django.core.urlresolvers.reverse, except works
    in Facebook. Returns an absolute URL to a Facebook canvas
    page.
    </span>'''
    ret = reverse(view, args=args, kwargs=kwargs)
    <span class="keyword">return</span> facebookUrl + ret[1:] <span class="comment"># Remove leading slash
</span>
<span class="keyword">def</span> <span class="function-name">makeReverse</span>(request, view, args = <span class="py-pseudo-keyword">None</span>):
    '''<span class="string">
    Returns the URL of a the specified view, either in or out of Facebook.
    </span>'''
    <span class="keyword">if</span> inFb(request):
        <span class="keyword">return</span> fbReverse(view, args)
    <span class="keyword">return</span> reverse(view, args=args)

<span class="keyword">def</span> <span class="function-name">makeRedirect</span>(request, view, args = <span class="py-pseudo-keyword">None</span>, extra = ''):
    '''<span class="string">
    Returns a Response object for a HTTP redirect, either in or out of
    Facebook.
    </span>'''
    <span class="keyword">if</span> inFb(request):
        <span class="keyword">return</span> request.facebook.redirect(fbReverse(view, args) + extra)
    <span class="keyword">return</span> HttpResponseRedirect(reverse(view, args=args) + extra)
</pre>
    <p>
      These are designed to simplify URL calculations. See the
      comments in the code for explanations of what they do.
    </p>
    <pre class="codeSnippet">
<span class="keyword">def</span> <span class="function-name">makeResponse</span>(request, template, context, common=<span class="py-pseudo-keyword">False</span>):
    context['<span class="string">pageName</span>'] = template
    <span class="keyword">if</span> (<span class="keyword">not</span> common) <span class="keyword">and</span> inFb(request):
        tmpl = '<span class="string">fb/%s.fbml</span>' % template
    <span class="keyword">else:</span>
        tmpl = template + '<span class="string">.tmpl</span>'
    <span class="keyword">return</span> render_to_response(tmpl,
                              context,
                              context_instance=RequestContext(request))
</pre>      
    <p>
      This one is a little different, and may need updating depending
      on how your code is organized. I keep my templates in the
      directory 'mySite/myApp/templates' and give them names like
      'myTemplate.tmpl'. I put my Facebook-specific templates in the
      subdirectory called 'fb' and give them names like
      'myTemplate.fbml'. This function allows me to create two
      templates for a view: one for inside Facebook and one for
      outside. The function will detect which one to use and render it
      into a Response object. <b>request</b> is the Request object
      that is passed to the view function. <b>template</b> is a string
      holding the base-name of the template file, for example
      'myTemplate'. <b>context</b> is a dictionary with the template
      context variables. And if <b>common</b> is <b>True</b>, the
      function will use the main non-Facebook version of the template
      no matter what (because ideally we would be able to share even
      these as much as possible).
    </p>
    <p>
      One extra little bit that the function does is add an extra
      template variable called <b>pageName</b> with the base-name of
      the template. I find this useful for code re-use within
      templates, though it's not actually a Facebook-related feature.
    </p>
    <h4>
      Authentication
    </h4>
    <p>
      The next thing I wanted to do was to tie in Facebook's user
      information with Django's authentication mechanism. Depending on
      your application, you may or may not want to do this. If you
      want to remember information about user-contributed content, it
      is useful. The way I did it was to create a <i>UserProfile</i>
      model, tied in to the User model by a ForeignKey one-to-one
      relationship, and with a <b>facebookId</b> field (among other,
      app-specific fields). Then I created a Django authentication
      backend to allow authenticating by facebook ID. Here is my code
      for the authentication back end. If a user does not exist with
      the given facebook ID, a new one is created. (That, of course,
      may not be what you want, so you may have to modify that code.)
    </p>
    <p>
      This code assumes that Python's logging facilities have been set
      up, for error reporting.
    </p>
    <pre class="codeSnippet">
<span class="keyword">class</span> <span class="type">FacebookBackend</span>:
    '''<span class="string">
    Authenticate against Facebook.
    </span>'''

    <span class="keyword">def</span> <span class="function-name">authenticate</span>(<span class="py-pseudo-keyword">self</span>, facebookId=<span class="py-pseudo-keyword">None</span>):
        <span class="keyword">if</span> <span class="keyword">not</span> facebookId: <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>
        <span class="keyword">try:</span>
            profile = UserProfile.objects.get(facebookId=facebookId)
            UpdateFbUserDetails(profile.user, facebookId)
            <span class="keyword">return</span> profile.user
        <span class="keyword">except</span> UserProfile.DoesNotExist:
            <span class="comment"># No user. Create one.
</span>            <span class="keyword">pass</span>
        username = '<span class="string">fb_%s</span>' % facebookId
        <span class="keyword">try:</span>
            user = User.objects.get(username=username)
            <span class="comment"># This shouldn't really happen. Log an error.
</span>            logging.error('<span class="string">Strange: user %s already exists.</span>' % username)
        <span class="keyword">except</span> User.DoesNotExist:
            user = User.objects.create_user('<span class="string">fb_%s</span>' % facebookId, '')
        <span class="keyword">if</span> <span class="keyword">not</span> UpdateFbUserDetails(user, facebookId):
            <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>
        user.save()
        profile, created = UserProfile.objects.get_or_create(user=user)
        profile.facebookId = facebookId
        profile.save()
        <span class="keyword">return</span> user

    <span class="keyword">def</span> <span class="function-name">get_user</span>(<span class="py-pseudo-keyword">self</span>, user_id):
        <span class="keyword">try:</span>
            <span class="keyword">return</span> User.objects.get(pk=user_id)
        <span class="keyword">except</span> User.DoesNotExist:
            <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>

<span class="keyword">def</span> <span class="function-name">UpdateFbUserDetails</span>(user, fbId):
    """
<span class="string">    Fill in a user's first and last name, from Facebook.
    "</span>""
    <span class="keyword">if</span> (<span class="keyword">not</span> user.first_name) <span class="keyword">or</span> (<span class="keyword">not</span> user.last_name) :
        <span class="keyword">try:</span>
            fb = get_facebook_client()
            userDetails = fb.users.getInfo(fbId, ['<span class="string">last_name</span>', '<span class="string">first_name</span>'])
            user.first_name = userDetails[0]['<span class="string">first_name</span>'][:30]
            user.last_name = userDetails[0]['<span class="string">last_name</span>'][:30]
            user.save()
            <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
        <span class="keyword">except</span> Exception, ex:
            logging.error('<span class="string">Error updating user: %s</span>' % ex)
            <span class="keyword">return</span> <span class="py-pseudo-keyword">False</span>
    <span class="keyword">return</span> <span class="py-pseudo-keyword">True</span>
</pre>
    <p>
      Now here is a function decorator you can use on your view
      functions. It will perform Facebook authentication if
      possible. It can also be used to require a login - either via
      Facebook or through a login page. With a parameter
      of <b>True</b>, it is equivalent to Django's
      built-in <b>login_required</b> decorator or to
      PyFacebook's <b>facebook.require_login</b> decorator, depending
      on whether the view is accessed inside or outside of Facebook.
    </p>
    <pre class="codeSnippet">
<span class="keyword">def</span> <span class="function-name">facebookView</span>(requireLogin=<span class="py-pseudo-keyword">False</span>):
    <span class="keyword">def</span> <span class="function-name">decorator</span>(func):
        <span class="keyword">def</span> <span class="function-name">wrapper</span>(request, *listArgs, **kwArgs):
            facebookLogin(request)
            fb = request.facebook
            <span class="keyword">if</span> requireLogin <span class="keyword">and</span> (<span class="keyword">not</span> request.user.is_authenticated()):
                <span class="keyword">if</span> inFb(request):
                    <span class="keyword">return</span> fb.redirect(fb.get_login_url(next=request.path))
                <span class="keyword">else:</span>
                    <span class="keyword">return</span> HttpResponseRedirect(settings.LOGIN_URL + '<span class="string">?next=%s</span>' % request.path)
            <span class="keyword">else:</span>
                <span class="keyword">return</span> func(request, *listArgs, **kwArgs)
        wrapper.__name__ = func.__name__
        wrapper.__doc__ = func.__doc__
        wrapper.__dict__ = func.__dict__
        wrapper.__module__ = func.__module__
        <span class="keyword">return</span> wrapper
    <span class="keyword">return</span> decorator

<span class="keyword">def</span> <span class="function-name">facebookLogin</span>(request):
    '''<span class="string">
    Attempt to login the user based on their Facebook credentials.
    Does nothing outside of Facebook.
    </span>'''
    facebook = get_facebook_client()
    <span class="keyword">if</span> (<span class="keyword">not</span> request.user.is_authenticated()) <span class="keyword">or</span> UserProfile.Get(request.user).facebookId != facebook.uid:
        <span class="keyword">if</span> request.facebook <span class="keyword">and</span> request.facebook.check_session(request):
            user = authenticate(facebookId=facebook.uid)
            login(request, user)
</pre>
    <p>
      And here is a very simple example of how to use it:
    </p>
    <pre class="codeSnippet">
@facebookView(<span class="py-pseudo-keyword">True</span>) <span class="comment"># Require login, in and out of Facebook
</span><span class="keyword">def</span> <span class="function-name">myView</span>(request):
    <span class="comment"># Put important view processing here.
</span>    <span class="keyword">return</span> makeResponse(request, '<span class="string">myTemplate</span>', {'<span class="string">templateVar</span>':'<span class="string">important data</span>'})
</pre>
    <h4>
      Templates
    </h4>
    <p>
      We are getting closer to the holy grail of being able to write
      one set of code that can run both in and out of Facebook. It
      would also be useful to be able to share templates, so I have
      worked out several mechanisms to facilitate this.
    </p>
    <h5>
      The Context Processor
    </h5>
    <p>
      Django has the useful concept of a "Context Processor," which
      allows pre-processing of a RequestContext object before the
      rendering of any template. I take advantage of this quite a
      bit. I already discussed the <b>cacheBreaker</b> variable in
      my <a href="http://www.chickenwingsoftware.com/scratches/python/django-facebook-2">post
      about Facebook and JavaScript</a>. Here are a couple more
      variables I've found useful:
    </p>
    <ul>
      <li>
	<b>fb</b> - The <i>facebook</i> object, for accessing the
	Facebook API, or <b>None</b> outside of Facebook.
      </li>
      <li>
	<b>profile</b> - The <i>UserProfile</i> object, if the user is
	logged in, or <b>None</b> otherwise.
      </li>
      <li>
	<b>baseTemplate</b> - The template to <i>extend</i> - either
	"base.tmpl" outside of Facebook or "fb/base.fbml" inside of
	Facebook.
      </li>
      <li>
	<b>loginRequired</b> - A useful string for including in
	hyperlinks. Within Facebook, it contains
	'loginrequired=true'. Outside of Facebook, it contains
	something like 'onclick="return checkLogin()"', which is some
	custom JavaScript to require the user to login before
	following the link. Of course, if the link already has an
	"onclick" event, this cannot be used.
      </li>
    </ul>
    <p>
      I'll leave it to you to write your custom template processor, as
      they can be very site-specific, but the above should get you
      started. Here
      is <a href="http://docs.djangoproject.com/en/dev/ref/templates/api/?from=olddocs#id1">Django's
      context processor documentation</a>.
    </p>
    <h5>
      Template tags
    </h5>
    <p>
      To allow more sharing, I've defined a couple of useful template
      tags. These must be defined in a file in a "templatetags"
      directory under your application directory, as described in
      the <a href="http://docs.djangoproject.com/en/dev//howto/custom-template-tags/#howto-custom-template-tags">Django
      custom tag and filter documentation</a>.
    </p>
    <p>
      The first is <b>fbUrl</b>. It is the equivalent of the built-in
      Django <b>url</b> tag, except that when used inside Facebook it
      produces an absolute link to the requested page within the
      context of the Facebook canvas. In fact, the code is copied
      directly from the Django implementation
      of <b>url</b>. <b>fbUrl</b> relies on the <b>fb</b> context
      variable, and the <b>fbReverse</b> function, as described above.
    </p>
    <pre class="codeSnippet">
<span class="keyword">from</span> django.template <span class="keyword">import</span> Node
<span class="keyword">class</span> <span class="type">FBURLNode</span>(Node):
    <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, view_name, args, kwargs):
        <span class="py-pseudo-keyword">self</span>.view_name = view_name
        <span class="py-pseudo-keyword">self</span>.args = args
        <span class="py-pseudo-keyword">self</span>.kwargs = kwargs

    <span class="keyword">def</span> <span class="function-name">render</span>(<span class="py-pseudo-keyword">self</span>, context):
        fb = template.Variable('<span class="string">fb</span>').resolve(context)
        <span class="keyword">if</span> fb:
            reverseFunc = fbReverse
        <span class="keyword">else:</span>
            reverseFunc = django.core.urlresolvers.reverse

        <span class="keyword">from</span> django.core.urlresolvers <span class="keyword">import</span> reverse, NoReverseMatch
        args = [arg.resolve(context) <span class="keyword">for</span> arg <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.args]
        kwargs = <span class="py-builtins">dict</span>([(smart_str(k,'<span class="string">ascii</span>'), v.resolve(context))
                       <span class="keyword">for</span> k, v <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.kwargs.items()])
        <span class="keyword">try:</span>
            <span class="keyword">return</span> reverseFunc(<span class="py-pseudo-keyword">self</span>.view_name, args=args, kwargs=kwargs)
        <span class="keyword">except</span> NoReverseMatch:
            <span class="keyword">try:</span>
                project_name = settings.SETTINGS_MODULE.split('<span class="string">.</span>')[0]
                <span class="keyword">return</span> reverseFunc(project_name + '<span class="string">.</span>' + <span class="py-pseudo-keyword">self</span>.view_name,
                                   args=args, kwargs=kwargs)
            <span class="keyword">except</span> NoReverseMatch:
                <span class="keyword">return</span> ''

<span class="keyword">def</span> <span class="function-name">fbUrl</span>(parser, token):
    """<span class="string">
    Just like Django's url tag, except also works inside Facebook.
    "</span>""
    bits = token.contents.split('<span class="string"> </span>', 2)
    <span class="keyword">if</span> <span class="py-builtins">len</span>(bits) &lt; 2:
        <span class="keyword">raise</span> TemplateSyntaxError("<span class="string">'%s' takes at least one argument</span>"
                                  "<span class="string"> (path to a view)</span>" % bits[0])
    args = []
    kwargs = {}
    <span class="keyword">if</span> <span class="py-builtins">len</span>(bits) &gt; 2:
        <span class="keyword">for</span> arg <span class="keyword">in</span> bits[2].split('<span class="string">,</span>'):
            <span class="keyword">if</span> '<span class="string">=</span>' <span class="keyword">in</span> arg:
                k, v = arg.split('<span class="string">=</span>', 1)
                k = k.strip()
                kwargs[k] = parser.compile_filter(v)
            <span class="keyword">else:</span>
                args.append(parser.compile_filter(arg))
    <span class="keyword">return</span> FBURLNode(bits[1], args, kwargs)
fbUrl = register.tag(fbUrl)
                        
</pre>
    <p>
      Next is <b>fbName</b>. This is to provide the same functionality
      as Facebook's <i>fb:name</i> FBML tag, except also useable
      outside of Facebook.
    </p>
    <p>
      The basic use of it looks like <i>{% fbName user %}</i>, where
      "user" is a template variable containing the user whose name to
      display. Then you can add options like <i>linked=false</i>,
      or <i>useyou=false</i>, as described in the Facebook
      documentation.
    </p>
    <p>
      Some differences from the FBML version are:
    </p>
    <ul>
      <li>
	<i>shownetwork</i>, <i>ifcantsee</i>, and <i>subjectid</i> are
	ignored outside of Facebook.
      </li>
      <li>
	<i>linked</i> behaves slightly differently. Outside of
	Facebook, or if its value is set to <i>internal</i>, the
	user's name will be linked to an app-specific profile
	page. The view for this page is specified in the
	variable <b>userProfileView</b>. The view is expected to take
	one parameter: the user ID.
      </li>
    </ul>
    <p>
      Here is the code:
    </p>
    <pre class="codeSnippet">
userProfileView = '<span class="string">userProfile</span>'
<span class="keyword">class</span> <span class="type">FbNameNode</span>(Node):
    <span class="keyword">def</span> <span class="function-name">__init__</span>(<span class="py-pseudo-keyword">self</span>, user, args, kwArgs):
        <span class="py-pseudo-keyword">self</span>.user = template.Variable(user)
        <span class="py-pseudo-keyword">self</span>.args = args
        <span class="py-pseudo-keyword">self</span>.kwArgs = kwArgs

    <span class="keyword">def</span> <span class="function-name">getBoolArg</span>(<span class="py-pseudo-keyword">self</span>, name, default=<span class="py-pseudo-keyword">False</span>):
        val = <span class="py-pseudo-keyword">self</span>.kwArgs.get(name, default)
        <span class="keyword">if</span> <span class="py-builtins">type</span>(val) <span class="keyword">is</span> <span class="keyword">not</span> bool:
            <span class="keyword">return</span> (val.lower() == '<span class="string">true</span>')
        <span class="keyword">return</span> val

    <span class="keyword">def</span> <span class="function-name">render</span>(<span class="py-pseudo-keyword">self</span>, context):
        user = <span class="py-pseudo-keyword">self</span>.user.resolve(context)
        fb = template.Variable('<span class="string">fb</span>').resolve(context)
        loggedInUser = template.Variable('<span class="string">user</span>').resolve(context)
        request = template.Variable('<span class="string">request</span>').resolve(context)
        <span class="keyword">if</span> fb:
            fbUserId = UserFbId(user)
            <span class="keyword">if</span> fbUserId:
                <span class="comment"># In Facebook
</span>                internalLink = <span class="py-pseudo-keyword">False</span>
                ret = '<span class="string">&lt;fb:name uid="%s" </span>' % fbUserId
                <span class="keyword">for</span> item, val <span class="keyword">in</span> <span class="py-pseudo-keyword">self</span>.kwArgs.items():
                    <span class="keyword">if</span> item == '<span class="string">linked</span>' <span class="keyword">and</span> val == '<span class="string">internal</span>':
                        internalLink = <span class="py-pseudo-keyword">True</span>
                        ret += '<span class="string">linked="false" </span>'
                    <span class="keyword">else:</span>
                        <span class="keyword">if</span> <span class="py-builtins">type</span>(val) <span class="keyword">is</span> bool:
                            <span class="keyword">if</span> val:
                                val = '<span class="string">true</span>'
                            <span class="keyword">else:</span>
                                val = '<span class="string">false</span>'
                        ret += '<span class="string">%s="%s" </span>' % (item, val)
                ret += '<span class="string">/&gt;</span>'
                <span class="keyword">if</span> internalLink:
                    ret = '<span class="string">&lt;a href="%s"&gt;%s&lt;/a&gt;</span>' % (fbReverse(userProfileView, [user.id]), ret)
                <span class="keyword">return</span> mark_safe(ret)
        <span class="comment"># Not in Facebook
</span>        <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">useyou</span>', <span class="py-pseudo-keyword">True</span>) <span class="keyword">and</span> user == loggedInUser:
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">capitalize</span>'):
                ret = '<span class="string">You</span>'
            <span class="keyword">else:</span>
                ret = '<span class="string">you</span>'
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">possessive</span>'):
                ret += '<span class="string">r</span>'
            <span class="keyword">elif</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">reflexive</span>'):
                ret += '<span class="string">rself</span>'
            <span class="comment"># ES: How to handle subjectid?
</span>        <span class="keyword">else:</span>
            ret = UserDisplayName(user)
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">firstnameonly</span>'):
                ret = user.first_name <span class="keyword">or</span> user.username
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">lastnameonly</span>'):
                ret = user.last_name <span class="keyword">or</span> user.username
            <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">possessive</span>'):
                ret += "<span class="string">'s</span>"
        <span class="keyword">if</span> <span class="py-pseudo-keyword">self</span>.getBoolArg('<span class="string">linked</span>', <span class="py-pseudo-keyword">True</span>) <span class="keyword">or</span> <span class="py-pseudo-keyword">self</span>.kwArgs.get('<span class="string">linked</span>', <span class="py-pseudo-keyword">None</span>) == '<span class="string">internal</span>':
            ret = '<span class="string">&lt;a href="%s"&gt;%s&lt;/a&gt;</span>' % \
                (makeReverse(request, userProfileView, args=[user.id]),
                 ret)
        <span class="keyword">return</span> mark_safe(ret)
            

@register.tag
<span class="keyword">def</span> <span class="function-name">fbName</span>(parser, token):
    '''<span class="string">
    Returns the name for the given user, based on the parameters.

    Acts much like the fb:name FBML tag, except can work in or out of
    Facebook.
    </span>'''
    <span class="keyword">try:</span>
        bits = token.split_contents()[1:]
    <span class="keyword">except</span> ValueError:
        <span class="keyword">raise</span> template.TemplateSyntaxError, "<span class="string">%r tag requires at least 1 argument: the user (%s)</span>" %\
            (token.contents.split()[0], token.split_contents())
    args = []
    kwArgs = {}
    <span class="keyword">for</span> b <span class="keyword">in</span> bits:
        <span class="keyword">if</span> '<span class="string">=</span>' <span class="keyword">in</span> b:
            name,val = b.split('<span class="string">=</span>', 1)
            kwArgs[name.strip()] = val.strip()
        <span class="keyword">else:</span>
            args.append(b.strip())
    <span class="keyword">if</span> <span class="py-builtins">len</span>(args) &lt; 1:
        <span class="keyword">raise</span> template.TemplateSyntaxError, "<span class="string">%r tag requires at least one argument: the user</span>" %\
            token.contents.split()[0]

    <span class="keyword">return</span> FbNameNode(args[0], args[1:], kwArgs)

<span class="keyword">def</span> <span class="function-name">UserFbId</span>(user):
    <span class="keyword">try:</span>
        <span class="keyword">return</span> UserProfile.objects.get(user=user).facebookId
    <span class="keyword">except</span> UserProfile.DoesNotExist:
        <span class="keyword">return</span> <span class="py-pseudo-keyword">None</span>
</pre>
    <h4>
      Moving on
    </h4>
    <p>
      I think that should be enough to work with for now. Next time,
      I'll discuss publishing stories to news feeds and all that
      social good stuff. Until then, please feel free to post any
      comments, questions, or improvements below.
    </p>
]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/django-facebook-3/feed</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Making a Facebook app (with Django) &#8211; part 2: JavaScript and FBJS</title>
		<link>http://www.chickenwingsw.com/scratches/python/django-facebook-2</link>
		<comments>http://www.chickenwingsw.com/scratches/python/django-facebook-2#comments</comments>
		<pubDate>Sun, 17 Aug 2008 14:45:10 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[django]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/?p=54</guid>
		<description><![CDATA[    
      Welcome to the second part in my series of posts about creating
      a Facebook application. I am using Django as my web development
      framework, but this post doesn't have much to do with Django,
  [...]]]></description>
			<content:encoded><![CDATA[    <p>
      Welcome to the second part in my series of posts about creating
      a Facebook application. I am using Django as my web development
      framework, but this post doesn't have much to do with Django,
      since it deals with the front end. In particular, it talks about
      how to write JavaScript that can work both in and out of
      Facebook.
    </p>
    <p>
      As I mentioned last time, Facebook lets developers use a subset
      of JavaScript, which they call FBJS. The FBJS is transformed on
      the fly into JavaScript as the page is loaded. All variables and
      functions you define or reference are prepended with a string
      like "a123456789_", including calls
      to <span class="code">document.getElementById</span>
      and <span class="code">setTimer</span> and the like. This is
      done in order to restrict what you can do with DOM elements, to
      avoid cross-site-scripting attacks and unwanted user-hostile
      behavior. <a href="http://wiki.developers.facebook.com/index.php/FBJS">FBJS is fairly well documented</a>, so if you plan to do
      some Facebook JavaScript development, you should start there.
    </p>
    <p>
      The biggest restriction that FBJS imposes is that you can no
      longer access the attributes of DOM elements directly, but must
      go through an abstraction API consisting of a series of setters
      and getters. For example, instead of saying something like
      <span class="code">imageEl.src = myImageUrl</span>, you instead need
      to call imageEl.setSrc(myImageUrl).
    </p>
<span id="more-54"></span>
    <p>
      This is not too big of an adjustment, if you are accustomed to
      writing raw JavaScript. It actually has some advantages, because
      FBJS abstracts away some of browser-dependent aspects into a
      standard API.
    </p>
    <p>
      The challenge, however, becomes apparent when you try debugging
      your JavaScript. With Internet Explorer and its horrendously
      useless error messages and debugging facilities, it's pretty
      much hopeless, since the line numbers don't correspond to line
      numbers in your source code. However, even with Firefox and the
      wonderful Firebug debugger, all the name mangling and rewriting
      makes tracking down problems more difficult. Ideally you would
      want to debug as much as possible <em>outside</em> of Facebook,
      before then testing on the real site.
    </p>
    <p>
      To make this easier, I developed some useful code to simulate as
      much as possible the FBJS environment when running locally or
      outside of Facebook. The idea was to re-create all the accessor
      functions on all DOM objects. You can <a href="http://www.chickenwingsoftware.com/static/fbHelper.js">download the file
      here</a>. You're free to use it, but please don't link directly to
      the file on my site - copy it to your site and use it there. And
      read the description below first.
    </p>
    <p>
      I considered several different approaches before settling on the
      final version. I considered trade-offs of performance and
      possible side-effects. Rejected approach number one was to
      modify Object.prototype to contain the new getters and
      setters. This would have been the fastest, but can cause
      problems with code like the following:
    </p>
    <pre>
<span class="keyword">for</span> (var param <span class="type">in</span> <span class="variable-name">obj</span>) {
  <span class="comment">// Do something with obj[param]
</span>}

</pre>
    <p>
      This would end up enumerating all of the added functions as well
      as the properties of the object in question. This is why it is
      generally considered a bad idea to modify Object.prototype.
    </p>
    <p>
      The second rejected approach was to create a wrapper class with
      all the accessor functions, that performs the requisite getting
      and setting on a member variable containing the actual DOM
      object. This one could have worked well, but it would have been
      a lot of code to implement, and would have made debugging with
      Firebug more difficult because of the added layer of
      indirection.
    </p>
    <p>
      The approach I settled on was to simply provide wrapper
      functions for document.getElementById and
      document.createElement, and for each element that is "getted" or
      created, to copy in the required member functions. This has a
      perfomance penalty during the getting or creation of elements,
      but the calls themselves are speedy. There is likely to be a lot
      more manipulation than getting, I would think.
    </p>
    <h3>
      How to use this code
    </h3>
    <p>
      To use this code, just reference this file from your web page
      before any of your own JavaScript, but only when you are outside
      of Facebook. Make sure to call fbGetEl and fbCreateEl instead of
      document.getElementById and document.createElement. In the
      version of your page that is intended to be run inside of
      Facebook, include this code:
    </p>
        <pre>
<span class="type">function</span> <span class="function-name">fbGetEl</span>(elId) {
  <span class="keyword">return</span> document.getElementById(elId);
}
<span class="type">function</span> <span class="function-name">fbCreateEl</span>(elType) {
  <span class="keyword">return</span> document.createElement(elType);
}
</pre>
    <p>
      Alternatively, if you are feeling a little tricky, you can add
      in some code like this to the end of fbHelper.js
    </p>
        <pre>
document.getElementById = fbGetEl;
document.createElement = fbGetEl;
</pre>
    <p>
      Then you can continue to use document.getElementById and
      document.createElement. (Note that I have not tested this
      approach.)
    </p>
    <p>
      I hope this comes in handy for some people.
    </p>
    <h3>
      More FBJS tips
    </h3>
    <h4>
      Beware of the cache!
    </h4>
    <p>
       If you make a change to your .js file and
      don't notice any difference in your app's behavior, chances are
      you are getting bitten by the cache bug. To get around this,
      Facebook recommends adding "cache-breaker" code to the URL. For
      example, instead of linking to "myFile.js", link to
      "myFile.js?v=2". The extra text from the question mark on is
      usually ignored by web servers for static files. In my Django
      context processor, I have code like the following:
    </p>
    <pre>
<span class="keyword">from</span> svnVersion <span class="keyword">import</span> svnVersion

<span class="comment"># Add this function to your TEMPLATE_CONTEXT_PROCESSORS
# list in settings.py
</span><span class="keyword">def</span> <span class="function-name">fbContextProcessor</span>(request):
    <span class="keyword">return</span> { <span class="comment"># Add any other template vars you want here.
</span>        '<span class="string">cacheBreaker</span>':'<span class="string">?v=%s</span>' % svnVersion }

</pre>
    <p>
      Then in my template, whenever a have a link, I do something like:
    </p>
    <pre>
&lt;a href="http://example.com/myFile.js{{ cacheBreaker }}"&gt;Click here!&lt;/a&gt;
    </pre>
      Then every time I update my code, I run a shell script that does
      something like:
    </p>
    <pre>
      #!/bin/sh
      echo "svnVersion = '`svnversion -n .`'" > svnVersion.py
    </pre>

    <p>
      That way, every time I update my code, I make sure to break the
      Facebook cache. Alternatively, you could call svnversion
      straight from Python.
    </p>
    <h4>
       console.log is your friend! 
    </h4>
    <p>
     This is true in general when
      JavaScript programming, but especially so with Facebook. Take
      the time to put in some extra logging messages while you're
      developing, and testing and debugging will be much easier. And
      read up on Firebug as much as possible.
    </p>
    <h4>
      Check out the <a href="http://wiki.developers.facebook.com/index.php/FBJS/Animation">Animation library</a>.
    </h4>
    <p>
      It's pretty cool, and it works outside of Facebook, too.
    </p>
    <h4>
      Beware the limitations.
    </h4>
    <p>
      Facebook only allows up to five external
      script files, so keep that in mind. You may unfortunately have
      to combine two or more .js files into one to work around this
      restriction. Also, FBJS doesn't run on profile pages until the
      user has interacted with the app.
    </p>]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/django-facebook-2/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Making a Facebook app (with Django) &#8211; part 1: The Perils</title>
		<link>http://www.chickenwingsw.com/scratches/python/django-facebook-1</link>
		<comments>http://www.chickenwingsw.com/scratches/python/django-facebook-1#comments</comments>
		<pubDate>Fri, 18 Jul 2008 19:03:11 +0000</pubDate>
		<dc:creator>Eddie Sullivan</dc:creator>
				<category><![CDATA[django]]></category>
		<category><![CDATA[facebook]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[python]]></category>

		<guid isPermaLink="false">http://www.chickenwingsoftware.com/scratches/?p=19</guid>
		<description><![CDATA[Facebook made a splash a year or two ago when they opened up their API. Now developers could write applications that integrate with the site. Instantly, users -- many of whom had fled to Facebook from a spam-filled MySpace -- were inundated with Requests to battle ninjas and News Items bearing obscene pictures. To Facebook's [...]]]></description>
			<content:encoded><![CDATA[Facebook made a splash a year or two ago when they opened up their API. Now developers could write applications that integrate with the site. Instantly, users -- many of whom had fled to Facebook from a spam-filled MySpace -- were inundated with Requests to battle ninjas and News Items bearing obscene pictures. To Facebook's credit, they did clamp down and put some restrictions on what apps can do. A few entertaining or useful applications have risen to the top, and the potential of the API is ready to be exploited. It's not an easy task for a developer, however.

In the next few Chicken Scratches posts, I'll talk about my experience developing two Facebook apps from scratch: <a href="http://apps.facebook.com/limericks">The Limerick Book, </a>a site that works both in and outside of Facebook and allows users to share and rate Limericks, and <strong>Play Scopa</strong>, a traditional Italian card game that users can play against each other in realtime (this one is not yet launched to the public).

This first post discusses some of the difficulties I have run into. In the next couple posts, I'll discuss how I dealt with them. First, to set the scene:
<h4>My setup</h4>
I am using the <a href="http://www.djangoproject.com">Django web framework</a> for my backend development, the latest SVN version running with Python version 2.4 on a shared host at <a href="http://www.dreamhost.com">Dreamhost</a>. In fact, it's the same server I use for this site and weblog. To connect Django to Facebook, I am using the nice <a href="http://wiki.developers.facebook.com/index.php/PythonPyFacebookTutorial">PyFacebook</a> library, which is pretty mature, though I had to modify the code to support some of the latest features of the Facebook API.

And now, on to the perils.
<span id="more-19"></span>
<h4>Peril 1: Birds of a Feather</h4>
The first peril I ran into is just what I described in this post's introduction: there are a lot of really crappy Facebook apps out there, and there is a very real danger of the product I worked so hard on being associated with all kinds of toy apps, spammy apps, buggy apps, or just poorly designed apps. This is similar to what it was like programming in JavaScript in its early days: nobody thought anyone could do "serious" programming in it. Luckily, Google changed all that with their Maps. The Facebook platform is still struggling with this stigma. Unfortunately, it is a fairly well deserved stigma, as you can see by browsing the Developers Forum archives.  There are a lot of amateur or inexperienced developers who think, "hey, that looks cool. I wanna write an app." It's tough to find anyone on the forum who can answer a legitimate question, and hard to find the answers through all the noise.
<h4>Peril 2: Layers of indirection</h4>
Debugging can be very difficult. The major added difficulty in debugging a Facebook app is simply that the app has to run on Facebook. In typical web development, you can usually edit and test right on your local machine, or at least on your local network. I have come up with some tricks, which I will document in future posts, to enable as much local testing as possible, but much of your time will be spent debugging interactions between users, between your app and users, and between your app and the Facebook platform. This requires a tedious cycle of edit, upload, test; edit, upload, test; edituploadtest edituploadtestedituploadtest, and so on.

Developing client-side scripting is especially difficult. You need to write in a limited variant of JavaScript, called FBJS, which is translated dynamically to JavaScript, but with all kinds of name-mangling and pre-processing, so line numbers don't match up and all variable names are prepended with a whole bunch of cruft. If you think Internet Explorer's error messages are cryptic <em>now</em>, you ain't seen nothing yet!
<h4>Peril 3: You're at their mercy</h4>
The Facebook API is still pretty new, and Facebook itself is still a young company. There are inevitably going to be growing pains, and in fact, as I write this, Facebook's backend servers are experiencing some major network issues, causing many apps to not function properly. It can certainly be frustrating not knowing whether something is failing due to a local bug or a problem with the API.

In addition, APIs, policies, and presentation are constantly changing. Can I post a profile message today? Can I send an email? To which users? Better check the rules, because they've probably changed. It is of course Facebook's playground, so it is their right to change the rules as much as they want, and we as developers just have to be ready to deal with that. It's a fact of life, and it's another unique challenge of developing a Facebook app.
<h4>Peril 4: It's different</h4>
Anybody who has developed web software for any length of time has built up a library of reusable "stuff:" page templates, JavaScript libraries, development patterns. Unfortunately, many of these things are useless when developing for Facebook. The markup language, FBML, is almost, but not quite, HTML. The front-end scripting language, FBJS, is almost, but not quite, JavaScript, and so on. It requires re-learning or re-implementing a lot of the standard tips and tricks.
<h4>But I'm doing it anyway</h4>
Well, what can I say? Developing for Facebook is fun. It's very visual, and it's rewarding to share what you've created with your online "friends." Stay tuned for more posts on my development experience, including some of the more technical issues and how I dealt with them, using Python and Django.]]></content:encoded>
			<wfw:commentRss>http://www.chickenwingsw.com/scratches/python/django-facebook-1/feed</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
	</channel>
</rss>
