Merge branch 'daniel/gci2013-image'
diff --git a/Gruntfile.js b/Gruntfile.js
index df36f08..04f095b 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -14,6 +14,7 @@
 				js_dir: './app/soc/content/js',
         tests_dir: './tests',
 				js_files: '<%= meta.src.js_dir %>/**/*.js',
+        js_thirdparty_files: '<%= meta.src.js_dir %>/thirdparty/**/*.*',
 				test_specs: '<%= meta.src.tests_dir %>/**/*_spec.js',
         test_all: '<%= meta.src.tests_dir %>/**/*.js'
 			},
@@ -169,10 +170,38 @@
           outdir: '<%= meta.reports.yuidoc %>'
         }
       }
+    },
+    jshint: {
+      options: {
+        browser: true,
+        trailing: true,
+        camelcase: true,
+        curly: true,
+        eqeqeq: true,
+        forin: true,
+        immed: true,
+        newcap: true,
+        noarg: true,
+        noempty: true,
+        quotmark: 'double',
+        undef: true,
+        unused: true,
+        maxlen: 80,
+        jquery: true,
+        globals: {
+          '$LAB': true,
+          'google': true,
+          'melange': true,
+          'Modernizr': true,
+          'tinyMCE': true
+        }
+      },
+      uses_defaults: ['<%= meta.src.js_files %>', '!<%= meta.src.js_thirdparty_files %>']
     }
 	});
 
   grunt.loadNpmTasks('grunt-contrib-jasmine');
+  grunt.loadNpmTasks('grunt-contrib-jshint');
   grunt.loadNpmTasks('grunt-contrib-yuidoc');
   grunt.loadNpmTasks('grunt-contrib-less');
   grunt.loadNpmTasks('grunt-plato');
diff --git a/app/melange/appengine/db.py b/app/melange/appengine/db.py
index 4940c6d..d8388fbb 100644
--- a/app/melange/appengine/db.py
+++ b/app/melange/appengine/db.py
@@ -16,6 +16,9 @@
 
 from django.core import validators
 
