Merge branch 'issue1658'.
diff --git a/app/app.yaml.template b/app/app.yaml.template
index a12b0fe..accfeaa 100644
--- a/app/app.yaml.template
+++ b/app/app.yaml.template
@@ -15,7 +15,7 @@
 # TODO(proto): uncomment and supply a Google App Engine application instance
 # application: FIXME
 # TODO(release): see the instructions in README about the "version:" field
-version: 2-0-20121128-p1
+version: 2-0-20121217
 runtime: python
 api_version: 1
 
diff --git a/app/soc/content/css/v2/gci/account_deletion.css b/app/soc/content/css/v2/gci/account_deletion.css
new file mode 100644
index 0000000..96e2d99
--- /dev/null
+++ b/app/soc/content/css/v2/gci/account_deletion.css
@@ -0,0 +1,7 @@
+.delete-info {
+    color: #000;
+}
+
+.moderate-delete-message {
+    padding: 10px 0 10px 0;
+}
diff --git a/app/soc/content/css/v2/gci/style.css b/app/soc/content/css/v2/gci/style.css
index 21e9773..65f5834 100644
--- a/app/soc/content/css/v2/gci/style.css
+++ b/app/soc/content/css/v2/gci/style.css
@@ -322,8 +322,10 @@
 .header {
     height: 143px;
 }
-    .header .logo img {
+    .header .logo {
         float: left;
+    }
+    .header .logo img {
         height: 127px;
         margin: 10px 0 0 58px;
         width: 252px;
@@ -1414,7 +1416,7 @@
             line-height: 18px;
             padding: 4px 25px 5px 10px;
         }
-        .block-how-it-works .block-how-it-works-start a.example-tasks {
+        .block-how-it-works .block-how-it-works-start a.example-tasks, a.all-tasks-tasks {
             color: #c53926;
             display: block;
             float: left;
@@ -1425,6 +1427,10 @@
             margin-left: 100px;
             padding: 4px 25px 5px 10px;
         }
+        a.all-tasks-tasks {
+            font-size: 14px;
+            margin-left: 75px;
+        }
 .block-featured-task {/*Featured Task*/
 }
     .block-featured-task .block-title {
diff --git a/app/soc/logic/delete_account.py b/app/soc/logic/delete_account.py
index 035a47e..789b015 100644
--- a/app/soc/logic/delete_account.py
+++ b/app/soc/logic/delete_account.py
@@ -19,9 +19,16 @@
 
 
 from google.appengine.api import mail
+from google.appengine.ext import db
 
 from soc.logic import accounts
 from soc.logic import system
+from soc.logic import user as user_logic
+from soc.models import user
+
+from soc.modules.gci.logic import profile as profile_logic
+from soc.modules.gci.models import comment
+from soc.modules.gci.models import task
 
 
 ADMIN_REQUEST_EMAIL_SUBJEST = """
@@ -39,7 +46,7 @@
 def request_account_deletion(user):
   """Requests deletion of user's account from application administrators
   by sending them an email.
-  
+
   This is a temporary method, until we have an automated solution.
   """
   account = accounts.getCurrentAccount(normalize=False)
@@ -55,3 +62,85 @@
       }
 
   mail.send_mail_to_admins(sender, subject, body)
+
+
+def confirm_delete(profile):
+  """Deletes the given profile entity and also the user entity if possible.
+
+  1. Deletes the profile.
+  2. Deletes the user entity if no other profiles exist for the user.
+  3. Removes the user from task notification subscription lists
+  4. Replaces GCITask created_by, modified_by, student and GCIComment
+     created_by properties with dummy "melange_deleted_user" profile or user
+     entity.
+
+  This method implements a giant XG transaction, but should not take a long
+  time because experience has shown that there won't be too much data to
+  modify or delete.
+
+  Args:
+    profile: GCIProfile entity of the user.
+  """
+  profile_key = profile.key()
+
+  # Cannot delete the user entity if the user has other profiles, so set it
+  # to False in that case.
+  user_delete = not (profile_logic.hasOtherGCIProfiles(profile) or
+                     profile_logic.hasOtherGCIProfiles(profile))
+
+  task_sub_q = task.GCITask.all().filter('subscribers', profile)
+
+  tasks_created_by_q = task.GCITask.all().filter('created_by', profile)
+
+  tasks_modified_by_q = task.GCITask.all().filter('modified_by', profile)
+
+  tasks_student_q = task.GCITask.all().filter('student', profile)
+
+  comments_created_by_q = comment.GCIComment.all().filter(
+      'created_by', profile.user)
+
+  dummy_user = user_logic.getOrCreateDummyMelangeDeletedUser()
+  dummy_profile = profile_logic.getOrCreateDummyMelangeDeletedProfile(
+      profile.scope)
+
+  options = db.create_transaction_options(xg=True)
+
+  def delete_account_txn():
+    entities_to_save = set([])
+    entities_to_del = set([])
+
+    # The batch size for query.run() is 20, in most of the cases we have
+    # seen so far the user had a few tasks with subscriptions, created_by,
+    # modified_by etc., so this should still be single datastore hits per
+    # loop.
+    for task in task_sub_q.run():
+      task.subscribers.remove(profile_key)
+      entities_to_save.add(task)
+
+    for task in tasks_created_by_q.run():
+      task.created_by = dummy_profile
+      entities_to_save.add(task)
+
+    for task in tasks_modified_by_q.run():
+      task.modified_by = dummy_profile
+      entities_to_save.add(task)
+
+    for task in tasks_student_q.run():
+      task.student = dummy_profile
+      entities_to_save.add(task)
+
+    for comment in comments_created_by_q.run():
+      comment.created_by = dummy_user
+      entities_to_save.add(comment)
+
+    if profile.student_info:
+      entities_to_del.add(profile.student_info)
+      entities_to_del.add(profile)
+
+    if user_delete:
+      entities_to_del.add(profile.parent())
+
+    db.put(entities_to_save)
+    db.delete(entities_to_del)
+
+  db.run_in_transaction_options(options, delete_account_txn)
diff --git a/app/soc/logic/user.py b/app/soc/logic/user.py
index 0d411f7..9a4bcbb 100644
--- a/app/soc/logic/user.py
+++ b/app/soc/logic/user.py
@@ -19,17 +19,20 @@
 
 
 from google.appengine.api import users
-from google.appengine.ext import db
+from google.appengine.runtime import apiproxy_errors
 
 from soc.logic import accounts
+from soc.logic import exceptions
+from soc.models import user
 
-from soc.models.user import User
+
+MELANGE_DELETED_USER = 'melange_deleted_user'
 
 
 def isFormerAccount(account):
   """Returns true if account is a former account of some User.
   """
-  return User.all().filter('former_accounts', account).count() > 0
+  return user.User.all().filter('former_accounts', account).count() > 0
 
 
 def forCurrentAccount():
@@ -41,25 +44,24 @@
   If there is no user logged in, or they have no valid associated User
   entity, None is returned.
   """
-
   account = accounts.getCurrentAccount()
 
   if not account:
     return None
 
-  user = forAccount(account)
+  user_ent = forAccount(account)
 
-  if user and not user.user_id and account.user_id():
-    from google.appengine.runtime.apiproxy_errors import CapabilityDisabledError
+  if user_ent and not user_ent.user_id and account.user_id():
     # update the user id that was added to GAE after Melange was launched
     try:
-      user.user_id = account.user_id()
-      user.put()
-    except CapabilityDisabledError, e:
+      user_ent.user_id = account.user_id()
+      user_ent.put()
+    except apiproxy_errors.CapabilityDisabledError, _:
       # readonly mode, that's fine
       pass
 
-  return user
+  return user_ent
+
 
 def forCurrentUserId():
   """Retrieves the user entity for the currently logged in user id.
@@ -67,26 +69,26 @@
   If there is no user logged in, or they have no valid associated User
   entity, None is returned.
   """
-
   user_id = accounts.getCurrentUserId()
 
   if not user_id:
     return None
 
-  user = forUserId(user_id)
+  user_ent = forUserId(user_id)
 
   current_account = accounts.getCurrentAccount()
-  if user and (str(user.account) != str(current_account)):
+  if user_ent and (str(user_ent.account) != str(current_account)):
     # The account of the user has changed, we use this account to send system
     # emails to.
     try:
-      user.account = current_account
-      user.put()
-    except CapabilityDisabledError, e:
+      user_ent.account = current_account
+      user_ent.put()
+    except apiproxy_errors.CapabilityDisabledError, _:
       # readonly mode, that's fine
       pass
 
-  return user
+  return user_ent
+
 
 def current():
   """Retrieves the user entity for the currently logged in user.
@@ -95,10 +97,10 @@
     The User entity of the logged in user or None if not available.
   """
   # look up with the unique id first
-  user = forCurrentUserId()
+  user_ent = forCurrentUserId()
 
-  if user:
-    return user
+  if user_ent:
+    return user_ent
 
   # look up using the account address thereby setting the unique id
   return forCurrentAccount()
@@ -110,13 +112,12 @@
   If there is no user logged in, or they have no valid associated User
   entity, None is returned.
   """
-
   if not account:
-    raise base.InvalidArgumentError("Missing argument 'account'")
+    raise exceptions.BadRequest("Missing argument 'account'")
 
   account = accounts.normalizeAccount(account)
 
-  q = User.all()
+  q = user.User.all()
   q.filter('account', account)
   q.filter('status', 'valid')
   return q.get()
@@ -128,38 +129,52 @@
   If there is no user logged in, or they have no valid associated User
   entity, None is returned.
   """
-
   if not user_id:
-    raise base.InvalidArgumentError("Missing argument 'user_id'")
+    raise exceptions.BadRequest("Missing argument 'user_id'")
 
-  q = User.all()
+  q = user.User.all()
   q.filter('user_id', user_id)
   q.filter('status', 'valid')
   return q.get()
 
 
-def isDeveloper(account=None, user=None):
+def isDeveloper(account=None, user_ent=None):
   """Returns true iff the specified user is a Developer.
 
   Args:
     account: if not supplied, defaults to the current account
-    user: if not specified, defaults to the current user
+    user_ent: if not specified, defaults to the current user
   """
-
   current = accounts.getCurrentAccount()
 
   if not account:
     # default account to the current logged in account
     account = current
 
-  if account and (not user):
+  if account and (not user_ent):
     # default user to the current logged in user
-    user = forAccount(account)
+    user_ent = forAccount(account)
 
   # pylint: disable=E1103
-  if user and user.is_developer:
+  if user_ent and user_ent.is_developer:
     return True
 
   if account and (account == current):
     return users.is_current_user_admin()
 
+
+def getOrCreateDummyMelangeDeletedUser():
+  """Fetches or creates the dummy melange deleted user entity.
+  """
+  q = user.User.all().filter('link_id', MELANGE_DELETED_USER)
+  user_ent = q.get()
+
+  # If the requested user does not exist, create one.
+  if not user_ent:
+    account = users.User(email=MELANGE_DELETED_USER)
+    user_ent = user.User(
+        key_name=MELANGE_DELETED_USER, account=account,
+        link_id=MELANGE_DELETED_USER)
+    user_ent.put()
+
+  return user_ent
diff --git a/app/soc/modules/gci/callback.py b/app/soc/modules/gci/callback.py
index 9962de4..627dc29 100644
--- a/app/soc/modules/gci/callback.py
+++ b/app/soc/modules/gci/callback.py
@@ -43,6 +43,7 @@
     from soc.modules.gci.views import homepage
     from soc.modules.gci.views import invite
     from soc.modules.gci.views import leaderboard
+    from soc.modules.gci.views import moderate_delete_account
     from soc.modules.gci.views import org_app
     from soc.modules.gci.views import org_home
     from soc.modules.gci.views import org_profile
@@ -78,6 +79,7 @@
     self.views.append(invite.ListUserInvitesPage())
     self.views.append(leaderboard.LeaderboardPage())
     self.views.append(leaderboard.StudentTasksPage())
+    self.views.append(moderate_delete_account.ModerateDeleteAccountPage())
     self.views.append(org_app.GCIOrgAppEditPage())
     self.views.append(org_profile.OrgProfilePage())
     self.views.append(org_app.GCIOrgAppPreviewPage())
diff --git a/app/soc/modules/gci/logic/comment.py b/app/soc/modules/gci/logic/comment.py
index 63a53f9..0912bb7 100644
--- a/app/soc/modules/gci/logic/comment.py
+++ b/app/soc/modules/gci/logic/comment.py
@@ -50,7 +50,7 @@
   to_emails = []
   profiles = GCIProfile.get(task.subscribers)
   for profile in profiles:
-    if ((not comment.created_by) or
+    if profile and ((not comment.created_by) or
         profile.user.key() != comment.created_by.key()):
       to_emails.append(profile.email)
 
diff --git a/app/soc/modules/gci/logic/profile.py b/app/soc/modules/gci/logic/profile.py
index 1c85d07..bd779bc 100644
--- a/app/soc/modules/gci/logic/profile.py
+++ b/app/soc/modules/gci/logic/profile.py
@@ -18,12 +18,38 @@
 """
 
 
+import datetime
+
+from soc.logic import user as user_logic
 from soc.tasks import mailer
 
+from soc.modules.gsoc.models import profile as gsoc_profile_model
+
 from soc.modules.gci.logic.helper import notifications
-from soc.modules.gci.models.profile import GCIProfile
-from soc.modules.gci.models.profile import GCIStudentInfo
-from soc.modules.gci.models.task import GCITask
+from soc.modules.gci.models import comment as comment_model
+from soc.modules.gci.models import profile as profile_model
+from soc.modules.gci.models import task as task_model
+
+
+MELANGE_DELETED_USER_PNAME = 'Melange Deleted User'
+
+MELANGE_DELETED_USER_GNAME = 'Melange Deleted User GName'
+
+MELANGE_DELETED_USER_SNAME = 'Melange Deleted User Surname'
+
+MELANGE_DELETED_USER_EMAIL = 'melange_deleted_user@gmail.com'
+
+MELANGE_DELETED_USER_RES_STREET = 'No address'
+
+MELANGE_DELETED_USER_RES_CITY = 'No city'
+
+MELANGE_DELETED_USER_RES_COUNTY = 'United States'
+
+MELANGE_DELETED_USER_RES_POSTAL_CODE = '00000'
+
+MELANGE_DELETED_USER_PHONE = '0000000000'
+
+MELANGE_DELETED_USER_BIRTH_DATE = datetime.datetime(1, 1, 1)
 
 
 def hasStudentFormsUploaded(student):
@@ -46,7 +72,7 @@
   """
 
   # get all mentors keys first
-  query = GCIProfile.all(keys_only=keys_only)
+  query = profile_model.GCIProfile.all(keys_only=keys_only)
   query.filter('mentor_for', org)
   mentors = query.fetch(limit=limit)
 
@@ -84,7 +110,7 @@
   Args:
     org: The GCIOrganization entity for which the admins should be found.
   """
-  query = GCIProfile.all()
+  query = profile_model.GCIProfile.all()
   query.filter('org_admin_for', org)
 
   return query.fetch(limit)
@@ -98,7 +124,7 @@
     user: User entity for which the profile should be found
     program: GCIProgram entity for which the profile should be found
   """
-  return GCIProfile.all().ancestor(user).filter('scope = ', program)
+  return profile_model.GCIProfile.all().ancestor(user).filter('scope = ', program)
 
 
 def queryStudentInfoForParent(parent):
@@ -108,4 +134,114 @@
   Args:
     parent: GCIProfile entity which is the parent of the entity to retrieve
   """
-  return GCIStudentInfo.all().ancestor(parent)
+  return profile_model.GCIStudentInfo.all().ancestor(parent)
+
+
+def hasTasks(profile):
+  """Returns True if the given student profile has been assigned to a task.
+
+  Assign also means the tasks completed by the student.
+
+  Args:
+    profile: GCIProfile entity of the student.
+  """
+  q = task_model.GCITask.all()
+  q.filter('student', profile)
+  return q.count() > 0
+
+
+def hasCreatedOrModifiedTask(profile):
+  """Returns True if the given user has created or modified a task.
+
+  Args:
+    profile: GCIProfile entity of the user.
+  """
+  q = task_model.GCITask.all()
+  q.filter('created_by', profile)
+  if q.count() > 0:
+    return True
+
+  q = task_model.GCITask.all()
+  q.filter('modified_by', profile)
+  return q.count() > 0
+
+
+def hasTaskComments(profile):
+  """Returns True if the given profile has task comments associated with it.
+
+  Args:
+    profile: GCIProfile entity of the user.
+  """
+  user = profile.parent()
+
+  q = comment_model.GCIComment.all()
+  q.filter('created_by', user)
+
+  return q.count() > 0
+
+
+def hasOtherGCIProfiles(profile):
+  """Returns True if the given user had profiles in previous GCIs.
+
+  Args:
+    profile: GCIProfile entity of the user.
+  """
+  user = profile.parent()
+
+  q = profile_model.GCIProfile.all()
+  q.ancestor(user)
+
+  # We check for > 1 not > 0 because we already know that there is one profile
+  # for this program. So we need to check if there are others.
+  return q.count() > 1
+
+
+def hasOtherGSoCProfiles(profile):
+  """Returns True if the given user has profiles in previous GSoCs.
+
+  Args:
+    profile: GCIProfile entity of the user.
+  """
+  user = profile.parent()
+
+  q = gsoc_profile_model.GSoCProfile.all()
+  q.ancestor(user)
+
+  return q.count() > 0
+
+
+def getOrCreateDummyMelangeDeletedProfile(program):
+  """Fetches or creates the dummy melange deleted profile for the given program.
+
+  Args:
+    program: The program entity for which the dummy profile should be fetched
+        or created.
+  """
+  q = profile_model.GCIProfile.all()
+  q.filter('link_id', user_logic.MELANGE_DELETED_USER)
+  q.filter('scope', program)
+  profile_ent = q.get()
+
+  # If the requested user does not exist, create one.
+  if not profile_ent:
+    user_ent = user_logic.getOrCreateDummyMelangeDeletedUser()
+    key_name = '%s/%s' % (program.key(), user_logic.MELANGE_DELETED_USER)
+
+    profile_ent = profile_model.GCIProfile(
+        parent=user_ent, key_name=key_name,
+        link_id=user_logic.MELANGE_DELETED_USER, scope=program,
+        scope_path=program.key().id_or_name(), user=user_ent,
+        public_name=MELANGE_DELETED_USER_PNAME,
+        given_name=MELANGE_DELETED_USER_GNAME,
+        surname=MELANGE_DELETED_USER_SNAME,
+        email=MELANGE_DELETED_USER_EMAIL,
+        res_street=MELANGE_DELETED_USER_RES_STREET,
+        res_city=MELANGE_DELETED_USER_RES_CITY,
+        res_country=MELANGE_DELETED_USER_RES_COUNTY,
+        res_postalcode=MELANGE_DELETED_USER_RES_POSTAL_CODE,
+        phone=MELANGE_DELETED_USER_PHONE,
+        birth_date=MELANGE_DELETED_USER_BIRTH_DATE)
+
+    profile_ent.put()
+
+  return profile_ent
diff --git a/app/soc/modules/gci/templates/task_list.py b/app/soc/modules/gci/templates/task_list.py
index e61e6c9..46f2ff4 100644
--- a/app/soc/modules/gci/templates/task_list.py
+++ b/app/soc/modules/gci/templates/task_list.py
@@ -97,7 +97,15 @@
     if 'mentors' in self._columns:
       list_config.addColumn('mentors', 'Mentors',
           lambda entity, mentors, *args: ', '.join(
-              mentors[i].name() for i in entity.mentors))
+              mentors[i].name() for i in entity.mentors), hidden=True)
+
+    if 'types' in self._columns:
+      list_config.addColumn('types', 'Category',
+          lambda entity, *args: ', '.join(entity.types))
+
+    if 'tags' in self._columns:
+      list_config.addColumn('tags', 'Tags',
+          lambda entity, *args: ', '.join(entity.tags))
 
     if 'status' in self._columns:
       list_config.addSimpleColumn('status', 'Status')
diff --git a/app/soc/modules/gci/views/accepted_orgs.py b/app/soc/modules/gci/views/accepted_orgs.py
index a1365c7..2b1afce 100644
--- a/app/soc/modules/gci/views/accepted_orgs.py
+++ b/app/soc/modules/gci/views/accepted_orgs.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GCI accepted orgs.
-"""
-
+"""Module containing the views for GCI accepted orgs."""
 
 from django.conf.urls.defaults import url as django_url
 
@@ -28,8 +24,7 @@
 from soc.modules.gci.logic import profile as profile_logic
 from soc.modules.gci.models.organization import GCIOrganization
 from soc.modules.gci.templates.org_list import OrgList
-from soc.modules.gci.views.base import RequestHandler
-#from soc.modules.gci.views.base_templates import ProgramSelect
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper.url_patterns import url
 from soc.modules.gci.views.helper import url_names
 
@@ -43,14 +38,19 @@
         self.data.program.name)
 
   def _getListConfig(self):
-    r = self.data.redirect
+    # TODO(nathaniel): squeeze this back into a lambda expression in
+    # the call to setRowAction below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=e)
+
+      return self.data.redirect.urlOf(url_names.GCI_ORG_HOME)
 
     list_config = lists.ListConfiguration()
     list_config.addColumn('name', 'Name',
         lambda e, *args: e.name.strip())
     list_config.addSimpleColumn('link_id', 'Link ID', hidden=True)
-    list_config.setRowAction(
-        lambda e, *args: r.organization(e).urlOf(url_names.GCI_ORG_HOME))
+    list_config.setRowAction(RowAction)
     list_config.addColumn(
         'ideas', 'Ideas',
         (lambda e, *args: url_helper.urlize(e.ideas, name="[ideas page]")),
@@ -66,7 +66,7 @@
     return query
 
 
-class AcceptedOrgsPage(RequestHandler):
+class AcceptedOrgsPage(GCIRequestHandler):
   """View for the accepted organizations page.
   """
 
@@ -107,14 +107,19 @@
         self.data.program.name)
 
   def _getListConfig(self):
-    r = self.data.redirect
+    # TODO(nathaniel): squeeze this back into a lambda expression in the
+    # call to setRowAction below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=e)
+
+      return self.data.redirect.urlOf(url_names.GCI_ORG_HOME)
 
     list_config = lists.ListConfiguration()
     list_config.addColumn('name', 'Name',
         lambda e, *args: e.name.strip())
     list_config.addSimpleColumn('link_id', 'Link ID', hidden=True)
-    list_config.setRowAction(
-        lambda e, *args: r.organization(e).urlOf(url_names.GCI_ORG_HOME))
+    list_config.setRowAction(RowAction)
     list_config.setDefaultPagination(False)
     list_config.setDefaultSort('name')
     list_config.addColumn(
@@ -140,7 +145,7 @@
     return query
 
 
-class AcceptedOrgsAdminPage(RequestHandler):
+class AcceptedOrgsAdminPage(GCIRequestHandler):
   """View for the accepted organizations page for admin with additional info.
   """
 
diff --git a/app/soc/modules/gci/views/admin.py b/app/soc/modules/gci/views/admin.py
index 0334ded..3b2281a 100644
--- a/app/soc/modules/gci/views/admin.py
+++ b/app/soc/modules/gci/views/admin.py
@@ -32,7 +32,7 @@
 
 from soc.modules.gci.models.profile import GCIProfile
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -77,7 +77,7 @@
     self.cleaned_data['profile'] = q.get()
 
 
-class DashboardPage(RequestHandler):
+class DashboardPage(GCIRequestHandler):
   """Dashboard for admins.
   """
 
@@ -229,13 +229,6 @@
             'title': 'List of documents',
             'link': r.urlOf('list_gci_documents')
         },
-        {
-            'name': 'students_info',
-            'description': ugettext(
-                'Details of students participating in the current program.'),
-            'title': 'Details of students',
-            'link': r.urlOf(url_names.GCI_STUDENTS_INFO) 
-        },
     ]
 
     super(ProgramSettingsDashboard, self).__init__(request, data, subpages)
@@ -362,6 +355,13 @@
             'title': 'List students',
             'link': r.urlOf(url_names.GCI_STUDENTS_INFO)
         },
+        {
+            'name': 'leaderboard',
+            'description': ugettext(
+                'Leaderboard for the program'),
+            'title': 'Leaderboard',
+            'link': r.urlOf(url_names.GCI_LEADERBOARD)
+        },
     ]
 
     super(ParticipantsDashboard, self).__init__(request, data, subpages)
@@ -384,7 +384,7 @@
     }
 
 
-class LookupLinkIdPage(RequestHandler):
+class LookupLinkIdPage(GCIRequestHandler):
   """View for the participant profile.
   """
 
@@ -428,4 +428,3 @@
       'posted': error,
       'page_name': 'Lookup profile',
     }
-
diff --git a/app/soc/modules/gci/views/age_check.py b/app/soc/modules/gci/views/age_check.py
index 080296c..6b45518 100644
--- a/app/soc/modules/gci/views/age_check.py
+++ b/app/soc/modules/gci/views/age_check.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI age check.
-"""
-
+"""Module for the GCI age check."""
 
 from django import forms
 
@@ -25,7 +21,7 @@
 from soc.views.helper import url_patterns
 
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper.url_patterns import url
 
 
@@ -42,7 +38,7 @@
       required=True)
 
 
-class AgeCheck(RequestHandler):
+class AgeCheck(GCIRequestHandler):
   """View for the GCI age check.
   """
 
@@ -109,4 +105,7 @@
       self.response.set_cookie('age_check', '0')
 
     # redirect to the same page and have the cookies sent across
-    self.redirect.program().to('gci_age_check')
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.redirect.program()
+
+    self.redirect.to('gci_age_check')
diff --git a/app/soc/modules/gci/views/all_tasks.py b/app/soc/modules/gci/views/all_tasks.py
index 78750f8..adf65b8 100644
--- a/app/soc/modules/gci/views/all_tasks.py
+++ b/app/soc/modules/gci/views/all_tasks.py
@@ -22,9 +22,9 @@
 from soc.views.helper import url_patterns
 
 from soc.modules.gci.logic import task as task_logic
-from soc.modules.gci.models.task import CLAIMABLE
 from soc.modules.gci.templates.task_list import TaskList
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
+from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
 
@@ -32,7 +32,8 @@
   """Template for list of all tasks which are claimable for the program.
   """
 
-  _LIST_COLUMNS = ['title', 'organization', 'mentors', 'status']
+  _LIST_COLUMNS = ['title', 'organization', 'tags', 'types',
+                   'mentors', 'status']
 
   def __init__(self, request, data):
     super(AllTasksList, self).__init__(request, data)
@@ -47,7 +48,7 @@
     return task_logic.queryClaimableTasksForProgram(self.data.program)
 
 
-class TaskListPage(RequestHandler):
+class TaskListPage(GCIRequestHandler):
   """View for the list task page.
   """
 
@@ -59,7 +60,7 @@
   def djangoURLPatterns(self):
     return [
         url(r'tasks/%s$' % url_patterns.PROGRAM, self,
-            name='gci_list_tasks'),
+            name=url_names.GCI_ALL_TASKS_LIST),
     ]
 
   def checkAccess(self):
diff --git a/app/soc/modules/gci/views/base.py b/app/soc/modules/gci/views/base.py
index 45904b5..943a5fb 100644
--- a/app/soc/modules/gci/views/base.py
+++ b/app/soc/modules/gci/views/base.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,26 +12,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the boiler plate required to construct GCI views.
-"""
+"""Module containing the boiler plate required to construct GCI views."""
 
+import httplib
 
-from soc.views.base import RequestHandler
+from django import http
+
+from soc.views import base
 
 from soc.modules.gci.views import base_templates
 from soc.modules.gci.views.helper import access_checker
