Saturday, October 31, 2009

Uploaded the application to App Engine

The application is available at http://ks-exp.appspot.com/runaround/

Populated the code in Github

The GitHub repository is:

http://github.com/ksachdeva/Google-App-Engine-experiments

Handler for the Home Page

class MainPage(webapp.RequestHandler):
    def get(self):
        template_values = {}
        path = os.path.join(os.path.dirname(__file__), 'templates/index_loggedout.html')
        self.response.out.write(template.render(path, template_values))

and updating _URLs as:

_URLS = [
    ('/runaround/', MainPage),
    ('/runaround/register/',RegisterPage),
]

As evident from these code snippets our home page is going to only render the page index_loggedout.html irrespective of use authentication status.

We need to now work on creating the login handler and have some sort of session management.

Templates for the Main Page

index_loggedout.html : Template to display when user is not logged in.

{% extends "base.html" %}

{% block content %}

  <img src="/ra/static/images/runaround_image.jpg" class="welcome_img" />

  <div class="welcome_dialog">
   <h3>Welcome to the Run Around</h3>

   <p>This is a simple site where you can log your runs and chart progress on your workout routine.</p>

  <div class="clearfix">
   <form action="/runaround/login/" method="post">
      <div class="login_sector">
       <div class="login_prompt">
        <b>Login</b>:
       </div>
       <div class="clearfix">
        <label>Username:</label>
        <input name="username" class="inputtext" type="text" size="20" value="" />
       </div>
         <div class="clearfix">
          <label>Password:</label>
          <input name="password" class="inputtext" type="password" size="20" value=""/>
         </div>
         <input id="submit" class="inputsubmit" value="Login" name="submit" type="submit" />
      </div>
      
      
      <div class="login_sector_fb">
       <div class="login_prompt">Or <b>login</b> with Facebook:</div>
        {% fbconnect_button "medium" %}
      </div>
      
    </form>
    
   </div>
   
    <div class="signup_container">
     Don't have an account? <a href="/runaround/register">Register Now!</a>
    </div>
    
  </div>
 
{% endblock content %}



index.html: Template to display when user is logged in


{% extends "base.html" %}

{% block content %}

 <div class="clearfix">
  <div class="bluebox">
  
   <h3>Where did you run recently?</h3>
   <form action="index.php" method="post">

    <table class="add_run_table">
       
       <tr>
        <td class="editor_key">
          <label id="label_route" for="route">Where did you go?</label>
         </td>
         <td class="editor_value">
           <input id="route" class="inputtext" type="text" size="20" value="" name="route"/>
         </td>
        </tr>
        
        <tr>
        <td class="editor_key">
          <label id="label_miles" for="miles">Number of miles</label>
         </td>
         <td class="editor_value">
           <input id="miles" class="inputtext" type="text" size="20" value="" name="miles"/>
         </td>
        </tr>
        
       <tr>
        <td class="editor_key"><label>Date (MM/DD/YYYY)</label></td>
         <td class="editor_value">
          <input id="date_month" class="inputtext datefield" name="date_month" type="text" size="2" maxlength="2" />
          /<input id="date_day" class="inputtext datefield" name="date_day" type="text" size="2" maxlength="2" />
          /<input id="date_year" class="inputtext datefield" name="date_year" type="text" size="4" maxlength="4" />
         </td>
         </tr>
      </table>
  
    <p id="publish_fb_checkbox" style="'.$style.'" >
        <img src="http://static.ak.fbcdn.net/images/icons/favicon.gif" /> 
        <input type="checkbox" name="publish_to_facebook" checked /> 
        Publish this run to Facebook
         </p>
    <input class="inputsubmit" type="submit" name="submit" value="Add Run"/>
    
   </form>
   
  </div>
 </div>
  
{% endblock content %}

The main page of runaround application