+from google.appengine.ext import db
+from google.appengine.ext import ndb
+
 
 def email_validator(property, value):
   """Validates whether the input value for the specified property
@@ -58,3 +61,23 @@
     _LINK_VALIDATOR(value)
   except Exception:
     raise ValueError('%s is not a valid URL.' % value)
+
+
+def toDict(entity):
+  """Returns a dict with all specified values of a datastore entity.
+
+  This function can be dropped when entire transition to ndb API is complete.
+
+  Args:
+    entity: datastore entity to be put in a dictionary
+
+  Raises:
+    TypeError: if the specified entity is not a app engine datastore entity
+  """
+  if isinstance(entity, db.Model):
+    return db.to_dict(entity)
+  elif isinstance(entity, ndb.Model):
+    return entity.to_dict()
+  else:
+    raise TypeError("%s object is not a valid datastore entity" % type(enitity))
+
diff --git a/app/melange/logic/cached_list.py b/app/melange/logic/cached_list.py
new file mode 100644
index 0000000..e5cf46e
--- /dev/null
+++ b/app/melange/logic/cached_list.py
@@ -0,0 +1,59 @@
+# Copyright 2013 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.
+
+"""Contains logic concerning cached lists."""
+
+from google.appengine.ext import ndb
+
+from melange.models import cached_list as cached_list_model
+
+
+def cacheItems(list_id, items):
+  """Save a given list of dictionaries in a cached list.
+  
+  If a list does not exists with the given list_id creates a new CachedList. 
+  This function should always be run in a transaction.
+
+  Args:
+    list_id: A string containing the unique id of the CachedList entity.
+    items: The list of dicts each representing an item in the list.
+  """
+  list_key = ndb.Key(cached_list_model.CachedList, list_id)
+  cached_list = list_key.get()
+  if not cached_list:
+    cached_list = cached_list_model.CachedList(id=list_id)
+  cached_list.list_data.extend(items)
+  cached_list.put()
+
+
+def getCachedItems(list_id, start, limit):
+  """Retrieve stored items from a cached list.
+
+  Args:
+    list_id: The unique id of the CachedList entity
+    start: The starting index of the items returned
+    limit: Number of items returned. If the number of items in the list, after
+      given starting index is less than specified here, only that number of
+      items will be returned
+
+  Returns:
+    A list of dicts each representing an item in the cached list
+  """
+  list_key = ndb.Key(cached_list_model.CachedList, list_id)
+  cached_list = list_key.get()
+
+  if not cached_list:
+    raise ValueError('A cached list with id %s does not exist' % list_id)
+
+  return cached_list.list_data[start:(start+limit)]
diff --git a/app/melange/models/cached_list.py b/app/melange/models/cached_list.py
new file mode 100644
index 0000000..d075f56
--- /dev/null
+++ b/app/melange/models/cached_list.py
@@ -0,0 +1,24 @@
+# Copyright 2013 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.
+
+"""Contains the model of a cached list."""
+
+from google.appengine.ext import ndb
+
+
+class CachedList(ndb.Model):
+  """The CachedList model, represents a list cached as a ndb entity."""
+
+  # The list of items cached in the list in json format
+  list_data = ndb.JsonProperty(repeated=True)
diff --git a/app/melange/request/access.py b/app/melange/request/access.py
index d6c9180..a44f92c 100644
--- a/app/melange/request/access.py
+++ b/app/melange/request/access.py
@@ -71,6 +71,16 @@
     raise NotImplementedError()
 
 
+class AllAllowedAccessChecker(AccessChecker):
+  """AccessChecker that allows all requests for access."""
+
+  def checkAccess(self, data, check, mutator):
+    """See AccessChecker.checkAccess for specification."""
+    pass
+
+ALL_ALLOWED_ACCESS_CHECKER = AllAllowedAccessChecker()
+
+
 # TODO(nathaniel): There's some ninja polymorphism to be addressed here -
 # RequestData doesn't actually have an "is_host" attribute, but its two
 # major subclasses (the GCI-specific and GSoC-specific RequestData classes)
diff --git a/app/melange/utils/lists.py b/app/melange/utils/lists.py
new file mode 100644
index 0000000..74de405
--- /dev/null
+++ b/app/melange/utils/lists.py
@@ -0,0 +1,40 @@
+# Copyright 2013 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 containing list utilities."""
+
+# These imports are needed for the toListItemDict function, to avoid 
+# 'KindError' by func(entity) if func access a db.ReferenceProperty of the 
+# entity.
+from soc.modules.gsoc.models.program import GSoCProgram
+from soc.modules.gsoc.models.timeline import GSoCTimeline
+
+
+def toListItemDict(entity, column_def):
+  """Create a list item from a datastore entity.
+
+  Args:
+    entity: The datastore entity regarding a list item.
+    column_def: a dictionary that has column names of the list as keys, and
+      lambda functions that create the value for that column for a list item as
+      values. These functions should take one parameter, the entity relevant to
+      one list item.
+
+  Returns:
+    A dictionary describing a list item.
+  """
+  output = {}
+  for col, func in column_def.items():
+    output[col] = func(entity)
+  return output
diff --git a/app/soc/content/js/templates/modules/gsoc/grading_record/details.js b/app/soc/content/js/templates/modules/gsoc/grading_record/details.js
new file mode 100644
index 0000000..a1e2f7a
--- /dev/null
+++ b/app/soc/content/js/templates/modules/gsoc/grading_record/details.js
@@ -0,0 +1,19 @@
+/* Copyright 2013 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.
+ */
+melange.templates.inherit(
+  function (_self, context) {
+    jQuery("select, input:radio, input:file, input:checkbox").uniform();
+  }
+);
diff --git a/app/soc/content/js/templates/soc/site/base.js b/app/soc/content/js/templates/soc/site/base.js
new file mode 100644
index 0000000..643665b
--- /dev/null
+++ b/app/soc/content/js/templates/soc/site/base.js
@@ -0,0 +1,20 @@
+/* Copyright 2013 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.
+ */
+melange.templates.inherit(
+  function (_self, context) {
+    jQuery("select, input:radio, input:file, input:checkbox").uniform();
+    melange.autocomplete.makeAutoComplete("tos");
+  }
+);
diff --git a/app/soc/mapreduce/cache_list_items.py b/app/soc/mapreduce/cache_list_items.py
new file mode 100644
index 0000000..53688da
--- /dev/null
+++ b/app/soc/mapreduce/cache_list_items.py
@@ -0,0 +1,73 @@
+# Copyright 2013 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.
+
+"""Mapreduce to cache datastore entities for lists."""
+
+from google.appengine.ext import ndb
+
+from melange.logic import cached_list
+from melange.utils import lists
+
+from mapreduce import context
+from mapreduce import base_handler
+from mapreduce import mapreduce_pipeline
+
+
+NO_OF_SHARDS = 4
+
+
+def mapProcess(entity):
+  ctx = context.get()
+  params = ctx.mapreduce_spec.mapper.params
+
+  list_id_func = eval(params['list_id_func'])
+  column_defs = eval(params['column_defs'])
+
+  item = lists.toListItemDict(entity, column_defs)
+
+  list_id = list_id_func(entity)
+
+  yield (list_id, item)
+
+
+def reduceProcess(list_id, entities):
+  ndb.transaction(lambda: cached_list.cacheItems(list_id, entities))
+
+
+class CacheListsPipeline(base_handler.PipelineBase):
+  """A pipeline to read datastore entities and cache them for lists.
+
+  Args:
+    kind: Kind of the entity the DatastoreInputReader should read.
+    list_id_func: A string representation of a lambda function. This function
+      should take one parameter, the entity relevant to one list item. It should
+      create an id for the list that list item should belong to.
+    column_defs: A string representation of a dictionary that has column names
+      of the list as keys, and lambda functions that create the value for that
+      column for a list item as values. These functions should take one
+      parameter, the entity relevant to one list item.
+  """
+
+  def run(self, kind, list_id_func, column_defs):
+    yield mapreduce_pipeline.MapreducePipeline(
+      'cache_list_items',
+      'soc.mapreduce.cache_list_items.mapProcess',
+      'soc.mapreduce.cache_list_items.reduceProcess',
+      'mapreduce.input_readers.DatastoreInputReader',
+      mapper_params={
+          'entity_kind': kind,
+          'list_id_func': list_id_func,
+          'column_defs': column_defs
+      },
+      shards=NO_OF_SHARDS)
diff --git a/app/soc/models/conversation.py b/app/soc/models/conversation.py
new file mode 100644
index 0000000..858a4a8
--- /dev/null
+++ b/app/soc/models/conversation.py
@@ -0,0 +1,122 @@
+# Copyright 2013 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 containing the Conversation model."""
+
+from google.appengine.ext import db
+from google.appengine.ext import ndb
+
+from datetime import datetime
+
+from django.utils import translation
+
+from soc.models import user as user_model
+
+#: Constants for specifiying the type of recipients
+PROGRAM       = 'Program'       #: Types of users within the program
+ORGANIZATION  = 'Organization'  #: Types of users within the specified org
+USER          = 'User'          #: Specific users, specified manually
+
+
+class Conversation(ndb.Model):
+  """Model of a conversation: a thread of messages."""
+
+  #: Subject of the conversation
+  subject = ndb.TextProperty(required=True,
+                             verbose_name=translation.ugettext('Subject'))
+
+  #: User who created the conversation.
+  #: Optional; If None, conversation was created by Melange.
+  creator = ndb.KeyProperty(required=False)
+
+  #: When the conversation was created
+  created_on = ndb.DateTimeProperty(required=True, auto_now_add=True)
+
+  #: When the last message was added
+  last_message_on = ndb.DateTimeProperty(
+      default=datetime.min,
+      verbose_name=translation.ugettext('Last Message'))
+
+  #: What type of recipients
+  recipients_type = ndb.StringProperty(required=True,
+                                       choices=[PROGRAM, ORGANIZATION, USER])
+
+  #: Program under which the conversation exists.
+  #: If recipient type is 'Program', this is also the scope of recipients.
+  program = ndb.KeyProperty(required=True,
+                            verbose_name=translation.ugettext('Program'))
+
+  #: Organization to limit to if recipients type is organization.
+  #: Ignored if recipient type is not 'Organization'.
+  organization = ndb.KeyProperty(
+      required=False,
+      verbose_name=translation.ugettext('Organization'))
+
+  #: Include admins as recipients if recipients type is program,
+  #: or organization admins as recipients if recipients type is organization.
+  #: Ignored if recipient type is not 'Program' or 'Organization'.
+  include_admins = ndb.BooleanProperty(required=False)
+
+  #: Include mentors as recipients if recipients type is program,
+  #: or organization mentors as recipients if recipients type is organization.
+  #: Ignored if recipient type is not 'Program' or 'Organization'.
+  include_mentors = ndb.BooleanProperty(required=False)
+
+  #: Include students as recipients if recipients type is program.
+  #: Ignored if recipient type is not 'Program'.
+  include_students = ndb.BooleanProperty(required=False)
+
+  #: Whether users will be automatically added/removed if they start/stop
+  #: matching the criteria defined above. Ignored if recipients type is 'User'.
+  auto_update_users = ndb.BooleanProperty(
+      default=True,
+      verbose_name=translation.ugettext('Automatically Update Users'))
+  auto_update_users.help_text = translation.ugettext(
+      'If set, users will be automatically added and removed from the '
+      'conversation if they no longer fit the criteria.')
+
+
+class ConversationUser(ndb.Model):
+  """Model representing a user's involvement in a conversation.
+
+  An instance of this model is created for every user in every conversation.
+
+  In addition to being a record of a user's involvement in a conversation, it
+  stores the time of the last message seen by the user, and it also store's the
+  user's preferences for this conversation.
+  """
+
+  #: Conversation the preferences apply to
+  conversation = ndb.KeyProperty(kind=Conversation, required=True)
+
+  #: User the preferences are for
+  user = ndb.KeyProperty(required=True)
+
+  #: Conversation's Program, to aid with querying
+  program = ndb.ComputedProperty(lambda self: self.conversation.get().program)
+
+  #: Conversation's last_message_on, to aid with querying
+  last_message_on = ndb.ComputedProperty(
+      lambda self: self.conversation.get().last_message_on)
+
+  #: Time of the last message seen by this user in this conversation
+  last_message_seen_on = ndb.DateTimeProperty(default=datetime.min)
+
+  #: Preference for receiving email notifications for new messages
+  enable_notifications = ndb.BooleanProperty(
+      default=True,
+      verbose_name=translation.ugettext('Get Email Notifications'))
+  enable_notifications.help_test = translation.ugettext(
+      'If set, you will receive email notifications about new '
+      'messages in this conversation.')
diff --git a/app/soc/models/message.py b/app/soc/models/message.py
new file mode 100644
index 0000000..d13e269
--- /dev/null
+++ b/app/soc/models/message.py
@@ -0,0 +1,45 @@
+# Copyright 2013 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 containing the Message and MessageSeen models."""
+
+from google.appengine.ext import ndb
+
+from django.utils import translation
+
+from soc.models import conversation as conversation_model
+
+
+class Message(ndb.Model):
+  """Model of a message within a conversation.
+
+  Parent:
+    soc.models.conversation.Conversation
+  """
+
+  #: Conversation the message belongs to
+  conversation = ndb.KeyProperty(kind=conversation_model.Conversation,
+                                 required=True)
+
+  #: User who wrote the message. If None, message was authored by Melange.
+  author = ndb.KeyProperty(required=False,
+                           verbose_name=translation.ugettext('Author'))
+
+  #: Content of the message
+  content = ndb.TextProperty(required=True,
+                             verbose_name=translation.ugettext('Message'))
+
+  #: Time when the message was sent
+  sent_on = ndb.DateTimeProperty(required=True, auto_now_add=True,
+                                 verbose_name=translation.ugettext('Time Sent'))
diff --git a/app/soc/modules/gci/logic/ranking.py b/app/soc/modules/gci/logic/ranking.py
index 110a9be..8e0d8ae 100644
--- a/app/soc/modules/gci/logic/ranking.py
+++ b/app/soc/modules/gci/logic/ranking.py
@@ -189,7 +189,6 @@
   Args:
     data: The RequestData object.
   """
-  r = data.redirect
   program = data.program
 
   q = GCIScore.all()
@@ -210,8 +209,8 @@
   for profile in profiles:
     winner = winners[profile.key()]
     winner['profile'] = profile
-    winner['completed_tasks_link'] = r.profile(profile.link_id).urlOf(
-            url_names.GCI_STUDENT_TASKS)
+    winner['completed_tasks_link'] = data.redirect.profile(
+        profile.link_id).urlOf(url_names.GCI_STUDENT_TASKS)
 
     if profile.avatar:
       avatar_groups = re.findall(forms.RE_AVATAR_COLOR, profile.avatar)
diff --git a/app/soc/modules/gci/templates/org_list.py b/app/soc/modules/gci/templates/org_list.py
index b68c302..b55a0a5 100644
--- a/app/soc/modules/gci/templates/org_list.py
+++ b/app/soc/modules/gci/templates/org_list.py
@@ -31,11 +31,9 @@
   def context(self):
     description = self._getDescription()
 
-    list = lists.ListConfigurationResponse(
-        self.data, self._list_config, 0, description)
-
     return {
-        'lists': [list],
+        'lists': [lists.ListConfigurationResponse(
+            self.data, self._list_config, 0, description)],
     }
 
   def getListData(self):
@@ -77,8 +75,6 @@
   def _getListConfig(self):
     """Returns ListConfiguration object for the list.
     """
-    r = self.data.redirect
-
     list_config = lists.ListConfiguration()
     list_config.addPlainTextColumn('name', 'Name',
         lambda e, *args: e.name.strip())
diff --git a/app/soc/modules/gci/templates/student_list.py b/app/soc/modules/gci/templates/student_list.py
index 133faef..648f94c 100644
--- a/app/soc/modules/gci/templates/student_list.py
+++ b/app/soc/modules/gci/templates/student_list.py
@@ -206,13 +206,13 @@
     return'modules/gci/students_info/_students_list.html'
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=self.idx)
 
     return {
         'name': 'students',
         'title': 'Participating students',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext(
             'List of participating students'),
     }
diff --git a/app/soc/modules/gci/templates/task_list.py b/app/soc/modules/gci/templates/task_list.py
index 705a876..27d0c85 100644
--- a/app/soc/modules/gci/templates/task_list.py
+++ b/app/soc/modules/gci/templates/task_list.py
@@ -77,7 +77,7 @@
     return lists.ListModelPrefetcher(GCITask, fields, list_fields)
 
   def _getListConfig(self):
-    r = self.data.redirect
+    self.data.redirect
 
     list_config = lists.ListConfiguration()
 
@@ -105,7 +105,8 @@
       list_config.addSimpleColumn('status', 'Status')
 
     list_config.setRowAction(
-        lambda e, *args: r.id(e.key().id()).urlOf('gci_view_task'))
+        lambda e, *args: self.data.redirect.id(e.key().id()).urlOf(
+            'gci_view_task'))
 
     return list_config
 
diff --git a/app/soc/modules/gci/views/admin.py b/app/soc/modules/gci/views/admin.py
index 2edd9ed..0132c61 100644
--- a/app/soc/modules/gci/views/admin.py
+++ b/app/soc/modules/gci/views/admin.py
@@ -126,8 +126,8 @@
   def context(self):
     """Returns the context of main dashboard.
     """
-    r = self.data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.program()
 
     program_settings = ProgramSettingsDashboard(self.data)
     organizations = OrgDashboard(self.data)
@@ -139,7 +139,7 @@
             'description': ugettext(
                 'Lookup profile of mentor or student from various program.'),
             'title': 'Lookup profile',
-            'link': r.urlOf('lookup_gci_profile')
+            'link': self.data.redirect.urlOf('lookup_gci_profile')
         },
         {
             'name': 'program_settings',
@@ -184,8 +184,8 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     linker = links.Linker()
 
@@ -196,7 +196,7 @@
                 'Edit your program settings such as information, slots, '
                 'documents, etc.'),
             'title': 'Edit program settings',
-            'link': r.urlOf(url_names.GCI_PROGRAM_EDIT)
+            'link': data.redirect.urlOf(url_names.GCI_PROGRAM_EDIT)
         },
         {
             'name': 'edit_timeline',
@@ -204,7 +204,7 @@
                 'Edit your program timeline such as program start/end date, '
                 'student signup start/end date, etc.'),
             'title': 'Edit timeline',
-            'link': r.urlOf('edit_gci_timeline')
+            'link': data.redirect.urlOf('edit_gci_timeline')
         },
         {
             'name': 'edit_program_messages',
@@ -212,14 +212,14 @@
                 'Edit program messages which will be sent in emails '
                 'to the specified participants.'),
             'title': 'Edit messages',
-            'link': r.urlOf(url_names.GCI_EDIT_PROGRAM_MESSAGES)
+            'link': data.redirect.urlOf(url_names.GCI_EDIT_PROGRAM_MESSAGES)
         },
         {
             'name': 'documents',
             'description': ugettext(
                 'List of documents from various program.'),
             'title': 'List of documents',
-            'link': r.urlOf('list_gci_documents')
+            'link': data.redirect.urlOf('list_gci_documents')
         },
         {
             'name': 'create_program',
@@ -263,8 +263,8 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     subpages = [
         {
@@ -272,35 +272,35 @@
             'description': ugettext(
                 'Create or edit organization application'),
             'title': 'Edit organization application',
-            'link': r.urlOf('gci_edit_org_app')
+            'link': data.redirect.urlOf('gci_edit_org_app')
         },
         {
             'name': 'preview_org_app',
             'description': ugettext(
                 'Preview of the organization application.'),
             'title': 'Preview organization application',
-            'link': r.urlOf('gci_preview_org_app')
+            'link': data.redirect.urlOf('gci_preview_org_app')
         },
         {
             'name': 'org_app_records',
             'description': ugettext(
                 'List of submitted organization application'),
             'title': 'Organization application records',
-            'link': r.urlOf('gci_list_org_app_records')
+            'link': data.redirect.urlOf('gci_list_org_app_records')
         },
         {
             'name': 'accepted_orgs',
             'description': ugettext(
                 'List of accepted organizations'),
             'title': 'Accepted Organizations',
-            'link': r.urlOf('gci_admin_accepted_orgs')
+            'link': data.redirect.urlOf('gci_admin_accepted_orgs')
         },
         {
             'name': 'org_scores',
             'description': ugettext(
                 'List of student scores for the chosen organization'),
             'title': 'Organization Scores',
-            'link': r.urlOf(url_names.GCI_ORG_CHOOSE_FOR_SCORE)
+            'link': data.redirect.urlOf(url_names.GCI_ORG_CHOOSE_FOR_SCORE)
         },
         {
             'name': 'org_tasks',
@@ -308,7 +308,7 @@
                 'List of tasks that have been created by '
                 'the chosen organization'),
             'title': 'Organization Tasks',
-            'link': r.urlOf(url_names.GCI_ORG_CHOOSE_FOR_ALL_TASKS)
+            'link': data.redirect.urlOf(url_names.GCI_ORG_CHOOSE_FOR_ALL_TASKS)
         },
         {
             'name': 'proposed_winners',
@@ -316,7 +316,7 @@
                 'List of the Grand Prize Winners that have been proposed by '
                 'organizations'),
             'title': 'Proposed Grand Prize Winners',
-            'link': r.urlOf(url_names.GCI_VIEW_PROPOSED_WINNERS)
+            'link': data.redirect.urlOf(url_names.GCI_VIEW_PROPOSED_WINNERS)
         },
     ]
 
@@ -350,8 +350,8 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     subpages = [
         {
@@ -359,21 +359,21 @@
             'description': ugettext(
                 'List of all the organization admins and mentors'),
             'title': 'List mentors and admins',
-            'link': r.urlOf('gci_list_mentors')
+            'link': data.redirect.urlOf('gci_list_mentors')
         },
         {
             'name': 'list_students',
             'description': ugettext(
                 'List of all participating students'),
             'title': 'List students',
-            'link': r.urlOf(url_names.GCI_STUDENTS_INFO)
+            'link': data.redirect.urlOf(url_names.GCI_STUDENTS_INFO)
         },
         {
             'name': 'leaderboard',
             'description': ugettext(
                 'Leaderboard for the program'),
             'title': 'Leaderboard',
-            'link': r.urlOf(url_names.GCI_LEADERBOARD)
+            'link': data.redirect.urlOf(url_names.GCI_LEADERBOARD)
         },
     ]
 
diff --git a/app/soc/modules/gci/views/all_tasks.py b/app/soc/modules/gci/views/all_tasks.py
index f1b6046..1cda9c9 100644
--- a/app/soc/modules/gci/views/all_tasks.py
+++ b/app/soc/modules/gci/views/all_tasks.py
@@ -14,6 +14,7 @@
 
 """Module containing the view for GCI tasks list page."""
 
+from melange.request import access
 from melange.request import exception
 from soc.views.helper import url_patterns
 
@@ -48,6 +49,8 @@
 
   TASK_LIST_COLUMNS = ['title', 'organization', 'mentors', 'status']
 
+  access_checker = access.ALL_ALLOWED_ACCESS_CHECKER
+
   def templatePath(self):
     return 'modules/gci/task/task_list.html'
 
@@ -57,9 +60,6 @@
             name=url_names.GCI_ALL_TASKS_LIST),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    pass
-
   def jsonContext(self, data, check, mutator):
     list_content = AllTasksList(data).getListData()
     if list_content:
diff --git a/app/soc/modules/gci/views/dashboard.py b/app/soc/modules/gci/views/dashboard.py
index 4e758be..361de39 100644
--- a/app/soc/modules/gci/views/dashboard.py
+++ b/app/soc/modules/gci/views/dashboard.py
@@ -358,73 +358,71 @@
 
   def _getMyInvitationsLink(self, data):
     """Get the link of incoming invitations list (invitations sent to me)."""
-    # TODO(nathaniel): This doesn't appear to be used?
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     return {
         'name': 'list_invites',
         'description': ugettext(
             'List of all invites which have been sent to me.'),
         'title': 'Invites to me',
-        'link': r.urlOf(url_names.GCI_LIST_INVITES)
+        'link': data.redirect.urlOf(url_names.GCI_LIST_INVITES)
         }
 
   def _getMyOrgInvitationsLink(self, data):
     """Get the link of outgoing invitations list (invitations sent by my orgs).
     """
-    # TODO(nathaniel): This also doesn't appear to be used?
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     return {
         'name': 'list_org_invites',
         'description': ugettext(
             'List of all invites which have been sent by my organizations.'),
         'title': 'My organization outgoing invitations',
-        'link': r.urlOf(url_names.GCI_LIST_ORG_INVITES)
+        'link': data.redirect.urlOf(url_names.GCI_LIST_ORG_INVITES)
         }
 
   def _getStudentFormsLink(self, data):
     """Get the link for uploading student forms."""
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     return {
         'name': 'form_uploads',
         'description': ugettext(
             'Upload student id and parental consent forms.'),
         'title': 'Form uploads',
-        'link': r.urlOf(url_names.GCI_STUDENT_FORM_UPLOAD)
+        'link': data.redirect.urlOf(url_names.GCI_STUDENT_FORM_UPLOAD)
         }
 
   def _getMyTasksLink(self, data):
     """Get the link to the list of all the tasks for the student
     who is currently logged in.
     """
-    r = data.redirect
-    r.profile(data.user.link_id)
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.profile(data.user.link_id)
 
     return {
         'name': 'student_tasks',
         'description': ugettext(
             'List of the tasks that you have completed so far in the program'),
         'title': 'My completed tasks',
-        'link': r.urlOf(url_names.GCI_STUDENT_TASKS)
+        'link': data.redirect.urlOf(url_names.GCI_STUDENT_TASKS)
         }
 
   def _getCurrentTaskLink(self, data, current_task):
     """Get the link to the task that the student is currently working on.
     """
-    r = data.redirect
-    r.id(current_task.key().id())
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.id(current_task.key().id())
 
     return {
         'name': 'current_task',
         'description': ugettext(
             'The task you are currently working on'),
         'title': 'My current task',
-        'link': r.urlOf('gci_view_task')
+        'link': data.redirect.urlOf('gci_view_task')
         }
 
   def _getMySubscribedTasksLink(self, data):
@@ -444,15 +442,16 @@
 
   def _getProposeWinnersLink(self, data):
     """Get the link to the list of organization to propose winners for."""
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     return {
         'name': 'propose_winners',
         'description': ugettext(
             'Propose the Grand Prize Winners'),
         'title': 'Propose the Grand Prize Winners',
-        'link': r.urlOf(url_names.GCI_ORG_CHOOSE_FOR_PROPOSE_WINNNERS)
+        'link': data.redirect.urlOf(
+            url_names.GCI_ORG_CHOOSE_FOR_PROPOSE_WINNNERS)
         }
 
 
@@ -503,15 +502,14 @@
     return 'modules/gci/dashboard/list_component.html'
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=0, preload_list=False)
 
     return {
         'name': 'org_app',
         'title': 'My organization applications',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('My organization applications'),
         }
 
@@ -907,10 +905,8 @@
             'organization.')}
 
   def _setRowAction(self, request, data):
-    r = data.redirect
-
     self._list_config.setRowAction(
-        lambda e, *args: r.invite('mentor', e)
+        lambda e, *args: data.redirect.invite('mentor', e)
             .urlOf(url_names.GCI_SEND_INVITE))
 
 
@@ -935,10 +931,8 @@
             'they will become mentors too.')}
 
   def _setRowAction(self, request, data):
-    r = data.redirect
-
     self._list_config.setRowAction(
-        lambda e, *args: r.invite('org_admin', e)
+        lambda e, *args: data.redirect.invite('org_admin', e)
             .urlOf(url_names.GCI_SEND_INVITE))
 
 
@@ -1012,15 +1006,14 @@
     return'modules/gci/dashboard/list_component.html'
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=6, preload_list=False)
 
     return {
         'name': 'all_orgs_mentors',
         'title': 'All mentors for my organizations',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('List of all mentors for my organizations'),
         }
 
@@ -1084,7 +1077,6 @@
 
   def __init__(self, data):
     self.data = data
-    r = data.redirect
 
     # GCIRequest entities have user entities as parents, so the keys
     # for the list items should be parent scoped.
@@ -1102,9 +1094,9 @@
       list_config.addPlainTextColumn('org', 'From',
         lambda entity, *args: entity.org.name)
 
-    list_config.setRowAction(
-        lambda e, *args: r.userId(e.parent_key().name(), e.key().id())
-            .urlOf(url_names.GCI_MANAGE_INVITE))
+    list_config.setRowAction(lambda e, *args: data.redirect.userId(
+        e.parent_key().name(), e.key().id()).urlOf(
+        url_names.GCI_MANAGE_INVITE))
 
     self.idx = 9
     self._list_config = list_config
diff --git a/app/soc/modules/gci/views/helper/access_checker.py b/app/soc/modules/gci/views/helper/access_checker.py
index 238b612..9b4ccf1 100644
--- a/app/soc/modules/gci/views/helper/access_checker.py
+++ b/app/soc/modules/gci/views/helper/access_checker.py
@@ -279,9 +279,12 @@
     self.hasNonStudentProfileInAProgram()
 
     program = self.data.program
-    r = self.data.redirect.createProfile('org_admin')
+
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.createProfile('org_admin')
     msg = DEF_NO_ORG_ADMIN_PROFILE % (
-        program.short_name, r.urlOf('create_gci_profile', secure=True))
+        program.short_name,
+        self.data.redirect.urlOf('create_gci_profile', secure=True))
 
     if not validate.hasNonStudentProfileForProgram(
         self.data.user, program, GCIProfile):
diff --git a/app/soc/modules/gci/views/invite.py b/app/soc/modules/gci/views/invite.py
index a57c4d1..143b25b 100644
--- a/app/soc/modules/gci/views/invite.py
+++ b/app/soc/modules/gci/views/invite.py
@@ -411,14 +411,13 @@
 
   def __init__(self, data):
     self.data = data
-    r = data.redirect
 
     list_config = lists.ListConfiguration()
     list_config.addPlainTextColumn('org', 'From',
         lambda entity, *args: entity.org.name)
     list_config.addSimpleColumn('status', 'Status')
     list_config.setRowAction(
-        lambda e, *args: r.id(e.key().id())
+        lambda e, *args: data.redirect.id(e.key().id())
             .urlOf(url_names.GCI_RESPOND_INVITE))
 
     self._list_config = list_config
diff --git a/app/soc/modules/gci/views/leaderboard.py b/app/soc/modules/gci/views/leaderboard.py
index 761ecf2..3c3b7f3 100644
--- a/app/soc/modules/gci/views/leaderboard.py
+++ b/app/soc/modules/gci/views/leaderboard.py
@@ -38,7 +38,6 @@
 
   def __init__(self, data):
     self.data = data
-    r = data.redirect
 
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn('key', 'Key', (lambda ent, *args: "%s" % (
@@ -51,7 +50,7 @@
     list_config.setDefaultSort('points', 'desc')
 
     list_config.setRowAction(
-        lambda e, *args: r.profile(e.parent().link_id).urlOf(
+        lambda e, *args: data.redirect.profile(e.parent().link_id).urlOf(
             url_names.GCI_STUDENT_TASKS))
 
     self._list_config = list_config
diff --git a/app/soc/modules/gci/views/org_home.py b/app/soc/modules/gci/views/org_home.py
index 415fe92..e9f922c 100644
--- a/app/soc/modules/gci/views/org_home.py
+++ b/app/soc/modules/gci/views/org_home.py
@@ -16,6 +16,7 @@
 
 from django.utils.translation import ugettext
 
+from melange.request import access
 from melange.request import exception
 from soc.logic import accounts
 from soc.views.helper import lists
@@ -91,10 +92,9 @@
 
   def context(self):
     description = 'List of all Open tasks.'
-    list = lists.ListConfigurationResponse(
-        self.data, self.list_config, 0, description)
     return {
-        'lists': [list],
+        'lists': [lists.ListConfigurationResponse(
+            self.data, self.list_config, 0, description)],
     }
 
   def getListData(self):
@@ -134,10 +134,9 @@
 
   def context(self):
     description = 'List of all Completed tasks.'
-    list = lists.ListConfigurationResponse(
-        self.data, self.list_config, 1, description)
     return {
-        'lists': [list],
+        'lists': [lists.ListConfigurationResponse(
+            self.data, self.list_config, 1, description)],
     }
 
   def getListData(self):
@@ -188,6 +187,8 @@
 class OrgHomepage(GCIRequestHandler):
   """Encapsulates all the methods required to render the org homepage."""
 
+  access_checker = access.ALL_ALLOWED_ACCESS_CHECKER
+
   def templatePath(self):
     return 'modules/gci/org_home/base.html'
 
@@ -198,9 +199,6 @@
         url(r'org/home/%s' % url_patterns.ORG, self),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    pass
-
   def jsonContext(self, data, check, mutator):
     idx = lists.getListIndex(data.request)
     list_content = None
diff --git a/app/soc/modules/gci/views/org_score.py b/app/soc/modules/gci/views/org_score.py
index e14a66d..b204a47 100644
--- a/app/soc/modules/gci/views/org_score.py
+++ b/app/soc/modules/gci/views/org_score.py
@@ -14,6 +14,7 @@
 
 """Module for the GCI organization score page."""
 
+from melange.request import access
 from melange.request import exception
 from soc.views.helper import lists
 from soc.views.helper import url_patterns
@@ -35,7 +36,6 @@
 
   def __init__(self, data):
     self.data = data
-    r = data.redirect
 
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn('key', 'Key', (lambda ent, *args: "%s" % (
@@ -47,7 +47,7 @@
     list_config.setDefaultSort('tasks', 'desc')
 
     list_config.setRowAction(
-        lambda e, *args: r.userOrg(user=e.parent().link_id).urlOf(
+        lambda e, *args: data.redirect.userOrg(user=e.parent().link_id).urlOf(
             url_names.GCI_STUDENT_TASKS_FOR_ORG))
 
     self._list_config = list_config
@@ -84,8 +84,9 @@
 
 
 class OrgScoresForOrgzanizationPage(GCIRequestHandler):
-  """View for the organizations scores page.
-  """
+  """View for the organizations scores page."""
+
+  access_checker = access.ALL_ALLOWED_ACCESS_CHECKER
 
   def templatePath(self):
     return 'modules/gci/org_score/base.html'
@@ -96,9 +97,6 @@
             name=url_names.GCI_ORG_SCORES),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    pass
-
   def context(self, data, check, mutator):
     return {
         'page_name': "Organization scores for %s" % data.organization.name,
diff --git a/app/soc/modules/gci/views/participants.py b/app/soc/modules/gci/views/participants.py
index c999b60..c0cd540 100644
--- a/app/soc/modules/gci/views/participants.py
+++ b/app/soc/modules/gci/views/participants.py
@@ -61,11 +61,9 @@
         'List of organization admins and mentors participating in %s' % (
             self.data.program.name)
 
-    list = lists.ListConfigurationResponse(
-        self.data, self._list_config, 0, description)
-
     return {
-        'lists': [list],
+        'lists': [lists.ListConfigurationResponse(
+            self.data, self._list_config, 0, description)],
     }
 
   def getListData(self):
diff --git a/app/soc/modules/gci/views/profile_show.py b/app/soc/modules/gci/views/profile_show.py
index 02f72a8..bb15e05 100644
--- a/app/soc/modules/gci/views/profile_show.py
+++ b/app/soc/modules/gci/views/profile_show.py
@@ -44,8 +44,7 @@
     self.profile = profile
 
   def context(self):
-    r = self.data.redirect
-    base_url = r.profile(self.profile.link_id).urlOf(
+    base_url = self.data.redirect.profile(self.profile.link_id).urlOf(
         url_names.GCI_STUDENT_FORM_DOWNLOAD)
     consent_form_url= '%s?%s' % (base_url, url_names.CONSENT_FORM_GET_PARAM)
     student_id_form_url = '%s?%s' % (
@@ -136,8 +135,10 @@
       else:
         context['verify_student_id_form_init'] = 'checked'
 
-      r = data.redirect.profile(profile.link_id)
-      context['student_task_link'] = r.urlOf(url_names.GCI_STUDENT_TASKS)
+      # TODO(nathaniel): Eliminate this state-setting call.
+      data.redirect.profile(profile.link_id)
+      context['student_task_link'] = data.redirect.urlOf(
+          url_names.GCI_STUDENT_TASKS)
 
     return context
 
diff --git a/app/soc/modules/gci/views/propose_winners.py b/app/soc/modules/gci/views/propose_winners.py
index b94aa3d..1d6905b 100644
--- a/app/soc/modules/gci/views/propose_winners.py
+++ b/app/soc/modules/gci/views/propose_winners.py
@@ -249,8 +249,6 @@
   def _getListConfig(self):
     """Returns ListConfiguration object for the list.
     """
-    r = self.data.redirect
-
     list_config = lists.ListConfiguration()
     list_config.addPlainTextColumn('name', 'Name',
         lambda e, *args: e.name.strip())
@@ -270,6 +268,8 @@
   he or she is moved to the propose winner page for this organization.
   """
 