-from soc.modules.gci.views.helper.request_data import RequestData
-from soc.modules.gci.views.helper.request_data import RedirectHelper
+from soc.modules.gci.views.helper import request_data
 
 
-class RequestHandler(RequestHandler):
-  """Customization required by GCI to handle HTTP requests.
-  """
+class GCIRequestHandler(base.RequestHandler):
+  """Customization required by GCI to handle HTTP requests."""
 
   def render(self, template_path, context):
     """Renders the page using the specified context.
 
-    See soc.views.base.RequestHandler.
+    See soc.views.base.RequestHandler for specification.
 
     The context object is extended with the following values:
       base_layout: path to the base template.
@@ -47,11 +45,11 @@
     context['header'] = base_templates.Header(self.data)
     context['mainmenu'] = base_templates.MainMenu(self.data)
     context['footer'] = base_templates.Footer(self.data)
-    super(RequestHandler, self).render(template_path, context)
+    return super(GCIRequestHandler, self).render(template_path, context)
 
   def init(self, request, args, kwargs):
-    self.data = RequestData()
-    self.redirect = RedirectHelper(self.data, self.response)
+    self.data = request_data.RequestData()
+    self.redirect = request_data.RedirectHelper(self.data, self.response)
     self.data.populate(self.redirect, request, args, kwargs)
     if self.data.is_developer:
       self.mutator = access_checker.DeveloperMutator(self.data)
@@ -59,19 +57,22 @@
     else:
       self.mutator = access_checker.Mutator(self.data)
       self.check = access_checker.AccessChecker(self.data)
-    super(RequestHandler, self).init(request, args, kwargs)
+    super(GCIRequestHandler, self).init(request, args, kwargs)
 
   def error(self, status, message=None):
+    """See base.RequestHandler.error for specification."""
     if not self.data.program:
-      return super(RequestHandler, self).error(status, message)
+      return super(GCIRequestHandler, self).error(status, message)
 
-    self.response.set_status(status, message=message)
+    # If message is not set, set it to the default associated with the
+    # given status (such as "Method Not Allowed" or "Service Unavailable").
+    message = message or httplib.responses.get(status, '')
 
-    template_path = "v2/modules/gci/error.html"
+    template_path = 'v2/modules/gci/error.html'
     context = {
-        'page_name': self.response.content,
-        'message': self.response.content,
+        'page_name': message,
+        'message': message,
     }
 
-    self.response.content = ''
-    self.render(template_path, context)
+    return http.HttpResponse(
+        content=self.render(template_path, context), status=status)
diff --git a/app/soc/modules/gci/views/base_templates.py b/app/soc/modules/gci/views/base_templates.py
index fb9ae20..492d5a2 100644
--- a/app/soc/modules/gci/views/base_templates.py
+++ b/app/soc/modules/gci/views/base_templates.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,7 +14,6 @@
 
 """This module contains the view for the site menus."""
 
-
 import datetime
 
 from google.appengine.api import users
@@ -62,7 +59,9 @@
     context['dashboard_link'] = redirect.dashboard().url()
 
   if data.timeline.tasksPubliclyVisible():
-    context['tasks_link'] = redirect.program().urlOf('gci_list_tasks')
+    # TODO(nathaniel): make this .program() call unnecessary.
+    redirect.program()
+    context['tasks_link'] = redirect.urlOf('gci_list_tasks')
     if not data.user:
       context['register_as_student_link'] = redirect.createProfile(
           'student').urlOf('create_gci_profile', secure=True)
diff --git a/app/soc/modules/gci/views/bulk_create.py b/app/soc/modules/gci/views/bulk_create.py
index d1c5478..2fdf0fd 100644
--- a/app/soc/modules/gci/views/bulk_create.py
+++ b/app/soc/modules/gci/views/bulk_create.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI view to bulk create GCITasks.
-"""
-
+"""Module for the GCI view to bulk create GCITasks."""
 
 from django import forms
 
@@ -25,7 +21,7 @@
 from soc.modules.gci.models.bulk_create_data import GCIBulkCreateData
 from soc.modules.gci.tasks import bulk_create
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -43,7 +39,7 @@
                               widget=forms.Textarea)
 
 
-class BulkCreate(RequestHandler):
+class BulkCreate(GCIRequestHandler):
   """View for bulk creation of GCITasks.
   """
 
@@ -97,5 +93,7 @@
         form.cleaned_data['task_data'], self.data.organization,
         self.data.profile)
 
-    self.redirect.organization(self.data.organization)
+    # TODO(nathaniel): make this .organization call unnecessary.
+    self.redirect.organization(organization=self.data.organization)
+
     self.redirect.to(url_names.GCI_TASK_BULK_CREATE, validated=True)
diff --git a/app/soc/modules/gci/views/dashboard.py b/app/soc/modules/gci/views/dashboard.py
index dd39a31..f2ff3bc 100644
--- a/app/soc/modules/gci/views/dashboard.py
+++ b/app/soc/modules/gci/views/dashboard.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,8 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI participant dashboard.
-"""
+"""Module for the GCI participant dashboard."""
 
 import logging
 
@@ -40,7 +37,7 @@
 from soc.modules.gci.models.task import CLAIMABLE
 from soc.modules.gci.models.task import GCITask
 from soc.modules.gci.models.task import UNPUBLISHED
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -107,7 +104,7 @@
     }
 
 
-class DashboardPage(RequestHandler):
+class DashboardPage(GCIRequestHandler):
   """View for the participant dashboard.
   """
 
@@ -892,9 +889,15 @@
             'organization you will create the task for.')}
 
   def _setRowAction(self, request, data):
-    self._list_config.setRowAction(
-        lambda e, *args: data.redirect.organization(e).
-            urlOf('gci_create_task'))
+    # TODO(nathaniel): squeeze this back into a lambda expression in the
+    # setRowAction call below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      data.redirect.organization(organization=e)
+
+      return data.redirect.urlOf('gci_create_task')
+
+    self._list_config.setRowAction(RowAction)
 
 
 class MyOrgsListBeforeBulkCreateTask(MyOrgsList):
@@ -918,9 +921,15 @@
             'organization you will upload the tasks for.')}
 
   def _setRowAction(self, request, data):
-    self._list_config.setRowAction(
-        lambda e, *args: data.redirect.organization(e).
-            urlOf(url_names.GCI_TASK_BULK_CREATE))
+    # TODO(nathaniel): squeeze this back into a lambda expression in the
+    # setRowAction call below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      data.redirect.organization(organization=e)
+
+      return data.redirect.urlOf(url_names.GCI_TASK_BULK_CREATE)
+
+    self._list_config.setRowAction(RowAction)
 
 
 class MyOrgsListBeforeInviteMentor(MyOrgsList):
@@ -987,9 +996,15 @@
     self.idx = 12
 
   def _setRowAction(self, request, data):
-    self._list_config.setRowAction(
-        lambda e, *args: data.redirect.organization(e)
-            .urlOf(url_names.GCI_ORG_SCORES))
+    # TODO(nathaniel): squeeze this back into a lambda expression in the
+    # call to setRowAction below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      data.redirect.organization(organization=e)
+
+      return data.redirect.urlOf(url_names.GCI_ORG_SCORES)
+
+    self._list_config.setRowAction(RowAction)
 
   def getListData(self):
     if lists.getListIndex(self.request) != self.idx:
@@ -1096,9 +1111,15 @@
             'organization you will edit the profile for.')}
 
   def _setRowAction(self, request, data):
-    self._list_config.setRowAction(
-        lambda e, *args: data.redirect.organization(e).
-            urlOf(url_names.EDIT_GCI_ORG_PROFILE, secure=True))
+    # TODO(nathaniel): squeeze this back into a lambda expression in the
+    # call to setRowAction below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      data.redirect.organization(organization=e)
+
+      return data.redirect.urlOf(url_names.EDIT_GCI_ORG_PROFILE, secure=True)
+
+    self._list_config.setRowAction(RowAction)
 
 
 class AllOrgsListBeforeRequestRole(MyOrgsList):
diff --git a/app/soc/modules/gci/views/delete_account.py b/app/soc/modules/gci/views/delete_account.py
index 019d25c..b71b4fc 100644
--- a/app/soc/modules/gci/views/delete_account.py
+++ b/app/soc/modules/gci/views/delete_account.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,19 +12,17 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI delete account page.
-"""
-
+"""Module for the GCI delete account page."""
 
 from soc.logic import delete_account
 
 from soc.views.helper import url_patterns
 
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views import base
 from soc.modules.gci.views.helper.url_patterns import url
 
 
-class DeleteAccountPage(RequestHandler):
+class DeleteAccountPage(base.GCIRequestHandler):
   """View for the GCI delete account page.
   """
 
@@ -49,4 +45,6 @@
 
   def post(self):
     delete_account.request_account_deletion(self.data.user)
-    self.redirect.program().to('gci_delete_account', validated=True)
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.redirect.program()
+    self.redirect.to('gci_delete_account', validated=True)
diff --git a/app/soc/modules/gci/views/document.py b/app/soc/modules/gci/views/document.py
index 7eb857f..7d61488 100644
--- a/app/soc/modules/gci/views/document.py
+++ b/app/soc/modules/gci/views/document.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GCI documents page.
-"""
-
+"""Module containing the views for GCI documents page."""
 
 from soc.logic.exceptions import AccessViolation
 from soc.models.document import Document
@@ -25,7 +21,7 @@
 from soc.views.helper.access_checker import isSet
 from soc.views.template import Template
 
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.forms import GCIModelForm
 #from soc.modules.gci.views.base_templates import ProgramSelect
 from soc.modules.gci.views.helper.url_patterns import url
@@ -44,7 +40,7 @@
     ]
 
 
-class EditDocumentPage(RequestHandler):
+class EditDocumentPage(GCIRequestHandler):
   """Encapsulate all the methods required to edit documents.
   """
 
@@ -91,7 +87,7 @@
       self.get()
 
 
-class DocumentPage(RequestHandler):
+class DocumentPage(GCIRequestHandler):
   """Encapsulate all the methods required to show documents.
   """
 
@@ -117,7 +113,7 @@
     }
 
 
-class EventsPage(RequestHandler):
+class EventsPage(GCIRequestHandler):
   """Encapsulates all the methods required to show the events page.
   """
 
@@ -153,7 +149,7 @@
     return 'v2/modules/gci/document/_document_list.html'
 
 
-class DocumentListPage(RequestHandler):
+class DocumentListPage(GCIRequestHandler):
   """View for the list documents page.
   """
 
diff --git a/app/soc/modules/gci/views/helper/url_names.py b/app/soc/modules/gci/views/helper/url_names.py
index 89776b2..a14d023 100644
--- a/app/soc/modules/gci/views/helper/url_names.py
+++ b/app/soc/modules/gci/views/helper/url_names.py
@@ -35,6 +35,8 @@
 GCI_ORG_CHOOSE_FOR_SCORE = 'gci_org_choose_for_score'
 GCI_ORG_TASKS_ALL = 'gci_org_tasks_all'
 
+GCI_ALL_TASKS_LIST = 'gci_list_tasks'
+
 GCI_LEADERBOARD = 'gci_leaderboard'
 GCI_STUDENT_TASKS = 'gci_student_tasks'
 GCI_STUDENT_TASKS_FOR_ORG = 'gci_student_tasks_for_org'
diff --git a/app/soc/modules/gci/views/homepage.py b/app/soc/modules/gci/views/homepage.py
index 286548c..0aaf40d 100644
--- a/app/soc/modules/gci/views/homepage.py
+++ b/app/soc/modules/gci/views/homepage.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GCI home page.
-"""
-
+"""Module containing the views for GCI home page."""
 
 from soc.views.helper import url_patterns
 from soc.views.template import Template
@@ -24,14 +20,13 @@
 from soc.modules.gci.logic import organization as org_logic
 from soc.modules.gci.logic import task as task_logic
 from soc.modules.gci.views import common_templates
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper.url_patterns import url
 from soc.modules.gci.views.helper import url_names
 
 
 class HowItWorks(Template):
-  """How it works template.
-  """
+  """How it works template."""
 
   CONTEST_BEGINS_ON_MSG = "Contest begins on %s %s"
 
@@ -41,30 +36,40 @@
     self.data = data
 
   def context(self):
-    r = self.data.redirect
     program = self.data.program
 
     from soc.modules.gci.models.program import GCIProgram
     about_page = GCIProgram.about_page.get_value_for_datastore(program)
 
     example_tasks_link = ''
+    all_tasks_link = ''
 
     main_text = self._getMainText()
 
     if self.data.timeline.orgSignup():
+      # TODO(nathaniel): make this .program() call unnecessary.
+      self.data.redirect.program()
+
       start_text = 'Sign up as organization'
-      start_link = r.program().urlOf('gci_take_org_app')
+      start_link = self.data.redirect.urlOf('gci_take_org_app')
       if self.data.program.example_tasks:
         example_tasks_link = self.data.program.example_tasks
     elif self.data.timeline.studentSignup() and not self.data.profile:
       start_text = 'Register As Student'
-      start_link = r.createProfile('student').urlOf('create_gci_profile',
-          secure=True)
-      if self.data.program.example_tasks:
-        example_tasks_link = self.data.program.example_tasks
+
+      start_link = self.data.redirect.createProfile('student').urlOf(
+          'create_gci_profile', secure=True)
+
+      # TODO(nathaniel): make this .program() call unnecessary.
+      self.data.redirect.program()
+
+      all_tasks_link = self.data.redirect.urlOf(url_names.GCI_ALL_TASKS_LIST)
     elif self.data.timeline.tasksPubliclyVisible():
+      # TODO(nathaniel): make this .program() call unnecessary.
+      self.data.redirect.program()
+
       start_text = 'Search for tasks'
-      start_link = self.data.redirect.program().urlOf('gci_list_tasks')
+      start_link = self.data.redirect.urlOf('gci_list_tasks')
     elif self.data.program.example_tasks:
       start_text = 'See example tasks'
       start_link = self.data.program.example_tasks
@@ -72,10 +77,11 @@
       start_text = start_link = ''
 
     return {
-        'about_link': r.document(about_page).url(),
+        'about_link': self.data.redirect.document(about_page).url(),
         'start_text': start_text,
         'start_link': start_link,
         'example_tasks_link': example_tasks_link,
+        'all_tasks_link': all_tasks_link,
         'main_text': main_text,
     }
 
@@ -123,14 +129,12 @@
     self.data = data
 
   def context(self):
-    r = self.data.redirect
-
     participating_orgs = []
     current_orgs = org_logic.participating(
         self.data.program, org_count=self._ORG_COUNT)
     for org in current_orgs:
       participating_orgs.append({
-          'link': r.orgHomepage(org.link_id).url(),
+          'link': self.data.redirect.orgHomepage(org.link_id).url(),
           'logo': org.logo_url,
           'name': org.short_name,
           })
@@ -147,12 +151,17 @@
         row, orgs = orgs[:self._TABLE_WIDTH], orgs[self._TABLE_WIDTH:]
         participating_orgs_table_rows.append(row)
 
-    accepted_orgs_url = r.program().urlOf('gci_accepted_orgs')
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.data.redirect.program()
+
+    accepted_orgs_url = self.data.redirect.urlOf('gci_accepted_orgs')
 
     return {
         'participating_orgs': participating_orgs,
         'participating_orgs_table_rows': participating_orgs_table_rows,
         'org_list_url': accepted_orgs_url,
+        'all_participating_orgs': (
+            self.data.program.nr_accepted_orgs <= len(participating_orgs)),
     }
 
   def templatePath(self):
@@ -160,16 +169,17 @@
 
 
 class Leaderboard(Template):
-  """Leaderboard template.
-  """
+  """Leaderboard template."""
 
   def __init__(self, data):
     self.data = data
 
   def context(self):
-    r = self.data.redirect
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.data.redirect.program()
+
     return {
-        'leaderboard_url': r.program().urlOf(url_names.GCI_LEADERBOARD),
+        'leaderboard_url': self.data.redirect.urlOf(url_names.GCI_LEADERBOARD),
     }
 
   def templatePath(self):
@@ -192,7 +202,7 @@
     return "v2/modules/gci/homepage/_connect_with_us.html"
 
 
-class Homepage(RequestHandler):
+class Homepage(GCIRequestHandler):
   """Encapsulate all the methods required to generate GCI Home page.
   """
 
diff --git a/app/soc/modules/gci/views/invite.py b/app/soc/modules/gci/views/invite.py
index abdf17f..8fc1004 100644
--- a/app/soc/modules/gci/views/invite.py
+++ b/app/soc/modules/gci/views/invite.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the view for GCI invitation page.
-"""
-
+"""Module containing the view for GCI invitation page."""
 
 import logging
 
@@ -46,7 +42,7 @@
 from soc.modules.gci.models.request import GCIRequest
 
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -82,7 +78,7 @@
     self.fields.insert(0, 'identifiers', field)
     field.help_text = ugettext(
         "Comma separated usernames or emails of the people to invite.")
-    
+
   def clean_identifiers(self):
     """Accepts link_ids or email addresses of users which may be invited.
     """
@@ -165,7 +161,7 @@
     query.filter('role', self.request_data.kwargs['role'])
     query.filter('org', self.request_data.organization)
     return query
-  
+
   def _getProfile(self, user_to_invite):
     key_name = '/'.join([
         self.request_data.program.key().name(), user_to_invite.link_id])
@@ -182,7 +178,7 @@
     fields = ['message']
 
 
-class InvitePage(RequestHandler):
+class InvitePage(GCIRequestHandler):
   """Encapsulate all the methods required to generate Invite page.
   """
 
@@ -227,7 +223,7 @@
     assert isSet(self.data.organization)
 
     invite_form = InviteForm(self.data, self.data.POST)
-    
+
     if not invite_form.is_valid():
       return False
 
@@ -264,7 +260,7 @@
     self.redirect.dashboard().to()
 
 
-class ManageInvite(RequestHandler):
+class ManageInvite(GCIRequestHandler):
   """View to manage the invitation by organization admins.
   """
 
@@ -358,7 +354,7 @@
     return GCIProfile.get_by_key_name(key_name, parent=self.data.invited_user)
 
 
-class RespondInvite(RequestHandler):
+class RespondInvite(GCIRequestHandler):
   """View to respond to the invitation by the user.
   """
 
@@ -453,7 +449,7 @@
     return 'v2/modules/gci/invite/_invite_list.html'
 
 
-class ListUserInvitesPage(RequestHandler):
+class ListUserInvitesPage(GCIRequestHandler):
   """View for the page that lists all the invites which have been sent to
   the current user.
   """
diff --git a/app/soc/modules/gci/views/leaderboard.py b/app/soc/modules/gci/views/leaderboard.py
index d89e2fe..1bef7ae 100644
--- a/app/soc/modules/gci/views/leaderboard.py
+++ b/app/soc/modules/gci/views/leaderboard.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -13,8 +11,8 @@
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 # See the License for the specific language governing permissions and
 # limitations under the License.
-"""Module containing the view for GCI leaderboard page.
-"""
+
+"""Module containing the view for GCI leaderboard page."""
 
 from soc.logic.exceptions import AccessViolation
 
@@ -28,7 +26,7 @@
 
 from soc.modules.gci.templates.task_list import TaskList
 from soc.modules.gci.views import common_templates
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -112,7 +110,7 @@
     return task_logic.queryAllTasksClosedByStudent(self.data.url_profile)
 
 
-class LeaderboardPage(RequestHandler):
+class LeaderboardPage(GCIRequestHandler):
   """View for the leaderboard page.
   """
 
@@ -126,7 +124,7 @@
     ]
 
   def checkAccess(self):
-    pass
+    self.check.isHost()
 
   def jsonContext(self):
     list_content = LeaderboardList(self.request, self.data).getListData()
@@ -152,7 +150,7 @@
     return context
 
 
-class StudentTasksPage(RequestHandler):
+class StudentTasksPage(GCIRequestHandler):
   """View for the list of all the tasks closed by the specified student.
   """
 
@@ -166,10 +164,16 @@
     ]
 
   def checkAccess(self):
-    pass
+    self.mutator.studentFromKwargs()
+    try:
+      self.check.isHost()
+    except AccessViolation:
+      self.check.hasProfile()
+      # check if the profile in URL kwargs is the current profile
+      if self.data.profile.key() != self.data.url_profile.key():
+        raise AccessViolation('You do not have access to this data')
 
   def jsonContext(self):
-    self.mutator.studentFromKwargs()
     list_content = AllStudentTasksList(self.request, self.data).getListData()
 
     if not list_content:
@@ -178,7 +182,6 @@
     return list_content.content()
 
   def context(self):
-    self.mutator.studentFromKwargs()
     return {
         'page_name': "Tasks closed by %s" % self.data.url_profile.name(),
         'tasks_list': AllStudentTasksList(self.request, self.data),
diff --git a/app/soc/modules/gci/views/moderate_delete_account.py b/app/soc/modules/gci/views/moderate_delete_account.py
new file mode 100644
index 0000000..c8932ab
--- /dev/null
+++ b/app/soc/modules/gci/views/moderate_delete_account.py
@@ -0,0 +1,60 @@
+# Copyright 2011 the Melange authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Module for the GCI delete account page."""
+
+from soc.logic import delete_account
+
+from soc.views.helper import url_patterns
+
+from soc.modules.gci.logic import profile as profile_logic
+from soc.modules.gci.views import base
+from soc.modules.gci.views.helper.url_patterns import url
+
+
+class ModerateDeleteAccountPage(base.GCIRequestHandler):
+  """View for the GCI delete account page.
+  """
+
+  def templatePath(self):
+    return 'v2/modules/gci/moderate_delete_account/base.html'
+
+  def djangoURLPatterns(self):
+    return [
+        url(r'admin/delete_account/%s$' % url_patterns.PROFILE,
+            self, name='gci_moderate_delete_account')
+    ]
+
+  def checkAccess(self):
+    self.check.isHost()
+
+    self.mutator.profileFromKwargs()
+
+  def context(self):
+    profile = self.data.url_profile
+
+    return {
+        'page_name': 'Moderate delete account requests',
+        'profile': profile,
+        'has_tasks': profile_logic.hasTasks(profile),
+        'has_created_or_modified_tasks': profile_logic.hasCreatedOrModifiedTask(
+            profile),
+        'has_task_comments': profile_logic.hasTaskComments(profile),
+        'has_other_gci_profiles': profile_logic.hasOtherGCIProfiles(profile),
+        'has_other_gsoc_profiles': profile_logic.hasOtherGSoCProfiles(profile),
+        }
+
+  def post(self):
+    delete_account.confirm_delete(self.data.url_profile)
+    self.redirect.program().to('gci_moderate_delete_account', validated=True)
diff --git a/app/soc/modules/gci/views/org_app.py b/app/soc/modules/gci/views/org_app.py
index 0bc48a2..9a71999 100644
--- a/app/soc/modules/gci/views/org_app.py
+++ b/app/soc/modules/gci/views/org_app.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI Organization application.
-"""
-
+"""Module for the GCI Organization application."""
 
 import logging
 
@@ -32,12 +28,12 @@
 
 from soc.logic import org_app as org_app_logic
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
 
-class GCIOrgAppEditPage(RequestHandler):
+class GCIOrgAppEditPage(GCIRequestHandler):
   """View for creating/editing organization application.
   """
 
@@ -66,9 +62,12 @@
     else:
       page_name = 'Create new organization application'
 
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.redirect.program()
+
     context = {
         'page_name': page_name,
-        'post_url': self.redirect.program().urlOf('gci_edit_org_app'),
+        'post_url': self.redirect.urlOf('gci_edit_org_app'),
         'forms': [form],
         'error': bool(form.errors),
         }
@@ -105,13 +104,15 @@
   def post(self):
     org_app = self.orgAppFromForm()
     if org_app:
-      r = self.redirect.program()
-      r.to('gci_edit_org_app', validated=True)
+      # TODO(nathaniel): make unnecessary this .program() call.
+      self.redirect.program()
+
+      self.redirect.to('gci_edit_org_app', validated=True)
     else:
       self.get()
 
 
-class GCIOrgAppPreviewPage(RequestHandler):
+class GCIOrgAppPreviewPage(GCIRequestHandler):
   """View for organizations to submit their application.
   """
 
@@ -141,7 +142,7 @@
     return context
 
 
-class GCIOrgAppTakePage(RequestHandler):
+class GCIOrgAppTakePage(GCIRequestHandler):
   """View for organizations to submit their application.
   """
 
@@ -161,7 +162,11 @@
     # FIXME: There will never be organization in kwargs
     show_url = None
     if 'organization' in self.kwargs:
-      show_url = self.data.redirect.organization().urlOf('gci_show_org_app')
+      # TODO(nathaniel): make this .organization() call unnecessary. Like,
+      # more than it already is (see the note above).
+      self.data.redirect.organization()
+
+      show_url = self.data.redirect.urlOf('gci_show_org_app')
 
     self.check.isSurveyActive(self.data.org_app, show_url)
 
@@ -229,12 +234,12 @@
       self.get()
 
 
-class GCIOrgAppRecordsList(org_app.OrgAppRecordsList, RequestHandler):
+class GCIOrgAppRecordsList(org_app.OrgAppRecordsList, GCIRequestHandler):
   """View for listing all records of a GCI Organization application.
   """
 
   def __init__(self, *args, **kwargs):
-    RequestHandler.__init__(self, *args, **kwargs)
+    GCIRequestHandler.__init__(self, *args, **kwargs)
     org_app.OrgAppRecordsList.__init__(self, 'gci_show_org_app')
 
   def djangoURLPatterns(self):
@@ -290,15 +295,13 @@
 
 
 class OrgAppReadOnlyTemplate(org_app.OrgAppReadOnlyTemplate):
-  """Template to construct readonly organization application record.
-  """
+  """Template to construct readonly organization application record."""
 
   template_path = 'v2/modules/gci/org_app/readonly_template.html'
 
 
-class GCIOrgAppShowPage(RequestHandler):
-  """View to display the readonly page for organization application.
-  """
+class GCIOrgAppShowPage(GCIRequestHandler):
+  """View to display the readonly page for organization application."""
 
   def djangoURLPatterns(self):
     return [
diff --git a/app/soc/modules/gci/views/org_home.py b/app/soc/modules/gci/views/org_home.py
index 5463568..5bb4ae9 100644
--- a/app/soc/modules/gci/views/org_home.py
+++ b/app/soc/modules/gci/views/org_home.py
@@ -12,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the Org Homepage view.
-"""
-
+"""Module containing the Org Homepage view."""
 
 from django.utils.translation import ugettext
 
@@ -29,17 +27,17 @@
 from soc.modules.gci.models.organization import GCIOrganization
 from soc.modules.gci.models.task import CLAIMABLE
 from soc.modules.gci.models.task import GCITask
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper.url_patterns import url
 from soc.modules.gci.views.helper import url_names
 
 
 class AboutUs(Template):
-  """About us template.
-  """
+  """About us template."""
+
   def __init__(self, data):
     self.data = data
-    
+
   def context(self):
     org = self.data.organization
     return {
@@ -48,14 +46,13 @@
         'homepage': org.home_page,
         'short_name': org.short_name,
     }
-  
+
   def templatePath(self):
     return 'v2/modules/gci/org_home/_about_us.html'
 
 
 class ContactUs(Template):
-  """Organization Contact template.
-  """
+  """Organization Contact template."""
 
   def __init__(self, data):
     self.data = data
@@ -70,13 +67,13 @@
 
 
 class OpenTasksList(Template):
-  """List to display all the open tasks for the current organization.
-  """
+  """List to display all the open tasks for the current organization."""
+
   def __init__(self, request, data):
     self.request = request
     self.data = data
     list_config = lists.ListConfiguration()