Depending on your logged in status the home page of runaround application (http://www.somethingtoputhere.com/therunaround/index.php) displays different pages.

When user is not logged in:



When user is logged in:




[ Note that our registration page is now capable of creating an account for user but still does not connect to Facebook. In the PHP based application when you use registration page it creates an account with Facebook also. We do not have this functionality yet. ]

Making the password field in Registration form

As shown in the register.html template file the "form" is sent by the handler to the template engine and we have not written the corresponding html. This html is generated based on the registration model we created.

In the registration model we have db.StringProperty as the type of the password field so the template engine renders a simple textbox for it and we would like to have a password field so user (or rather people looking at his screen) can not see the password being typed in this input field.

In django forms it is quite simple, you just have to say that the widget for this field should be PasswordInput as described here. Even though it is called djangoforms the functionalities are not quite similar at App Engine.

Here is how I solved it (with the help of information here) :

Extend db.StringProperty:

class PasswordProperty(db.StringProperty):
    def __init__(self, size=None, maxlength=None, password=False,
                 cssClass=None, **kwargs):
        self._size = size
        self._maxlength = maxlength
        self._password = password
        self._cssClass = cssClass
        super(PasswordProperty, self).__init__(**kwargs)

    def get_form_field(self, **kwargs):
        defaults = {}
        attrs={}
        if self._size:
            attrs['size']=self._size
        if self._maxlength:
            attrs['maxlength']=self._maxlength
        if self._cssClass:
            attrs['class']=self._cssClass
        if self._password:
            defaults['widget']=PasswordInput(attrs)
        else:
            defaults['widget']=TextInput(attrs)
        defaults.update(kwargs)
        return super(PasswordProperty, self).get_form_field(**defaults)

and now our model would look like this:

class RunAroundUser(db.Model):
    username = db.StringProperty(required=True)
    password = PasswordProperty(password=True,required=True)
    name     = db.StringProperty(required=True)
    email    = db.EmailProperty(required=True)
    fb_uid   = db.StringProperty()


Note that the password field is now of type PasswordProperty. I still need to refine the original idea that was here and then the PasswordProperty would be more refined and would not need to have "password=True" attribute.

Registering templates in App Engine

Although in App Engine we are using django templates language the loading of custom template tags is bit different.

In django you can use {% load my_custom_tags %} in your templates to load the custom template tags. This does not worked for me in the App Engine.

Here is how I made it work. In you handler file (which is runaround/runaround.py for us in this example) I have a code snippet

from google.appengine.ext.webapp import template

template.register_template_library('runaround.templatetags.runaround_tags')


runaround/templatetags/runaround_tags.py is the name of file/module which contains the template tags. Its contents were described in this post.

Handler for Registration Page

In my runaround application I have runaround.py, and you must have seen in the app.yaml mentioned in previous post that request to all the urls which have the pattern "/runaround.*: are sent to this python script i.e. runaround/runaround.py

from google.appengine.ext import webapp
from google.appengine.ext.webapp.util import run_wsgi_app
from google.appengine.ext.webapp import template

import os
import cgi

from runaround import models

template.register_template_library('runaround.templatetags.runaround_tags')

from runaround import rforms

class RegisterPage(webapp.RequestHandler):
    def get(self):
        template_values = {
            'form' : rforms.RegisterForm() 
        }
        path = os.path.join(os.path.dirname(__file__), 'templates/register.html')
        self.response.out.write(template.render(path, template_values))
        
    def post(self):
        data = rforms.RegisterForm(data=self.request.POST)
        if data.is_valid():
            # save the data and redirect to the run page
            entity = data.save(commit=False)
            entity.put()
            self.redirect('/runaround/')
        else:
            # re-print the form
            template_values = {
                'form' : data
            }
            path = os.path.join(os.path.dirname(__file__), 'templates/register.html')
            self.response.out.write(template.render(path, template_values))

_URLS = [
    ('/runaround/register/',RegisterPage),
]

application = webapp.WSGIApplication(_URLS, debug=True)

def main():
    run_wsgi_app(application)

if __name__ == "__main__":
    main()

Registration Form

I have created a file rforms.py in my runaround application and for now the contents look like this:

from google.appengine.ext.webapp import template

from google.appengine.ext.db import djangoforms

from django.newforms.widgets import PasswordInput

import models

class RegisterForm(djangoforms.ModelForm):
    class Meta:
        model = models.RunAroundUser
        exclude = ['fb_uid']   


So as the code shows we are inheriting from djangoforms.ModelForm which helps in maintaining the needed information at one place only. Since we would not ask user to enter "fb_uid" which is some internal information we can exclude it.

Looks pretty neat.

app.yaml and static directory structure

application: "PUT_NAME_OF_APPENGINE_ID_HERE"
version: 1
runtime: python
api_version: 1

handlers:

- url: /ra
  static_dir: static/runaround
 
- url: /runaround.*
  script: runaround/runaround.py

and our static directory looks something like this:



All the css, images and javascript files shown in this image are retrieved from the PHP runaround application.

Master and Registration Page templates

base.html

<!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" xmlns:fb="http://www.facebook.com/2008/fbml"> 
  <head> 
   <title>The Run Around</title> 
    <link type="text/css" rel="stylesheet" href="/ra/static/css/style.css" /> 
    <script type="text/javascript" src="/ra/static/js/base.js"></script> 
  
  </head> 
  
  <body>
  
   <div id="header">
    <div class="header_content">
     <a href="/runaround" class="title">
      <img src="/ra/static/images/runaround_logo.gif" />
     </a>
     
      <div class="account">Hello Guest | 
     <a href="/runaround/register">Register for an account</a>
    </div>
   
    </div>
   </div>
   
   <div class="body_content">
   
    {% block content %} {% endblock %}
    
   </div>
   
   <div class="footer_stuff">This is an awesome running app.</div>

 <script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/FeatureLoader.js.php" type="text/javascript"></script>
     <script type="text/javascript">
       FB.init("edbc02640bc38965940b56cece534ad5", "/runaround/xd_receiver");
     </script>
 <script type="text/javascript" src="/ra/static/js/fbconnect.js"></script> 
  
  </body>
  
</html> 

Nothing fancy here, a simple and typical django base template page which other templates/pages would inherit from.

register.html

{% extends "base.html" %}

{% block content %}

<div class="register">
 <div class="login_sector">
  <h2>Do you use Facebook?</h2>
    Use Facebook to register for The Run Around:
   <br/><br />
   
   {% fbconnect_button "medium" %}
   
    </div>

 <div class="login_sector_fb">
  <h2>Register</h2>
  <form action="/runaround/register/" method="post">
   
   <table>
   
     {{ form }}
      
   </table>
   
   <input type="hidden" name="save" value="1">
   <input type="submit" class="inputsubmit" value="Register" style="margin-left: 80px">

  </form>

 </div>
</div>

{% endblock content %}


The "form" variable shown in the above template would be passed by the handler to the template engine, which we will discuss in next few posts.

Tuesday, October 27, 2009

Templatetag for displaying Facebook Connect button

You normally create a templatetags directory in your application which should contain __int__.py so as to make it a package. In App Engine however there is no need. Here is my python module runaround_tags.py which contain this code:

from google.appengine.ext.webapp import template

register = template.create_template_register()

def fbconnect_button(button_size="medium"):
    return """
        
    """
    
register.simple_tag(fbconnect_button)

Model for Registration information

Here is my model which would contain the registration information

class RunAroundUser(db.Model):
    username = db.StringProperty(required=True)
    password = db.StringProperty(required=True)
    name     = db.StringProperty(required=True)
    email    = db.EmailProperty(required=True)
    fb_uid   = db.StringProperty()

This model is similar to the user class in PHP application but does not yet contain the utilities methods. We will talk about fb_uid field later when we would be integrating Facebook Connect.

Registration Page

Here is how the registration page of runaround application looks like :



pretty nice page. Good thing is that I do not need to worry about look and feed or layout (read 'css and images') of the application.

In the above image you can see that we need to build

  • A form which will register the user
  • Display Facebook connect button

Since all the pages in runaround application has same design i.e. header and footer with main area where the real action is it may be a good idea to use django templates and django templatetags.

Monday, October 26, 2009

To use django or webapp framework

I have some experience developing web applications using django but there are some problems using it in app engine. The app engine models are different from that of django and session middleware along with many other nice features of django would not work on app engine.

App Engine does have django as one of its built in libraries but I think I would give webapp framework a go. It is simple, elegant and seems good enough for my simple application.

May be I will port my application to django once I have learned about webapp and we can then compare them also at that time.

If you want to use django on app engine you may want to check out following projects which make it possible:

Configuring Pydev for App Engine application development

No need for me to describe it. Here is the link:

http://code.google.com/appengine/articles/eclipse.html

SDK, Libraries and IDE

So lets setup the development environment and here is mine (assuming Python 2.5 is installed) :
I am sure I will need to use some more libraries as I made progress.

The runaround Facebook application

In my search for an ideal not-so-simple-but-not-so-complex project I stumbled upon the runaround application. This is decent web application which demonstrates following functionalities :
  • Registration of user
  • Authenticate user using username-password or Facebook Connect
  • A simple form for user to enter his runarounds and a way to display them
  • Post the runarounds on the Facebook wall
  • Pull the runarounds of your Facebook friends and display them 
If I can implement these functionalities as an app engine web application I think I should be able to get a good idea on how it works and how to use its framework(s). I would also get to learn how to integrate Facebook connect and potentially other Facebook APIs. This is what I call "killing two birds with one stone"

The runaround application has been written in PHP and its design is described in detail here with links to its sources in subversion repository.

App Engine to rescue

The idea of some one else worrying about the scalability of your application is very appealing and that brings me to Google App Engine. I know that even though App Engine is going to do heavy lifting in terms of running and maintaining the servers & databases (read 'BigTable'), a developer needs to make right and informed decisions regarding creating data model, using appropriate caching mechanism and following many other software design principles.

This is why I am starting this blog where I would be writing down my experiences with App Engine as I learn and play with it.

I have always believed that the best way to learn a language and/or software technology is create a not-so-simple-but-no-so-complex project and that is what I intend to do here.