+  access_checker = access.ALL_ALLOWED_ACCESS_CHECKER
+
   def templatePath(self):
     return 'modules/gci/org_list/base.html'
 
@@ -280,9 +280,6 @@
             name=url_names.GCI_ORG_CHOOSE_FOR_PROPOSE_WINNNERS),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    pass
-
   def jsonContext(self, data, check, mutator):
     list_content = OrganizationsForProposeWinnersList(data).getListData()
     if list_content:
@@ -318,8 +315,6 @@
   def _getListConfig(self):
     """Returns ListConfiguration object for the list.
     """
-    r = self.data.redirect
-
     def proposedWinnersFunc(organization, *args):
       profiles = profile_model.GCIProfile.get(organization.proposed_winners)
       return ', '.join([p.name() for p in profiles if p])
diff --git a/app/soc/modules/gci/views/task_list.py b/app/soc/modules/gci/views/task_list.py
index fc3257e..5b8182a 100644
--- a/app/soc/modules/gci/views/task_list.py
+++ b/app/soc/modules/gci/views/task_list.py
@@ -35,12 +35,11 @@
 
   def __init__(self, data):
     self.data = data
-    r = data.redirect
 
     list_config = lists.ListConfiguration()
     list_config.addSimpleColumn('title', 'Title')
     list_config.setRowAction(
-        lambda e, *args: r.id(e.key().id()).urlOf('gci_view_task'))
+        lambda e, *args: data.redirect.id(e.key().id()).urlOf('gci_view_task'))
 
     self._list_config = list_config
 