-    
+
     list_config.addSimpleColumn('title', 'Title')
     #list_config.addColumn(
     #    'task_type', 'Type',
@@ -87,12 +84,12 @@
                           lambda entity, *args: entity.taskTimeToComplete())
     list_config.addColumn('types', 'Type',
                           lambda entity, *args: ", ".join(entity.types))
-    
+
     list_config.setRowAction(
         lambda e, *args: data.redirect.id(e.key().id()).urlOf(url_names.GCI_VIEW_TASK))
 
     self.list_config = list_config
-  
+
   def context(self):
     description = 'List of all Open tasks.'
     list = lists.ListConfigurationResponse(
@@ -100,7 +97,7 @@
     return {
         'lists': [list],
     }
-  
+
   def getListData(self):
     if lists.getListIndex(self.request) != 0:
       return None
@@ -112,30 +109,30 @@
     response_builder = lists.RawQueryContentResponseBuilder(
         self.request, self.list_config, q, starter)
     return response_builder.build()
-  
+
   def templatePath(self):
     return 'v2/modules/gci/org_home/_open_tasks.html'
 
 class CompletedTasksList(Template):
-  """List to display all the closed/completed tasks for the current organization.
-  """
+  """List to display all the closed/completed tasks for the current organization."""
+
   def __init__(self, request, data):
     self.request = request
     self.data = data
-    
+
     list_config = lists.ListConfiguration()
-    
+
     list_config.addSimpleColumn('title', 'Title')
     list_config.addColumn('student', 'Student',
                           lambda entity, *args: entity.student.name())
     list_config.addColumn('types', 'Type',
                           lambda entity, *args: ", ".join(entity.types))
-    
+
     list_config.setRowAction(
         lambda e, *args: data.redirect.id(e.key().id()).urlOf(url_names.GCI_VIEW_TASK))
 
     self.list_config = list_config
-  
+
   def context(self):
     description = 'List of all Completed tasks.'
     list = lists.ListConfigurationResponse(
@@ -143,7 +140,7 @@
     return {
         'lists': [list],
     }
-  
+
   def getListData(self):
     if lists.getListIndex(self.request) != 1:
       return None
@@ -155,14 +152,13 @@
     response_builder = lists.RawQueryContentResponseBuilder(
         self.request, self.list_config, q, starter)
     return response_builder.build()
-  
+
   def templatePath(self):
     return 'v2/modules/gci/org_home/_closed_tasks.html'
 
 
-class GCIBanOrgPost(BanOrgPost, RequestHandler):
-  """Handles banning/unbanning of GCI organizations.
-  """
+class GCIBanOrgPost(BanOrgPost, GCIRequestHandler):
+  """Handles banning/unbanning of GCI organizations."""
 
   def _getModulePrefix(self):
     return 'gci'
@@ -178,9 +174,8 @@
 
 
 class GCIHostActions(HostActions):
-  """Template to render the left side host actions.
-  """
-  
+  """Template to render the left side host actions."""
+
   DEF_BAN_ORGANIZATION_HELP = ugettext(
       'When an organization is banned, students cannot work on their tasks')
 
@@ -191,9 +186,9 @@
     return self.DEF_BAN_ORGANIZATION_HELP
 
 
-class OrgHomepage(RequestHandler):
-  """Encapsulates all the methods required to render the org homepage.
-  """
+class OrgHomepage(GCIRequestHandler):
+  """Encapsulates all the methods required to render the org homepage."""
+
   def templatePath(self):
     return 'v2/modules/gci/org_home/base.html'
 
diff --git a/app/soc/modules/gci/views/org_profile.py b/app/soc/modules/gci/views/org_profile.py
index 8da06a1..f8d1184 100644
--- a/app/soc/modules/gci/views/org_profile.py
+++ b/app/soc/modules/gci/views/org_profile.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,15 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI organization profile page.
-"""
-
+"""Module for the GCI organization profile page."""
 
 from soc.views.helper import url_patterns
 from soc.views import org_profile
 
 from soc.modules.gci.models.organization import GCIOrganization
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views import forms as gci_forms
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
@@ -31,9 +27,9 @@
     'task_quota_limit',
 ]
 
+
 class OrgProfileForm(org_profile.OrgProfileForm):
-  """Django form for the organization profile.
-  """
+  """Django form for the organization profile."""
 
   def __init__(self, *args, **kwargs):
     super(OrgProfileForm, self).__init__(
@@ -49,8 +45,7 @@
 
 
 class OrgCreateProfileForm(OrgProfileForm):
-  """Django form to create the organization profile.
-  """
+  """Django form to create the organization profile."""
 
   class Meta:
     model = GCIOrganization
@@ -58,9 +53,8 @@
     exclude = PROFILE_EXCLUDE
 
 
-class OrgProfilePage(RequestHandler):
-  """View for the Organization Profile page.
-  """
+class OrgProfilePage(GCIRequestHandler):
+  """View for the Organization Profile page."""
 
   def djangoURLPatterns(self):
     return [
@@ -102,15 +96,18 @@
         }
 
     if self.data.organization:
-      r = self.data.redirect.organization()
-      context['org_home_page_link'] = r.urlOf('gci_org_home')
+      # TODO(nathaniel): make this .organization() call unnecessary.
+      self.data.redirect.organization()
+      context['org_home_page_link'] = self.data.redirect.urlOf('gci_org_home')
 
     return context
 
   def post(self):
     org_profile = self.createOrgProfileFromForm()
     if org_profile:
-      self.redirect.organization(org_profile)
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.redirect.organization(organization=org_profile)
+
       self.redirect.to('edit_gci_org_profile', validated=True)
     else:
       self.get()
@@ -121,7 +118,6 @@
     Returns:
       a newly created organization entity or None
     """
-
     if self.data.organization:
       form = OrgProfileForm(self.data.POST, instance=self.data.organization)
     else:
@@ -134,7 +130,7 @@
       org_id = self.data.GET['org_id']
       form.cleaned_data['founder'] = self.data.user
       form.cleaned_data['scope'] = self.data.program
-      form.cleaned_data['scope_path'] = self.data.program.key().name() 
+      form.cleaned_data['scope_path'] = self.data.program.key().name()
       form.cleaned_data['link_id'] = org_id
       key_name = '%s/%s' % (self.data.program.key().name(), org_id)
       entity = form.create(key_name=key_name)
diff --git a/app/soc/modules/gci/views/org_score.py b/app/soc/modules/gci/views/org_score.py
index 320dae8..73061a0 100644
--- a/app/soc/modules/gci/views/org_score.py
+++ b/app/soc/modules/gci/views/org_score.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2012 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI organization score page.
-"""
-
+"""Module for the GCI organization score page."""
 
 from soc.logic import exceptions
 from soc.views.helper import lists
@@ -25,7 +21,7 @@
 
 from soc.modules.gci.models.score import GCIOrgScore
 from soc.modules.gci.templates.org_list import BasicOrgList
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -88,7 +84,7 @@
     return 'v2/modules/gci/leaderboard/_leaderboard_list.html'
 
 
-class OrgScoresForOrgzanizationPage(RequestHandler):
+class OrgScoresForOrgzanizationPage(GCIRequestHandler):
   """View for the organizations scores page.
   """
 
@@ -106,7 +102,7 @@
 
   def context(self):
     return {
-        'page_name': "Organization scores for %s" % 
+        'page_name': "Organization scores for %s" %
             self.data.organization.name,
         'org_scores_list': OrgScoresList(self.request, self.data),
     }
@@ -130,12 +126,14 @@
 
   def _getRedirect(self):
     def redirect(e, *args):
-      r = self.data.redirect
-      return r.organization(e).urlOf(url_names.GCI_ORG_SCORES)
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=e)
+
+      return self.data.redirect.urlOf(url_names.GCI_ORG_SCORES)
     return redirect
 
 
-class ChooseOrganizationForOrgScorePage(RequestHandler):
+class ChooseOrganizationForOrgScorePage(GCIRequestHandler):
   """View with a list of organizations. When a user clicks on one of them,
   he or she is moved to the organization scores for this organization.
   """
diff --git a/app/soc/modules/gci/views/participants.py b/app/soc/modules/gci/views/participants.py
index d311574..8e42d33 100644
--- a/app/soc/modules/gci/views/participants.py
+++ b/app/soc/modules/gci/views/participants.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the view for GCI tasks list page.
-"""
-
+"""Module containing the view for GCI tasks list page."""
 
 from soc.logic.exceptions import AccessViolation
 from soc.views.helper import addresses
@@ -25,7 +21,7 @@
 from soc.views.template import Template
 
 from soc.modules.gci.models.profile import GCIProfile
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper.url_patterns import url
 
 
@@ -95,9 +91,8 @@
     return "v2/modules/gci/participants/_mentors_list.html"
 
 
-class MentorsListAdminPage(RequestHandler):
-  """View for the organization admin and mentors page for admin.
-  """
+class MentorsListAdminPage(GCIRequestHandler):
+  """View for the organization admin and mentors page for admin."""
 
   def templatePath(self):
     return 'v2/modules/gci/participants/base.html'
diff --git a/app/soc/modules/gci/views/profile.py b/app/soc/modules/gci/views/profile.py
index 88a1e64..a90a749 100644
--- a/app/soc/modules/gci/views/profile.py
+++ b/app/soc/modules/gci/views/profile.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GCI profile page.
-"""
-
+"""Module for the GCI profile page."""
 
 from django import forms as django_forms
 from django.core.urlresolvers import reverse
@@ -37,7 +33,7 @@
 from soc.modules.gci.models.profile import GCIProfile
 from soc.modules.gci.models.profile import GCIStudentInfo
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 
 
@@ -268,9 +264,8 @@
         model, ['school_country', 'school_type', 'degree'])
 
 
-class GCIProfilePage(profile.ProfilePage, RequestHandler):
-  """View for the GCI participant profile.
-  """
+class GCIProfilePage(profile.ProfilePage, GCIRequestHandler):
+  """View for the GCI participant profile."""
 
   def checkAccess(self):
     self.check.isProgramVisible()
@@ -317,7 +312,7 @@
     if 'delete_account' in self.data.POST:
       self.deleteAccountPostAction()
     else: # regular POST request
-      self.editProfilePostAction() 
+      self.editProfilePostAction()
 
   def deleteAccountPostAction(self):
     """Handler for Delete Account POST action.
@@ -326,19 +321,20 @@
     self.redirect.to('gci_delete_account', secure=True)
 
   def editProfilePostAction(self):
-    """Handler for regular (edit/create profile) POST action.
-    """
+    """Handler for regular (edit/create profile) POST action."""
     if not self.validate():
       self.get()
       return
 
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.redirect.program()
+
     org_id = self.data.GET.get('new_org')
 
     if org_id:
-      create_url = self.redirect.program().urlOf('create_gci_org_profile')
+      create_url = self.redirect.urlOf('create_gci_org_profile')
       raise RedirectRequest(create_url + '?org_id=' + org_id)
 
-    self.redirect.program()
     self.redirect.to(self._getEditProfileURLName(), validated=True, secure=True)
 
   def _getModulePrefix(self):
@@ -390,4 +386,3 @@
   def _getStudentInfoForm(self):
     return GCIStudentInfoForm(self.data.POST or None,
                               instance=self.data.student_info)
-
diff --git a/app/soc/modules/gci/views/profile_show.py b/app/soc/modules/gci/views/profile_show.py
index f1550c5..a73741c 100644
--- a/app/soc/modules/gci/views/profile_show.py
+++ b/app/soc/modules/gci/views/profile_show.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,10 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for displaying the GCI profile read-only page.
-"""
+"""Module for displaying the GCI profile read-only page."""
 
-
+import httplib
 import logging
 
 from django.utils import translation
@@ -30,7 +27,7 @@
 
 from soc.modules.gci.models.profile import GCIProfile
 from soc.modules.gci.views import readonly_template
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -86,9 +83,8 @@
               'tshirt_style', 'tshirt_size', 'gender', 'program_knowledge']
 
 
-class GCIProfileShowPage(profile_show.ProfileShowPage, RequestHandler):
-  """View to display the read-only profile page.
-  """
+class GCIProfileShowPage(profile_show.ProfileShowPage, GCIRequestHandler):
+  """View to display the read-only profile page."""
 
   def djangoURLPatterns(self):
     return [
@@ -155,11 +151,10 @@
     return context
 
   def post(self):
-    """Handles student form verification by host.
-    """
+    """Handles student form verification by host."""
     if not self.data.url_profile.student_info:
       logging.warn(NON_STUDENT_ERR_MSG)
-      self.error(405)
+      self.response = self.error(httplib.METHOD_NOT_ALLOWED)
       return
 
     post_data = self.data.POST
diff --git a/app/soc/modules/gci/views/program.py b/app/soc/modules/gci/views/program.py
index a46f3eb..d3cd001 100644
--- a/app/soc/modules/gci/views/program.py
+++ b/app/soc/modules/gci/views/program.py
@@ -29,7 +29,7 @@
 from soc.modules.gci.models.program import GCIProgram
 from soc.modules.gci.models.program import GCIProgramMessages
 from soc.modules.gci.models.timeline import GCITimeline
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.forms import GCIModelForm
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
@@ -86,9 +86,8 @@
     model = GCIProgramMessages
 
 
-class ProgramPage(RequestHandler):
-  """View for the program profile.
-  """
+class ProgramPage(GCIRequestHandler):
+  """View for the program profile."""
 
   def djangoURLPatterns(self):
     return [
@@ -145,7 +144,7 @@
       self.get()
 
 
-class TimelinePage(RequestHandler):
+class TimelinePage(GCIRequestHandler):
   """View for the participant profile."""
 
   def djangoURLPatterns(self):
@@ -192,7 +191,7 @@
 
 
 class GCIProgramMessagesPage(
-    program_view.ProgramMessagesPage, RequestHandler):
+    program_view.ProgramMessagesPage, GCIRequestHandler):
   """View for the content of GCI program specific messages to be sent."""
 
   def djangoURLPatterns(self):
diff --git a/app/soc/modules/gci/views/request.py b/app/soc/modules/gci/views/request.py
index 0406cbd..78c6c66 100644
--- a/app/soc/modules/gci/views/request.py
+++ b/app/soc/modules/gci/views/request.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the view for GCI request page.
-"""
-
+"""Module containing the view for GCI request page."""
 
 from google.appengine.ext import db
 
@@ -33,23 +29,21 @@
 from soc.modules.gci.models.profile import GCIProfile
 from soc.modules.gci.models.request import GCIRequest
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
 
 class RequestForm(gci_forms.GCIModelForm):
-  """Django form for the invite page.
-  """
+  """Django form for the invite page."""
 
   class Meta:
     model = GCIRequest
     css_prefix = 'gci_intivation'
     fields = ['message']
 
-class SendRequestPage(RequestHandler):
-  """Encapsulate all the methods required to generate Send Request page.
-  """
+class SendRequestPage(GCIRequestHandler):
+  """Encapsulate all the methods required to generate Send Request page."""
 
   def templatePath(self):
     return 'v2/modules/gci/request/base.html'
@@ -125,9 +119,8 @@
     self.redirect.id(request.key().id()).to(url_names.GCI_MANAGE_REQUEST)
 
 
-class ManageRequestPage(RequestHandler):
-  """View to manage the invitation by the sender.
-  """
+class ManageRequestPage(GCIRequestHandler):
+  """View to manage the invitation by the sender."""
 
   def templatePath(self):
     return 'v2/modules/gci/request/base.html'
@@ -206,9 +199,8 @@
       return 'Resubmit'
 
 
-class RespondRequestPage(RequestHandler):
-  """View to accept or reject requests by organization admins. 
-  """
+class RespondRequestPage(GCIRequestHandler):
+  """View to accept or reject requests by organization admins."""
 
   def templatePath(self):
     return 'v2/modules/gci/request/show.html'
@@ -224,7 +216,7 @@
 
     key_name = self.data.kwargs['user']
     user_key = db.Key.from_path('User', key_name)
-    
+
     # fetch the request entity based on the id and parent key
     request_id = int(self.data.kwargs['id'])
     self.data.request_entity = GCIRequest.get_by_id(
@@ -252,6 +244,13 @@
     user_key = GCIRequest.user.get_value_for_datastore(
         self.data.request_entity)
 
+    profile_key_name = '/'.join([
+        self.data.program.key().name(), user_key.name()])
+    profile_key = db.Key.from_path(
+        'GCIProfile', profile_key_name, parent=user_key)
+
+    self.data.requester_profile = profile = db.get(profile_key)
+
     if 'accept' in self.data.POST:
       options = db.create_transaction_options(xg=True)
 
@@ -259,14 +258,8 @@
       organization_key = self.data.organization.key()
       messages = self.data.program.getProgramMessages()
 
-      link_id = user_key.name()
-      profile_key_name = '/'.join([self.data.program.key().name(), link_id])
-      profile_key = db.Key.from_path(
-          'GCIProfile', profile_key_name, parent=user_key)
-
       def accept_request_txn():
         request = db.get(request_key)
-        self.data.requester_profile = profile = db.get(profile_key)
 
         request.status = 'accepted'
 
@@ -351,7 +344,7 @@
     return 'v2/modules/gci/request/_request_list.html'
 
 
-class ListUserRequestsPage(RequestHandler):
+class ListUserRequestsPage(GCIRequestHandler):
   """View for the page that lists all the requests which have been sent by
   the current user.
   """
diff --git a/app/soc/modules/gci/views/student_forms.py b/app/soc/modules/gci/views/student_forms.py
index d503dc9..5a3ccdf 100644
--- a/app/soc/modules/gci/views/student_forms.py
+++ b/app/soc/modules/gci/views/student_forms.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for students in GCI to upload their forms.
-"""
-
+"""Module for students in GCI to upload their forms."""
 
 from google.appengine.ext import blobstore
 from google.appengine.dist import httplib
@@ -32,7 +28,7 @@
 from soc.modules.gci.logic import profile as profile_logic
 from soc.modules.gci.models.profile import GCIStudentInfo
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
 
@@ -67,8 +63,10 @@
     """
     super(UploadForm, self).__init__(*args, **kwargs)
 
-    base_url = request_data.redirect.program().urlOf(
-        url_names.GCI_STUDENT_FORM_UPLOAD)
+    # TODO(nathaniel): make this .program() call unnecessary.
+    request_data.redirect.program()
+
+    base_url = request_data.redirect.urlOf(url_names.GCI_STUDENT_FORM_UPLOAD)
 
     self['consent_form'].field.widget = gci_forms.AsyncFileInput(
         download_url='%s?%s' % (base_url, url_names.CONSENT_FORM_GET_PARAM),
@@ -82,7 +80,7 @@
             self['consent_form'].field.help_text,
             request_data.program.form_translations_url))
     self['student_id_form'].field.help_text = (
-        DEF_STUDENT_ID_FORM_TEXT_HELP % 
+        DEF_STUDENT_ID_FORM_TEXT_HELP %
             request_data.program.form_translations_url)
 
   def clean(self):
@@ -114,9 +112,8 @@
     return student_info
 
 
-class StudentFormUpload(RequestHandler):
-  """View for uploading your student forms.
-  """
+class StudentFormUpload(GCIRequestHandler):
+  """View for uploading your student forms."""
 
   def djangoURLPatterns(self):
     """The URL pattern for the view.
@@ -138,14 +135,16 @@
     return 'v2/modules/gci/student_forms/base.html'
 
   def jsonContext(self):
-    url = self.redirect.program().urlOf('gci_student_form_upload', secure=True)
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.redirect.program()
+
+    url = self.redirect.urlOf('gci_student_form_upload', secure=True)
     return {
         'upload_link': blobstore.create_upload_url(url),
         }
 
   def get(self):
-    """Handles download of the forms otherwise resumes normal rendering.
-    """
+    """Handles download of the forms otherwise resumes normal rendering."""
     if 'consent_form' in self.data.GET:
       download = self.data.student_info.consent_form
     elif 'student_id_form' in self.data.GET:
@@ -154,14 +153,13 @@
       return super(StudentFormUpload, self).get()
 
     # download has been requested
-    if not download:
-      self.error(httplib.NOT_FOUND, 'File not found')
-
-    self.response = bs_helper.sendBlob(download)
+    if download:
+      self.response = bs_helper.sendBlob(download)
+    else:
+      self.response = self.error(httplib.NOT_FOUND, message='File not found')
 
   def context(self):
-    """Handler for default HTTP GET request.
-    """
+    """Handler for default HTTP GET request."""
     context = {
         'page_name': 'Student form upload'
         }
@@ -215,30 +213,28 @@
 
     form.save()
 
-    self.redirect.program().to('gci_student_form_upload')
+    # TODO(nathaniel): make this .program() call unnecessary.
+    self.redirect.program()
+
+    self.redirect.to('gci_student_form_upload')
 
 
-class StudentFormDownload(RequestHandler):
-  """View for uploading your student forms.
-  """
+class StudentFormDownload(GCIRequestHandler):
+  """View for uploading your student forms."""
 
   def djangoURLPatterns(self):
-    """The URL pattern for the view.
-    """
+    """The URL pattern for the view."""
     return [
         url(r'student/forms/%s$' % url_patterns.PROFILE, self,
             name=url_names.GCI_STUDENT_FORM_DOWNLOAD)]
 
   def checkAccess(self):
-    """Denies access if you are not a host.
-    """
+    """Denies access if you are not a host."""
     self.check.isHost()
     self.mutator.studentFromKwargs()
 
   def get(self):
-    """Allows hosts to download the student forms.
-    """
-    download = None
+    """Allows hosts to download the student forms."""
     if url_names.CONSENT_FORM_GET_PARAM in self.data.GET:
       download = self.data.url_student_info.consent_form
     elif url_names.STUDENT_ID_FORM_GET_PARAM in self.data.GET:
@@ -247,7 +243,7 @@
       raise BadRequest('No file requested')
 
     # download has been requested
-    if not download:
-      self.error(httplib.NOT_FOUND, 'File not found')
-
-    self.response = bs_helper.sendBlob(download)
+    if download:
+      self.response = bs_helper.sendBlob(download)
+    else:
+      self.response = self.error(httplib.NOT_FOUND, 'File not found')
diff --git a/app/soc/modules/gci/views/students_info.py b/app/soc/modules/gci/views/students_info.py
index 5b54a31..1934b76 100644
--- a/app/soc/modules/gci/views/students_info.py
+++ b/app/soc/modules/gci/views/students_info.py
@@ -12,34 +12,25 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the Students Info view for the admin.
-"""
+"""Module containing the Students Info view for the admin."""
 
-
-from google.appengine.ext import db
-
-from django.utils.dateformat import format
 from django.utils.translation import ugettext
 
-from soc.logic.exceptions import AccessViolation
+from soc.logic import exceptions
 from soc.views.helper import lists
 from soc.views.helper import url_patterns
 
-from soc.modules.gci.models.profile import GCIStudentInfo
-from soc.modules.gci.models.score import GCIScore
-from soc.modules.gci.templates.student_list import StudentList
-from soc.modules.gci.views.base import RequestHandler
-from soc.modules.gci.views.helper.url_patterns import url
+from soc.modules.gci.templates import student_list
+from soc.modules.gci.views import base
 from soc.modules.gci.views.helper import url_names
+from soc.modules.gci.views.helper import url_patterns as gci_url_patterns
 
 
-class AllParticipatingStudentList(StudentList):
-  """Component for listing all the students participating in GCI.
-  """
+class AllParticipatingStudentsList(student_list.StudentList):
+  """Component for listing all the students participating in GCI."""
 
   def __init__(self, request, data):
-    super(AllParticipatingStudentList, self).__init__(request, data)
-
+    super(AllParticipatingStudentsList, self).__init__(request, data)
 
     def formVerified(verified_prop):
       """Returns Yes/No based on whether the form verified property's value."""
@@ -63,46 +54,45 @@
             sp[e.parent_key()].link_id).urlOf(url_names.GCI_PROFILE_SHOW_ADMIN))
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    all_participating_students_list = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=self.idx)
 
     return {
         'name': 'students',
         'title': 'Participating students',
-        'lists': [list],
-        'description': ugettext(
-            'List of all participating students'),
+        'lists': [all_participating_students_list],
+        'description': ugettext('List of all participating students'),
     }
 
 
-class StudentsInfoPage(RequestHandler):
-  """View for the students info page for the admin.
-  """
+class StudentsInfoPage(base.GCIRequestHandler):
+  """View for the students info page for the admin."""
 
   def templatePath(self):
     return 'v2/modules/gci/students_info/base.html'
 
   def djangoURLPatterns(self):
     return [
-        url(r'admin/students_info/%s$' % url_patterns.PROGRAM, self,
-            name=url_names.GCI_STUDENTS_INFO),
+        gci_url_patterns.url(r'admin/students_info/%s$' % url_patterns.PROGRAM,
+                             self, name=url_names.GCI_STUDENTS_INFO),
     ]
 
   def checkAccess(self):
     self.check.isHost()
 
   def jsonContext(self):
-    list_content = AllParticipatingStudentList(
-        self.request, self.data).getListData()
+    all_participating_students_list = AllParticipatingStudentsList(
+        self.request, self.data)
+    list_content = all_participating_students_list.getListData()
 