@@ -48,11 +47,9 @@
     description = 'List of tasks for %s' % (
             self.data.program.name)
 
-    list = lists.ListConfigurationResponse(
-        self.data, self._list_config, 0, description)
-
     return {
-        'lists': [list],
+        'lists': [lists.ListConfigurationResponse(
+            self.data, self._list_config, 0, description)],
     }
 
   def getListData(self):
@@ -74,8 +71,9 @@
 
 
 class TaskListPage(GCIRequestHandler):
-  """View for the list task page.
-  """
+  """View for the list task page."""
+
+  access_checker = access.ALL_ALLOWED_ACCESS_CHECKER
 
   def templatePath(self):
     return 'modules/gci/task/task_list.html'
@@ -86,9 +84,6 @@
             name='list_gci_finished_tasks'),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    pass
-
   def jsonContext(self, data, check, mutator):
     list_content = TaskList2(data).getListData()
     if list_content:
diff --git a/app/soc/modules/gsoc/templates/org_list.py b/app/soc/modules/gsoc/templates/org_list.py
index a7fc724..a3363b8 100644
--- a/app/soc/modules/gsoc/templates/org_list.py
+++ b/app/soc/modules/gsoc/templates/org_list.py
@@ -39,11 +39,11 @@
     """See template.Template.context for specification."""
     description = self._getDescription()
 
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, 0, description)
 
     return {
-        'lists': [list],
+        'lists': [list_configuration_response],
     }
 
   def getListData(self):
diff --git a/app/soc/modules/gsoc/views/accept_withdraw_projects.py b/app/soc/modules/gsoc/views/accept_withdraw_projects.py
index 013b378..d3bd787 100644
--- a/app/soc/modules/gsoc/views/accept_withdraw_projects.py
+++ b/app/soc/modules/gsoc/views/accept_withdraw_projects.py
@@ -87,14 +87,14 @@
     self._list_config = list_config
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=0,
         description='List of proposals submitted for %s' % (
             self.data.program.name))
 
     return {
         'list_title': 'Submitted Proposals',
-        'lists': [list],
+        'lists': [list_configuration_response],
         }
 
   def post(self):
@@ -262,14 +262,14 @@
     self._list_config = list_config
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=0,
         description='List of %s projects whether accepted or withdrawn' % (
             self.data.program.name))
 
     return {
         'list_title': 'Accepted Projects',
-        'lists': [list],
+        'lists': [list_configuration_response],
         }
 
   def post(self):
diff --git a/app/soc/modules/gsoc/views/admin.py b/app/soc/modules/gsoc/views/admin.py
index 7e46537..2e8fe0d 100644
--- a/app/soc/modules/gsoc/views/admin.py
+++ b/app/soc/modules/gsoc/views/admin.py
@@ -147,8 +147,8 @@
 
   def context(self):
     """Returns the context of main dashboard."""
-    r = self.data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.program()
 
     manage_orgs = ManageOrganizationsDashboard(self.data)
     program_settings = ProgramSettingsDashboard(self.data)
@@ -161,7 +161,7 @@
             'description': ugettext(
                 'Lookup profile of mentor or student from various program.'),
             'title': 'Lookup profile',
-            'link': r.urlOf('lookup_gsoc_profile')
+            'link': self.data.redirect.urlOf('lookup_gsoc_profile')
         },
         {
             'name': 'allocate_slots',
@@ -169,14 +169,14 @@
                 'Allocate slots (number of acceptable projects) per '
                 'organization'),
             'title': 'Allocate slots',
-            'link': r.urlOf('gsoc_slots')
+            'link': self.data.redirect.urlOf('gsoc_slots')
         },
         {
             'name': 'slots_transfer',
             'description': ugettext(
                 'Transfer slots for organizations'),
             'title': 'Slots transfer',
-            'link': r.urlOf('gsoc_admin_slots_transfer')
+            'link': self.data.redirect.urlOf('gsoc_admin_slots_transfer')
         },
         {
             'name': 'duplicates',
@@ -184,7 +184,7 @@
                 'Calculate how many duplicate proposals, students that have '
                 'accepted proposals more than one'),
             'title': 'Duplicates',
-            'link': r.urlOf('gsoc_view_duplicates')
+            'link': self.data.redirect.urlOf('gsoc_view_duplicates')
         },
         {
             'name': 'accept_proposals',
@@ -192,7 +192,7 @@
                 'Start proposals into projects conversion'),
             'title': 'Bulk accept proposals and send acceptance/rejection '
                      'emails',
-            'link': r.urlOf('gsoc_accept_proposals')
+            'link': self.data.redirect.urlOf('gsoc_accept_proposals')
         },
         {
             'name': 'manage_proposals',
@@ -200,14 +200,14 @@
                 'Lists all the proposals submitted to the program and lets '
                 'accept individual proposals.'),
             'title': 'Proposals submitted',
-            'link': r.urlOf('gsoc_admin_accept_proposals')
+            'link': self.data.redirect.urlOf('gsoc_admin_accept_proposals')
         },
         {
             'name': 'withdraw_projects',
             'description': ugettext(
                 'Withdraw accepted projects or accept withdrawn projects'),
             'title': 'Accept/withdraw projects',
-            'link': r.urlOf('gsoc_withdraw_projects')
+            'link': self.data.redirect.urlOf('gsoc_withdraw_projects')
         },
         {
             'name': 'students',
@@ -264,8 +264,8 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     linker = links.Linker()
 
@@ -276,7 +276,7 @@
                 'Edit your program settings such as information, slots, '
                 'documents, etc.'),
             'title': 'Edit program settings',
-            'link': r.urlOf(url_names.GSOC_PROGRAM_EDIT)
+            'link': data.redirect.urlOf(url_names.GSOC_PROGRAM_EDIT)
         },
         {
             'name': 'edit_timeline',
@@ -284,7 +284,7 @@
                 'Edit your program timeline such as program start/end date, '
                 'student signup start/end date, etc.'),
             'title': 'Edit timeline',