-    if not list_content:
-      raise AccessViolation(
-          'You do not have access to this data')
-    return list_content.content()
+    if list_content:
+      return list_content.content()
+    else:
+      raise exceptions.AccessViolation('You do not have access to this data')
 
   def context(self):
     return {
-        'page_name': "List of Students for %s" % self.data.program.name,
-        'students_info_list': AllParticipatingStudentList(
+        'page_name': 'List of Students for %s' % self.data.program.name,
+        'students_info_list': AllParticipatingStudentsList(
             self.request, self.data),
     }
diff --git a/app/soc/modules/gci/views/task.py b/app/soc/modules/gci/views/task.py
index 155ece0..f6de11c 100644
--- a/app/soc/modules/gci/views/task.py
+++ b/app/soc/modules/gci/views/task.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,11 +12,10 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Views for the GCI Task view page.
-"""
-
+"""Views for the GCI Task view page."""
 
 import datetime
+import httplib
 
 from google.appengine.ext import blobstore
 from google.appengine.ext import db
@@ -44,7 +41,7 @@
 from soc.modules.gci.models.task import UNPUBLISHED
 from soc.modules.gci.models.work_submission import GCIWorkSubmission
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_patterns
 from soc.modules.gci.views.helper.url_patterns import url
 from soc.modules.gci.views.helper import url_names
@@ -62,14 +59,14 @@
 DEF_NO_URL = ugettext(
     'An error occurred, please submit a valid URL.')
 
-DEF_NO_WORK_FOUND = ugettext('No submission found with id %i')
+DEF_NO_WORK_FOUND = ugettext('No submission found with id %s')
 
 DEF_NOT_ALLOWED_TO_DELETE = ugettext(
     'You are not allowed to delete this submission')
 
 DEF_CANT_SEND_FOR_REVIEW = ugettext(
-    'Only a task that you own and that has submitted work can be send in '
-    'for review.')
+    'Only a task that you own and that has submitted work and that has '
+    'not been closed can be send in for review.')
 
 
 class CommentForm(gci_forms.GCIModelForm):
@@ -176,9 +173,8 @@
     return url
 
 
-class TaskViewPage(RequestHandler):
-  """View for the GCI Task view page where all the actions happen.
-  """
+class TaskViewPage(GCIRequestHandler):
+  """View for the GCI Task view page where all the actions happen."""
 
   def djangoURLPatterns(self):
     """URL pattern for this view.
@@ -231,7 +227,8 @@
       if 'send_for_review' in self.data.GET:
         self.check.isBeforeAllWorkStopped()
         if not task_logic.isOwnerOfTask(self.data.task, self.data.profile) or \
-            not self.data.work_submissions:
+            not self.data.work_submissions or \
+            self.data.task.status not in TASK_IN_PROGRESS:
           self.check.fail(DEF_CANT_SEND_FOR_REVIEW)
 
       if 'delete_submission' in self.data.GET:
@@ -304,7 +301,7 @@
     elif 'work_file_submit' in self.data.POST or 'submit_work' in self.data.GET:
       return self._postSubmitWork()
     else:
-      self.error(405)
+      self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
   def _postComment(self):
     """Handles the POST call for the form that creates comments.
@@ -435,11 +432,13 @@
   def _postDeleteSubmission(self):
     """POST handler to delete a GCIWorkSubmission.
     """
-    id = self._submissionId()
-    work = GCIWorkSubmission.get_by_id(id, parent=self.data.task)
+    submission_id = self._submissionId()
+    work = GCIWorkSubmission.get_by_id(submission_id, parent=self.data.task)
 
     if not work:
-      return self.error(400, DEF_NO_WORK_FOUND %id)
+      self.response = self.error(
+          httplib.BAD_REQUEST, message=DEF_NO_WORK_FOUND % submission_id)
+      return
 
     # Deletion of blobs always runs separately from transaction so it has no
     # added value to use it here.
@@ -520,7 +519,7 @@
     is_owner = task_logic.isOwnerOfTask(task, profile)
 
     if is_org_admin:
-      can_unpublish = (task.status in CLAIMABLE) and not task.student
+      can_unpublish = task.status == 'Open' and not task.student
       context['button_unpublish'] = can_unpublish
 
       can_publish = task.status in UNPUBLISHED
@@ -540,7 +539,10 @@
     if is_student:
       if not self.data.timeline.tasksClaimEnded():
         if not profile_logic.hasStudentFormsUploaded(profile.student_info):
-          context['student_forms_link'] = self.data.redirect.program().urlOf(
+          # TODO(nathaniel): make this .program() call unnecessary.
+          self.data.redirect.program()
+
+          context['student_forms_link'] = self.data.redirect.urlOf(
               url_names.GCI_STUDENT_FORM_UPLOAD)
         # TODO(lennie): Separate the access check out in to different
         # methods and add a context variable to show separate messages.
@@ -699,33 +701,28 @@
     return context
 
   def _commentingAllowed(self):
-    """Returns true iff the comments are allowed to be posted at this time.
-    """
+    """Returns true iff the comments are allowed to be posted at this time."""
     return not self.data.timeline.allWorkStopped() or (
         not self.data.timeline.allReviewsStopped() and
         self.data.mentorFor(self.data.task.org))
 
   def templatePath(self):
-    """Returns the path to the template that should be used in render().
-    """
+    """Returns the path to the template that should be used in render()."""
     return 'v2/modules/gci/task/_comments.html'
 
 
-class WorkSubmissionDownload(RequestHandler):
-  """Request handler for downloading blobs from a GCIWorkSubmission.
-  """
+class WorkSubmissionDownload(GCIRequestHandler):
+  """Request handler for downloading blobs from a GCIWorkSubmission."""
 
   def djangoURLPatterns(self):
-    """URL pattern for this view.
-    """
+    """URL pattern for this view."""
     return [
         url(r'work/download/%s$' % url_patterns.TASK, self,
             name='gci_download_work'),
     ]
 
   def checkAccess(self):
-    """Checks whether this task is visible to the public.
-    """
+    """Checks whether this task is visible to the public."""
     self.mutator.taskFromKwargs()
     self.check.isTaskVisible()
 
@@ -733,13 +730,13 @@
     """Attempts to download the blob in the worksubmission that is specified
     in the GET argument.
     """
-    id_s = self.request.GET.get('id', '')
-    id = int(id_s) if id_s.isdigit() else -1
+    id_string = self.request.GET.get('id', '')
+    submission_id = int(id_string) if id_string.isdigit() else -1
 
-    work = GCIWorkSubmission.get_by_id(id, self.data.task)
+    work = GCIWorkSubmission.get_by_id(submission_id, self.data.task)
 
-    if not work or not work.upload_of_work:
-      return self.error(400, DEF_NO_WORK_FOUND %id)
-
-    upload = work.upload_of_work
-    self.response = bs_helper.sendBlob(upload)
+    if work and work.upload_of_work:
+      self.response = bs_helper.sendBlob(work.upload_of_work)
+    else:
+      self.response = self.error(
+          httplib.BAD_REQUEST, message=DEF_NO_WORK_FOUND % id_string)
diff --git a/app/soc/modules/gci/views/task_create.py b/app/soc/modules/gci/views/task_create.py
index daa12a8..5ccf15c 100644
--- a/app/soc/modules/gci/views/task_create.py
+++ b/app/soc/modules/gci/views/task_create.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Views for creating/editing GCI Tasks.
-"""
-
+"""Views for creating/editing GCI Tasks."""
 
 import datetime
 
@@ -35,7 +31,7 @@
 from soc.modules.gci.models import task
 from soc.modules.gci.models.task import DifficultyLevel
 from soc.modules.gci.views import forms as gci_forms
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper.url_patterns import url
 
 
@@ -289,9 +285,8 @@
       return "v2/modules/gci/task_create/_full_edit.html"
 
 
-class TaskCreatePage(RequestHandler):
-  """View to create a new task.
-  """
+class TaskCreatePage(GCIRequestHandler):
+  """View to create a new task."""
 
   def djangoURLPatterns(self):
     return [
diff --git a/app/soc/modules/gci/views/task_list.py b/app/soc/modules/gci/views/task_list.py
index ffae9d3..9afab77 100644
--- a/app/soc/modules/gci/views/task_list.py
+++ b/app/soc/modules/gci/views/task_list.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,22 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GCI historic task page.
-"""
-
+"""Module containing the views for GCI historic task page."""
 
 from soc.logic.exceptions import AccessViolation
 from soc.views.helper import url_patterns
 from soc.views.helper import lists
-from soc.views.helper.access_checker import isSet
 from soc.views.template import Template
 
 from soc.modules.gci.logic import task as task_logic
 from soc.modules.gci.models.task import GCITask
 from soc.modules.gci.templates.org_list import BasicOrgList
 from soc.modules.gci.templates.task_list import TaskList
-from soc.modules.gci.views.base import RequestHandler
-from soc.modules.gci.views.forms import GCIModelForm
+from soc.modules.gci.views.base import GCIRequestHandler
 #from soc.modules.gci.views.base_templates import ProgramSelect
 from soc.modules.gci.views.helper import url_names
 from soc.modules.gci.views.helper.url_patterns import url
@@ -80,7 +74,7 @@
     return 'v2/modules/gci/task/_task_list.html'
 
 
-class TaskListPage(RequestHandler):
+class TaskListPage(GCIRequestHandler):
   """View for the list task page.
   """
 
@@ -131,7 +125,7 @@
         self.data.url_profile, self.data.organization, 'Closed')
 
 
-class StudentTasksForOrganizationPage(RequestHandler):
+class StudentTasksForOrganizationPage(GCIRequestHandler):
   """View for the list of student tasks for organization.
   """
 
@@ -172,15 +166,17 @@
 
   def _getRedirect(self):
     def redirect(e, *args):
-      r = self.data.redirect
-      return r.organization(e).urlOf(url_names.GCI_ORG_TASKS_ALL)
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=e)
+
+      return r.urlOf(url_names.GCI_ORG_TASKS_ALL)
     return redirect
 
   def _getDescription(self):
     return 'Choose an organization for which to display tasks.'
 
 
-class ChooseOrganizationPage(RequestHandler):
+class ChooseOrganizationPage(GCIRequestHandler):
   """View with a list of organizations. When a user clicks on one of them,
   he or she is moved to the organization tasks for this organization.
   """
@@ -229,7 +225,7 @@
     return task_logic.queryForOrganization(self.data.organization)
 
 
-class AllOrganizationTasksPage(RequestHandler):
+class AllOrganizationTasksPage(GCIRequestHandler):
   """View for program admins to see all tasks created by an organization
   which is specified in the URL.
   """
diff --git a/app/soc/modules/gsoc/logic/helper/notifications.py b/app/soc/modules/gsoc/logic/helper/notifications.py
index d040fef..e42562d 100644
--- a/app/soc/modules/gsoc/logic/helper/notifications.py
+++ b/app/soc/modules/gsoc/logic/helper/notifications.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2012 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,15 +12,13 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Notifications for the GSoC module.
-"""
+"""Notifications for the GSoC module."""
 
 from django.utils.translation import ugettext
 
 from soc.logic.helper.notifications import getContext
 from soc.views.helper.access_checker import isSet
 
-
 DEF_NEW_PROPOSAL_SUBJECT = ugettext(
     '[%(org)s] New proposal by %(proposer_name)s: %(proposal_name)s')
 
@@ -155,8 +151,10 @@
     slot_transfer: entity that holds the slot transfer request information
     update: True if the request was updated, False if the new one was created
   """
+  # TODO(nathaniel): make unnecessary this .program() call.
+  data.redirect.program()
 
-  slot_transfer_admin_url = data.redirect.program().urlOf(
+  slot_transfer_admin_url = data.redirect.urlOf(
       'gsoc_admin_slots_transfer', full=True)
 
   message_properties = {
diff --git a/app/soc/modules/gsoc/views/accept_proposals.py b/app/soc/modules/gsoc/views/accept_proposals.py
index 3f4fd52..fc4dced 100644
--- a/app/soc/modules/gsoc/views/accept_proposals.py
+++ b/app/soc/modules/gsoc/views/accept_proposals.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GSoC accept proposals.
-"""
-
+"""Module containing the views for GSoC accept proposals."""
 
 from google.appengine.api import taskqueue
 
@@ -25,13 +21,12 @@
 from soc.views.helper import url_patterns
 
 from soc.modules.gsoc.logic import accept_proposals as conversion_logic
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
-class AcceptProposalsPage(RequestHandler):
-  """View for the host to trigger proposals to projets conversion.
-  """
+class AcceptProposalsPage(GSoCRequestHandler):
+  """View for the host to trigger proposals to projets conversion."""
 
   def templatePath(self):
     return 'v2/modules/gsoc/accept_proposals/base.html'
diff --git a/app/soc/modules/gsoc/views/accept_withdraw_projects.py b/app/soc/modules/gsoc/views/accept_withdraw_projects.py
index c041933..fc8d1ac 100644
--- a/app/soc/modules/gsoc/views/accept_withdraw_projects.py
+++ b/app/soc/modules/gsoc/views/accept_withdraw_projects.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -37,7 +35,7 @@
 from soc.modules.gsoc.models.profile import GSoCStudentInfo
 from soc.modules.gsoc.models.project import GSoCProject
 from soc.modules.gsoc.models.proposal import GSoCProposal
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
@@ -218,7 +216,7 @@
     return "v2/modules/gsoc/accept_withdraw_projects/_project_list.html"
 
 
-class AcceptProposals(RequestHandler):
+class AcceptProposals(GSoCRequestHandler):
   """View for accepting individual proposals.
   """
 
@@ -429,7 +427,7 @@
     return "v2/modules/gsoc/accept_withdraw_projects/_project_list.html"
 
 
-class WithdrawProjects(RequestHandler):
+class WithdrawProjects(GSoCRequestHandler):
   """View methods for withdraw projects
   """
 
diff --git a/app/soc/modules/gsoc/views/accepted_orgs.py b/app/soc/modules/gsoc/views/accepted_orgs.py
index 0d9da8e..03bc260 100644
--- a/app/soc/modules/gsoc/views/accepted_orgs.py
+++ b/app/soc/modules/gsoc/views/accepted_orgs.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GSoC accepted orgs.
-"""
-
+"""Module containing the views for GSoC accepted orgs."""
 
 from django.conf.urls.defaults import url as django_url
 
@@ -28,25 +24,30 @@
 from soc.views.helper import url_patterns
 
 from soc.modules.gsoc.models.organization import GSoCOrganization
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
 class AcceptedOrgsList(Template):
-  """Template for list of accepted organizations.
-  """
+  """Template for list of accepted organizations."""
 
   def __init__(self, request, data):
     self.request = request
     self.data = data
-    r = data.redirect
+
+    # TODO(nathaniel): reduce this back to a lambda expression
+    # inside the setRowAction call below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(e)
+
+      return self.data.redirect.urlOf('gsoc_org_home')
 
     list_config = lists.ListConfiguration()
     list_config.addColumn('name', 'Name',
         lambda e, *args: e.name.strip())
     list_config.addSimpleColumn('link_id', 'Link ID', hidden=True)
-    list_config.setRowAction(
-        lambda e, *args: r.organization(e).urlOf('gsoc_org_home'))
+    list_config.setRowAction(RowAction)
     list_config.addColumn('tags', 'Tags',
                           lambda e, *args: ", ".join(e.tags))
     list_config.addColumn(
@@ -88,7 +89,7 @@
     return "v2/modules/gsoc/accepted_orgs/_project_list.html"
 
 
-class AcceptedOrgsPage(RequestHandler):
+class AcceptedOrgsPage(GSoCRequestHandler):
   """View for the accepted organizations page.
   """
 
diff --git a/app/soc/modules/gsoc/views/admin.py b/app/soc/modules/gsoc/views/admin.py
index 8db1160..0010568 100644
--- a/app/soc/modules/gsoc/views/admin.py
+++ b/app/soc/modules/gsoc/views/admin.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the admin pages.
-"""
-
+"""Module for the admin pages."""
 
 import logging
 
@@ -53,7 +49,7 @@
 from soc.modules.gsoc.models.proposal import GSoCProposal
 from soc.modules.gsoc.models.proposal_duplicates import GSoCProposalDuplicate
 from soc.modules.gsoc.views import forms as gsoc_forms
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.dashboard import BIRTHDATE_FORMAT
 from soc.modules.gsoc.views.helper import url_names
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -111,7 +107,7 @@
     return r.urlOf('gsoc_admin_dashboard')
 
 
-class DashboardPage(RequestHandler):
+class DashboardPage(GSoCRequestHandler):
   """Dashboard for admins.
   """
 
@@ -772,7 +768,7 @@
     }
 
 
-class LookupLinkIdPage(RequestHandler):
+class LookupLinkIdPage(GSoCRequestHandler):
   """View for the participant profile.
   """
 
@@ -837,15 +833,21 @@
     list_config.addColumn('org_admin', 'Org Admins',
         (lambda e, *args: args[0][e.key()]))
 
-    r = self.data.redirect
-    list_config.setRowAction(
-        lambda e, *args: r.organization(e).urlOf('gsoc_org_home'))
+    # TODO(nathaniel): squeeze this back into a lambda expression
+    # in the call to setRowAction below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=e)
+
+      return self.data.redirect.urlOf('gsoc_org_home')
+
+    list_config.setRowAction(RowAction)
 
     return list_config
 
   def context(self):
     description = 'List of organizations accepted into %s' % (
-            self.data.program.name)
+        self.data.program.name)
 
     list = lists.ListConfigurationResponse(
         self.data, self._list_config, 0, description)
@@ -887,14 +889,18 @@
   """
 
   def extraColumn(self, list_config):
-    use_cbox = False
-    if self.request.GET.get('cbox'):
-      use_cbox = True
+    use_cbox = bool(self.request.GET.get('cbox'))
+
+    # TODO(nathaniel): squeeze this back into a lambda expression in the
+    # call to setRowAction below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=e)
+
+      return self.data.redirect.urlOf('gsoc_proposals_org', cbox=use_cbox)
 
     r = self.data.redirect
-    list_config.setRowAction(
-        lambda e, *args: r.organization(e).urlOf('gsoc_proposals_org',
-            cbox=use_cbox))
+    list_config.setRowAction(RowAction)
     list_config.addSimpleColumn('slots_desired', 'min', width=20)
     list_config.addSimpleColumn('max_slots_desired', 'max', width=20)
     list_config.addSimpleColumn('slots', 'Slots', width=20)
@@ -914,7 +920,7 @@
     }
 
 
-class ProposalsAcceptedOrgsPage(RequestHandler):
+class ProposalsAcceptedOrgsPage(GSoCRequestHandler):
   """View for accepted orgs.
   """
 
@@ -952,14 +958,18 @@
   """
 
   def extraColumn(self, list_config):
-    use_cbox = False
-    if self.request.GET.get('cbox'):
-      use_cbox = True
+    use_cbox = bool(self.request.GET.get('cbox'))
+
+    # TODO(nathaniel): squeeze this back into a lambda expression in
+    # the call to setRowAction below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=e)
+
+      return self.data.redirect.urlOf('gsoc_projects_org', cbox=use_cbox)
 
     r = self.data.redirect
-    list_config.setRowAction(
-        lambda e, *args: r.organization(e).urlOf('gsoc_projects_org',
-            cbox=use_cbox))
+    list_config.setRowAction(RowAction)
     list_config.addSimpleColumn('slots_desired', 'min', width=20)
     list_config.addSimpleColumn('max_slots_desired', 'max', width=20)
     list_config.addSimpleColumn('slots', 'Slots', width=20)
@@ -988,7 +998,7 @@
     }
 
 
-class ProjectsAcceptedOrgsPage(RequestHandler):
+class ProjectsAcceptedOrgsPage(GSoCRequestHandler):
   """View for accepted orgs.
   """
 
@@ -1031,7 +1041,6 @@
     self.request = request
     self.data = data
 
-    r = data.redirect
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addColumn('key', 'Key', (lambda ent, *args: "%s/%s" % (
         ent.parent().key().name(), ent.key().id())), hidden=True)
@@ -1149,7 +1158,7 @@
     return response_builder.build(accepted, duplicates)
 
 
-class ProposalsPage(RequestHandler):
+class ProposalsPage(GSoCRequestHandler):
   """View for proposals for particular org.
   """
 
@@ -1251,7 +1260,7 @@
     return "v2/modules/gsoc/admin/_projects_list.html"
 
 
-class ProjectsPage(RequestHandler):
+class ProjectsPage(GSoCRequestHandler):
   """View for projects of particular org.
   """
 
@@ -1402,7 +1411,7 @@
     return response_builder.build()
 
 
-class SlotsPage(RequestHandler):
+class SlotsPage(GSoCRequestHandler):
   """View for the participant profile.
   """
 
@@ -1441,7 +1450,7 @@
     }
 
 
-class SurveyReminderPage(RequestHandler):
+class SurveyReminderPage(GSoCRequestHandler):
   """Page to send out reminder emails to fill out a Survey.
   """
 
@@ -1623,7 +1632,7 @@
     }
 
 
-class StudentsListPage(RequestHandler):
+class StudentsListPage(GSoCRequestHandler):
   """View that lists all the students associated with the program.
   """
 
@@ -1655,7 +1664,7 @@
     }
 
 
-class ProjectsListPage(RequestHandler):
+class ProjectsListPage(GSoCRequestHandler):
   """View that lists all the projects associated with the program.
   """
 
@@ -1692,7 +1701,7 @@
     }
 
 
-class OrgsListPage(RequestHandler):
+class OrgsListPage(GSoCRequestHandler):
   """View that lists all the projects associated with the program.
   """
 
diff --git a/app/soc/modules/gsoc/views/base.py b/app/soc/modules/gsoc/views/base.py
index b9c9a5d..02da11d 100644
--- a/app/soc/modules/gsoc/views/base.py
+++ b/app/soc/modules/gsoc/views/base.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,26 +12,26 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the boiler plate required to construct GSoC views.
-"""
+"""Module containing the boiler plate required to construct GSoC views."""
 
+import httplib
 
-from soc.views.base import RequestHandler
+from django import http
+
+from soc.views import base
 
 from soc.modules.gsoc.views import base_templates
 from soc.modules.gsoc.views.helper import access_checker
-from soc.modules.gsoc.views.helper.request_data import RequestData
-from soc.modules.gsoc.views.helper.request_data import RedirectHelper
+from soc.modules.gsoc.views.helper import request_data
 
 
-class RequestHandler(RequestHandler):
-  """Customization required by GSoC to handle HTTP requests.
-  """
+class GSoCRequestHandler(base.RequestHandler):
+  """Customization required by GSoC to handle HTTP requests."""
 
   def render(self, template_path, context):
     """Renders the page using the specified context.
 
-    See soc.views.base.RequestHandler.
+    See soc.views.base.RequestHandler for specification.
 
     The context object is extended with the following values:
       base_layout: path to the base template. cbox is for a page that need
@@ -56,11 +54,11 @@
     context['header'] = base_templates.Header(self.data)
     context['mainmenu'] = base_templates.MainMenu(self.data)
     context['footer'] = base_templates.Footer(self.data)
-    super(RequestHandler, self).render(template_path, context)
+    return super(GSoCRequestHandler, self).render(template_path, context)
 
   def init(self, request, args, kwargs):
-    self.data = RequestData()
-    self.redirect = RedirectHelper(self.data, self.response)
+    self.data = request_data.RequestData()
+    self.redirect = request_data.RedirectHelper(self.data, self.response)
     self.data.populate(self.redirect, request, args, kwargs)
     if self.data.is_developer:
       self.mutator = access_checker.DeveloperMutator(self.data)
@@ -68,20 +66,23 @@
     else:
       self.mutator = access_checker.Mutator(self.data)
       self.check = access_checker.AccessChecker(self.data)
-    super(RequestHandler, self).init(request, args, kwargs)
+    super(GSoCRequestHandler, self).init(request, args, kwargs)
 
   def error(self, status, message=None):
+    """See base.RequestHandler.error for specification."""
     if not self.data.program:
-      return super(RequestHandler, self).error(status, message)
+      return super(GSoCRequestHandler, self).error(status, message)
 
-    self.response.set_status(status, message=message)
+    # If message is not set, set it to the default associated with the
+    # given status (such as "Method Not Allowed" or "Service Unavailable").
+    message = message or httplib.responses.get(status, '')
 
-    template_path = "v2/modules/gsoc/error.html"
+    template_path = 'v2/modules/gsoc/error.html'
     context = {
-        'page_name': self.response.content,
-        'message': self.response.content,
+        'page_name': message,
+        'message': message,
         'logged_in_msg': base_templates.LoggedInMsg(self.data, apply_link=False),
     }
 
-    self.response.content = ''
-    self.render(template_path, context)
+    return http.HttpResponse(
+        content=self.render(template_path, context), status=status)
diff --git a/app/soc/modules/gsoc/views/dashboard.py b/app/soc/modules/gsoc/views/dashboard.py
index 9d691bc..9bb29a9 100644
--- a/app/soc/modules/gsoc/views/dashboard.py
+++ b/app/soc/modules/gsoc/views/dashboard.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC participant dashboard.
-"""
-
+"""Module for the GSoC participant dashboard."""
 
 import logging
 
@@ -57,7 +53,7 @@
 from soc.modules.gsoc.models.proposal_duplicates import GSoCProposalDuplicate
 from soc.modules.gsoc.models.request import GSoCRequest
 from soc.modules.gsoc.models.score import GSoCScore
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 from soc.modules.gsoc.views.helper import url_names
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -134,7 +130,7 @@
     }
 
 
-class DashboardPage(RequestHandler):
+class DashboardPage(GSoCRequestHandler):
   """View for the participant dashboard.
   """
 
@@ -1136,12 +1132,17 @@
   """
 
   def __init__(self, request, data):
-    """Initializes this component.
-    """
-    r = data.redirect
+    """Initializes this component."""
+    # TODO(nathaniel): put this back into a lambda expression in the
+    # setRowAction call below.
+    def RowAction(e, *args):
+      # TODO(nathaniel): make this .organization call unnecessary.
+      data.redirect.organization(organization=e)
+
+      return data.redirect.urlOf('gsoc_org_home')
+
     list_config = lists.ListConfiguration()
-    list_config.setRowAction(
-        lambda e, *args: r.organization(e).urlOf('gsoc_org_home'))
+    list_config.setRowAction(RowAction)
 
     if not data.program.allocations_visible:
       list_config.addSimpleColumn('name', 'name')
@@ -1398,12 +1399,14 @@
     def rowAction(d, *args):
       key = d['key']
       if key == 'tax_form':
-        return data.redirect.program().urlOf('gsoc_tax_form', secure=True)
+        data.redirect.program()
+        return data.redirect.urlOf('gsoc_tax_form', secure=True)
       if key == 'enrollment_form':
-        return data.redirect.program().urlOf('gsoc_enrollment_form',
-                                             secure=True)
+        data.redirect.program()
+        return data.redirect.urlOf('gsoc_enrollment_form', secure=True)
       if key == 'school_name':
-        url = data.redirect.program().urlOf('edit_gsoc_profile', secure=True)
+        data.redirect.program()
+        url = data.redirect.urlOf('edit_gsoc_profile', secure=True)
         return url + '#form_row_school_name'
       if key.isdigit():
         project_id = int(key)
diff --git a/app/soc/modules/gsoc/views/document.py b/app/soc/modules/gsoc/views/document.py
index 99be5b7..7fc2568 100644
--- a/app/soc/modules/gsoc/views/document.py
+++ b/app/soc/modules/gsoc/views/document.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GSoC documents page.
-"""
-
+"""Module containing the views for GSoC documents page."""
 
 from django.conf.urls.defaults import url as django_url
 
@@ -28,7 +24,7 @@
 from soc.views.helper import url_patterns
 from soc.views.helper.access_checker import isSet
 
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.forms import GSoCModelForm
 from soc.modules.gsoc.views.helper.url_patterns import url
 from soc.modules.gsoc.views.helper import url_patterns as gsoc_url_patterns
@@ -46,7 +42,7 @@
     ]
 
 
-class EditDocumentPage(RequestHandler):
+class EditDocumentPage(GSoCRequestHandler):
   """Encapsulate all the methods required to edit documents.
   """
 
@@ -93,7 +89,7 @@
       self.get()
 
 
-class DocumentPage(RequestHandler):
+class DocumentPage(GSoCRequestHandler):
   """Encapsulate all the methods required to show documents.
   """
 
@@ -127,7 +123,7 @@
     }
 
 
-class EventsPage(RequestHandler):
+class EventsPage(GSoCRequestHandler):
   """Encapsulates all the methods required to show the events page.
   """
 
@@ -163,7 +159,7 @@
     return 'v2/modules/gsoc/document/_document_list.html'
 
 
-class DocumentListPage(RequestHandler):
+class DocumentListPage(GSoCRequestHandler):
   """View for the list documents page.
   """
 
diff --git a/app/soc/modules/gsoc/views/duplicates.py b/app/soc/modules/gsoc/views/duplicates.py
index 9a2b292..0b95fd4 100644
--- a/app/soc/modules/gsoc/views/duplicates.py
+++ b/app/soc/modules/gsoc/views/duplicates.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GSoC proposal duplicates.
-"""
-
+"""Module containing the views for GSoC proposal duplicates."""
 
 from google.appengine.api import taskqueue
 from google.appengine.ext import db
@@ -29,13 +25,12 @@
 from soc.modules.gsoc.logic import duplicates as duplicates_logic
 from soc.modules.gsoc.models.proposal_duplicates import GSoCProposalDuplicate
 from soc.modules.gsoc.models.profile import GSoCProfile
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
-class DuplicatesPage(RequestHandler):
-  """View for the host to see duplicates.
-  """
+class DuplicatesPage(GSoCRequestHandler):
+  """View for the host to see duplicates."""
 
   def templatePath(self):
     return 'v2/modules/gsoc/duplicates/base.html'
@@ -110,19 +105,19 @@
     super(Duplicate, self).__init__(data)
 
   def context(self):