-            'link': r.urlOf('edit_gsoc_timeline')
+            'link': data.redirect.urlOf('edit_gsoc_timeline')
         },
         {
             'name': 'edit_program_messages',
@@ -292,14 +292,14 @@
                 'Edit program messages which will be sent in emails '
                 'to the specified participants.'),
             'title': 'Edit messages',
-            'link': r.urlOf(url_names.GSOC_EDIT_PROGRAM_MESSAGES)
+            'link': data.redirect.urlOf(url_names.GSOC_EDIT_PROGRAM_MESSAGES)
         },
         {
             'name': 'documents',
             'description': ugettext(
                 'List of documents from various program.'),
             'title': 'List of documents',
-            'link': r.urlOf('list_gsoc_documents')
+            'link': data.redirect.urlOf('list_gsoc_documents')
         },
         {
             'name': 'create_program',
@@ -340,8 +340,8 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     subpages = [
         {
@@ -349,28 +349,28 @@
             'description': ugettext(
                 'Create or edit organization application'),
             'title': 'Edit organization application',
-            'link': r.urlOf('gsoc_edit_org_app')
+            'link': data.redirect.urlOf('gsoc_edit_org_app')
         },
         {
             'name': 'preview_org_app',
             'description': ugettext(
                 'Preview of the organization application.'),
             'title': 'Preview organization application',
-            'link': r.urlOf('gsoc_preview_org_app')
+            'link': data.redirect.urlOf('gsoc_preview_org_app')
         },
         {
             'name': 'org_app_records',
             'description': ugettext(
                 'List of submitted organization application'),
             'title': 'Organization application records',
-            'link': r.urlOf('gsoc_list_org_app_records')
+            'link': data.redirect.urlOf('gsoc_list_org_app_records')
         },
         {
             'name': 'accepted_orgs',
             'description': ugettext(
                 'List of accepted organizations'),
             'title': 'Accepted Organizations',
-            'link': r.urlOf(url_names.GSOC_ORG_LIST_FOR_HOST),
+            'link': data.redirect.urlOf(url_names.GSOC_ORG_LIST_FOR_HOST),
         },
     ]
 
@@ -406,8 +406,8 @@
     student_evaluations = StudentEvaluationsDashboard(data)
     evaluation_group = EvaluationGroupDashboard(data)
 
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     subpages = [
         {
@@ -415,7 +415,7 @@
             'description': ugettext(
                 'Send reminder emails for evaluations.'),
             'title': 'Send reminder',
-            'link': r.urlOf('gsoc_survey_reminder_admin')
+            'link': data.redirect.urlOf('gsoc_survey_reminder_admin')
         },
         {
             'name': 'mentor_evaluations',
@@ -471,8 +471,8 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.survey('midterm')
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.survey('midterm')
 
     subpages = [
         {
@@ -480,44 +480,45 @@
             'description': ugettext('Create or edit midterm evaluation for '
                 'mentors in active program'),
             'title': 'Create or Edit Midterm',
-            'link': r.urlOf('gsoc_edit_mentor_evaluation')
+            'link': data.redirect.urlOf('gsoc_edit_mentor_evaluation')
         },
         {
             'name': 'preview_mentor_evaluation',
             'description': ugettext('Preview midterm evaluation to be '
                 'administered mentors.'),
             'title': 'Preview Midterm Evaluation',
-            'link': r.urlOf('gsoc_preview_mentor_evaluation')
+            'link': data.redirect.urlOf('gsoc_preview_mentor_evaluation')
         },
         {
             'name': 'view_mentor_evaluation',
             'description': ugettext('View midterm evaluation for mentors'),
             'title': 'View Midterm Records',
-            'link': r.urlOf('gsoc_list_mentor_eval_records')
+            'link': data.redirect.urlOf('gsoc_list_mentor_eval_records')
         },
     ]
 
-    r.survey('final')
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.survey('final')
     subpages += [
         {
             'name': 'edit_mentor_evaluation',
             'description': ugettext('Create or edit midterm evaluation for '
                 'mentors in active program'),
             'title': 'Create or Edit Final Evaluation',
-            'link': r.urlOf('gsoc_edit_mentor_evaluation')
+            'link': data.redirect.urlOf('gsoc_edit_mentor_evaluation')
         },
         {
             'name': 'preview_mentor_evaluation',
             'description': ugettext('Preview final evaluation to be '
                 'administered mentors.'),
             'title': 'Preview Final Evaluation',
-            'link': r.urlOf('gsoc_preview_mentor_evaluation')
+            'link': data.redirect.urlOf('gsoc_preview_mentor_evaluation')
         },
         {
             'name': 'view_mentor_evaluation',
             'description': ugettext('View final evaluation for mentors'),
             'title': 'View Final Evaluation Records',
-            'link': r.urlOf('gsoc_list_mentor_eval_records')
+            'link': data.redirect.urlOf('gsoc_list_mentor_eval_records')
         },
     ]
 
@@ -554,8 +555,8 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.survey('midterm')
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.survey('midterm')
 
     subpages = [
         {
@@ -563,44 +564,45 @@
             'description': ugettext('Create or edit midterm evaluation for '
                 'students in active program'),
             'title': 'Create or Edit Midterm Evaluation',
-            'link': r.urlOf('gsoc_edit_student_evaluation')
+            'link': data.redirect.urlOf('gsoc_edit_student_evaluation')
         },
         {
             'name': 'preview_student_evaluation',
             'description': ugettext('Preview midterm evaluation to be '
                 'administered to the students.'),
             'title': 'Preview Midterm Evaluation',
-            'link': r.urlOf('gsoc_preview_student_evaluation')
+            'link': data.redirect.urlOf('gsoc_preview_student_evaluation')
         },
         {
             'name': 'view_student_evaluation',
             'description': ugettext('View midterm evaluation for students'),
             'title': 'View Midterm Evaluation Records',
-            'link': r.urlOf('gsoc_list_student_eval_records')
+            'link': data.redirect.urlOf('gsoc_list_student_eval_records')
         },
     ]
 
-    r.survey('final')
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.survey('final')
     subpages += [
         {
             'name': 'edit_student_evaluation',
             'description': ugettext('Create or edit final evaluation for '
                 'students in active program'),
             'title': 'Create or Edit Final Evaluation',
-            'link': r.urlOf('gsoc_edit_student_evaluation')
+            'link': data.redirect.urlOf('gsoc_edit_student_evaluation')
         },
         {
             'name': 'preview_student_evaluation',
             'description': ugettext('Preview final evaluation to be '
                 'administered to the students.'),
             'title': 'Preview Final Evaluation',
-            'link': r.urlOf('gsoc_preview_student_evaluation')
+            'link': data.redirect.urlOf('gsoc_preview_student_evaluation')
         },
         {
             'name': 'view_student_evaluation',
             'description': ugettext('View final evaluation for students'),
             'title': 'View Final Evaluation Records',
-            'link': r.urlOf('gsoc_list_student_eval_records')
+            'link': data.redirect.urlOf('gsoc_list_student_eval_records')
         },
     ]
 
@@ -637,15 +639,15 @@
     Args:
       data: The RequestData object
     """
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     subpages = [
         {
             'name': 'edit_evaluation_group',
             'description': ugettext('Create evaluation group'),
             'title': 'Create',
-            'link': r.urlOf('gsoc_grading_group')
+            'link': data.redirect.urlOf('gsoc_grading_group')
         },
     ]
 
@@ -659,7 +661,7 @@
             'name': 'view_evaluation_group_%s' % group.key().id(),
             'description': ugettext('View this group'),
             'title': 'View %s' % group.name,
-            'link': r.urlOf('gsoc_grading_record_overview')
+            'link': data.redirect.urlOf('gsoc_grading_record_overview')
         }
       )
 
@@ -695,9 +697,8 @@
     Args:
       data: The RequestData object
     """
-
-    r = data.redirect
-    r.program()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    data.redirect.program()
 
     subpages = [
         {
@@ -705,14 +706,14 @@
             'description': ugettext(
                 'List of all the students who have registered to the program.'),
             'title': 'All Students',
-            'link': r.urlOf('gsoc_students_list_admin')
+            'link': data.redirect.urlOf('gsoc_students_list_admin')
         },
         {
             'name': 'list_projects',
             'description': ugettext(
                 'List of all the projects who have accepted to the program.'),
             'title': 'All Projects',
-            'link': r.urlOf('gsoc_projects_list_admin')
+            'link': data.redirect.urlOf('gsoc_projects_list_admin')
         },
     ]
 
@@ -862,12 +863,12 @@
   def context(self):
     description = 'List of proposals submitted into %s' % self.data.organization.name
 
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=0, description=description)
     return {
         'name': 'proposals_submitted',
         'title': 'PROPOSALS SUBMITTED TO MY ORGS',
-        'lists': [list],
+        'lists': [list_configuration_response],
         }
 
   def getListData(self):
@@ -966,14 +967,14 @@
     self._list_config = list_config
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=0,
         description='List of projects under %s that ' \
             'accepted into %s' % (
             self.data.organization.name, self.data.program.name))
 
     return {
-        'lists': [list],
+        'lists': [list_configuration_response],
         }
 
   def getListData(self):
@@ -1124,7 +1125,6 @@
     """Initializes this component."""
     self.data = data
 
-    r = self.data.redirect
     list_config = lists.ListConfiguration()
     list_config.addPlainTextColumn(
         'name', 'Name', lambda ent, *args: ent.name())
@@ -1138,8 +1138,8 @@
         'birth_date', "Birthdate",
         (lambda ent, *args: dateformat.format(ent.birth_date, BIRTHDATE_FORMAT)),
         hidden=True)
-    list_config.setRowAction(lambda e, *args:
-        r.profile(e.link_id).urlOf(url_names.GSOC_PROFILE_SHOW, secure=True))
+    list_config.setRowAction(lambda e, *args: data.redirect.profile(
+        e.link_id).urlOf(url_names.GSOC_PROFILE_SHOW, secure=True))
 
     def formsSubmitted(ent, si):
       info = si[ent.key()]
@@ -1222,13 +1222,13 @@
 
   def context(self):
     description = ugettext('List of participating students')
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=0, description=description)
 
     return {
         'name': 'students',
         'title': 'Participating students',
-        'lists': [list],
+        'lists': [list_configuration_response],
     }
 
 
diff --git a/app/soc/modules/gsoc/views/dashboard.py b/app/soc/modules/gsoc/views/dashboard.py
index c60e497..c7f4992 100644
--- a/app/soc/modules/gsoc/views/dashboard.py
+++ b/app/soc/modules/gsoc/views/dashboard.py
@@ -403,15 +403,14 @@
     return 'modules/gsoc/dashboard/list_component.html'
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=self.IDX, preload_list=False)
 
     return {
         'name': 'org_app',
         'title': 'My organization applications',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('My organization applications'),
         }
 
@@ -454,13 +453,12 @@
 
   def __init__(self, data):
     """Initializes this component."""
-    r = data.redirect
     list_config = lists.ListConfiguration()
     list_config.addSimpleColumn('title', 'Title')
     list_config.addPlainTextColumn('org', 'Organization',
                           lambda ent, *args: ent.org.name)
     list_config.setRowAction(lambda e, *args:
-        r.review(e.key().id_or_name(), e.parent().link_id).
+        data.redirect.review(e.key().id_or_name(), e.parent().link_id).
         urlOf('review_gsoc_proposal'))
     self._list_config = list_config
 
@@ -473,15 +471,14 @@
     return'modules/gsoc/dashboard/list_component.html'
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=1,
         description=MyProposalsComponent.DESCRIPTION, preload_list=False)
     return {
         'name': 'proposals',
         'title': 'Proposals',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('List of my submitted proposals'),
         }
 
@@ -512,8 +509,6 @@
 
   def __init__(self, data):
     """Initializes this component."""
-    r = data.redirect
-
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn('key', 'Key',
         (lambda ent, *args: "%s/%s" % (
@@ -521,9 +516,9 @@
     list_config.addSimpleColumn('title', 'Title')
     list_config.addPlainTextColumn('org', 'Organization Name',
         lambda ent, *args: ent.org.name)
-    list_config.setRowAction(lambda e, *args:
-        r.project(id=e.key().id_or_name(), student=e.parent().link_id).
-        urlOf('gsoc_project_details'))
+    list_config.setRowAction(lambda e, *args: data.redirect.project(
+        id=e.key().id_or_name(), student=e.parent().link_id).urlOf(
+        'gsoc_project_details'))
     self._list_config = list_config
 
     super(MyProjectsComponent, self).__init__(data)
@@ -554,14 +549,13 @@
     return response_builder.build()
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=2, preload_list=False)
     return {
         'name': 'projects',
         'title': 'Projects',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('Projects'),
     }
 
@@ -645,15 +639,14 @@
     return response_builder.build()
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=3, preload_list=False)
 
     return {
         'name': 'evaluations',
         'title': 'Evaluations',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('Evaluations'),
     }
 
@@ -714,15 +707,14 @@
     return response_builder.build()
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=3, preload_list=False)
 
     return {
         'name': 'evaluations',
         'title': 'My Evaluations',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('Evaluations that I must complete'),
     }
 
@@ -747,7 +739,6 @@
   # TODO(nathaniel): Wait, is this seriously a 100+-line *constructor*?
   def __init__(self, data):
     """Initializes this component."""