-    """Returns the context for the current template.
-    """
-    r = self.data.redirect
-
+    """Returns the context for the current template."""
     context = {'duplicate': self.duplicate}
     orgs = db.get(self.duplicate.orgs)
     proposals = db.get(self.duplicate.duplicates)
 
     orgs_details = {}
     for org in orgs:
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=org)
+
       orgs_details[org.key().id_or_name()] = {
           'name': org.name,
-          'link': r.organization(org).urlOf('gsoc_org_home')
+          'link': self.data.redirect.urlOf('gsoc_org_home')
           }
       q = GSoCProfile.all()
       q.filter('org_admin_for', org)
@@ -142,9 +137,9 @@
           orgs_details[org.key().id_or_name()]['proposals'].append({
               'key': proposal.key().id_or_name(),
               'title': proposal.title,
-              'link': r.review(proposal.key().id_or_name(),
-                               proposal.parent().link_id).urlOf(
-                                   'review_gsoc_proposal')
+              'link': self.data.redirect.review(
+                  proposal.key().id_or_name(),
+                  proposal.parent().link_id).urlOf('review_gsoc_proposal'),
               })
 
     context['orgs'] = orgs_details
@@ -152,6 +147,5 @@
     return context
 
   def templatePath(self):
-    """Returns the path to the template that should be used in render().
-    """
+    """Returns the path to the template that should be used in render()."""
     return 'v2/modules/gsoc/duplicates/proposal_duplicate.html'
diff --git a/app/soc/modules/gsoc/views/grading_record_details.py b/app/soc/modules/gsoc/views/grading_record_details.py
index 870f717..e9bc0d5 100644
--- a/app/soc/modules/gsoc/views/grading_record_details.py
+++ b/app/soc/modules/gsoc/views/grading_record_details.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for displaying GradingSurveyGroups and records.
-"""
-
+"""Module for displaying GradingSurveyGroups and records."""
 
 import collections
 
@@ -32,12 +28,12 @@
 from soc.modules.gsoc.logic import grading_record
 from soc.modules.gsoc.models.grading_record import GSoCGradingRecord
 from soc.modules.gsoc.views import forms as gsoc_forms
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper import url_patterns as gsoc_url_patterns
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
-class GradingRecordsOverview(RequestHandler):
+class GradingRecordsOverview(GSoCRequestHandler):
   """View to display all GradingRecords for a single group.
   """
 
@@ -232,7 +228,7 @@
     widgets = forms.choiceWidgets(GSoCGradingRecord, ['grade_decision'])
 
 
-class GradingRecordDetails(RequestHandler):
+class GradingRecordDetails(GSoCRequestHandler):
   """View to display GradingRecord details.
   """
 
diff --git a/app/soc/modules/gsoc/views/helper/access_checker.py b/app/soc/modules/gsoc/views/helper/access_checker.py
index 0969ae2..a36685b 100644
--- a/app/soc/modules/gsoc/views/helper/access_checker.py
+++ b/app/soc/modules/gsoc/views/helper/access_checker.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,7 +16,6 @@
 for checking access.
 """
 
-
 from google.appengine.ext import db
 
 from django.utils.translation import ugettext
@@ -440,8 +437,10 @@
     gsoc_org = q.get()
 
     if gsoc_org:
-      edit_url = self.data.redirect.organization(gsoc_org).urlOf(
-          'edit_gsoc_org_profile')
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=gsoc_org)
+
+      edit_url = self.data.redirect.urlOf('edit_gsoc_org_profile')
 
       raise AccessViolation(DEF_ORG_EXISTS % (org_id, edit_url))
 
diff --git a/app/soc/modules/gsoc/views/homepage.py b/app/soc/modules/gsoc/views/homepage.py
index 10533c3..c6f7eb8 100644
--- a/app/soc/modules/gsoc/views/homepage.py
+++ b/app/soc/modules/gsoc/views/homepage.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GSoC home page.
-"""
-
+"""Module containing the views for GSoC home page."""
 
 from django.conf.urls.defaults import url as django_url
 
@@ -26,7 +22,7 @@
 
 from soc.modules.gsoc.logic import organization as org_logic
 from soc.modules.gsoc.logic import project as project_logic
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 from soc.modules.gsoc.views.helper.url_patterns import url
 
@@ -73,8 +69,7 @@
 
 
 class Apply(Template):
-  """Apply template.
-  """
+  """Apply template."""
 
   def __init__(self, data):
     self.data = data
@@ -82,11 +77,12 @@
   def context(self):
     context = {}
     accepted_orgs = None
-    r = self.data.redirect.program()
+    redirector = self.data.redirect
+    redirector.program()
 
     if self.data.timeline.orgsAnnounced():
       # accepted orgs block
-      accepted_orgs = r.urlOf('gsoc_accepted_orgs')
+      accepted_orgs = redirector.urlOf('gsoc_accepted_orgs')
       nr_orgs = self.data.program.nr_accepted_orgs
       context['nr_accepted_orgs'] = nr_orgs if nr_orgs else ""
       context['accepted_orgs_link'] = accepted_orgs
@@ -94,13 +90,13 @@
       current_orgs = org_logic.participating(self.data.program)
       for org in current_orgs:
         participating_orgs.append({
-            'link': r.orgHomepage(org.link_id).url(),
+            'link': redirector.orgHomepage(org.link_id).url(),
             'logo': org.logo_url,
             'name': org.short_name,
             })
       context['participating_orgs'] = participating_orgs
 
-    context['org_signup'] = self.data.timeline.orgSignup()  
+    context['org_signup'] = self.data.timeline.orgSignup()
     context['student_signup'] = self.data.timeline.studentSignup()
     context['mentor_signup'] = self.data.timeline.mentorSignup()
 
@@ -112,23 +108,25 @@
 
     # signup block
     if signup and not self.data.gae_user:
-      context['login_link'] = r.login().url()
+      context['login_link'] = redirector.login().url()
     if signup and not self.data.profile:
       if self.data.timeline.orgSignup():
-        r.createProfile('org_admin')
+        redirector.createProfile('org_admin')
       elif self.data.timeline.studentSignup():
-        r.createProfile('mentor')
-        context['mentor_profile_link'] = r.urlOf('create_gsoc_profile',
-                                                 secure=True)
-        r.createProfile('student')
+        redirector.createProfile('mentor')
+        context['mentor_profile_link'] = redirector.urlOf(
+            'create_gsoc_profile', secure=True)
+        redirector.createProfile('student')
       elif self.data.timeline.mentorSignup():
-        r.createProfile('mentor')
+        redirector.createProfile('mentor')
 
-      context['profile_link'] = r.urlOf('create_gsoc_profile', secure=True)
+      context['profile_link'] = redirector.urlOf(
+          'create_gsoc_profile', secure=True)
 
     if self.data.timeline.orgSignup() and self.data.profile:
-      context['org_apply_link'] = r.orgAppTake().urlOf('gsoc_take_org_app')
-      context['dashboard_link'] = r.dashboard().url()
+      context['org_apply_link'] = redirector.orgAppTake().urlOf(
+          'gsoc_take_org_app')
+      context['dashboard_link'] = redirector.dashboard().url()
 
     if ((self.data.timeline.studentSignup() or
         self.data.timeline.mentorSignup()) and self.data.profile):
@@ -194,7 +192,7 @@
     return "v2/modules/gsoc/_connect_with_us.html"
 
 
-class Homepage(RequestHandler):
+class Homepage(GSoCRequestHandler):
   """Encapsulate all the methods required to generate GSoC Home page.
   """
 
diff --git a/app/soc/modules/gsoc/views/invite.py b/app/soc/modules/gsoc/views/invite.py
index 39ce1ab..6d3267d 100644
--- a/app/soc/modules/gsoc/views/invite.py
+++ b/app/soc/modules/gsoc/views/invite.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the view for GSoC invitation page.
-"""
-
+"""Module containing the view for GSoC invitation page."""
 
 from google.appengine.ext import db
 from google.appengine.api import users
@@ -34,7 +30,7 @@
 
 from soc.modules.gsoc.models.profile import GSoCProfile
 from soc.modules.gsoc.models.request import GSoCRequest
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 from soc.modules.gsoc.views import forms as gsoc_forms
 
@@ -69,7 +65,7 @@
     field.help_text = ugettext(
         'The link_id or email address of the invitee, '
         ' separate multiple values with a comma')
-    
+
   def clean_link_id(self):
     """Accepts link_id of users which may be invited.
     """
@@ -155,7 +151,7 @@
       raise djangoforms.ValidationError('That user already has this role.')
 
 
-class InvitePage(RequestHandler):
+class InvitePage(GSoCRequestHandler):
   """Encapsulate all the methods required to generate Invite page.
   """
 
@@ -201,7 +197,7 @@
     assert isSet(self.data.organization)
 
     invite_form = InviteForm(self.data, self.data.POST)
-    
+
     if not invite_form.is_valid():
       return None
 
@@ -239,7 +235,7 @@
       self.get()
 
 
-class ShowInvite(RequestHandler):
+class ShowInvite(GSoCRequestHandler):
   """Encapsulate all the methods required to generate Show Invite page.
   """
 
diff --git a/app/soc/modules/gsoc/views/mentor_evaluation.py b/app/soc/modules/gsoc/views/mentor_evaluation.py
index 7c39459..b019e93 100644
--- a/app/soc/modules/gsoc/views/mentor_evaluation.py
+++ b/app/soc/modules/gsoc/views/mentor_evaluation.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC project evaluations.
-"""
-
+"""Module for the GSoC project evaluations."""
 
 from django.utils.translation import ugettext
 
@@ -32,7 +28,7 @@
 from soc.modules.gsoc.models.grading_project_survey_record import \
     GSoCGradingProjectSurveyRecord
 from soc.modules.gsoc.views import forms as gsoc_forms
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 from soc.modules.gsoc.views.helper import url_patterns
 
@@ -89,7 +85,7 @@
     return True if grade == 'True' else False
 
 
-class GSoCMentorEvaluationEditPage(RequestHandler):
+class GSoCMentorEvaluationEditPage(GSoCRequestHandler):
   """View for creating/editing organization evaluation form.
   """
 
@@ -168,7 +164,7 @@
       self.get()
 
 
-class GSoCMentorEvaluationTakePage(RequestHandler):
+class GSoCMentorEvaluationTakePage(GSoCRequestHandler):
   """View for the organization to submit student evaluation.
   """
 
@@ -255,7 +251,7 @@
       self.get()
 
 
-class GSoCMentorEvaluationPreviewPage(RequestHandler):
+class GSoCMentorEvaluationPreviewPage(GSoCRequestHandler):
   """View for the host preview mentor evaluation.
   """
 
@@ -289,7 +285,7 @@
     return context
 
 
-class GSoCMentorEvaluationRecordsList(RequestHandler):
+class GSoCMentorEvaluationRecordsList(GSoCRequestHandler):
   """View for listing all records of a GSoCGradingProjectSurveyRecord.
   """
 
@@ -358,7 +354,7 @@
     survey_name = 'Mentor Evaluation'
 
 
-class GSoCMentorEvaluationShowPage(RequestHandler):
+class GSoCMentorEvaluationShowPage(GSoCRequestHandler):
   """View to display the readonly page for mentor evaluation.
   """
 
diff --git a/app/soc/modules/gsoc/views/org_app.py b/app/soc/modules/gsoc/views/org_app.py
index 2508f6e..463ae05 100644
--- a/app/soc/modules/gsoc/views/org_app.py
+++ b/app/soc/modules/gsoc/views/org_app.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GSoC Organization Application.
-"""
-
+"""Module containing the views for GSoC Organization Application."""
 
 import logging
 
@@ -32,7 +28,7 @@
 
 from soc.logic import org_app as org_app_logic
 from soc.modules.gsoc.views import forms as gsoc_forms
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper import url_names
 from soc.modules.gsoc.views.helper.url_patterns import url
 
@@ -71,7 +67,7 @@
     return 'v2/modules/gsoc/_form.html'
 
 
-class GSoCOrgAppEditPage(RequestHandler):
+class GSoCOrgAppEditPage(GSoCRequestHandler):
   """View for creating/editing organization application.
   """
 
@@ -100,9 +96,12 @@
     else:
       page_name = 'Create new organization application'
 
+    # TODO(nathaniel): is this really necessary?
+    self.redirect.program()
+
     context = {
         'page_name': page_name,
-        'post_url': self.redirect.program().urlOf('gsoc_edit_org_app'),
+        'post_url': self.redirect.urlOf('gsoc_edit_org_app'),
         'forms': [form],
         'error': bool(form.errors),
         }
@@ -139,13 +138,14 @@
   def post(self):
     org_app = self.orgAppFromForm()
     if org_app:
-      r = self.redirect.program()
-      r.to('gsoc_edit_org_app', validated=True)
+      # TODO(nathaniel): is this necessary?
+      self.redirect.program()
+      self.redirect.to('gsoc_edit_org_app', validated=True)
     else:
       self.get()
 
 
-class GSoCOrgAppPreviewPage(RequestHandler):
+class GSoCOrgAppPreviewPage(GSoCRequestHandler):
   """View for organizations to submit their application.
   """
 
@@ -177,7 +177,7 @@
     return context
 
 
-class GSoCOrgAppTakePage(RequestHandler):
+class GSoCOrgAppTakePage(GSoCRequestHandler):
   """View for organizations to submit their application.
   """
 
@@ -265,12 +265,12 @@
       self.get()
 
 
-class GSoCOrgAppRecordsList(org_app.OrgAppRecordsList, RequestHandler):
+class GSoCOrgAppRecordsList(org_app.OrgAppRecordsList, GSoCRequestHandler):
   """View for listing all records of a GSoC Organization application.
   """
 
   def __init__(self, *args, **kwargs):
-    RequestHandler.__init__(self, *args, **kwargs)
+    GSoCRequestHandler.__init__(self, *args, **kwargs)
     org_app.OrgAppRecordsList.__init__(self, 'gsoc_show_org_app')
 
   def djangoURLPatterns(self):
@@ -332,7 +332,7 @@
   template_path = 'v2/modules/gsoc/org_app/readonly_template.html'
 
 
-class GSoCOrgAppShowPage(RequestHandler):
+class GSoCOrgAppShowPage(GSoCRequestHandler):
   """View to display the readonly page for organization application.
   """
 
@@ -363,9 +363,9 @@
 
     if record:
       context['record'] = OrgAppReadOnlyTemplate(record)
-      
+
       # admin info should be available only to the hosts
-      if self.data.is_host: 
+      if self.data.is_host:
         context['main_admin_url'] = self.data.redirect.profile(
             record.main_admin.link_id).urlOf(url_names.GSOC_PROFILE_SHOW)
         context['backup_admin_url'] = self.data.redirect.profile(
@@ -376,7 +376,8 @@
         context['update_link'] = self.data.redirect.id().urlOf(
             'gsoc_retake_org_app')
       else:
-        context['create_link'] = self.data.redirect.program().urlOf(
-            'gsoc_take_org_app')
+        # TODO(nathaniel): is this program() necessary?
+        self.data.redirect.program()
+        context['create_link'] = self.data.redirect.urlOf('gsoc_take_org_app')
 
     return context
diff --git a/app/soc/modules/gsoc/views/org_home.py b/app/soc/modules/gsoc/views/org_home.py
index 7fc81f1..23d69d8 100644
--- a/app/soc/modules/gsoc/views/org_home.py
+++ b/app/soc/modules/gsoc/views/org_home.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for GSoC Homepage.
-"""
-
+"""Module containing the views for GSoC Homepage."""
 
 from django.conf.urls.defaults import url as django_url
 from django.utils.translation import ugettext
@@ -36,7 +32,7 @@
 from soc.modules.gsoc.models.organization import GSoCOrganization
 from soc.modules.gsoc.models.profile import GSoCProfile
 from soc.modules.gsoc.models.project import GSoCProject
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper import url_names
 from soc.modules.gsoc.views.helper.url_patterns import url
 
@@ -51,7 +47,6 @@
 
   def context(self):
     organization = self.data.organization
-    r = self.data.redirect
 
     context = {
         'request_data': self.data,
@@ -67,21 +62,24 @@
 
       if self.data.timeline.studentSignup():
         context['student_apply_block'] = True
-        profile_link = r.createProfile('student').urlOf('create_gsoc_profile',
-                                                        secure=True)
+        profile_link = self.data.redirect.createProfile('student').urlOf(
+            'create_gsoc_profile', secure=True)
         context['student_profile_link'] = profile_link + suffix
       else:
         context['mentor_apply_block'] = True
 
-      profile_link = r.createProfile('mentor').urlOf('create_gsoc_profile',
-                                                     secure=True)
+      profile_link = self.data.redirect.createProfile('mentor').urlOf(
+          'create_gsoc_profile', secure=True)
       context['mentor_profile_link'] = profile_link + suffix
       return context
 
     if self.data.student_info:
       if self.data.timeline.studentSignup():
         context['student_apply_block'] = True
-        submit_proposal_link = r.organization().urlOf('submit_gsoc_proposal')
+        # TODO(nathaniel): make this .organization() call unnecessary.
+        self.data.redirect.organization()
+
+        submit_proposal_link = self.data.redirect.urlOf('submit_gsoc_proposal')
         context['submit_proposal_link'] = submit_proposal_link
 
       return context
@@ -110,7 +108,10 @@
       context['invited_role'] = 'an administrator'
       return context
 
-    request_mentor_link = r.organization().urlOf('gsoc_request')
+    # TODO(nathaniel): make this .organization() call unnecessary.
+    self.data.redirect.organization()
+
+    request_mentor_link = self.data.redirect.urlOf('gsoc_request')
     context['mentor_request_link'] = request_mentor_link
     return context
 
@@ -199,7 +200,7 @@
     return "v2/modules/gsoc/org_home/_project_list.html"
 
 
-class GSoCBanOrgPost(BanOrgPost, RequestHandler):
+class GSoCBanOrgPost(BanOrgPost, GSoCRequestHandler):
   """Handles banning/unbanning of GSoC organizations.
   """
 
@@ -219,7 +220,7 @@
 class GSoCHostActions(HostActions):
   """Template to render the left side host actions.
   """
-  
+
   DEF_BAN_ORGANIZATION_HELP = ugettext(
       'When an organization is banned, it is not active in the program')
 
@@ -230,7 +231,7 @@
     return self.DEF_BAN_ORGANIZATION_HELP
 
 
-class OrgHome(RequestHandler):
+class OrgHome(GSoCRequestHandler):
   """View methods for Organization Home page.
   """
 
@@ -290,15 +291,21 @@
       context['ideas_link_trimmed'] = url_helper.trim_url_to(ideas, 50)
 
     if self.data.orgAdminFor(organization):
-      r = self.redirect
-      r.organization(organization)
-      context['edit_link'] =  r.urlOf('edit_gsoc_org_profile')
-      context['invite_admin_link'] = r.invite('org_admin').urlOf('gsoc_invite')
-      context['invite_mentor_link'] = r.invite('mentor').urlOf('gsoc_invite')
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.redirect.organization(organization=organization)
+
+      context['edit_link'] =  self.redirect.urlOf('edit_gsoc_org_profile')
+      context['invite_admin_link'] = self.redirect.invite('org_admin').urlOf(
+          'gsoc_invite')
+      context['invite_mentor_link'] = self.redirect.invite('mentor').urlOf(
+          'gsoc_invite')
 
       if (self.data.program.allocations_visible and
           self.data.timeline.beforeStudentsAnnounced()):
-        context['slot_transfer_link'] = r.organization(organization).urlOf(
+        # TODO(nathaniel): make this .organization call unnecessary.
+        self.redirect.organization(organization=organization)
+
+        context['slot_transfer_link'] = self.redirect.urlOf(
             'gsoc_slot_transfer')
 
     if self.data.timeline.studentsAnnounced():
@@ -312,13 +319,12 @@
     return context
 
   def getCurrentTimeline(self, timeline, org_app):
-    """Return where we are currently on the timeline.
-    """
+    """Return where we are currently on the timeline."""
     if timeline_helper.isActivePeriod(org_app, 'survey'):
       return 'org_signup_period'
     elif timeline_helper.isActivePeriod(timeline, 'student_signup'):
       return 'student_signup_period'
     elif timeline_helper.isActivePeriod(timeline, 'program'):
       return 'program_period'
-
-    return 'offseason'
+    else:
+      return 'offseason'
diff --git a/app/soc/modules/gsoc/views/org_profile.py b/app/soc/modules/gsoc/views/org_profile.py
index d84822e..33584ef 100644
--- a/app/soc/modules/gsoc/views/org_profile.py
+++ b/app/soc/modules/gsoc/views/org_profile.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC organization profile page.
-"""
-
+"""Module for the GSoC organization profile page."""
 
 from soc.views import forms
 
@@ -27,7 +23,7 @@
 from soc.views import org_profile
 
 from soc.modules.gsoc.models.organization import GSoCOrganization
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 from soc.modules.gsoc.views import forms as gsoc_forms
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -143,7 +139,7 @@
         ['contact_country', 'shipping_country'])
 
 
-class OrgProfilePage(RequestHandler):
+class OrgProfilePage(GSoCRequestHandler):
   """View for the Organization Profile page.
   """
 
@@ -191,18 +187,21 @@
         }
 
     if self.data.organization:
-      r = self.data.redirect.organization()
-      context['org_home_page_link'] = r.urlOf('gsoc_org_home')
+      # TODO(nathaniel): make this .organization() unnecessary.
+      self.data.redirect.organization()
+
+      context['org_home_page_link'] = self.data.redirect.urlOf('gsoc_org_home')
       if (self.data.program.allocations_visible and
             self.data.timeline.beforeStudentsAnnounced()):
-        context['slot_transfer_page_link'] = r.urlOf('gsoc_slot_transfer')
+        context['slot_transfer_page_link'] = self.data.redirect.urlOf(
+            'gsoc_slot_transfer')
 
     return context
 
   def post(self):
     org_profile = self.createOrgProfileFromForm()
     if org_profile:
-      self.redirect.organization(org_profile)
+      self.redirect.organization(organization=org_profile)
       self.redirect.to('edit_gsoc_org_profile', validated=True)
     else:
       self.get()
diff --git a/app/soc/modules/gsoc/views/profile.py b/app/soc/modules/gsoc/views/profile.py
index a13d67b..9f33d44 100644
--- a/app/soc/modules/gsoc/views/profile.py
+++ b/app/soc/modules/gsoc/views/profile.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC profile page.
-"""
-
+"""Module for the GSoC profile page."""
 
 from django.forms import fields
 from django.core.urlresolvers import reverse
@@ -35,7 +31,7 @@
 from soc.modules.gsoc.models.profile import GSoCProfile
 from soc.modules.gsoc.models.profile import GSoCStudentInfo
 from soc.modules.gsoc.views import forms as gsoc_forms
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 
 
@@ -195,9 +191,8 @@
   clean_school_home_page =  cleaning.clean_url('school_home_page')
 
 
-class GSoCProfilePage(profile.ProfilePage, RequestHandler):
-  """View for the GSoC participant profile.
-  """
+class GSoCProfilePage(profile.ProfilePage, GSoCRequestHandler):
+  """View for the GSoC participant profile."""
 
   def checkAccess(self):
     self.check.isLoggedIn()
diff --git a/app/soc/modules/gsoc/views/profile_show.py b/app/soc/modules/gsoc/views/profile_show.py
index aab7629..73522c7 100644
--- a/app/soc/modules/gsoc/views/profile_show.py
+++ b/app/soc/modules/gsoc/views/profile_show.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for displaying the GSoC profile read only page.
-"""
-
+"""Module for displaying the GSoC profile read only page."""
 
 from django.utils.translation import ugettext
 
@@ -29,7 +25,7 @@
 from soc.modules.gsoc.models.profile import GSoCProfile
 from soc.modules.gsoc.models.project import GSoCProject
 from soc.modules.gsoc.views import readonly_template
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 from soc.modules.gsoc.views.helper import url_names
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -54,7 +50,7 @@
 class GSoCHostActions(profile_show.HostActions):
   """Template to render the left side host actions.
   """
-  
+
   DEF_BAN_PROFILE_HELP = ugettext(
       'When a profile is banned, the user cannot participate in the program')
 
@@ -65,7 +61,7 @@
     return self.DEF_BAN_PROFILE_HELP
 
 
-class GSoCBanProfilePost(profile_show.BanProfilePost, RequestHandler):
+class GSoCBanProfilePost(profile_show.BanProfilePost, GSoCRequestHandler):
   """Handles banning/unbanning of GSoC profiles.
   """
 
@@ -82,7 +78,7 @@
     return GSoCProfile
 
 
-class GSoCProfileShowPage(profile_show.ProfileShowPage, RequestHandler):
+class GSoCProfileShowPage(profile_show.ProfileShowPage, GSoCRequestHandler):
   """View to display the read-only profile page.
   """
 
@@ -99,7 +95,7 @@
     return GSoCProfileReadOnlyTemplate(profile)
 
 
-class GSoCProfileAdminPage(RequestHandler):
+class GSoCProfileAdminPage(GSoCRequestHandler):
   """View to display the readonly profile page.
   """
 