-    r = data.redirect
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn('key', 'Key',
         (lambda ent, *args: "%s/%s" % (
@@ -863,7 +854,7 @@
 
     # row action
     list_config.setRowAction(lambda e, *args:
-        r.review(e.key().id_or_name(), e.parent().link_id).
+        data.redirect.review(e.key().id_or_name(), e.parent().link_id).
         urlOf('review_gsoc_proposal'))
     list_config.setDefaultSort('last_modified_on', 'desc')
 
@@ -913,13 +904,13 @@
     if self.has_extra_columns:
       description += self.CUSTOM_COLUMNS
 
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=4, description=description,
         preload_list=False)
     return {
         'name': 'proposals_submitted',
         'title': 'Proposals submitted to my organizations',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext(
             'List of proposals submitted to my organizations'),
         }
@@ -1074,7 +1065,6 @@
 
   def __init__(self, data):
     """Initializes this component."""
-    r = data.redirect
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn('key', 'Key',
         (lambda ent, *args: "%s/%s" % (
@@ -1085,9 +1075,9 @@
     list_config.addPlainTextColumn('org', 'Organization',
                           lambda ent, *args: ent.org.name)
     list_config.setDefaultSort('title')
-    list_config.setRowAction(lambda e, *args:
-        r.project(id=e.key().id_or_name(), student=e.parent().link_id).
-        urlOf('gsoc_project_details'))
+    list_config.setRowAction(lambda e, *args: data.redirect.project(
+        id=e.key().id_or_name(), student=e.parent().link_id).urlOf(
+        'gsoc_project_details'))
     self._list_config = list_config
 
     super(ProjectsIMentorComponent, self).__init__(data)
@@ -1123,9 +1113,8 @@
     return response_builder.build()
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=5)
 
     if self.data.is_org_admin:
@@ -1136,7 +1125,7 @@
     return {
         'name': 'mentoring_projects',
         'title': title,
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext(title),
     }
 
@@ -1225,15 +1214,14 @@
     return response
 
   def context(self):
-    """Returns the context of this component.
-    """
-    list = lists.ListConfigurationResponse(
+    """Returns the context of this component."""
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=6, preload_list=False)
 
     return {
         'name': 'adminning_organizations',
         'title': 'My organizations',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext(
             'List of organizations which I participate in'),
     }
@@ -1518,13 +1506,13 @@
     return response_builder.build()
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=9, preload_list=False)
 
     return {
         'name': 'participants',
         'title': 'Members of my organizations',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext(
             'List of your organizations members'),
     }
@@ -1535,7 +1523,6 @@
   """
 
   def __init__(self, data):
-    r = data.redirect
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn(
         'key', 'Key', (lambda d, *args: d['key']), hidden=True)
@@ -1556,7 +1543,8 @@
         return url + '#form_row_school_name'
       if key.isdigit():
         project_id = int(key)
-        r.project(id=project_id, student=data.profile.link_id)
+        # TODO(nathaniel): Eliminate this state-setting call.
+        data.redirect.project(id=project_id, student=data.profile.link_id)
         return data.redirect.urlOf(url_names.GSOC_PROJECT_UPDATE)
       return None
 
@@ -1620,13 +1608,13 @@
     return response
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=11, preload_list=False)
 
     return {
         'name': 'todo',
         'title': 'My todos',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'description': ugettext('List of my todos'),
     }
 
@@ -1705,12 +1693,12 @@
     return colorize(bool(self.record), "Submitted", "Not submitted")
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=self.IDX, preload_list=False)
 
     return {
         'name': 'student_evaluations',
-        'lists': [list],
+        'lists': [list_configuration_response],
         'title': 'Student Evaluations',
         'description': ugettext(
           'List of student evaluations for my organizations'),
diff --git a/app/soc/modules/gsoc/views/grading_record_details.py b/app/soc/modules/gsoc/views/grading_record_details.py
index b5fdd53..3fc5948 100644
--- a/app/soc/modules/gsoc/views/grading_record_details.py
+++ b/app/soc/modules/gsoc/views/grading_record_details.py
@@ -282,17 +282,15 @@
         'mentor_record', 'Evaluation by Mentor', mentorRecordInfo)
 
     list_config.addSimpleColumn('grade_decision', 'Decision')
-    r = data.redirect
     list_config.setRowAction(lambda e, *args:
-        r.grading_record(e).urlOf('gsoc_grading_record_detail'))
+        data.redirect.grading_record(e).urlOf('gsoc_grading_record_detail'))
 
     self._list_config = list_config
 
   def context(self):
-    """Returns the context for the current template.
-    """
-    list = lists.ListConfigurationResponse(self.data, self._list_config, idx=0)
-    return {'lists': [list]}
+    """Returns the context for the current template."""
+    return {'lists': [lists.ListConfigurationResponse(
+        self.data, self._list_config, idx=0)]}
 
   def listContent(self):
     """Returns the ListContentResponse object that is constructed from the data.
diff --git a/app/soc/modules/gsoc/views/helper/access_checker.py b/app/soc/modules/gsoc/views/helper/access_checker.py
index 8ef2cbf..1f2c09f 100644
--- a/app/soc/modules/gsoc/views/helper/access_checker.py
+++ b/app/soc/modules/gsoc/views/helper/access_checker.py
@@ -473,9 +473,13 @@
     self.isLoggedIn()
 
     program = self.data.program
-    r = self.data.redirect.createProfile('org_admin')
+
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.createProfile('org_admin')
+
     msg = DEF_NO_ORG_ADMIN_PROFILE % (
-          program.short_name, r.urlOf('create_gsoc_profile', secure=True))
+          program.short_name,
+          self.data.redirect.urlOf('create_gsoc_profile', secure=True))
 
     if not self.data.user:
       raise exception.Forbidden(message=msg)
diff --git a/app/soc/modules/gsoc/views/org_home.py b/app/soc/modules/gsoc/views/org_home.py
index 9c555f0..3cdb4a3 100644
--- a/app/soc/modules/gsoc/views/org_home.py
+++ b/app/soc/modules/gsoc/views/org_home.py
@@ -17,6 +17,7 @@
 from django.conf.urls.defaults import url as django_url
 from django.utils.translation import ugettext
 
+from melange.request import access
 from melange.request import exception
 from soc.logic import accounts
 from soc.logic.helper import timeline as timeline_helper
@@ -143,7 +144,6 @@
   def __init__(self, data):
     self.data = data
 
-    r = data.redirect
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn('key', 'Key',
         (lambda ent, *args: "%s/%s" % (
@@ -156,19 +156,19 @@
         lambda entity, m, *args: ", ".join(
             [m[i].name() for i in entity.mentors]))
     list_config.setDefaultSort('student')
-    list_config.setRowAction(lambda e, *args, **kwargs:
-        r.project(id=e.key().id_or_name(), student=e.parent().link_id).
-        urlOf('gsoc_project_details'))
+    list_config.setRowAction(lambda e, *args, **kwargs: data.redirect.project(
+        id=e.key().id_or_name(), student=e.parent().link_id).urlOf(
+        'gsoc_project_details'))
     self._list_config = list_config
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=0,
         description='List of projects accepted into %s' % (
             self.data.organization.name))
 
     return {
-        'lists': [list],
+        'lists': [list_configuration_response],
         }
 
   def getListData(self):
@@ -231,6 +231,8 @@
 class OrgHome(GSoCRequestHandler):
   """View methods for Organization Home page."""
 
+  access_checker = access.ALL_ALLOWED_ACCESS_CHECKER
+
   def templatePath(self):
     return 'modules/gsoc/org_home/base.html'
 
@@ -246,10 +248,6 @@
         django_url(r'^org/home/%s$' % url_patterns.ORG, self),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    """Access checks for GSoC Organization Homepage."""
-    pass
-
   def jsonContext(self, data, check, mutator):
     """Handler for JSON requests."""
     assert isSet(data.organization)
diff --git a/app/soc/modules/gsoc/views/profile_show.py b/app/soc/modules/gsoc/views/profile_show.py
index 8576bfd..c9a0d00 100644
--- a/app/soc/modules/gsoc/views/profile_show.py
+++ b/app/soc/modules/gsoc/views/profile_show.py
@@ -135,11 +135,16 @@
 
     if profile:
       links = []
-      r = data.redirect.profile()
+
+      # TODO(nathaniel): Eliminate this state-setting call.
+      data.redirect.profile()
+
       for project in GSoCProject.all().ancestor(profile):
-        r.project(project.key().id())
-        links.append(r.urlOf('gsoc_project_details', full=True))
-      r = data.redirect.profile()
+        data.redirect.project(project.key().id())
+        links.append(data.redirect.urlOf('gsoc_project_details', full=True))
+
+      # TODO(nathaniel): Eliminate this state-setting call.
+      data.redirect.profile()
 
       user_role = None
       if profile.is_student:
@@ -152,8 +157,9 @@
       context.update({
           'profile': GSoCProfileReadOnlyTemplate(profile),
           'links': links,
-          'submit_tax_link': r.urlOf('gsoc_tax_form_admin'),
-          'submit_enrollment_link': r.urlOf('gsoc_enrollment_form_admin'),
+          'submit_tax_link': data.redirect.urlOf('gsoc_tax_form_admin'),
+          'submit_enrollment_link': data.redirect.urlOf(
+              'gsoc_enrollment_form_admin'),
           'page_name': '%s Profile - %s' % (
               program.short_name, profile.name()),
           'user_role': user_role,
diff --git a/app/soc/modules/gsoc/views/project_details.py b/app/soc/modules/gsoc/views/project_details.py
index 0498b20..66e33a2 100644
--- a/app/soc/modules/gsoc/views/project_details.py
+++ b/app/soc/modules/gsoc/views/project_details.py
@@ -379,11 +379,12 @@
   def context(self):
     assert isSet(self.data.project)
 
-    r = self.data.redirect.project()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.project()
 
     featured_project = ToggleButtonTemplate(
         self.data, 'on_off', 'Featured', 'project-featured',
-        r.urlOf('gsoc_featured_project'),
+        self.data.redirect.urlOf('gsoc_featured_project'),
         checked=self.data.project.is_featured,
         help_text=self.DEF_FEATURED_PROJECT_HELP,
         labels={
@@ -396,12 +397,11 @@
         'toggle_buttons': self.toggle_buttons,
         }
 
-    r = self.data.redirect
     all_mentors_keys = profile_logic.queryAllMentorsKeysForOrg(
         self.data.project.org)
     context['assign_mentor'] = assign_mentor.AssignMentorFields(
         self.data, self.data.project.mentors,
-        r.project().urlOf('gsoc_project_assign_mentors'),
+        self.data.redirect.project().urlOf('gsoc_project_assign_mentors'),
         all_mentors=all_mentors_keys, mentor_required=True,
         allow_multiple=True)
 
diff --git a/app/soc/modules/gsoc/views/projects_list.py b/app/soc/modules/gsoc/views/projects_list.py
index f353a4b..f190921 100644
--- a/app/soc/modules/gsoc/views/projects_list.py
+++ b/app/soc/modules/gsoc/views/projects_list.py
@@ -77,7 +77,6 @@
 
     self.idx = self.DEFAULT_IDX if idx is None else idx
 
-    r = data.redirect
     list_config = lists.ListConfiguration(add_key_column=False)
     list_config.addPlainTextColumn('key', 'Key',
         (lambda ent, *args: "%s/%s" % (
@@ -92,19 +91,19 @@
         lambda entity, *args: args[0][entity.key()], hidden=True)
     list_config.setDefaultPagination(False)
     list_config.setDefaultSort('student')
-    list_config.setRowAction(lambda e, *args:
-        r.project(id=e.key().id_or_name(), student=e.parent().link_id).
-        urlOf('gsoc_project_details'))
+    list_config.setRowAction(lambda e, *args: data.redirect.project(
+        id=e.key().id_or_name(), student=e.parent().link_id).urlOf(
+        'gsoc_project_details'))
     self._list_config = list_config
 
   def context(self):
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, idx=self.idx,
         description='List of projects accepted into %s' % (
             self.data.program.name))
 
     return {
-        'lists': [list],
+        'lists': [list_configuration_response],
         }
 
   def getListData(self):
diff --git a/app/soc/modules/gsoc/views/proposal_review.py b/app/soc/modules/gsoc/views/proposal_review.py
index 8333765..3d94ed2 100644
--- a/app/soc/modules/gsoc/views/proposal_review.py
+++ b/app/soc/modules/gsoc/views/proposal_review.py
@@ -162,11 +162,12 @@
   def _mentorContext(self):
     """Construct the context needed for mentor actions.
     """
-    r = self.data.redirect.review()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.review()
 
     wish_to_mentor = ToggleButtonTemplate(
         self.data, 'on_off', 'Wish to Mentor', 'wish-to-mentor',
-        r.urlOf('gsoc_proposal_wish_to_mentor'),
+        self.data.redirect.urlOf('gsoc_proposal_wish_to_mentor'),
         checked=self.data.isPossibleMentorForProposal(),
         help_text=self.DEF_WISH_TO_MENTOR_HELP,
         labels = {
@@ -177,7 +178,7 @@
     if self.data.timeline.afterStudentSignupEnd():
       proposal_modification_button = ToggleButtonTemplate(
           self.data, 'long', 'Proposal Modifications', 'proposal-modification',
-          r.urlOf('gsoc_proposal_modification'),
+          self.data.redirect.urlOf('gsoc_proposal_modification'),
           checked=self.data.proposal.is_editable_post_deadline,
           help_text=self.DEF_PROPOSAL_MODIFICATION_HELP,
           labels = {
@@ -191,7 +192,9 @@
     """Construct the context needed for org admin actions.
     """
     context = {}
-    r = self.data.redirect.review()
+
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.review()
 
     ignore_button_checked = False
     if self.data.proposal.status == 'ignored':
@@ -199,7 +202,7 @@
     if self.data.proposal.status in ['pending', 'ignored']:
       ignore_proposal = ToggleButtonTemplate(
           self.data, 'on_off', 'Ignore Proposal', 'proposal-ignore',
-          r.urlOf('gsoc_proposal_ignore'),
+          self.data.redirect.urlOf('gsoc_proposal_ignore'),
           checked=ignore_button_checked,
           help_text=self.DEF_IGNORE_PROPOSAL_HELP,
           note=self.DEF_IGNORE_PROPOSAL_NOTE,
@@ -211,7 +214,7 @@
     if not self.proposal_ignored:
       accept_proposal = ToggleButtonTemplate(
           self.data, 'on_off', 'Accept proposal', 'accept-proposal',
-          r.urlOf('gsoc_proposal_accept'),
+          self.data.redirect.urlOf('gsoc_proposal_accept'),
           checked=self.data.proposal.accept_as_project,
           help_text=self.DEF_ACCEPT_PROPOSAL_HELP,
           labels = {
@@ -219,7 +222,6 @@
               'unchecked': 'No',})
       self.toggle_buttons.append(accept_proposal)
 
-      r = self.data.redirect
       possible_mentors_keys = self.data.proposal.possible_mentors
       all_mentors_keys = profile_logic.queryAllMentorsKeysForOrg(
           self.data.proposal_org) if self.data.proposal_org.list_all_mentors \
@@ -231,7 +233,7 @@
 
       context['assign_mentor'] = assign_mentor.AssignMentorFields(
           self.data, current_mentors,
-          r.review().urlOf('gsoc_proposal_assign_mentor'),
+          self.data.redirect.review().urlOf('gsoc_proposal_assign_mentor'),
           all_mentors_keys, possible_mentors_keys)
 
     return context
@@ -239,11 +241,12 @@
   def _proposerContext(self):
     """Construct the context needed for proposer actions.
     """
-    r = self.data.redirect.review()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.review()
 
     publicly_visible = ToggleButtonTemplate(
         self.data, 'on_off', 'Publicly Visible', 'publicly-visible',
-        r.urlOf('gsoc_proposal_publicly_visible'),
+        self.data.redirect.urlOf('gsoc_proposal_publicly_visible'),
         checked=self.data.proposal.is_publicly_visible,
         help_text=self.DEF_PUBLICLY_VISIBLE_HELP,
         labels = {
@@ -258,7 +261,7 @@
         checked=False
       withdraw_proposal = ToggleButtonTemplate(
           self.data, 'on_off', 'Withdraw Proposal', 'withdraw-proposal',
-          r.urlOf('gsoc_proposal_withdraw'), checked=checked,
+          self.data.redirect.urlOf('gsoc_proposal_withdraw'), checked=checked,
           help_text=self.DEF_WITHDRAW_PROPOSAL_HELP,
           labels = {
               'checked': 'Yes',
diff --git a/app/soc/modules/gsoc/views/search.py b/app/soc/modules/gsoc/views/search.py
index cdce3d2..94bf2c9 100644
--- a/app/soc/modules/gsoc/views/search.py
+++ b/app/soc/modules/gsoc/views/search.py
@@ -16,6 +16,7 @@
 
 import os
 
+from melange.request import access
 from soc.views.helper import url_patterns
 
 from soc.modules.gsoc.views import base
@@ -25,6 +26,8 @@
 class SearchGsocPage(base.GSoCRequestHandler):
   """View for the search gsoc page."""
 
+  access_checker = access.ALL_ALLOWED_ACCESS_CHECKER
+
   def djangoURLPatterns(self):
     return [
         url(r'search/%s$' % url_patterns.PROGRAM, self, name='search_gsoc'),
@@ -39,6 +42,3 @@
 
   def templatePath(self):
     return 'modules/gsoc/search.html'
-
-  def checkAccess(self, data, check, mutator):
-    pass
diff --git a/app/soc/templates/modules/gsoc/grading_record/details.html b/app/soc/templates/modules/gsoc/grading_record/details.html
index 643d8f0..14b445a 100644
--- a/app/soc/templates/modules/gsoc/grading_record/details.html
+++ b/app/soc/templates/modules/gsoc/grading_record/details.html
@@ -43,8 +43,6 @@
   [
     dep.uniform,
     null,
-    function () {
-      jQuery("select, input:radio, input:file, input:checkbox").uniform();
-    }
+    tc("/soc/content/{{ app_version }}/js/templates/modules/gsoc/grading_record/details.js")
   ]
 {% endblock dependencies %}
\ No newline at end of file
diff --git a/app/soc/templates/soc/host/base.html b/app/soc/templates/soc/host/base.html
deleted file mode 100644
index 403d061..0000000
--- a/app/soc/templates/soc/host/base.html
+++ /dev/null
@@ -1,25 +0,0 @@
-{% extends "modules/gsoc/form_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 dependencies %}
-  [
-    dep.uniform,
-    null,
-    function () {
-      jQuery("select, input:radio, input:file, input:checkbox").uniform();
-    }
-  ]
-{% endblock dependencies %}
diff --git a/app/soc/templates/soc/site/base.html b/app/soc/templates/soc/site/base.html
index fe47247..e1ac392 100644
--- a/app/soc/templates/soc/site/base.html
+++ b/app/soc/templates/soc/site/base.html
@@ -39,9 +39,6 @@
     dep.melange.autocomplete,
     dep.uniform,
     null,
-    function () {
-      jQuery("select, input:radio, input:file, input:checkbox").uniform();
-      melange.autocomplete.makeAutoComplete("tos");
-    }
+    tc("/soc/content/{{ app_version }}/js/templates/soc/site/base.js")
   ]
 {% endblock dependencies %}
diff --git a/app/soc/views/document.py b/app/soc/views/document.py
index 45ec19f..c6201cd 100644
--- a/app/soc/views/document.py
+++ b/app/soc/views/document.py
@@ -86,13 +86,12 @@
 
   def __init__(self, data, edit_name):
     self.data = data
-    r = data.redirect
 
     list_config = lists.ListConfiguration()
     list_config.addSimpleColumn('title', 'Title')
     list_config.addSimpleColumn('link_id', 'Document ID', hidden=True)
     list_config.setRowAction(
-        lambda e, *args: r.document(e).urlOf(edit_name))
+        lambda e, *args: data.redirect.document(e).urlOf(edit_name))
 
     list_config.setDefaultPagination(False)
     list_config.setDefaultSort('title')
@@ -103,11 +102,11 @@
     description = 'List of documents for %s' % (
             self.data.program.name)
 
-    list = lists.ListConfigurationResponse(
+    list_configuration_response = lists.ListConfigurationResponse(
         self.data, self._list_config, 0, description)
 
     return {
-        'lists': [list],
+        'lists': [list_configuration_response],
     }
 
   def getListData(self):
diff --git a/app/soc/views/org_home.py b/app/soc/views/org_home.py
index 6d07f87..9c7686f 100644
--- a/app/soc/views/org_home.py
+++ b/app/soc/views/org_home.py
@@ -18,6 +18,7 @@
 
 from django import http
 
+from melange.request import access
 from soc.views.helper import url_patterns
 from soc.views.helper.access_checker import isSet
 from soc.views.template import Template
@@ -27,6 +28,8 @@
 class BanOrgPost(object):
   """Handles banning/unbanning of organizations."""
 
+  access_checker = access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER
+
   def djangoURLPatterns(self):
     return [
          url_patterns.url(
@@ -35,9 +38,6 @@
              self, name=self._getURLName()),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    check.isHost();
-
   def post(self, data, check, mutator):
     """See soc.views.base.RequestHandler.post for specification."""
     assert isSet(data.organization)
diff --git a/app/soc/views/profile_show.py b/app/soc/views/profile_show.py
index 8d76b20..ad52fd9 100644
--- a/app/soc/views/profile_show.py
+++ b/app/soc/views/profile_show.py
@@ -18,6 +18,7 @@
 
 from django import http
 
+from melange.request import access
 from soc.models.user import User
 from soc.views import readonly_template
 from soc.views.helper import url_patterns
@@ -53,12 +54,14 @@
     assert isSet(self.data.url_user)
     assert isSet(self.data.url_profile)
 
-    r = self.data.redirect.profile()
+    # TODO(nathaniel): Eliminate this state-setting call.
+    self.data.redirect.profile()
+
     is_banned = self.data.url_profile.status == 'invalid'
 
     profile_banned = ToggleButtonTemplate(
         self.data, 'on_off', 'Banned', 'user-banned',
-        r.urlOf(self._getActionURLName()),
+        self.data.redirect.urlOf(self._getActionURLName()),
         checked=is_banned,
         help_text=self._getHelpText(),
         labels={
@@ -86,6 +89,8 @@
 class BanProfilePost(object):
   """Handles banning/unbanning of profiles."""
 
+  access_checker = access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER
+
   def djangoURLPatterns(self):
     return [
          url_patterns.url(
@@ -94,13 +99,9 @@
              self, name=self._getURLName()),
     ]
 
-  def checkAccess(self, data, check, mutator):
-    """See soc.views.base.RequestHandler.checkAccess for specification."""
-    check.isHost()
-    mutator.profileFromKwargs()
-
   def post(self, data, check, mutator):
     """See soc.views.base.RequestHandler.post for specification."""
+    mutator.profileFromKwargs()
     assert isSet(data.url_profile)
 
     value = data.POST.get('value')
diff --git a/app/soc/views/program.py b/app/soc/views/program.py
index 3ae5eb6..36060d3 100644
--- a/app/soc/views/program.py
+++ b/app/soc/views/program.py
@@ -16,6 +16,8 @@
 
 from google.appengine.ext import db
 
+from melange.request import access
+
 
 class CreateProgramPage(object):
   """View to create a new program.
@@ -24,9 +26,7 @@
   function will be used by inheriting, module-specific classes.
   """
 
-  def checkAccess(self, data, check, mutator):
-    "See soc.views.base.RequestHandler.checkAccess for specification."
-    check.isHost()
+  access_checker = access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER
 
   def context(self, data, check, mutator):
     """See soc.views.base.RequestHandler.context for specification."""
@@ -120,8 +120,7 @@
 class ProgramMessagesPage(object):
   """View for the content of program specific messages to be sent."""
 
-  def checkAccess(self, data, check, mutator):
-    check.isHost()
+  access_checker = access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER
 
   def context(self, data, check, mutator):
     """See soc.views.base.RequestHandler.context for specification."""
diff --git a/package.json b/package.json
index fe4c7f9..7d86fef 100644
--- a/package.json
+++ b/package.json
@@ -12,6 +12,7 @@
     "grunt-plato": "~0.2.0",
     "grunt-contrib-yuidoc": "~0.4.0",
     "phantomjs": "~1.9.0-4",
-    "grunt-contrib-less": "~0.6.1"
+    "grunt-contrib-less": "~0.6.1",
+    "grunt-contrib-jshint": "~0.6.0"
   }
 }
diff --git a/tests/app/melange/appengine/test_db.py b/tests/app/melange/appengine/test_db.py
index abaddab..a820f34 100644
--- a/tests/app/melange/appengine/test_db.py
+++ b/tests/app/melange/appengine/test_db.py
@@ -16,7 +16,10 @@
 
 import unittest
 
-from melange.appengine import db
+from google.appengine.ext import db
+from google.appengine.ext import ndb
+
+from melange.appengine import db as melange_db
 
 
 class EmailValidatorTest(unittest.TestCase):
@@ -32,12 +35,12 @@
 
   def testValidEmail(self):
     """Tests that the function returns normally on a valid email."""
-    db.email_validator(None, 'test@example.com')
+    melange_db.email_validator(None, 'test@example.com')
 
   def testInvalidEmail(self):
     """Tests that the function returns ValueError on an invalid email."""
     with self.assertRaises(ValueError):
-      db.email_validator(None, 'invalid_email_address')
+      melange_db.email_validator(None, 'invalid_email_address')
 
 
 class LinkValidatorTest(unittest.TestCase):
@@ -53,9 +56,51 @@
 
   def testValidLink(self):
     """Tests that the function returns normally on a valid URL."""
-    db.link_validator(None, 'http://www.melange.com')
+    melange_db.link_validator(None, 'http://www.melange.com')
 
   def testInvalidLink(self):
     """Tests that the function returns ValueError on an invalid URL."""
     with self.assertRaises(ValueError):
-      db.link_validator(None, 'invalid_url_address')
+      melange_db.link_validator(None, 'invalid_url_address')
+
+
+class TestToDict(unittest.TestCase):
+  """Unit tests for toDict function."""
+  
+  def testForDBModel(self):
+    """Tests whether a correct dict is returned for a db model."""
+    class Books(db.Model):
+      item_freq = db.StringProperty()
+      freq = db.IntegerProperty()
+      details = db.TextProperty()
+      released = db.BooleanProperty()
+
+    entity = Books()
+    entity.item_freq = '5'
+    entity.freq = 4
+    entity.details = 'Test Entity'
+    entity.released = True
+    entity.put()
+
+    expected_dict = {'freq': 4, 'item_freq': '5', 'details': 'Test Entity',
+                     'released': True}
+    self.assertEqual(melange_db.toDict(entity), expected_dict)
+
+  def testForNDBModel(self):
+    """Tests whether a correct dict is returned for a db model."""
+    class Books(ndb.Model):
+      item_freq = ndb.StringProperty()
+      freq = ndb.IntegerProperty()
+      details = ndb.TextProperty()
+      released = ndb.BooleanProperty()
+
+    entity = Books()
+    entity.item_freq = '5'
+    entity.freq = 4
+    entity.details = 'Test Entity'
+    entity.released = True
+    entity.put()
+
+    expected_dict = {'freq': 4, 'item_freq': '5', 'details': 'Test Entity',
+                     'released': True}
+    self.assertEqual(melange_db.toDict(entity), expected_dict)
diff --git a/tests/app/melange/logic/test_cached_list.py b/tests/app/melange/logic/test_cached_list.py
new file mode 100644
index 0000000..9f1508f
--- /dev/null
+++ b/tests/app/melange/logic/test_cached_list.py
@@ -0,0 +1,78 @@
+# Copyright 2013 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.
+
+"""Tests functions in soc.logic.cached_list module."""
+
+import unittest
+
+from melange.models import cached_list as cached_list_model
+from melange.logic import cached_list as cached_list_logic
+
+from soc.modules.seeder.logic.seeder import logic as seeder_logic
+
+
+class TestCacheItems(unittest.TestCase):
+  """Test cacheItems function."""
+
+  def testAddingNewCachedList(self):
+    cached_list_logic.cacheItems('foo_list', [{'foo': 'bar'}, {'baz': 'qux'}])
+    cached_list = cached_list_model.CachedList.query().get()
+    self.assertIsNotNone(cached_list)
+
+  def testAddingNewItems(self):
+    new_item1 = {'name': 'foo'}
+    new_item2 = {'name': 'bar'}
+    new_item3 = {'name': 'baz'}
+    cached_list_logic.cacheItems('foo_list', [new_item1, new_item2, new_item3])
+    cached_list = cached_list_model.CachedList.query().get()
+    self.assertIn(new_item1, cached_list.list_data)
+    self.assertIn(new_item2, cached_list.list_data)
+
+class TestGetCachedItems(unittest.TestCase):
+  """Tests getCachedItems function."""
+
+  def setUp(self):
+    self.item1 = {'name': 'foo'}
+    self.item2 = {'name': 'bar'}
+    self.item3 = {'name': 'baz'}
+    self.item4 = {'name': 'qux'}
+    self.item5 = {'name': 'quux'}
+    cached_list_properties = {
+        'id': 'test_list',
+        'list_data':
+            [self.item1, self.item2, self.item3, self.item4, self.item5]
+        }
+    seeder_logic.seed(cached_list_model.CachedList, cached_list_properties)
+
+  def testRetrievingCachedItems(self):
+    cached_items = cached_list_logic.getCachedItems('test_list', 0, 5)
+    self.assertSequenceEqual(
+        [self.item1, self.item2, self.item3, self.item4, self.item5],
+        cached_items)
+
+  def testRetrievingPartOfCachedItems(self):
+    cached_items = cached_list_logic.getCachedItems('test_list', 1, 3)
+    self.assertSequenceEqual([self.item2, self.item3, self.item4], cached_items)
+
+  def testRetrievingWithOverSpecifiedLimit(self):
+    cached_items = cached_list_logic.getCachedItems('test_list', 2, 100)
+    self.assertSequenceEqual([self.item3, self.item4, self.item5], cached_items)
+
+  def testRetrievingWithOverSpecifiedStart(self):
+    cached_items = cached_list_logic.getCachedItems('test_list', 100, 3)
+    self.assertEqual(0, len(cached_items))
+
+  def testErrorForNonExsistentList(self):
+    with self.assertRaises(ValueError):
+      cached_list_logic.getCachedItems('none_existent', 0, 1)
diff --git a/tests/app/melange/request/test_access.py b/tests/app/melange/request/test_access.py
index c78847e..54c492b 100644
--- a/tests/app/melange/request/test_access.py
+++ b/tests/app/melange/request/test_access.py
@@ -18,6 +18,24 @@
 
 from nose.plugins import skip
 
+from melange.request import access
+
+
+class Explosive(object):
+  """Raises an exception on any attribute access."""
+
+  def __getattribute__(self, attribute_name):
+    raise ValueError()
+
+
+class AllAllowedAccessCheckerTest(unittest.TestCase):
+  """Tests the AllAllowedAccessChecker class."""
+
+  def testAccessAllowedWithPhonyInputs(self):
+    """Tests that access is allowed without examining inputs."""
+    access_checker = access.AllAllowedAccessChecker()
+    access_checker.checkAccess(Explosive(), Explosive(), Explosive())
+
 
 # TODO(nathaniel): Because the idea of RequestData objects having
 # an "is_host" attribute isn't unified across all program types
diff --git a/tests/app/melange/utils/test_lists.py b/tests/app/melange/utils/test_lists.py
new file mode 100644
index 0000000..06e4dac
--- /dev/null
+++ b/tests/app/melange/utils/test_lists.py
@@ -0,0 +1,60 @@
+# Copyright 2013 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.
+
+"""Tests for functions in the lists module."""
+
+import unittest
+
+from google.appengine.ext import db
+from google.appengine.ext import ndb
+
+from melange.utils import lists
+
+
+class TestToListItemDict(unittest.TestCase):
+  """Unit tests for toListItemDict function."""
+
+  def testToListItemDict(self):
+    """Tests whether correct is dict is returned for a db model."""
+    class Book(db.Model):
+      item_freq = db.StringProperty()
+      freq = db.IntegerProperty()
+      details = db.TextProperty()
+      released = db.BooleanProperty()
+      owner = db.ReferenceProperty()
+
+    class Author(db.Model):
+      name = db.StringProperty()
+
+    entity = Book()
+    entity.item_freq = '5'
+    entity.freq = 4
+    entity.details = 'Test Entity'
+    entity.released = True
+    entity.owner = Author(name='Foo Bar').put()
+    entity.put()
+
+    columns = {
+        'details': lambda ent: ent.details,
+        'freq': lambda ent: '%s - %s' % (ent.item_freq, ent.freq),
+        'released': lambda ent: "Yes" if ent.released else "No",
+        'author': lambda ent: ent.owner.name
+    }
+
+    list_item_dict = lists.toListItemDict(entity, columns)
+
+    expected_dict = {'details': 'Test Entity', 'freq': '5 - 4',
+                     'released': 'Yes', 'author': 'Foo Bar'}
+
+    self.assertEqual(list_item_dict, expected_dict)