diff --git a/app/soc/modules/gsoc/views/program.py b/app/soc/modules/gsoc/views/program.py
index 83b72a8..520b599 100644
--- a/app/soc/modules/gsoc/views/program.py
+++ b/app/soc/modules/gsoc/views/program.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,37 +12,32 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the program settings pages.
-"""
+"""Module for the program settings pages."""
 
+from soc.models import document
 
-from soc.models.document import Document
+from soc.views import program as soc_program_view
+from soc.views.helper import url_patterns as soc_url_patterns
 
-from soc.views import program as program_view
-from soc.views.helper import url_patterns
-
-from soc.modules.gsoc.models.program import GSoCProgram
-from soc.modules.gsoc.models.program import GSoCProgramMessages
-from soc.modules.gsoc.models.timeline import GSoCTimeline
-from soc.modules.gsoc.views.base import RequestHandler
-from soc.modules.gsoc.views.forms import GSoCModelForm
+from soc.modules.gsoc.models import program
+from soc.modules.gsoc.models import timeline
+from soc.modules.gsoc.views import base
+from soc.modules.gsoc.views import forms
 from soc.modules.gsoc.views.helper import url_names
-from soc.modules.gsoc.views.helper.url_patterns import url
+from soc.modules.gsoc.views.helper import url_patterns
 
 
-class TimelineForm(GSoCModelForm):
-  """Django form to edit timeline settings.
-  """
+class TimelineForm(forms.GSoCModelForm):
+  """Django form to edit timeline settings."""
 
   class Meta:
     css_prefix = 'timeline_form'
-    model = GSoCTimeline
+    model = timeline.GSoCTimeline
     exclude = ['link_id', 'scope', 'scope_path']
 
 
-class ProgramForm(GSoCModelForm):
-  """Django form for the program settings.
-  """
+class ProgramForm(forms.GSoCModelForm):
+  """Django form for the program settings."""
 
   def __init__(self, request_data, *args, **kwargs):
     self.request_data = request_data
@@ -52,38 +45,36 @@
 
   class Meta:
     css_prefix = 'program_form'
-    model = GSoCProgram
+    model = program.GSoCProgram
     exclude = ['link_id', 'scope', 'scope_path', 'timeline',
                'home', 'slots_allocation', 'student_max_age',
                'min_slots']
 
 
-class GSoCProgramMessagesForm(GSoCModelForm):
-  """Django form for the program settings.
-  """
+class GSoCProgramMessagesForm(forms.GSoCModelForm):
+  """Django form for the program settings."""
 
   def __init__(self, request_data, *args, **kwargs):
     self.request_data = request_data
-    super(GSoCProgramMessagesForm, self).__init__(*args, **kwargs)
+    super(program.GSoCProgramMessagesForm, self).__init__(*args, **kwargs)
 
   class Meta:
     css_prefix = 'program_messages_form'
-    model = GSoCProgramMessages
+    model = program.GSoCProgramMessages
 
 
-class ProgramPage(RequestHandler):
-  """View for the program profile.
-  """
+class ProgramPage(base.GSoCRequestHandler):
+  """View for the program profile."""
 
   def djangoURLPatterns(self):
     return [
-        url(r'program/%s$' % url_patterns.PROGRAM, self,
+        url_patterns.url(r'program/%s$' % soc_url_patterns.PROGRAM, self,
             name='edit_gsoc_program'),
-        url(r'program/edit/%s$' % url_patterns.PROGRAM, self),
+        url_patterns.url(r'program/edit/%s$' % soc_url_patterns.PROGRAM, self),
     ]
 
   def jsonContext(self):
-    q = Document.all()
+    q = document.Document.all()
     q.filter('prefix', 'gsoc_program')
     q.filter('scope', self.data.program.key())
 
@@ -115,19 +106,15 @@
     program_form = ProgramForm(self.data, self.data.POST,
                                instance=self.data.program)
 
-    if not program_form.is_valid():
+    if program_form.is_valid():
+      program_form.save()
+      return True
+    else:
       return False
 
-    program_form.save()
-    return True
-
   def post(self):
-    """Handler for HTTP POST request.
-    """
-    if self.data.GET.get('cbox'):
-      cbox = True
-    else:
-      cbox = False
+    """Handler for HTTP POST request."""
+    cbox = bool(self.data.GET.get('cbox'))
 
     if self.validate():
       self.redirect.program()
@@ -136,15 +123,14 @@
       self.get()
 
 
-class TimelinePage(RequestHandler):
-  """View for the participant profile.
-  """
+class TimelinePage(base.GSoCRequestHandler):
+  """View for the participant profile."""
 
   def djangoURLPatterns(self):
     return [
-        url(r'timeline/%s$' % url_patterns.PROGRAM, self,
+        url_patterns.url(r'timeline/%s$' % soc_url_patterns.PROGRAM, self,
             name='edit_gsoc_timeline'),
-        url(r'timeline/edit/%s$' % url_patterns.PROGRAM, self),
+        url_patterns.url(r'timeline/edit/%s$' % soc_url_patterns.PROGRAM, self),
     ]
 
   def checkAccess(self):
@@ -166,19 +152,15 @@
     timeline_form = TimelineForm(self.data.POST,
                                  instance=self.data.program_timeline)
 
-    if not timeline_form.is_valid():
+    if timeline_form.is_valid():
+      timeline_form.save()
+      return True
+    else:
       return False
 
-    timeline_form.save()
-    return True
-
   def post(self):
-    """Handler for HTTP POST request.
-    """
-    if self.data.GET.get('cbox'):
-      cbox = True
-    else:
-      cbox = False
+    """Handler for HTTP POST request."""
+    cbox = bool(self.data.GET.get('cbox'))
 
     if self.validate():
       self.redirect.program()
@@ -188,13 +170,13 @@
 
 
 class GSoCProgramMessagesPage(
-    program_view.ProgramMessagesPage, RequestHandler):
-  """View for the content of GSoC program specific messages to be sent.
-  """
+    soc_program_view.ProgramMessagesPage, base.GSoCRequestHandler):
+  """View for the content of GSoC program specific messages to be sent."""
 
   def djangoURLPatterns(self):
     return [
-        url(r'program/messages/edit/%s$' % url_patterns.PROGRAM, self,
+        url_patterns.url(
+            r'program/messages/edit/%s$' % soc_url_patterns.PROGRAM, self,
             name=self._getUrlName()),
     ]
 
@@ -202,11 +184,11 @@
     return 'v2/modules/gsoc/program/messages.html'
 
   def _getForm(self, entity):
-    return GSoCProgramMessagesForm(self.data, self.data.POST or None,
+    return program.GSoCProgramMessagesForm(self.data, self.data.POST or None,
         instance=entity)
 
   def _getModel(self):
-    return GSoCProgramMessages
+    return program.GSoCProgramMessages
 
   def _getUrlName(self):
     return url_names.GSOC_EDIT_PROGRAM_MESSAGES
diff --git a/app/soc/modules/gsoc/views/project_details.py b/app/soc/modules/gsoc/views/project_details.py
index 14af15c..fc0def6 100644
--- a/app/soc/modules/gsoc/views/project_details.py
+++ b/app/soc/modules/gsoc/views/project_details.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the view for GSoC project details page.
-"""
+"""Module containing the view for GSoC project details page."""
 
+import httplib
 
 from google.appengine.ext import blobstore
 from google.appengine.ext import db
@@ -37,7 +35,7 @@
 from soc.modules.gsoc.models.code_sample import GSoCCodeSample
 from soc.modules.gsoc.views import assign_mentor
 from soc.modules.gsoc.views import forms as gsoc_forms
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper import url_names
 from soc.modules.gsoc.views.helper import url_patterns
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -169,7 +167,7 @@
     return 'v2/modules/gsoc/project_details/_upload_code_samples.html'
 
 
-class ProjectDetailsUpdate(RequestHandler):
+class ProjectDetailsUpdate(GSoCRequestHandler):
   """Encapsulate the methods required to generate Project Details update form.
   """
 
@@ -235,7 +233,7 @@
       self.get()
 
 
-class CodeSampleUploadFilePost(RequestHandler):
+class CodeSampleUploadFilePost(GSoCRequestHandler):
   """Handler for POST requests to upload files with code samples.
   """
 
@@ -291,7 +289,7 @@
     self.redirect.to('gsoc_project_details')
 
 
-class CodeSampleDownloadFileGet(RequestHandler):
+class CodeSampleDownloadFileGet(GSoCRequestHandler):
   """Handler for POST requests to download files with code samples.
   """
 
@@ -325,7 +323,7 @@
       raise BadRequest('id argument in GET data is not a number')
 
 
-class CodeSampleDeleteFilePost(RequestHandler):
+class CodeSampleDeleteFilePost(GSoCRequestHandler):
   """Handler for POST requests to delete code sample files.
   """
 
@@ -423,7 +421,7 @@
     return "v2/modules/gsoc/project_details/_user_action.html"
 
 
-class ProjectDetails(RequestHandler):
+class ProjectDetails(GSoCRequestHandler):
   """Encapsulate all the methods required to generate GSoC project
   details page.
   """
@@ -441,21 +439,18 @@
     ]
 
   def checkAccess(self):
-    """Access checks for GSoC project details page.
-    """
+    """Access checks for GSoC project details page."""
     self.mutator.projectFromKwargs()
 
   def context(self):
-    """Handler to for GSoC project details page HTTP get request.
-    """
-    project = self.data.project
-
-    r = self.redirect
+    """Handler to for GSoC project details page HTTP get request."""
+    # TODO(nathaniel): make this .organization call unnecessary?
+    self.redirect.organization(organization=self.data.project.org)
 
     context = {
         'page_name': 'Project details',
-        'project': project,
-        'org_home_link': r.organization(project.org).urlOf('gsoc_org_home'),
+        'project': self.data.project,
+        'org_home_link': self.redirect.urlOf('gsoc_org_home'),
     }
 
     if self.data.orgAdminFor(self.data.project.org):
@@ -464,7 +459,8 @@
     user_is_owner = self.data.user and \
         (self.data.user.key() == self.data.project_owner.parent_key())
     if user_is_owner:
-      context['update_link'] = r.project().urlOf(url_names.GSOC_PROJECT_UPDATE)
+      context['update_link'] = self.redirect.project().urlOf(
+          url_names.GSOC_PROJECT_UPDATE)
 
     if len(self.data.project.passed_evaluations) >= \
         project_logic.NUMBER_OF_EVALUATIONS:
@@ -473,7 +469,7 @@
     return context
 
 
-class AssignMentors(RequestHandler):
+class AssignMentors(GSoCRequestHandler):
   """View which handles assigning mentor to a project.
   """
 
@@ -542,10 +538,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class FeaturedProject(RequestHandler):
+class FeaturedProject(GSoCRequestHandler):
   """View which handles making the project featured by toggle button.
   """
 
@@ -597,4 +593,4 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
diff --git a/app/soc/modules/gsoc/views/projects_list.py b/app/soc/modules/gsoc/views/projects_list.py
index d87614b..6c43769 100644
--- a/app/soc/modules/gsoc/views/projects_list.py
+++ b/app/soc/modules/gsoc/views/projects_list.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +13,7 @@
 # limitations under the License.
 
 """Module containing the views for listing all the projects accepted
-into a GSoC program, excluding those which have been withdrawn 
+into a GSoC program, excluding those which have been withdrawn
 or failed one of the evaluations.
 """
 
@@ -28,7 +26,7 @@
 
 from soc.modules.gsoc.logic import project as project_logic
 from soc.modules.gsoc.models.project import GSoCProject
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
@@ -38,7 +36,7 @@
 
   def __init__(self, request, data, query, idx=0):
     """Initializes a new object.
-    
+
     Args:
       request: request object
       data: RequestData object associated with the request
@@ -117,7 +115,7 @@
     return "v2/modules/gsoc/projects_list/_project_list.html"
 
 
-class ListProjects(RequestHandler):
+class ListProjects(GSoCRequestHandler):
   """View methods for listing all the projects accepted into a program.
   """
 
diff --git a/app/soc/modules/gsoc/views/proposal.py b/app/soc/modules/gsoc/views/proposal.py
index 7231d4f..6b29a7d 100644
--- a/app/soc/modules/gsoc/views/proposal.py
+++ b/app/soc/modules/gsoc/views/proposal.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC proposal page.
-"""
-
+"""Module for the GSoC proposal page."""
 
 from google.appengine.ext import db
 
@@ -30,7 +26,7 @@
 from soc.modules.gsoc.logic.helper import notifications
 from soc.modules.gsoc.models.proposal import GSoCProposal
 from soc.modules.gsoc.models.profile import GSoCProfile
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.forms import GSoCModelForm
 from soc.modules.gsoc.views.helper import url_patterns as gsoc_url_patterns
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -49,7 +45,7 @@
 
   clean_content = cleaning.clean_html_content('content')
 
-class ProposalPage(RequestHandler):
+class ProposalPage(GSoCRequestHandler):
   """View for the submit proposal.
   """
 
@@ -139,7 +135,7 @@
       self.get()
 
 
-class UpdateProposal(RequestHandler):
+class UpdateProposal(GSoCRequestHandler):
   """View for the update proposal page.
   """
 
diff --git a/app/soc/modules/gsoc/views/proposal_review.py b/app/soc/modules/gsoc/views/proposal_review.py
index 767df31..4b84568 100644
--- a/app/soc/modules/gsoc/views/proposal_review.py
+++ b/app/soc/modules/gsoc/views/proposal_review.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,9 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC proposal page.
-"""
+"""Module for the GSoC proposal page."""
 
+import httplib
 
 from google.appengine.ext import db
 
@@ -41,7 +39,7 @@
 from soc.modules.gsoc.models.profile import GSoCProfile
 from soc.modules.gsoc.models.score import GSoCScore
 from soc.modules.gsoc.views import assign_mentor
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.forms import GSoCModelForm
 from soc.modules.gsoc.views.helper import url_patterns
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -95,10 +93,7 @@
     super(Duplicate, self).__init__(data)
 
   def context(self):
-    """The context for this template used in render().
-    """
-    r = self.data.redirect
-
+    """The context for this template used in render()."""
     orgs = []
     for org in db.get(self.duplicate.orgs):
       q = GSoCProfile.all()
@@ -106,8 +101,11 @@
       q.filter('status', 'active')
       admins = q.fetch(1000)
 
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.data.redirect.organization(organization=org)
+
       data = {'name': org.name,
-              'link': r.organization(org).urlOf('gsoc_org_home'),
+              'link': self.data.redirect.urlOf('gsoc_org_home'),
               'admins': admins}
 
       orgs.append(data)
@@ -301,7 +299,7 @@
     return "v2/modules/gsoc/proposal/_user_action.html"
 
 
-class ReviewProposal(RequestHandler):
+class ReviewProposal(GSoCRequestHandler):
   """View for the Propsal Review page.
   """
 
@@ -492,7 +490,7 @@
     return context
 
 
-class PostComment(RequestHandler):
+class PostComment(GSoCRequestHandler):
   """View which handles publishing comments.
   """
 
@@ -585,10 +583,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class PostScore(RequestHandler):
+class PostScore(GSoCRequestHandler):
   """View which handles posting scores.
   """
 
@@ -674,10 +672,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class WishToMentor(RequestHandler):
+class WishToMentor(GSoCRequestHandler):
   """View handling wishing to mentor requests.
   """
 
@@ -738,10 +736,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class AssignMentor(RequestHandler):
+class AssignMentor(GSoCRequestHandler):
   """View which handles assigning mentor to a proposal.
   """
 
@@ -826,10 +824,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class IgnoreProposal(RequestHandler):
+class IgnoreProposal(GSoCRequestHandler):
   """View which allows org admins to ignore a proposal.
   """
 
@@ -884,10 +882,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class ProposalModificationPostDeadline(RequestHandler):
+class ProposalModificationPostDeadline(GSoCRequestHandler):
   """View allowing mentors to allow students to modify the proposal.
   """
 
@@ -940,10 +938,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class AcceptProposal(RequestHandler):
+class AcceptProposal(GSoCRequestHandler):
   """View allowing org admins to directly accept the proposal.
   """
 
@@ -995,10 +993,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class ProposalPubliclyVisible(RequestHandler):
+class ProposalPubliclyVisible(GSoCRequestHandler):
   """View allowing the proposer to make the proposal publicly visible.
   """
 
@@ -1049,10 +1047,10 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
 
-class WithdrawProposal(RequestHandler):
+class WithdrawProposal(GSoCRequestHandler):
   """View allowing the proposer to withdraw the proposal.
   """
 
@@ -1104,4 +1102,4 @@
   def get(self):
     """Special Handler for HTTP GET request since this view only handles POST.
     """
-    self.error(405)
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
diff --git a/app/soc/modules/gsoc/views/request.py b/app/soc/modules/gsoc/views/request.py
index c4f8390..4134f51 100644
--- a/app/soc/modules/gsoc/views/request.py
+++ b/app/soc/modules/gsoc/views/request.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the view for GSoC request page.
-"""
-
+"""Module containing the view for GSoC request page."""
 
 from google.appengine.ext import db
 
@@ -33,7 +29,7 @@
 
 from soc.modules.gsoc.models.profile import GSoCProfile
 from soc.modules.gsoc.models.request import GSoCRequest
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 from soc.modules.gsoc.views.forms import GSoCModelForm
 from soc.modules.gsoc.views.helper.url_patterns import url
@@ -74,7 +70,7 @@
     fields = ['message']
 
 
-class RequestPage(RequestHandler):
+class RequestPage(GSoCRequestHandler):
   """Encapsulate all the methods required to generate Request page.
   """
   def templatePath(self):
@@ -169,7 +165,7 @@
     return db.run_in_transaction(create_request_txn)
 
 
-class ShowRequest(RequestHandler):
+class ShowRequest(GSoCRequestHandler):
   """Encapsulate all the methods required to generate Show Request page.
   """
   # maps actions with button names
diff --git a/app/soc/modules/gsoc/views/search.py b/app/soc/modules/gsoc/views/search.py
index 30bfa60..3d78f2d 100644
--- a/app/soc/modules/gsoc/views/search.py
+++ b/app/soc/modules/gsoc/views/search.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,21 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC search page.
-"""
-
+"""Module for the GSoC search page."""
 
 import os
 
 from soc.views.helper import url_patterns
 
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views import base
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
-class SearchGsocPage(RequestHandler):
-  """View for the search gsoc page.
-  """
+class SearchGsocPage(base.GSoCRequestHandler):
+  """View for the search gsoc page."""
 
   def djangoURLPatterns(self):
     return [
diff --git a/app/soc/modules/gsoc/views/slot_transfer.py b/app/soc/modules/gsoc/views/slot_transfer.py
index 0d5a7b5..a18ce6b 100644
--- a/app/soc/modules/gsoc/views/slot_transfer.py
+++ b/app/soc/modules/gsoc/views/slot_transfer.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC slot transfer page.
-"""
-
+"""Module for the GSoC slot transfer page."""
 
 from google.appengine.ext import db
 
@@ -31,7 +27,7 @@
 from soc.modules.gsoc.logic.helper import notifications
 from soc.modules.gsoc.models.slot_transfer import GSoCSlotTransfer
 from soc.modules.gsoc.views import readonly_template
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views import forms
 from soc.modules.gsoc.views.helper.url_patterns import url
 
@@ -72,7 +68,7 @@
     exclude = ['program']
 
 
-class SlotTransferPage(RequestHandler):
+class SlotTransferPage(GSoCRequestHandler):
   """View for transferring the slots.
   """
 
@@ -92,8 +88,10 @@
     self.mutator.slotTransferEntities()
     if not self.data.slot_transfer_entities:
       if 'new' not in self.data.kwargs:
-        r = self.data.redirect
-        new_url = r.organization().urlOf('gsoc_update_slot_transfer')
+        # TODO(nathaniel): make this .organization() call unnecessary.
+        self.data.redirect.organization()
+
+        new_url = self.data.redirect.urlOf('gsoc_update_slot_transfer')
         raise RedirectRequest(new_url)
 
   def templatePath(self):
@@ -114,8 +112,10 @@
 
     if (self.data.program.allocations_visible and
         self.data.timeline.beforeStudentsAnnounced()):
-      r = self.data.redirect.organization()
-      edit_url = r.urlOf('gsoc_update_slot_transfer')
+      # TODO(nathaniel): make this .organization() call unnecessary.
+      self.data.redirect.organization()
+
+      edit_url = self.data.redirect.urlOf('gsoc_update_slot_transfer')
       if require_new_link:
         context['new_slot_transfer_page_link'] = edit_url
       else:
@@ -124,7 +124,7 @@
     return context
 
 
-class UpdateSlotTransferPage(RequestHandler):
+class UpdateSlotTransferPage(GSoCRequestHandler):
   """View for transferring the slots.
   """
 
@@ -170,9 +170,12 @@
         'error': slot_transfer_form.errors
         }
 
-    r = self.data.redirect.organization()
-    context['org_home_page_link'] = r.urlOf('gsoc_org_home')
-    context['slot_transfer_page_link'] = r.urlOf('gsoc_slot_transfer')
+    # TODO(nathaniel): make this .organization() call unnecessary.
+    self.data.redirect.organization()
+
+    context['org_home_page_link'] = self.data.redirect.urlOf('gsoc_org_home')
+    context['slot_transfer_page_link'] = self.data.redirect.urlOf(
+        'gsoc_slot_transfer')
 
     return context
 
@@ -230,12 +233,13 @@
     return db.run_in_transaction(create_or_update_slot_transfer_trx)
 
   def post(self):
-    """Handler for HTTP POST request.
-    """
+    """Handler for HTTP POST request."""
 
     slot_transfer_entity = self.createOrUpdateFromForm()
     if slot_transfer_entity:
-      self.redirect.organization(self.data.organization)
+      # TODO(nathaniel): make this .organization call unnecessary.
+      self.redirect.organization(organization=self.data.organization)
+
       self.redirect.to('gsoc_update_slot_transfer', validated=True)
     else:
       self.get()
diff --git a/app/soc/modules/gsoc/views/slot_transfer_admin.py b/app/soc/modules/gsoc/views/slot_transfer_admin.py
index aec740d..ca28c58 100644
--- a/app/soc/modules/gsoc/views/slot_transfer_admin.py
+++ b/app/soc/modules/gsoc/views/slot_transfer_admin.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC slot transfer admin page.
-"""
-
+"""Module for the GSoC slot transfer admin page."""
 
 import logging
 
@@ -31,7 +27,7 @@
 from soc.views.template import Template
 
 from soc.modules.gsoc.models.slot_transfer import GSoCSlotTransfer
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 
@@ -60,7 +56,7 @@
     list_config.addSimpleColumn('admin_remarks', 'Admin remarks')
     list_config.setColumnEditable('admin_remarks', True) #, edittype='textarea')
     list_config.addColumn(
-        'slots_desired', 'Min desired', 
+        'slots_desired', 'Min desired',
         (lambda e, *args: e.parent().slots_desired), width=25, hidden=True)
     list_config.addColumn(
         'max_slots_desired', 'Max desired',
@@ -110,7 +106,7 @@
 
     if button_id == 'reject':
       return self.postAccept(parsed, False)
-  
+
     if button_id == 'save':
       return self.postSave(parsed)
 
@@ -125,7 +121,7 @@
         slot_transfer = db.get(slot_transfer_key)
 
         if not slot_transfer:
-          logging.warning("Invalid slot_transfer_key '%s'" % 
+          logging.warning("Invalid slot_transfer_key '%s'" %
                           slot_transfer_key)
           return
 
@@ -222,7 +218,7 @@
     return "v2/modules/gsoc/slot_transfer_admin/_list.html"
 
 
-class SlotsTransferAdminPage(RequestHandler):
+class SlotsTransferAdminPage(GSoCRequestHandler):
   """View for the the list of slot transfer requests.
   """
 
diff --git a/app/soc/modules/gsoc/views/statistic.py b/app/soc/modules/gsoc/views/statistic.py
index 8b3a4e1..0f16fbc 100644
--- a/app/soc/modules/gsoc/views/statistic.py
+++ b/app/soc/modules/gsoc/views/statistic.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,6 +14,8 @@
 
 """Module for the GSoC statistics page."""
 
+# TODO(nathaniel): as of 1 December 2012 this module is unused
+# (see soc.modules.gsoc.callback:62). Should it be removed?
 
 from django.utils import simplejson
 from django.core.urlresolvers import reverse
@@ -27,7 +27,7 @@
 from soc.views.toggle_button import ToggleButtonTemplate
 
 from soc.modules.gsoc.models.statistic_info import GSoCStatisticInfo
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.helper.url_patterns import url
 
 from soc.modules.gsoc.statistics import mapping
@@ -36,8 +36,7 @@
 
 
 class ManageActions(Template):
-  """Template to render the left side admin actions.
-  """
+  """Template to render the left side admin actions."""
 
   IS_VISIBLE_HELP_MSG = ugettext(
       'Whether this statistic is publicly visible to all users or not.')
@@ -52,7 +51,7 @@
             labels = {
                 'checked': 'Yes',
                 'unchecked': 'No'})]
-    
+
     return {
         'toggle_buttons': self.toggle_buttons
     }
@@ -64,7 +63,7 @@
   pass
 
 
-class StatisticDashboard(RequestHandler):
+class StatisticDashboard(GSoCRequestHandler):
   """View for the statistic page.
   """
 
@@ -121,7 +120,7 @@
       manage_urls[name] = reverse(
           'gsoc_statistic_manage', kwargs={'key_name': name})
     return manage_urls
-  
+
   def _constructVisibilities(self, infos):
     visibilities = {}
     if self.isHost:
@@ -129,7 +128,7 @@
         visibilities[str(info.name)] = True if info.is_visible else False
     return simplejson.dumps(visibilities)
 
-class StatisticFetcher(RequestHandler):
+class StatisticFetcher(GSoCRequestHandler):
   """Loads data for a particular statistic.
   """
 
@@ -138,7 +137,7 @@
 
   def checkAccess(self):
     key_name = self.data.kwargs['key_name']
-    
+
     # TODO(dhans): check if the statistic is visible
     pass
 
@@ -161,14 +160,14 @@
       raise UnsupportedFormatException('Requested format is not supported.')
 
     return self._presenter.get(key_name)
-    
+
   def jsonContext(self):
     key_name = self.data.kwargs['key_name']
     presentation = self._getPresentation(key_name)
     return presentation
 
 
-class StatisticManager(RequestHandler):
+class StatisticManager(GSoCRequestHandler):
   """Manages the statistic entities.
   """
 
@@ -192,4 +191,3 @@
     if statistic.getVisible() != value:
       statistic.setVisible(value)
       GSoCStatisticInfo.getInstance().updateStatistic(statistic)
-      
\ No newline at end of file
diff --git a/app/soc/modules/gsoc/views/student_evaluation.py b/app/soc/modules/gsoc/views/student_evaluation.py
index 67c7764..4adeb10 100644
--- a/app/soc/modules/gsoc/views/student_evaluation.py
+++ b/app/soc/modules/gsoc/views/student_evaluation.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC project student survey.
-"""
-
+"""Module for the GSoC project student survey."""
 
 from soc.views import forms
 from soc.views import survey
@@ -33,7 +29,7 @@
 from soc.modules.gsoc.models.project_survey_record import \
     GSoCProjectSurveyRecord
 from soc.modules.gsoc.views import forms as gsoc_forms
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.base_templates import LoggedInMsg
 from soc.modules.gsoc.views.helper import url_patterns
 
@@ -66,7 +62,7 @@
     exclude = ['project', 'org', 'user', 'survey', 'created', 'modified']
 
 
-class GSoCStudentEvaluationEditPage(RequestHandler):
+class GSoCStudentEvaluationEditPage(GSoCRequestHandler):
   """View for creating/editing student evalution.
   """
 
@@ -144,7 +140,7 @@
     else:
       self.get()
 
-class GSoCStudentEvaluationTakePage(RequestHandler):
+class GSoCStudentEvaluationTakePage(GSoCRequestHandler):
   """View for students to submit their evaluation.
   """
 
@@ -238,7 +234,7 @@
       self.get()
 
 
-class GSoCStudentEvaluationPreviewPage(RequestHandler):
+class GSoCStudentEvaluationPreviewPage(GSoCRequestHandler):
   """View for the host to preview the evaluation.
   """
 
@@ -272,7 +268,7 @@
     return context
 
 
-class GSoCStudentEvaluationRecordsList(RequestHandler):
+class GSoCStudentEvaluationRecordsList(GSoCRequestHandler):
   """View for listing all records of a GSoCGProjectSurveyRecord.
   """
 
@@ -339,7 +335,7 @@
     survey_name = 'Student Evaluation'
 
 
-class GSoCStudentEvaluationShowPage(RequestHandler):
+class GSoCStudentEvaluationShowPage(GSoCRequestHandler):
   """View to display the readonly page for student evaluation.
   """
 
diff --git a/app/soc/modules/gsoc/views/student_forms.py b/app/soc/modules/gsoc/views/student_forms.py
index 74f2171..086073c 100644
--- a/app/soc/modules/gsoc/views/student_forms.py
+++ b/app/soc/modules/gsoc/views/student_forms.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the GSoC student forms.
-"""
-
+"""Module for the GSoC student forms."""
 
 from google.appengine.ext import blobstore
 
@@ -26,7 +22,7 @@
 from soc.views.helper import url_patterns
 
 from soc.modules.gsoc.models.profile import GSoCStudentInfo
-from soc.modules.gsoc.views.base import RequestHandler
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 from soc.modules.gsoc.views.forms import GSoCModelForm
 from soc.modules.gsoc.views.helper.url_patterns import url
 
@@ -53,8 +49,11 @@
     return self.request_data.kwargs['admin']
 
   def _r(self):
-    r = self.request_data.redirect
-    return r.profile() if self._admin() else r.program()
+    if self._admin:
+      self.request_data.redirect.profile()
+    else:
+      self.request_data.redirect.program()
+    return self.request_data.redirect
 
   def _urlName(self):
     if self._admin():
@@ -97,8 +96,11 @@
     return self.request_data.kwargs['admin']
 
   def _r(self):
-    r = self.request_data.redirect
-    return r.profile() if self._admin() else r.program()
+    if self._admin():
+      self.request_data.redirect.profile()
+    else:
+      self.request_data.redirect.program()
+    return self.request_data.redirect
 
   def _urlName(self):
     if self._admin():
@@ -119,7 +121,7 @@
       field._link = self._r().urlOf(self._urlName())
 
 
-class FormPage(RequestHandler):
+class FormPage(GSoCRequestHandler):
   """View to upload student forms.
   """
 
@@ -195,7 +197,11 @@
     return 'gsoc_enrollment_form'
 
   def _r(self):
-    return self.redirect.profile() if self._admin() else self.redirect.program()
+    if self._admin():
+      self.redirect.profile()
+    else:
+      self.redirect.program()
+    return self.redirect
 
   def jsonContext(self):
     url = self._r().urlOf(self._urlName(), secure=True)
@@ -230,7 +236,7 @@
     self._r().to(self._urlName(), validated=True)
 
 
-class DownloadForm(RequestHandler):
+class DownloadForm(GSoCRequestHandler):
   """View for downloading a student form.
   """
 
diff --git a/app/soc/templates/v2/modules/gci/homepage/_how_it_works.html b/app/soc/templates/v2/modules/gci/homepage/_how_it_works.html
index 4357f43..3cdfab4 100644
--- a/app/soc/templates/v2/modules/gci/homepage/_how_it_works.html
+++ b/app/soc/templates/v2/modules/gci/homepage/_how_it_works.html
@@ -48,6 +48,9 @@
             {% if example_tasks_link %}
             <a class="example-tasks" href="{{ example_tasks_link }}">Or see example tasks</a>
             {% endif %}
+            {% if all_tasks_link %}
+            <a class="all-tasks-tasks" href="{{ all_tasks_link }}">Or see list of tasks</a>
+            {% endif %}
         </div>
     </div>
     {% endif %}
diff --git a/app/soc/templates/v2/modules/gci/homepage/_participating_orgs.html b/app/soc/templates/v2/modules/gci/homepage/_participating_orgs.html
index 4522d49..cb5452e 100644
--- a/app/soc/templates/v2/modules/gci/homepage/_participating_orgs.html
+++ b/app/soc/templates/v2/modules/gci/homepage/_participating_orgs.html
@@ -14,7 +14,7 @@
     {% endfor %}
    </table>
   </div>
-  <div class="block-footer"></div>
+  <div class="block-footer"><a href="{{ org_list_url }}">{% if all_participating_orgs %}Participating organization details{% else %}See all participating organizations{% endif %}</a></div>
  </div>
 {% endif %}
 <!-- end .block.block-home-participating-orgs -->
diff --git a/app/soc/templates/v2/modules/gci/moderate_delete_account/base.html b/app/soc/templates/v2/modules/gci/moderate_delete_account/base.html
new file mode 100644
index 0000000..6d7322f
--- /dev/null
+++ b/app/soc/templates/v2/modules/gci/moderate_delete_account/base.html
@@ -0,0 +1,73 @@
+{% extends "v2/modules/gci/base.html" %}
+{% comment %}
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+  http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+{% endcomment %}
+
+{% block stylesheets %}
+  {{ block.super }}
+  <link rel="stylesheet" type="text/css" media="screen" href="/soc/content/{{ app_version }}/css/v2/gci/account_deletion.css" />
+{% endblock stylesheets %}
+
+{% block page_content %}
+{% if posted %}
+<div class="block block-user-message">
+  <p>You have requested your account to be deleted. All your information will be removed shortly.</p>
+</div>
+{% endif %}
+<div class="block block-page block-delete-account">
+  <div class="block-form-title">
+    <span class="title">Moderate account delete request</span>
+  </div>
+  <div class="block-content clearfix">
+    <div class="delete-info">
+      Name: {{ profile.name }}
+    </div>
+    <div class="delete-info">
+      Link ID: {{ profile.link_id }}
+    </div>
+    <div class="delete-info">
+      User has tasks assigned/closed: {{ has_tasks|yesno:"Yes,No,Maybe" }}
+    </div>
+    <div class="delete-info">
+      User has created or modified tasks: {{ has_created_or_modified_tasks|yesno:"Yes,No,Maybe" }}
+    </div>
+    <div class="delete-info">
+      User has task comments: {{ has_task_comments|yesno:"Yes,No,Maybe" }}
+    </div>
+    <div class="delete-info">
+      User has profiles in previous GCIs: {{ has_other_gci_profiles|yesno:"Yes,No,Maybe" }}
+    </div>
+    <div class="delete-info">
+      User has profiles in previous GSoCs: {{ has_other_gsoc_profiles|yesno:"Yes,No,Maybe" }}
+    </div>
+    <div class="moderate-delete-message">
+      {% if has_tasks or has_created_or_modified_tasks or has_task_comments %}
+        Deleting this profile will replace the current user's profile or
+        user entity with a dummy melange_deleted_user entity.
+      {% endif %}
+    </div>
+    <div class="moderate-delete-message">
+      {% if has_other_gci_profiles or has_other_gsoc_profiles %}
+        Confirming delete will only delete the profile entity for this program
+        and not the corresponding user entity because the user has profiles
+        for other programs.
+      {% endif %}
+    </div>
+    <form action="#" method="post" class="clearfix">
+      <p class="delete-btn-p">
+        <input value="Confirm delete" class="delete-btn" type="submit">
+      </p>
+    </form>
+  </div>
+</div>
+{% endblock page_content %}
\ No newline at end of file
diff --git a/app/soc/views/base.py b/app/soc/views/base.py
index 127a9f0..19fa5e6 100644
--- a/app/soc/views/base.py
+++ b/app/soc/views/base.py
@@ -16,25 +16,20 @@
 module is largely based on appengine's webapp framework's code.
 """
 
-
+import httplib
 import urllib
 
 from google.appengine.ext import db
 
+from django import http
 from django.utils import simplejson
 from django.template import loader
 
-from soc.logic.exceptions import LoginRequest
-from soc.logic.exceptions import RedirectRequest
-from soc.logic.exceptions import AccessViolation
-from soc.logic.exceptions import GDocsLoginRequest
-from soc.logic.exceptions import MaintainceMode
-from soc.logic.exceptions import Error
+from soc.logic import exceptions
 from soc.views.helper import access_checker
-from soc.views.helper.response import Response
 from soc.views.helper import context as context_helper
-from soc.views.helper.request_data import RequestData
-from soc.views.helper.request_data import RedirectHelper
+from soc.views.helper import request_data
+from soc.views.helper import response as response_helper
 
 
 class RequestHandler(object):
@@ -50,12 +45,14 @@
     those to render to construct the page.
     """
     context = self.context()
-    self.render(self.templatePath(), context)
+    template_path = self.templatePath()
+    response_content = self.render(template_path, context)
+    self.response.write(response_content)
 
   def json(self):
     """Handler for HTTP GET request with a 'fmt=json' parameter."""
 
-    if not self.request.GET.get('plain'):
+    if not self.data.request.GET.get('plain'):
       self.response['Content-Type'] = 'application/json'
 
     # if the browser supports HTTP/1.1
@@ -68,7 +65,7 @@
 
     context = self.jsonContext()
 
-    if self.request.GET.get('marker'):
+    if self.data.request.GET.get('marker'):
       # allow the django test framework to capture the context dictionary
       loader.render_to_string('json_marker.html', dictionary=context)
 
@@ -84,130 +81,175 @@
     with 'fmt=json' parameter.
     """
     return {
-        'error': "json() method not implemented",
+        'error': 'json() method not implemented',
     }
 
   def post(self):
-    """Handler for HTTP POST request.
-    """
-    self.error(405)
+    """Handler for HTTP POST request."""
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
   def head(self):
     """Handler for HTTP HEAD request.
+
+    Returns:
+      An http.HttpResponse appropriate for this RequestHandler's request
+        object.
     """
-    self.error(405)
+    return self.error(httplib.METHOD_NOT_ALLOWED)
 
   def options(self):
     """Handler for HTTP OPTIONS request.
+
+    Returns:
+      An http.HttpResponse appropriate for this RequestHandler's request
+        object.
     """
-    self.error(405)
+    return self.error(httplib.METHOD_NOT_ALLOWED)
 
   def put(self):
-    """Handler for HTTP PUT request.
-    """
-    self.error(405)
+    """Handler for HTTP PUT request."""
+    self.response = self.error(httplib.METHOD_NOT_ALLOWED)
 
   def delete(self):
     """Handler for HTTP DELETE request.
+
+    Returns:
+      An http.HttpResponse appropriate for this RequestHandler's request
+        object.
     """
-    self.error(405)
+    return self.error(httplib.METHOD_NOT_ALLOWED)
 
   def trace(self):
     """Handler for HTTP TRACE request.
+
+    Returns:
+      An http.HttpResponse appropriate for this RequestHandler's request
+        object.
     """
-    self.error(405)
+    return self.error(httplib.METHOD_NOT_ALLOWED)
 
   def error(self, status, message=None):
-    """Sets the error response code and message when an error is encountered.
+    """Constructs an HttpResponse indicating an error.
 
     Args:
-      status: the HTTP status error code
-      message: the message to set, uses default if None
+      status: The HTTP status code for the error.
+      message: A message to display to the user. If not supplied, a default
+        appropriate for the given status code (such as "Bad Gateway" or
+        "Payment Required") will be used.
+
+    Returns:
+      An http.HttpResponse indicating an error.
     """
-    self.response.set_status(status, message=message)
-    template_path = "error.html"
+    message = message or httplib.responses.get(status, '')
+
+    template_path = 'error.html'
     context = {
-        'page_name': self.response.content,
-        'message': self.response.content,
+        'page_name': message,
+        'message': message,
     }
 
-    self.response.content = ''
-    self.render(template_path, context)
+    return http.HttpResponse(
+        content=self.render(template_path, context), status=status)
 
   def djangoURLPatterns(self):
-    """Returns a list of Django URL pattern tuples."""
-    return []
+    """Returns a list of Django URL pattern tuples.
+
+    Implementing subclasses must override this method.
+    """
+    raise NotImplementedError()
 
   def checkAccess(self):
-    """Raise an exception if the user doesn't have access to the
-    requested URL.
+    # TODO(nathaniel): eliminate this - it doesn't actually simplify
+    # the HTTP method implementations all that much to have it
+    # separated out.
+    """Ensure that the user's request should be satisfied.
+
+    Implementing subclasses must override this method.
+
+    Implementations must not mutate any of this RequestHandler's state and
+    should merely raise an exception if the user's request should not be
+    satisfied or return normally if the user's request should be satisfied.
+
+    Raises:
+      exceptions.Error: If the user's request should not be satisfied for
+        any reason.
     """
-    self.error(401, "checkAccess in base RequestHandler has not been changed "
-               "to grant access")
+    raise NotImplementedError()
 
   def render(self, template_path, render_context):
-    """Renders the page using the specified context.
+    """Renders the page content from the specified template and context.
 
-    The page is rendered using the template and context specified and
-    is written to the response object.
-
-    The context object is extended with the values from helper.context.default.
+    Values supplied by helper.context.default are used in the rendering in
+    addition to those supplied by render_context (render_context overrides
+    in cases of conflict).
 
     Args:
-      template_path: the path of the template that should be used
-      render_context: the context that should be used
+      template_path: The path of the template that should be used.
+      render_context: The context dictionary that should be used.
+
+    Returns:
+      The page content.
     """
     context = context_helper.default(self.data)
     context.update(render_context)
-    rendered = loader.render_to_string(template_path, dictionary=context)
-    self.response.write(rendered)
+    return loader.render_to_string(template_path, dictionary=context)
 
   def templatePath(self):
     """Returns the path to the template that should be used in render().
 
-    Subclasses should override this method.
+    Implementing subclasses must override this method.
     """
     raise NotImplementedError()
 
-  def accessViolation(self, status, message):
-    """Default access violation handler."""
-    self.error(status, message)
-
   def _dispatch(self):
-    """Dispatches the HTTP request to its respective handler method."""
-    if self.request.method == 'GET':
-      if self.request.GET.get('fmt') == 'json':
+    """Dispatches the HTTP request to its respective handler method.
+
+    Returns:
+      An http.HttpResponse appropriate for this RequestHandler's request
+        object.
+    """
+    if self.data.request.method == 'GET':
+      if self.data.request.GET.get('fmt') == 'json':
         self.json()
       else:
         self.get()
-    elif self.request.method == 'POST':
+      return self.response
+    elif self.data.request.method == 'POST':
       if db.WRITE_CAPABILITY.is_enabled():
         self.post()
       else:
-        referrer = self.request.META.get('HTTP_REFERER', '')
+        referrer = self.data.request.META.get('HTTP_REFERER', '')
         params = urllib.urlencode({'dsw_disabled': 1})
         url_with_params = '%s?%s' % (referrer, params)
         self.redirect.toUrl(url_with_params)
-    elif self.request.method == 'HEAD':
-      self.head()
-    elif self.request.method == 'OPTIONS':
-      self.options()
-    elif self.request.method == 'PUT':
+      return self.response
+    elif self.data.request.method == 'HEAD':
+      return self.head()
+    elif self.data.request.method == 'OPTIONS':
+      return self.options()
+    elif self.data.request.method == 'PUT':
       self.put()
-    elif self.request.method == 'DELETE':
-      self.delete()
-    elif self.request.method == 'TRACE':
-      self.trace()
+      return self.response
+    elif self.data.request.method == 'DELETE':
+      return self.delete()
+    elif self.data.request.method == 'TRACE':
+      return self.trace()
     else:
-      self.error(501)
+      return self.error(httplib.NOT_IMPLEMENTED)
 
+  # TODO(nathaniel): Note that while this says that it sets the "data" and
+  # "check" attributes, this implementation makes use of the "data" attribute
+  # without having set it. Therefore extending classes must set at least the
+  # "data" attribute before calling this superclass implementation if they
+  # choose to do so (they do). This is an obstacle just waiting to cause
+  # bigger problems.
   def init(self, request, args, kwargs):
     """Initializes the RequestHandler.
 
     Sets the data and check fields.
     """
     if self.data.site.maintenance_mode and not self.data.is_developer:
-      raise MaintainceMode(
+      raise exceptions.MaintainceMode(
           'The site is currently in maintenance mode. Please try again later.')
 
   def __call__(self, request, *args, **kwargs):
@@ -224,24 +266,22 @@
     self.args = args
     self.kwargs = kwargs
 
-    self.response = Response()
+    self.response = response_helper.Response()
 
     try:
       self.init(request, args, kwargs)
       self.checkAccess()
-      self._dispatch()
-    except LoginRequest, e:
+      self.response = self._dispatch()
+    except exceptions.LoginRequest, e:
       request.get_full_path().encode('utf-8')
       self.redirect.login().to()
-    except RedirectRequest, e:
+    except exceptions.RedirectRequest, e:
       self.redirect.toUrl(e.url)
-    except AccessViolation, e:
-      self.accessViolation(e.status, e.args[0])
-    except GDocsLoginRequest, e:
+    except exceptions.GDocsLoginRequest, e:
       self.redirect.toUrl('%s?%s' % (self.redirect.urlOf(e.url_name),
                                      urllib.urlencode({'next':e.next})))
-    except Error, e:
-      self.error(e.status, message=e.args[0])
+    except exceptions.Error, e:
+      self.response = self.error(e.status, message=e.args[0])
     finally:
       response = self.response
       self.response = None
@@ -257,12 +297,11 @@
 
 
 class SiteRequestHandler(RequestHandler):
-  """Customization required by global site pages to handle HTTP requests.
-  """
+  """Customization required by global site pages to handle HTTP requests."""
 
   def init(self, request, args, kwargs):
-    self.data = RequestData()
-    self.redirect = RedirectHelper(self.data, self.response)
+    self.data = request_data.RequestData()
+    self.redirect = request_data.RedirectHelper(self.data, self.response)
     self.data.populate(None, request, args, kwargs)
     if self.data.is_developer:
       self.mutator = access_checker.DeveloperMutator(self.data)
diff --git a/app/soc/views/base_templates.py b/app/soc/views/base_templates.py
index 0e621e6..665f89e 100644
--- a/app/soc/views/base_templates.py
+++ b/app/soc/views/base_templates.py
@@ -1,13 +1,11 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-# 
+#
 #   http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -16,7 +14,6 @@
 
 """This module contains the view for the site menus."""
 
-
 from soc.models.site import Site
 
 from soc.views.template import Template
@@ -66,12 +63,16 @@
 
   def context(self):
     def url(program):
-      r = self.data.redirect.program(program)
-      return r.urlOf(self.url_name)
+      # TODO(nathaniel): make this .program call unnecessary.
+      self.data.redirect.program(program=program)
+
+      return self.data.redirect.urlOf(self.url_name)
+
     def attr(program):
       if program.key() == self.data.program.key():
         return "selected=selected"
-      return ""
+      else:
+        return ""
 
     program_key = Site.active_program.get_value_for_datastore(self.data.site)
 
diff --git a/app/soc/views/helper/blobstore.py b/app/soc/views/helper/blobstore.py
index f1a7bd5..644c1b8 100644
--- a/app/soc/views/helper/blobstore.py
+++ b/app/soc/views/helper/blobstore.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2008 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -27,10 +25,11 @@
 import cgi
 import logging
 
+from django import http
+
 from google.appengine.ext import blobstore
 
-from soc.logic.exceptions import BadRequest
-from soc.views.helper.response import Response
+from soc.logic import exceptions
 
 
 def _parseField(request, key, field):
@@ -106,17 +105,25 @@
 
 
 def sendBlob(blob_info):
-  """Send a blob-response based on a blob_key.
+  """Constructs a response that App Engine will interpret as a blob send.
 
-  Sets the correct response header for serving a blob.  If BlobInfo
-  is provided and no content_type specified, will set request content type
-  to BlobInfo's content type.
+  The returned http.HttpResponse will have a "Content-Disposition" header
+  based on blob_info's stored file name, a "Content-Type" header based on
+  blob_info's stored content type, and a blobstore.BLOB_KEY_HEADER header
+  storing blob key of the blob to be sent to the user.
+
+  The returned http.HttpResponse may also have other headers set.
 
   Args:
-    blob_info: BlobInfo record to serve
+    blob_info: BlobInfo record representing the blob to be received by
+      the user.
+
+  Returns:
+    An http.HttpResponse object with at least "Content-Type",
+      "Content-Disposition", and blobstore.BLOB_KEY_HEADER headers set.
 
   Raises:
-    BadRequest: on missing filename in blob_info
+    exceptions.BadRequest: If blob_info is missing a file name.
   """
   logging.debug(blob_info)
   assert isinstance(blob_info, blobstore.BlobInfo)
@@ -130,14 +137,19 @@
     content_type = content_type.encode('utf-8')
 
   if not filename:
-    raise BadRequest('No filename in blob_info.')
+    raise exceptions.BadRequest('No filename in blob_info.')
 
   if isinstance(filename, unicode):
     filename = filename.encode('utf-8')
 
-  response = Response()
-  response['Content-Type'] = content_type
-  response['Content-Disposition'] = (CONTENT_DISPOSITION % filename)
+  response = http.HttpResponse(content_type=content_type)
+  # We set the cache control to disable all kinds of caching hoping
+  # that Appengine does not cache the blob keys in the header if we
+  # set this.
+  response['Cache-Control'] = (
+      'no-store, no-cache, must-revalidate, post-check=0, pre-check=0')
+
+  response['Content-Disposition'] = CONTENT_DISPOSITION % filename
   response[blobstore.BLOB_KEY_HEADER] = str(blob_info.key())
 
   return response
diff --git a/app/soc/views/helper/context.py b/app/soc/views/helper/context.py
index e44a84d..0e4807b 100644
--- a/app/soc/views/helper/context.py
+++ b/app/soc/views/helper/context.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the boiler plate required to construct templates
-"""
-
+"""Module containing the boiler plate required to construct templates."""
 
 from soc.logic import system
 from soc.logic.helper import xsrfutil
@@ -35,8 +31,11 @@
       google_api_key: the google api key for this website
       ga_tracking_num: the google tracking number for this website
       ds_write_disabled: if datastore writes are disabled
-      css_path: part of the path to the css files to distinguish modules  
+      css_path: part of the path to the css files to distinguish modules
+      gdata_is_logged_in: the string "true" or "false" as appropriate
   """
+  app_version = system.getMelangeVersion()
+
   posted = data.request.POST or 'validated' in data.request.GET
 
   xsrf_secret_key = site.xsrfSecretKey(data.site)
@@ -47,23 +46,19 @@
   else:
     google_api_key = data.site.google_api_key
 
-  if data.user and oauth_helper.getAccessToken(data.user):
-    gdata_is_logged_in = 'true'
-  else:
-    gdata_is_logged_in = 'false'
-
   css_path = '/'.join([
-      'soc', 'content', system.getMelangeVersion(), 'css', 'v2',
-      data.css_path])
+      'soc', 'content', app_version, 'css', 'v2', data.css_path])
+
+  gdata_is_logged_in = data.user and oauth_helper.getAccessToken(data.user)
 
   return {
-      'app_version': system.getMelangeVersion(),
+      'app_version': app_version,
       'is_local': system.isLocal(),
       'posted': posted,
       'xsrf_token': xsrf_token,
       'google_api_key': google_api_key,
       'ga_tracking_num': data.site.ga_tracking_num,
       'ds_write_disabled': data.ds_write_disabled,
-      'gdata_is_logged_in': gdata_is_logged_in,
-      'css_path': css_path
+      'css_path': css_path,
+      'gdata_is_logged_in': str(bool(gdata_is_logged_in)).lower(),
   }
diff --git a/app/soc/views/helper/request_data.py b/app/soc/views/helper/request_data.py
index f3f2a60..eb045cb 100644
--- a/app/soc/views/helper/request_data.py
+++ b/app/soc/views/helper/request_data.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -18,18 +16,18 @@
 request in the GSoC module.
 """
 
-
 import datetime
 
 from google.appengine.api import users
 from google.appengine.ext import db
 
-from django.core.urlresolvers import reverse
+from django.core import urlresolvers
+from django.utils import encoding
 
 from soc.logic import system
 from soc.logic import site
 from soc.logic import user
-from soc.views.helper.access_checker import isSet
+from soc.views.helper import access_checker
 
 
 def isBefore(date):
@@ -49,8 +47,7 @@
 
 
 def isBetween(start, end):
-  """Returns True iff utcnow() is between start and end.
-  """
+  """Returns True iff utcnow() is between start and end."""
   return isAfter(start) and isBefore(end)
 
 
@@ -67,13 +64,11 @@
     self.org_app = org_app
 
   def currentPeriod(self):
-    """Return where we are currently on the timeline.
-    """
+    """Return where we are currently on the timeline."""
     pass
 
   def nextDeadline(self):
-    """Determines the next deadline on the timeline.
-    """
+    """Determines the next deadline on the timeline."""
     pass
 
   def orgsAnnouncedOn(self):
@@ -169,8 +164,7 @@
   """
 
   def __init__(self):
-    """Constructs an empty RequestData object.
-    """
+    """Constructs an empty RequestData object."""
     self.site = None
     self.user = None
     self.request = None
@@ -189,24 +183,21 @@
 
   @property
   def login_url(self):
-    """Memoizes and returns the login_url for the current path.
-    """
+    """Memoizes and returns the login_url for the current path."""
     if not self._login_url:
       self._login_url = users.create_login_url(self.full_path)
     return self._login_url
 
   @property
   def logout_url(self):
-    """Memoizes and returns the logout_url for the current path.
-    """
+    """Memoizes and returns the logout_url for the current path."""
     if not self._logout_url:
       self._logout_url = users.create_logout_url(self.full_path)
     return self._logout_url
 
   @property
   def ds_write_disabled(self):
-    """Memoizes and returns whether datastore writes are disabled.
-    """
+    """Memoizes and returns whether datastore writes are disabled."""
     if self._ds_write_disabled is not None:
       return self._ds_write_disabled
 
@@ -267,20 +258,18 @@
     return invite.role if invite else None
 
 
+# TODO(nathaniel): This should be immutable.
 class RedirectHelper(object):
-  """Helper for constructing redirects.
-  """
+  """Helper for constructing redirects."""
 
   def __init__(self, data, response):
-    """Initializes the redirect helper.
-    """
+    """Initializes the redirect helper."""
     self._data = data
     self._response = response
     self._clear()
 
   def _clear(self):
-    """Clears the internal state.
-    """
+    """Clears the internal state."""
     self._no_url = False
     self._url_name = None
     self._url = None
@@ -288,38 +277,31 @@
     self.kwargs = {}
 
   def sponsor(self, program=None):
-    """Sets kwargs for an url_patterns.SPONSOR redirect.
-    """
+    """Sets kwargs for an url_patterns.SPONSOR redirect."""
     if not program:
-      assert isSet(self._data.program)
+      assert access_checker.isSet(self._data.program)
       program = self._data.program
     self._clear()
     self.kwargs['sponsor'] = program.scope_path
-    return self
 
   def program(self, program=None):
-    """Sets kwargs for an url_patterns.PROGRAM redirect.
-    """
+    """Sets kwargs for an url_patterns.PROGRAM redirect."""
     if not program:
-      assert isSet(self._data.program)
+      assert access_checker.isSet(self._data.program)
       program = self._data.program
     self.sponsor(program)
     self.kwargs['program'] = program.link_id
-    return self
 
   def organization(self, organization=None):
-    """Sets the kwargs for an url_patterns.ORG redirect.
-    """
+    """Sets the kwargs for an url_patterns.ORG redirect."""
     if not organization:
-      assert isSet(self._data.organization)
+      assert access_checker.isSet(self._data.organization)
       organization = self._data.organization
     self.program()
     self.kwargs['organization'] = organization.link_id
-    return self
 
   def id(self, id=None):
-    """Sets the kwargs for an url_patterns.ID redirect.
-    """
+    """Sets the kwargs for an url_patterns.ID redirect."""
     if not id:
       assert 'id' in self._data.kwargs
       id = self._data.kwargs['id']
@@ -328,8 +310,7 @@
     return self
 
   def key(self, key=None):
-    """Sets the kwargs for an url_patterns.KEY redirect.
-    """
+    """Sets the kwargs for an url_patterns.KEY redirect."""
     if not key:
       assert 'key' in self._data.kwargs
       key = self._data.kwargs['key']
@@ -338,15 +319,13 @@
     return self
 
   def createProfile(self, role):
-    """Sets args for an url_patterns.CREATE_PROFILE redirect.
-    """
+    """Sets args for an url_patterns.CREATE_PROFILE redirect."""
     self.program()
     self.kwargs['role'] = role
     return self
 
   def profile(self, user=None):
-    """Sets args for an url_patterns.PROFILE redirect.
-    """
+    """Sets args for an url_patterns.PROFILE redirect."""
     if not user:
       assert 'user' in self._data.kwargs
       user = self._data.kwargs['user']
@@ -374,14 +353,13 @@
     return self
 
   def userOrg(self, user=None, organization=None):
-    """Sets args for an url_patterns.USER_ORG redirect.
-    """
+    """Sets args for an url_patterns.USER_ORG redirect."""
     if not user:
       assert 'user' in self._data.kwargs
       user = self._data.kwargs['user']
 
     if not organization:
-      assert isSet(self._data.organization)
+      assert access_checker.isSet(self._data.organization)
       organization = self._data.organization
 
     self.program()
@@ -391,8 +369,7 @@
 
 
   def userId(self, user=None, id=None):
-    """Sets args for url_patterns.USER_ID redirect.
-    """
+    """Sets args for url_patterns.USER_ID redirect."""
     if not user:
       assert 'user' in self._data.kwargs
       user = self._data.kwargs['user']
@@ -411,20 +388,24 @@
 
     Uses internal state for args and kwargs.
     """
+    # TODO(nathaniel): Why isn't this just "url = reverse(name, args=self.args,
+    # kwargs=self.kwargs)"? Current suspicion: it's because there's a
+    # there's a difference in behavior between passing None and passing empty
+    # dicts. It's also curious that there isn't an "if self.args and
+    # self.kwargs" case at the top.
     if self.args:
-      url = reverse(name, args=self.args)
+      url = urlresolvers.reverse(name, args=self.args)
     elif self.kwargs:
-      url = reverse(name, kwargs=self.kwargs)
+      url = urlresolvers.reverse(name, kwargs=self.kwargs)
     else:
-      url = reverse(name)
+      url = urlresolvers.reverse(name)
 
     url = self._appendGetArgs(url, cbox=cbox, extra_get_args=extra)
 
     return self._fullUrl(url, full, secure)
 
   def url(self, full=False, secure=False):
-    """Returns the url of the current state.
-    """
+    """Returns the url of the current state."""
     if self._no_url:
       return None
     assert self._url or self._url_name
@@ -440,6 +421,7 @@
     if (not full) and (system.isLocal() or not secure):
       return url
 
+    # TODO(nathaniel): consider using scheme-relative urls here?
     if secure:
       protocol = 'https'
       hostname = system.getSecureHostname()
@@ -450,18 +432,17 @@
     return '%s://%s%s' % (protocol, hostname, url)
 
   def _appendAnchor(self, url, anchor=None):
-    """Appends the anchor to the URL.
-    """
+    """Appends the anchor to the URL."""
     if anchor:
       url = '%s#%s' % (url, anchor)
 
     return url
 
-  def _appendGetArgs(self, url, cbox=False, validated=False,
-      extra_get_args=[]):
-    """Appends GET arguments to the specified URL.
-    """
-    get_args = extra_get_args[:]
+  # TODO(nathaniel): Django's got to have a utility function for most of this.
+  def _appendGetArgs(
+      self, url, cbox=False, validated=False, extra_get_args=None):
+    """Appends GET arguments to the specified URL."""
+    get_args = extra_get_args or []
     if cbox:
       get_args.append('cbox=true')
 
@@ -509,30 +490,25 @@
     self.toUrl(url, full=full, secure=secure)
 
   def toUrl(self, url, full=False, secure=False):
-    """Redirects to the specified url.
-    """
-    from django.utils.encoding import iri_to_uri
+    """Redirects to the specified url."""
     url = self._fullUrl(url, full, secure)
     self._response.status_code = 302
-    self._response["Location"] = iri_to_uri(url)
+    self._response["Location"] = encoding.iri_to_uri(url)
 
   def login(self):
-    """Sets the _url to the login url.
-    """
+    """Sets the _url to the login url."""
     self._clear()
     self._url = self._data.login_url
     return self
 
   def logout(self):
-    """Sets the _url to the logout url.
-    """
+    """Sets the _url to the logout url."""
     self._clear()
     self._url = self._data.logout_url
     return self
 
   def acceptedOrgs(self):
-    """Sets the _url_name to the list of all accepted orgs.
-    """
+    """Sets the _url_name to the list of all accepted orgs."""
     self.program()
     return self
 
@@ -546,26 +522,22 @@
     return self
 
   def searchpage(self):
-    """Sets the _url_name for the searchpage of the current program.
-    """
+    """Sets the _url_name for the searchpage of the current program."""
     self.program()
     return self
 
   def orgHomepage(self, link_id):
-    """Sets the _url_name for the specified org homepage
-    """
+    """Sets the _url_name for the specified org homepage."""
     self.program()
     self.kwargs['organization'] = link_id
     return self
 
   def dashboard(self):
-    """Sets the _url_name for dashboard page of the current program.
-    """
+    """Sets the _url_name for dashboard page of the current program."""
     self.program()
     return self
 
   def events(self):
-    """Sets the _url_name for the events page, if it is set.
-    """
+    """Sets the _url_name for the events page, if it is set."""
     self.program()
     return self
diff --git a/app/soc/views/helper/requests.py b/app/soc/views/helper/requests.py
deleted file mode 100644
index 15a9d87..0000000
--- a/app/soc/views/helper/requests.py
+++ /dev/null
@@ -1,184 +0,0 @@
-#!/usr/bin/env python2.5
-#
-# Copyright 2008 the Melange authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Helpers for manipulating HTTP requests.
-"""
-
-
-import urlparse
-
-from soc.logic import system
-
-
-def getSingleIndexedParamValue(request, param_name, values=()):
-  """Returns a value indexed by a query parameter in the HTTP request.
-  
-  Args:
-    request: the Django HTTP request object
-    param_name: name of the query parameter in the HTTP request
-    values: list (or tuple) of ordered values; one of which is
-      retrieved by the index value of the param_name argument in
-      the HTTP request
-      
-  Returns:
-    None if the query parameter was not present, was not an integer, or
-      was an integer that is not a valid [0..len(values)-1] index into
-      the values list.
-    Otherwise, returns values[int(param_name value)]
-  """
-  value_idx = request.GET.get(param_name)
-  
-  if isinstance(value_idx, (tuple, list)):
-    # keep only the first argument if multiple are present
-    value_idx = value_idx[0]
-
-  try:
-    # GET parameter 'param_name' should be an integer value index
-    value_idx = int(value_idx) if value_idx is not None else -1
-  except ValueError:
-    # ignore bogus or missing parameter values, so return None (no message)
-    return None
-    
-  if value_idx < 0:
-    # value index out of range, so return None (no value)
-    return None
-
-  if value_idx >= len(values):
-    # value index out of range, so return None (no value)
-    return None
-
-  # return value associated with valid value index
-  return values[value_idx]
-
-
-def getSingleIndexedParamValueIfMissing(value, request, param_name,
-                                        values=()):
-  """Returns missing value indexed by a query parameter in the HTTP request.
-  
-  Args:
-    value: an existing value, or a "False" value such as None
-    request, param_name, values: see getSingleIndexParamValue()
-    
-  Returns:
-    value, if value is "non-False"
-    Otherwise, returns getSingleIndexedParamValue() result.
-  """
-  if value:
-    # value already present, so return it
-    return value
-
-  return getSingleIndexedParamValue(request, param_name, values=values)
-
-
-# TODO(tlarsen):  write getMultipleIndexParamValues() that returns a
-#   list of values if present, omitting those values that are
-#   out of range
-
-
-def isReferrerSelf(request,
-                   expected_prefix=None, suffix=None, url_name=None):
-  """Returns True if HTTP referrer path starts with the HTTP request path.
-    
-  Args:
-    request: the Django HTTP request object; request.path is used if
-      expected_path is not supplied (the most common usage)
-    expected_prefix: optional HTTP path to use instead of the one in
-      request.path; default is None (use request.path)
-    suffix: suffix to remove from the HTTP request path before comparing
-      it to the HTTP referrer path in the HTTP request object headers
-      (this is often an link ID, for example, that may be changing from
-      a POST referrer to a GET redirect target) 
-    url_name: url name of the entity that is being created
-  
-  Returns:
-    True if HTTP referrer path begins with the HTTP request path (either
-      request.path or expected_prefix instead if it was supplied), after
-      any suffix was removed from that request path
-    False otherwise
-       
-  """
-  http_from = request.META.get('HTTP_REFERER')
-
-  if not http_from:
-    # no HTTP referrer, so cannot possibly start with expected prefix
-    return False
-
-  http_host = 'http://%s/%s' % (system.getHostname(), url_name)
-
-  if http_from.startswith(http_host):
-    return True
-
-  from_path = urlparse.urlparse(http_from).path
-
-  if not expected_prefix:
-    # use HTTP request path, since expected_prefix was not supplied
-    expected_prefix = request.path
-
-  if suffix:
-    # remove suffix (such as a link ID) before comparison
-    chars_to_remove = len(suffix)
-    
-    if not suffix.startswith('/'):
-      chars_to_remove = chars_to_remove + 1
-
-    expected_prefix = expected_prefix[:-chars_to_remove]
-
-  if not from_path.startswith(expected_prefix):
-    # expected prefix did not match first part of HTTP referrer path
-    return False
-
-  # HTTP referrer started with (possibly truncated) expected prefix
-  return True
-
-
-def replaceSuffix(path, old_suffix, new_suffix=None, params=None):
-  """Replace the last part of a URL path with something else.
-
-  Also appends an optional list of query parameters.  Used for
-  replacing, for example, one link ID at the end of a relative
-  URL path with another.
-
-  Args:
-    path: HTTP request relative URL path (with no query arguments)
-    old_suffix: expected suffix at the end of request.path component;
-      if any False value (such as None), the empty string '' is used
-    new_suffix: if non-False, appended to request.path along with a
-      '/' separator (after removing old_suffix if necessary)
-    params: an optional dictionary of query parameters to append to
-      the redirect target; appended as ?<key1>=<value1>&<key2>=...
-      
-  Returns:
-    /path/with/new_suffix?a=1&b=2
-  """    
-  if not old_suffix:
-    old_suffix = ''
-
-  old_suffix = '/' + old_suffix
-
-  if path.endswith(old_suffix):
-    # also removes any trailing '/' if old_suffix was empty
-    path = path[:-len(old_suffix)]
-
-  if new_suffix:
-    # if present, appends new_suffix, after '/' separator
-    path = '%s/%s' % (path, new_suffix)
-
-  if params:
-    # appends any query parameters, after a '?' and separated by '&'
-    path = '%s?%s' % (path, '&'.join(
-        ['%s=%s' % (p,v) for p,v in params.iteritems()]))
-
-  return path
diff --git a/app/soc/views/helper/response.py b/app/soc/views/helper/response.py
index 72d8c8a..342653c 100644
--- a/app/soc/views/helper/response.py
+++ b/app/soc/views/helper/response.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,84 +12,27 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+"""Module containing the Response object."""
 
-"""Module containing the Response object.
-"""
+import httplib
 
 from django import http
 
 
+# TODO(nathaniel): eliminate this in favor of using its superclass everywhere.
 class Response(http.HttpResponse):
   """Response class that wraps the Django's HttpResponse class but
   with message for every possible HTTP response code.
   """
 
-  DEFAULT_CONTENT_TYPE = 'text/html'
+  def set_status(self, status):
+    """Sets the HTTP status and content for this response.
 
-  HTTP_STATUS_MESSAGES = {
-      100: 'Continue',
-      101: 'Switching Protocols',
-      200: 'OK',
-      201: 'Created',
-      202: 'Accepted',
-      203: 'Non-Authoritative Information',
-      204: 'No Content',
-      205: 'Reset Content',
-      206: 'Partial Content',
-      300: 'Multiple Choices',
-      301: 'Moved Permanently',
-      302: 'Moved Temporarily',
-      303: 'See Other',
-      304: 'Not Modified',
-      305: 'Use Proxy',
-      306: 'Unused',
-      307: 'Temporary Redirect',
-      400: 'Bad Request',
-      401: 'Unauthorized',
-      402: 'Payment Required',
-      403: 'Forbidden',
-      404: 'Not Found',
-      405: 'Method Not Allowed',
-      406: 'Not Acceptable',
-      407: 'Proxy Authentication Required',
-      408: 'Request Time-out',
-      409: 'Conflict',
-      410: 'Gone',
-      411: 'Length Required',
-      412: 'Precondition Failed',
-      413: 'Request Entity Too Large',
-      414: 'Request-URI Too Large',
-      415: 'Unsupported Media Type',
-      416: 'Requested Range Not Satisfiable',
-      417: 'Expectation Failed',
-      500: 'Internal Server Error',
-      501: 'Not Implemented',
-      502: 'Bad Gateway',
-      503: 'Service Unavailable',
-      504: 'Gateway Time-out',
-      505: 'HTTP Version not supported'
-      }
-
-  def __init__(self, content='', mimetype=None, status=200,
-               content_type=DEFAULT_CONTENT_TYPE):
-    """Default constructor for an empty 200 response.
-    """
-    super(Response, self).__init__(content, mimetype,
-                                   status, content_type)
-
-  def set_status(self, status, message=None):
-    """Sets the HTTP status and message for this response.
+    The content of this Response will be set to the standard response for
+    the given status as found in httplib.responses.
 
     Args:
-      status: HTTP status code
-      message: the HTTP status string to use
-
-    If no status string is given, we use the default from the HTTP/1.1
-    specification defined in the dictionary HTTP_STATUS_MESSAGE.
+      status: HTTP status code.
     """
-    if not message:
-      message = self.HTTP_STATUS_MESSAGES.get(status, '')
-
     self.status_code = status
-    self.content = message
-
+    self.content = httplib.responses.get(status, '')
diff --git a/app/soc/views/oauth.py b/app/soc/views/oauth.py
index dd459c2..00614c0 100644
--- a/app/soc/views/oauth.py
+++ b/app/soc/views/oauth.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,20 +12,18 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing views for Open Auth.
-"""
-
+"""Module containing views for Open Auth."""
 
 from django.conf.urls.defaults import url as django_url
 
 from soc.views.helper.gdata_apis import oauth as oauth_helper
 
-from soc.modules.gsoc.views.base import RequestHandler
+# TODO(nathaniel): modules-gsoc code being imported in non modules-gsoc code.
+from soc.modules.gsoc.views.base import GSoCRequestHandler
 
 
-class OAuthRedirectPage(RequestHandler):
-  """Redirect page to Google Documents.
-  """
+class OAuthRedirectPage(GSoCRequestHandler):
+  """Redirect page to Google Documents."""
 
   def djangoURLPatterns(self):
     patterns = [
@@ -57,9 +53,8 @@
     pass
 
 
-class OAuthVerifyToken(RequestHandler):
-  """Verify request token and redirect user.
-  """
+class OAuthVerifyToken(GSoCRequestHandler):
+  """Verify request token and redirect user."""
 
   def djangoURLPatterns(self):
     patterns = [
@@ -75,9 +70,8 @@
     return self.response
 
 
-class PopupOAuthRedirectPage(RequestHandler):
-  """Redirects popup page to Google Documents.
-  """
+class PopupOAuthRedirectPage(GSoCRequestHandler):
+  """Redirects popup page to Google Documents."""
 
   def djangoURLPatterns(self):
     patterns = [
@@ -104,9 +98,8 @@
     return self.response
 
 
-class PopupOAuthVerified(RequestHandler):
-  """ Calls parent window's methods to indicate successful login.
-  """
+class PopupOAuthVerified(GSoCRequestHandler):
+  """ Calls parent window's methods to indicate successful login."""
 
   def djangoURLPatterns(self):
     patterns = [
diff --git a/app/soc/views/org_home.py b/app/soc/views/org_home.py
index fb2df46..fd05387 100644
--- a/app/soc/views/org_home.py
+++ b/app/soc/views/org_home.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python
-#
 # Copyright 2012 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module containing the views for Organization Homepage.
-"""
-
+"""Module containing the views for Organization Homepage."""
 
 from google.appengine.ext import db
 
@@ -27,8 +23,7 @@
 
 
 class BanOrgPost(object):
-  """Handles banning/unbanning of organizations.
-  """
+  """Handles banning/unbanning of organizations."""
 
   def djangoURLPatterns(self):
     return [
@@ -43,7 +38,7 @@
 
   def post(self):
     assert isSet(self.data.organization)
-    
+
     value = self.data.POST.get('value')
     org_key = self.data.organization.key()
 
@@ -83,12 +78,14 @@
   def context(self):
     assert isSet(self.data.organization)
 
-    r = self.data.redirect.organization()
+    # TODO(nathaniel): make this .organization() call unnecessary.
+    self.data.redirect.organization()
+
     is_banned = self.data.organization.status == 'invalid'
 
     org_banned = ToggleButtonTemplate(
         self.data, 'on_off', 'Banned', 'organization-banned',
-        r.urlOf(self._getActionURLName()),
+        self.data.redirect.urlOf(self._getActionURLName()),
         checked=is_banned,
         help_text=self._getHelpText(),
         labels={
diff --git a/app/soc/views/profile_show.py b/app/soc/views/profile_show.py
index 255c850..7d618d4 100644
--- a/app/soc/views/profile_show.py
+++ b/app/soc/views/profile_show.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2012 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,9 +12,7 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for displaying the Profile read-only page.
-"""
-
+"""Module for displaying the Profile read-only page."""
 
 from google.appengine.ext import db
 
@@ -27,8 +23,6 @@
 from soc.views.template import Template
 from soc.views.toggle_button import ToggleButtonTemplate
 
-from soc.modules.gsoc.views.base import RequestHandler
-
 
 class UserReadOnlyTemplate(readonly_template.ModelReadOnlyTemplate):
   """Template to construct readonly Profile data.
@@ -105,7 +99,7 @@
 
   def post(self):
     assert isSet(self.data.url_profile)
-    
+
     value = self.data.POST.get('value')
     profile_key = self.data.url_profile.key()
 
diff --git a/app/soc/views/site.py b/app/soc/views/site.py
index 52ea178..9e923ef 100644
--- a/app/soc/views/site.py
+++ b/app/soc/views/site.py
@@ -1,5 +1,3 @@
-#!/usr/bin/env python2.5
-#
 # Copyright 2011 the Melange authors.
 #
 # Licensed under the Apache License, Version 2.0 (the "License");
@@ -14,33 +12,28 @@
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
-"""Module for the site global pages.
-"""
-
+"""Module for the site global pages."""
 
 import os
 
 from google.appengine.api import users
 
+from django import http
 from django.conf.urls.defaults import url as django_url
 from django.forms import widgets as django_widgets
 from django.utils.functional import lazy
 from django.utils.translation import ugettext
 
-from soc.models.document import Document
 from soc.logic import cleaning
-from soc.logic import site
-from soc.logic.exceptions import AccessViolation
-from soc.logic.exceptions import Error
-from soc.models.site import Site
-from soc.views.base import Response
-from soc.views.base import SiteRequestHandler
-from soc.views.forms import ModelForm
-
+from soc.logic import exceptions
+from soc.logic import site as site_logic
+from soc.models import document
+from soc.models import site
+from soc.views import base
+from soc.views import forms as views_forms
 
 from soc.modules import callback
 
-
 DEF_NO_DEVELOPER = ugettext(
     'This page is only accessible to developers.')
 
@@ -51,12 +44,11 @@
   return choices
 
 
-class SiteForm(ModelForm):
-  """Django form for the site settings.
-  """
+class SiteForm(views_forms.ModelForm):
+  """Django form for the site settings."""
 
   class Meta:
-    model = Site
+    model = site.Site
     exclude = ['link_id', 'scope', 'scope_path', 'home', 'xsrf_secret_key']
     widgets = {
         'active_program': django_widgets.Select(
@@ -74,9 +66,8 @@
   clean_noreply_email = cleaning.clean_empty_field('noreply_email')
 
 
-class EditSitePage(SiteRequestHandler):
-  """View for the participant profile.
-  """
+class EditSitePage(base.SiteRequestHandler):
+  """View for the participant profile."""
 
   def djangoURLPatterns(self):
     return [
@@ -84,7 +75,7 @@
     ]
 
   def jsonContext(self):
-    entities = Document.all().filter('prefix', 'site')
+    entities = document.Document.all().filter('prefix', 'site')
 
     data = [{'key': str(i.key()),
             'link_id': i.link_id,
@@ -95,7 +86,7 @@
 
   def checkAccess(self):
     if not self.data.is_developer:
-      raise AccessViolation(DEF_NO_DEVELOPER)
+      raise exceptions.AccessViolation(DEF_NO_DEVELOPER)
 
   def templatePath(self):
     # TODO: make this specific to the current active program
@@ -123,17 +114,15 @@
     site_form.save()
 
   def post(self):
-    """Handler for HTTP POST request.
-    """
+    """Handler for HTTP POST request."""
     if self.validate():
       self.redirect.to('edit_site_settings')
     else:
       self.get()
 
 
-class SiteHomepage(SiteRequestHandler):
-  """View for the site home page.
-  """
+class SiteHomepage(base.SiteRequestHandler):
+  """View for the site home page."""
 
   def djangoURLPatterns(self):
     return [
@@ -143,29 +132,31 @@
     ]
 
   def __call__(self, request, *args, **kwargs):
-    """Custom call implementation.
-
-    This avoids looking up unneeded data.
-    """
-    self.response = Response()
-
+    """Custom call implementation that avoids looking up unneeded data."""
+    # TODO(nathaniel): eliminate this - the RedirectHelper (self.redirect)
+    # should simply return a newly-crafted HttpResponse.
+    # TODO(nathaniel): this blocks (and is part of) issue 1665.
+    self.response = http.HttpResponse()
     try:
       self.init(request, args, kwargs)
-  
+
       action = args[0] if args else ''
-  
+
       if action == 'login':
         self.redirect.toUrl(users.create_login_url('/'))
       elif action == 'logout':
         self.redirect.toUrl(users.create_logout_url('/'))
       else:
-        settings = site.singleton()
+        settings = site_logic.singleton()
         program = settings.active_program
         if program:
-          self.redirect.program(program).to(program.homepage_url_name)
+          # TODO(nathaniel): make this .program call unnecessary.
+          self.redirect.program(program=program)
+
+          self.redirect.to(program.homepage_url_name)
         else:
           self.redirect.to('edit_site_settings')
-    except Error, e:
-      self.error(e.status, message=e.args[0])
 
-    return self.response
+      return self.response
+    except exceptions.Error, e:
+      return self.error(e.status, message=e.args[0])
diff --git a/app/soc/views/sitemap/__init__.py b/app/soc/views/sitemap/__init__.py
deleted file mode 100644
index 79b8182..0000000
--- a/app/soc/views/sitemap/__init__.py
+++ /dev/null
@@ -1,16 +0,0 @@
-#
-# Copyright 2008 the Melange authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-# 
-#   http://www.apache.org/licenses/LICENSE-2.0
-# 
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""This module contains sitemap and sidebar related submodules."""
\ No newline at end of file
diff --git a/app/soc/views/sitemap/sitemap.py b/app/soc/views/sitemap/sitemap.py
deleted file mode 100644
index 245ba1c..0000000
--- a/app/soc/views/sitemap/sitemap.py
+++ /dev/null
@@ -1,73 +0,0 @@
-#!/usr/bin/env python2.5
-#
-# Copyright 2008 the Melange authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Module contains sidemap related functions.
-"""
-
-
-def getDjangoURLPatterns(params):
-  """Retrieves a list of sidebar entries for this View.
-
-  Params usage:
-    The params dictionary is passed to the getKeyFieldsPatterns
-    method, see it's docstring on how it is used.
-    
-    django_patterns: The django_patterns value is returned directly
-      if it is non-False.
-    django_patterns_defaults: The dajngo_patterns_defaults value is
-      used to construct the url patterns. It is expected to be a
-      list of tuples. The tuples should contain an url, a module
-      name, and the name of the url. The name is used as the
-      page_name passed as keyword argument, but also as the name
-      by which the url is known to Django internally.
-    url_name: The url_name argument is passed as argument to each
-      url, together with the link_id pattern, the link_id core
-      pattern, and the key fields for this View.
-
-  Args:
-    params: a dict with params for this View
-  """
-
-  # Return the found result
-  if params['django_patterns']:
-    return params['django_patterns']
-
-  # Construct defaults manualy
-  default_django_patterns = params['django_patterns_defaults']
-  default_patterns = default_django_patterns[:]
-  default_patterns += params['extra_django_patterns']
-
-  patterns = []
-
-  for url, module, name in default_patterns:
-    name = name % params
-    module = module % params
-
-    url = url % {
-        'url_name': params['url_name'],
-        'lnp': params['link_id_arg_pattern'],
-        'ulnp': params['link_id_pattern_core'],
-        'key_fields': params['key_fields_pattern'],
-        'scope': params['scope_path_pattern'],
-        'sans_link_id': params['sans_link_id_pattern'],
-        }
-
-    kwargs = {'page_name': name}
-
-    item = (url, module, kwargs, name)
-    patterns.append(item)
-
-  return patterns
diff --git a/tests/app/soc/modules/gci/views/helper/test_redirect_helper.py b/tests/app/soc/modules/gci/views/helper/test_redirect_helper.py
index e2c00b4..18fc6c4 100644
--- a/tests/app/soc/modules/gci/views/helper/test_redirect_helper.py
+++ b/tests/app/soc/modules/gci/views/helper/test_redirect_helper.py
@@ -3,9 +3,9 @@
 # Licensed under the Apache License, Version 2.0 (the "License");
 # you may not use this file except in compliance with the License.
 # You may obtain a copy of the License at
-# 
+#
 #   http://www.apache.org/licenses/LICENSE-2.0
-# 
+#
 # Unless required by applicable law or agreed to in writing, software
 # distributed under the License is distributed on an "AS IS" BASIS,
 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -14,11 +14,10 @@
 
 """This module unit tests for RedirectHelper class."""
 
-
 from soc.views.helper.access_checker import unset
 from soc.views.helper.response import Response
 
-from soc.modules.gci.views.base import RequestHandler
+from soc.modules.gci.views.base import GCIRequestHandler
 from soc.modules.gci.views.helper import url_names
 
 from tests.test_utils import GCITestCase
@@ -33,7 +32,7 @@
     self.init()
     request = MockRequest(path="/")
 
-    self.handler = RequestHandler()
+    self.handler = GCIRequestHandler()
     self.handler.response = Response()
     self.handler.init(request, (), {})
 
diff --git a/tests/app/soc/modules/gci/views/test_task.py b/tests/app/soc/modules/gci/views/test_task.py
index 1d4c4f4..5339096 100644
--- a/tests/app/soc/modules/gci/views/test_task.py
+++ b/tests/app/soc/modules/gci/views/test_task.py
@@ -131,6 +131,25 @@
     self.assertResponseRedirect(response)
     self.assertEqual(task.status, 'Unpublished')
 
+  def testPostButtonUnpublishReopenedTaskForbidden(self):
+    """Tests the unpublish button on.
+    """
+    self.data.createOrgAdmin(self.org)
+
+    url = self._taskPageUrl(self.task)
+
+    # try to unpublish a reopened task
+    task = GCITask.get(self.task.key())
+    task.status = 'Reopened'
+    task.put()
+
+    response = self.buttonPost(url, 'button_unpublish')
+
+    task = GCITask.get(self.task.key())
+
+    self.assertResponseForbidden(response)
+    self.assertEqual(task.status, 'Reopened')
+
   def testPostButtonUnpublishByUserWithNoRole(self):
     """Tests the unpublish button by a user with no role.
     """
@@ -514,19 +533,43 @@
     self.task.status = 'Claimed'
     self.task.student = self.data.profile
     # set deadline to far future
-    self.task.deadline = datetime.datetime.utcnow() + datetime.timedelta(days=1)
+    self.task.deadline = datetime.datetime.utcnow() + \
+        datetime.timedelta(days=1)
     self.task.put()
 
     GCITaskHelper(self.program).createWorkSubmission(
         self.task, self.data.profile)
 
-    url = '%s?send_for_review' %self._taskPageUrl(self.task)
+    url = '%s?send_for_review' % self._taskPageUrl(self.task)
     response = self.post(url)
 
     task = GCITask.get(self.task.key())
     self.assertResponseRedirect(response)
     self.assertEqual(task.status, 'NeedsReview')
 
+  def testPostSendForReviewClosedTaskForbidden(self):
+    """Tests for submitting work for a task whose status is Closed.
+    """
+    self.data.createStudent()
+
+    self.task.status = 'Closed'
+    self.task.student = self.data.profile
+    # set deadline to far future
+    self.task.deadline = datetime.datetime.utcnow() + \
+        datetime.timedelta(days=1)
+    self.task.put()
+
+    GCITaskHelper(self.program).createWorkSubmission(
+        self.task, self.data.profile)
+
+    url = '%s?send_for_review' % self._taskPageUrl(self.task)
+    response = self.post(url)
+
+    self.assertResponseForbidden(response)
+
+    task = GCITask.get(self.task.key())
+    self.assertEqual(task.status, 'Closed')
+
   def testPostDeleteSubmission(self):
     """Tests for deleting work.
     """