Refactor nearly all the soc.logic code to use the Base class
authorSverre Rabbelier <srabbelier@gmail.com>
Sun, 12 Oct 2008 00:12:53 +0000
changeset 299 a1cc853a56e5
parent 298 c76a366c7ab4
child 300 d36b597ef29d
Refactor nearly all the soc.logic code to use the Base class Instead of having a lot of duplicate code, this patch aims to reduce this duplication by introducing a Base abstraction. Patch by: Sverre Rabbelier Reviewed by: to-be-reviewed
app/soc/logic/__init__.py
app/soc/logic/document.py
app/soc/logic/helper/access.py
app/soc/logic/key_name.py
app/soc/logic/model.py
app/soc/logic/site/id_user.py
app/soc/logic/site/map.py
app/soc/logic/site/settings.py
app/soc/logic/sponsor.py
app/soc/logic/works.py
app/soc/views/helper/responses.py
app/soc/views/person/profile.py
app/soc/views/simple.py
app/soc/views/site/docs/edit.py
app/soc/views/site/docs/list.py
app/soc/views/site/home.py
app/soc/views/site/sponsor/list.py
app/soc/views/site/sponsor/profile.py
app/soc/views/site/user/list.py
app/soc/views/site/user/profile.py
app/soc/views/user/profile.py
app/soc/views/user/roles.py
--- a/app/soc/logic/__init__.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/logic/__init__.py	Sun Oct 12 00:12:53 2008 +0000
@@ -0,0 +1,119 @@
+#!/usr/bin/python2.5
+#
+# Copyright 2008 the Melange authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#   http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+"""Various (Model) query functions.
+"""
+
+__authors__ = [
+  '"Sverre Rabbelier" <sverer@rabbelier.nl>',
+  ]
+
+
+import key_name
+import model
+import soc.models.document
+import soc.models.sponsor
+import soc.models.work
+import soc.models.site_settings
+
+
+class DocumentLogic(model.BaseLogic):
+  """Logic methods for the Document model
+  """
+
+  def __init__(self):
+    """Defines the name, key_name and model for this entity.
+    """
+
+    self._name = "document"
+    self._model = soc.models.document.Document
+    self._keyName = key_name.nameDocument
+    self._skip_properties = []
+
+
+class SettingsLogic(model.BaseLogic):
+  """Logic methods for the Settings model
+  """
+
+
+  def __init__(self):
+    """Defines the name, key_name and model for this entity.
+    """
+
+    self._name = "settings"
+    self._model = soc.models.site_settings.SiteSettings
+    self._keyName = key_name.nameSiteSettings
+    self._skip_properties = []
+
+
+class SponsorLogic(model.BaseLogic):
+  """Logic methods for the Sponsor model
+  """
+
+  def __init__(self):
+    """Defines the name, key_name and model for this entity.
+    """
+
+    self._name = "sponsor"
+    self._model = soc.models.sponsor.Sponsor
+    self._keyName = key_name.nameSponsor
+    self._skip_properties = []
+
+
+class UserLogic(model.BaseLogic):
+  """Logic methods for the User model
+  """
+
+  def __init__(self):
+    """Defines the name, key_name and model for this entity.
+    """
+
+    self._name = "user"
+    self._model = soc.models.user.User
+    self._keyName = key_name.nameUser
+    self._skip_properties = ['former_ids']
+
+  def _updateField(self, model, name, value):
+    """Special case logic for id.
+
+    When the id is changed, the former_ids field should be appended
+    with the old id.
+    """
+    if name == 'id' and model.id != value:
+      model.former_ids.append(model.id)
+
+    return True
+
+class WorkLogic(model.BaseLogic):
+  """Logic methods for the Work model
+  """
+
+  def __init__(self):
+    """Defines the name, key_name and model for this entity.
+    """
+
+    self._name = "work"
+    self._model = soc.models.work.Work
+    self._keyName = key_name.nameWork
+    self._skip_properties = []
+    # TODO(tlarsen) write a nameWork method
+
+
+document_logic = DocumentLogic()
+settings_logic = SettingsLogic()
+sponsor_logic = SponsorLogic()
+user_logic = UserLogic()
+work_logic = WorkLogic()
--- a/app/soc/logic/document.py	Sun Oct 12 00:08:54 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,115 +0,0 @@
-#!/usr/bin/python2.5
-#
-# Copyright 2008 the Melange authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Document (Model) query functions.
-"""
-
-__authors__ = [
-  '"Pawel Solyga" <pawel.solyga@gmail.com>',
-  '"Todd Larsen" <tlarsen@google.com>',
-  ]
-
-
-import re
-
-from google.appengine.ext import db
-
-from soc.logic import key_name
-from soc.logic import out_of_band
-from soc.logic.site import id_user
-
-from soc.logic import model
-
-import soc.models.document
-
-
-def getDocument(path, link_name=None):
-  """Returns Document entity for a given path, or None if not found.  
-    
-  Args:
-    path: a request path of the Document that uniquely identifies it
-    link_name: optional link name to append to path (when supplied,
-      path is actually a "partial path" that needs to link name appended
-      to it)
-  """
-  # lookup by Doc:path key name
-  name = key_name.nameDocument(path, link_name=link_name)
-  
-  if name:
-    document = soc.models.document.Document.get_by_key_name(name)
-  else:
-    document = None
-  
-  return document
-
-
-def getDocumentIfPath(path, link_name=None):
-  """Returns Document entity for supplied path if one exists.
-  
-  Args:
-    path: path used in URLs to identify document
-
-  Returns:
-    * None if path is false.
-    * Document entity that has supplied path
-
-  Raises:
-    out_of_band.ErrorResponse if path is not false, but no Document entity
-    with the supplied path exists in the Datastore
-  """
-  if not path:
-    # exit without error, to let view know that link_name was not supplied
-    return None
-
-  path_doc = getDocument(path, link_name=link_name)
-    
-  if path_doc:
-    # a Document has this path, so return that corresponding Document entity
-    return path_doc
-
-  # else: a path was supplied, but there is no Document that has it
-  raise out_of_band.ErrorResponse(
-      'There is no document with a "path" of "%s".' % path, status=404)
-
-
-def updateOrCreateDocument(**document_properties):
-  """Update existing Document entity, or create new one with supplied properties.
-
-  Args:
-    path: a request path of the Document that uniquely identifies it
-    **document_properties: keyword arguments that correspond to Document entity
-      properties and their values
-
-  Returns:
-    the Document entity corresponding to the path, with any supplied
-    properties changed, or a new Document entity now associated with the 
-    supplied path and properties.
-  """
-  # attempt to retrieve the existing Document
-  document = getDocument(document_properties['partial_path'],
-                         link_name=document_properties['link_name'])
-
-  if not document:
-    # document did not exist, so create one in a transaction
-    name = key_name.nameDocument(document_properties['partial_path'],
-                                 document_properties['link_name'])
-    document = soc.models.document.Document.get_or_insert(
-        name, **document_properties)
-
-  # there is no way to be sure if get_or_insert() returned a new Document or
-  # got an existing one due to a race, so update with document_properties anyway,
-  # in a transaction
-  return soc.logic.model.updateModelProperties(document, **document_properties)
--- a/app/soc/logic/helper/access.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/logic/helper/access.py	Sun Oct 12 00:12:53 2008 +0000
@@ -97,7 +97,7 @@
   checkIsLoggedIn(request)
 
   id = users.get_current_user()
-  user = id_user.getUserFromId(id)
+  user = soc.logic.user_logic.getFromFields(email=id)
 
   if user:
     return
--- a/app/soc/logic/key_name.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/logic/key_name.py	Sun Oct 12 00:12:53 2008 +0000
@@ -144,3 +144,13 @@
     raise Error('"link_name" must be non-False: "%s"' % link_name)
 
   return 'Group/Club:%s' % link_name
+
+
+def nameWork(link_name):
+  """Placeholder for work namer"""
+
+  if not link_name:
+    raise Error('"link_name" must be non-False: "%s"' % link_name)
+
+  return 'Work:%s' % link_name
+
--- a/app/soc/logic/model.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/logic/model.py	Sun Oct 12 00:12:53 2008 +0000
@@ -18,13 +18,17 @@
 """
 
 __authors__ = [
+  '"Todd Larsen" <tlarsen@google.com>',
+  '"Sverre Rabbelier" <sverer@rabbelier.nl>',
   '"Pawel Solyga" <pawel.solyga@gmail.com>',
-  '"Todd Larsen" <tlarsen@google.com>',
   ]
 
 
 from google.appengine.ext import db
 
+from soc.logic import key_name
+from soc.logic import out_of_band
+
 
 def getFullClassName(cls):
   """Returns fully-qualified module.class name string.""" 
@@ -176,34 +180,167 @@
   return None
 
 
-def updateModelProperties(model, **model_properties):
-  """Update existing model entity using supplied model properties.
+class BaseLogic():
+  """Base logic for entity classes.
+
+  The BaseLogic class functions specific to Entity classes by relying
+  on the the child-classes to implement _model, _name and _key_name
+  """
+
+  def _updateField(self, model, name, value):
+    """Hook called when a field is updated.
+
+    Base classes should override if any special actions need to be
+    taken when a field is updated. The field is not updated if the
+    method does not return a True value.
+    """
+
+    return True
 
-  Args:
-    model: a model entity
-    **model_properties: keyword arguments that correspond to model entity
-      properties and their values
+  def getFromKeyName(self, key_name):
+    """"Returns User entity for key_name or None if not found.
+-
+-    Args:
+-      key_name: key name of entity
+    """
+    return self._model.get_by_key_name(key_name)
+
+  def getFromFields(self, **kwargs):
+    """Returns the entity for a given link name, or None if not found.
+
+    Args:
+      link_name: a link name of the entity that uniquely identifies it
+    """
+    # lookup by Sponsor key name
+    key_name = self.getKeyNameForFields(**kwargs)
 
-  Returns:
-    the original model entity with any supplied properties changed 
-  """
-  def update():
-    return _unsafeUpdateModelProperties(model, **model_properties)
+    if key_name:
+      entity = self._model.get_by_key_name(key_name)
+    else:
+      entity = None
+
+    return entity
+
+  def getIfFields(self, **kwargs):
+    """Returns Sponsor entity for supplied link name if one exists.
+
+    Args:
+      link_name: a link name of the Sponsor that uniquely identifies it
+
+    Returns:
+      * None if link name is false.
+      * Sponsor entity for supplied link_name
 
-  return db.run_in_transaction(update)
+    Raises:
+      out_of_band.ErrorResponse if link name is not false, but no Sponsor entity
+      with the supplied link name exists in the Datastore
+    """
+    if not all(kwargs.values()):
+      # exit without error, to let view know that link_name was not supplied
+      return None
+
+    entity = self.getFromFields(**kwargs)
+
+    if entity:
+      # a Sponsor exist for this link_name, so return that Sponsor entity
+      return entity
+
+    fields = []
+
+    for key, value in kwargs.iteritems():
+      fields.extend('"%s" is "%s"' % (key, value))
+
+    # else: fields were supplied, but there is no Entity that has it
+    raise out_of_band.ErrorResponse(
+        'There is no %s with %s.' % (self._name, ''.join(fields)), status=404)
+
+  def getKeyNameForFields(self, **kwargs):
+    """Return a Datastore key_name for a Sponsor from the link name.
 
+    Args:
+      link_name: a link name of the entity that uniquely identifies it
+    """
+    if not all(kwargs.values()):
+      return None
 
-def _unsafeUpdateModelProperties(model, **model_properties):
-  """(see updateModelProperties)
+    return self._keyName(**kwargs)
+
+  def getForLimitAndOffset(self, limit, offset=0):
+    """Returns entities for given offset and limit or None if not found.
+
+    Args:
+      limit: max amount of entities to return
+      offset: optional offset in entities list which defines first entity to
+        return; default is zero (first entity)
+    """
+    query = self._model.all()
+    return query.fetch(limit, offset)
 
-  Like updateModelProperties(), but not run within a transaction. 
-  """
-  properties = model.properties()
+  def updateModelProperties(self, model, **model_properties):
+    """Update existing model entity using supplied model properties.
+
+    Args:
+      model: a model entity
+      **model_properties: keyword arguments that correspond to model entity
+        properties and their values
+
+    Returns:
+      the original model entity with any supplied properties changed
+    """
+    def update():
+      return self._unsafeUpdateModelProperties(model, **model_properties)
+
+    return db.run_in_transaction(update)
+
+  def _unsafeUpdateModelProperties(self, model, **model_properties):
+    """(see updateModelProperties)
+
+    Like updateModelProperties(), but not run within a transaction.
+    """
+    properties = model.properties()
 
-  for prop in properties.values():
-    if prop.name in model_properties:
-      value = model_properties[prop.name]
-      prop.__set__(model, value)
+    for prop in properties.values():
+      name = prop.name
+
+      if not name in self._skip_properties and name in model_properties:
+        value = model_properties[prop.name]
+
+        if self._updateField(model, name, value):
+          prop.__set__(model, value)
+
+    model.put()
+    return model
+
+  def updateOrCreateFromKeyName(self, properties, key_name):
+    """Update existing entity, or create new one with supplied properties.
+
+    Args:
+      link_name: a link_name of the entity that uniquely identifies it
+      **properties: keyword arguments that correspond to entity
+        properties and their values
 
-  model.put()
-  return model
\ No newline at end of file
+    Returns:
+      the entity corresponding to the key_name, with any supplied
+      properties changed, or a new entity now associated with the
+      supplied key_name and properties.
+    """
+
+    entity = self.getFromKeyName(key_name)
+
+    if not entity:
+      # entity did not exist, so create one in a transaction
+      entity = self._model.get_or_insert(key_name, **properties)
+
+    # there is no way to be sure if get_or_insert() returned a new entity or
+    # got an existing one due to a race, so update with sponsor_properties anyway,
+    # in a transaction
+    return self.updateModelProperties(entity, **properties)
+
+  def updateOrCreateFromFields(self, properties, **kwargs):
+    """Like updateOrCreateFromKeyName, but resolves **kwargs to a key_name first
+    """
+
+    # attempt to retrieve the existing entity
+    key_name  = self.getKeyNameForFields(**kwargs)
+
+    return self.updateOrCreateFromKeyName(properties, key_name)
--- a/app/soc/logic/site/id_user.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/logic/site/id_user.py	Sun Oct 12 00:12:53 2008 +0000
@@ -28,6 +28,7 @@
 from google.appengine.api import users
 from google.appengine.ext import db
 
+import soc.logic
 from soc.logic import key_name
 from soc.logic import model
 from soc.logic import out_of_band
@@ -35,107 +36,6 @@
 import soc.models.user
 
 
-def getUserKeyNameFromId(id):
-  """Return a Datastore key_name for a User derived from a Google Account.
-  
-  Args:
-    id: a Google Account (users.User) object
-  """
-  if not id:
-    return None
-
-  return key_name.nameUser(id.email())
-
-
-def getIdIfMissing(id=None):
-  """Gets Google Account of logged-in user (possibly None) if id is false.
-  
-  This is a convenience function that simplifies a lot of view code that
-  accepts an optional id argument from the caller (such as one looked up
-  already by another view that decides to "forward" the request to this
-  other view).
-
-  Args:
-    id: a Google Account (users.User) object, or None
-    
-  Returns:
-    If id is non-false, it is simply returned; otherwise, the Google Account
-    of currently logged-in user is returned (which could be None if no user
-    is logged in).
-  """
-  if not id:
-    # id not initialized, so check if a Google Account is currently logged in
-    id = users.get_current_user()
-
-  return id
-
-
-def getUsersForLimitAndOffset(limit, offset=0):
-  """Returns Users entities for given offset and limit or None if not found.
-    
-  Args:
-    limit: max amount of entities to return
-    offset: optional offset in entities list which defines first entity to
-      return; default is zero (first entity)
-  """
-  return model.getEntitiesForLimitAndOffset(
-      soc.models.user.User, limit, offset=offset, order_by='id')
-
-
-def getUserFromId(id):
-  """Returns User entity for a Google Account, or None if not found.  
-    
-  Args:
-    id: a Google Account (users.User) object
-  """
-  return soc.models.user.User.gql('WHERE id = :1', id).get()
-
-
-def getUserIfMissing(user, id):
-  """Conditionally returns User entity for a Google Account.
-  
-  This function is used to look up the User entity corresponding to the
-  supplied Google Account *if* the user parameter is false (usually None).
-  This function is basically a no-op if user already refers to a User
-  entity.  This is a convenience function that simplifies a lot of view
-  code that accepts an optional user argument from the caller (such as
-  one looked up already by another view that decides to "forward" the
-  HTTP request to this other view).
-
-  Args:
-    user: None (usually), or an existing User entity
-    id: a Google Account (users.User) object
-    
-  Returns:
-    * user (which may have already been None if passed in that way by the
-      caller) if id is false or user is non-false
-    * results of getUserFromId() if user is false and id is non-false
-  """
-  if id and (not user):
-    # Google Account supplied and User uninitialized, so look up User entity
-    user = getUserFromId(id)
-    
-  return user
-
-
-def getNearestUsers(id=None, link_name=None):
-  """Get User entities just before and just after the specified User.
-    
-  Args:
-    id: a Google Account (users.User) object; default is None (not supplied)
-    link_name: link name string; default is None (not supplied)
-
-  Returns:
-    User entities being those just before and just after the (possibly
-    non-existent) User for given id or link_name,
-      OR
-    possibly None if query had no results or neither id or link_name were
-    supplied.
-  """
-  return model.getNearestEntities(
-      soc.models.user.User, [('id', id), ('link_name', link_name)])
-
-
 def findNearestUsersOffset(width, id=None, link_name=None):
   """Finds offset of beginning of a range of Users around the nearest User.
   
@@ -156,40 +56,6 @@
     width, soc.models.user.User, [('id', id), ('link_name', link_name)])
 
 
-def doesUserExist(id):
-  """Returns True if User exists in the Datastore for a Google Account.
-    
-  Args:
-    id: a Google Account object
-  """
-  if getUserFromId(id):
-    return True
-  else:
-    return False
-
-
-def isIdUser(id=None):
-  """Returns True if a Google Account has it's User entity in datastore.
-
-  Args:
-    id: a Google Account (users.User) object; if id is not supplied,
-      the current logged-in user is checked
-  """
-  id = getIdIfMissing(id)
-
-  if not id:
-    # no Google Account was supplied or is logged in
-    return False
-
-  user = getUserFromId(id)
-
-  if not user:
-    # no User entity for this Google Account
-    return False
-  
-  return True
-
-
 def isIdDeveloper(id=None):
   """Returns True if a Google Account is a Developer with special privileges.
   
@@ -206,20 +72,25 @@
     id: a Google Account (users.User) object; if id is not supplied,
       the current logged-in user is checked
   """
-  id = getIdIfMissing(id)
- 
-  if not id:
+
+  # Get the currently logged in user
+  current_id = users.get_current_user()
+
+  if not (id or current_id):
     # no Google Account was supplied or is logged in, so an unspecified
     # User is definitely *not* a Developer
     return False
 
-  if id == users.get_current_user():
-    if users.is_current_user_admin():
-      # supplied id is current logged-in user, and that user is in the
-      # Administration->Developers list in the App Engine console
-      return True
-  
-  user = getUserFromId(id)
+  if (not id or id == current_id) and users.is_current_user_admin():
+    # no id supplied, or current logged-in user, and that user is in the
+    # Administration->Developers list in the App Engine console
+    return True
+
+  # If no id is specified, default to logged in user
+  if not id:
+    id = current_id
+
+  user = soc.logic.user_logic.getFromFields(id=id)
 
   if not user:
     # no User entity for this Google Account, and id is not the currently
@@ -241,7 +112,7 @@
       when existing_user is not supplied; default is None
   """
   if not existing_user:
-    existing_user = getUserFromKeyName(existing_key_name)
+    existing_user = soc.logic.user_logic.getFromKeyName(existing_key_name)
 
   if existing_user:
     old_email = existing_user.id.email()
@@ -253,7 +124,7 @@
     return True
   # else: "new" email truly is new to the existing User, so keep checking
 
-  if not isIdUser(new_id):
+  if not soc.logic.user_logic.getFromFields(id=new_id):
     # new email address also does not belong to any other User,
     # so it is available
     return True
@@ -271,201 +142,38 @@
   return soc.models.user.User.gql('WHERE link_name = :1', link_name).get()
 
 
-def getUserFromKeyName(key_name):
-  """Returns User entity for key_name or None if not found.
-    
-  Args:
-    key_name: key name of User entity
-  """
-  return soc.models.user.User.get_by_key_name(key_name)
-
-
-def getUserIfLinkName(link_name):
-  """Returns User entity for supplied link_name if one exists.
-  
-  Args:
-    link_name: link name used in URLs to identify user
-
-  Returns:
-    * None if link_name is false.
-    * User entity that has supplied link_name
+def getUserFromLinkNameOrDie(link_name):
+  """Like getUserFromLinkName but expects to find a user
 
   Raises:
-    out_of_band.ErrorResponse if link_name is not false, but no User entity
-    with the supplied link_name exists in the Datastore
+    out_of_band.ErrorResponse if no User entity is found
   """
-  if not link_name:
-    # exit without error, to let view know that link_name was not supplied
-    return None
 
-  link_name_user = getUserFromLinkName(link_name)
-    
-  if link_name_user:
-    # a User has this link name, so return that corresponding User entity
-    return link_name_user
+  user = getUserFromLinkName(link_name)
 
-  # else: a link name was supplied, but there is no User that has it
+  if user:
+    return user
+
   raise out_of_band.ErrorResponse(
       'There is no user with a "link name" of "%s".' % link_name, status=404)
 
 
-def isLinkNameAvailableForId(link_name, id=None):
-  """Indicates if link name is available for the given Google Account.
-  
-  Args:
-    link_name: link name used in URLs to identify user
-    id: a Google Account object; optional, current logged-in user will
-      be used (or False will be returned if no user is logged in)
-      
-  Returns:
-    True: the link name does not exist in the Datastore,
-      so it is currently "available" to any User
-    True: the link name exists and already belongs to the User entity
-      associated with the specified Google Account
-    False: the link name exists and belongs to a User entity other than
-      that associated with the supplied Google Account
-  """
-  link_name_exists = doesLinkNameExist(link_name)
- 
-  if not link_name_exists:
-    # if the link name does not exist, it is clearly available for any User
-    return True
-
-  return doesLinkNameBelongToId(link_name, id=id)
-
-
-def doesLinkNameExist(link_name=None):
-  """Returns True if link name exists in the Datastore.
-
-  Args:
-    link_name: link name used in URLs to identify user
-  """
-  if getUserFromLinkName(link_name):
-    return True
-  else:
-    return False
-
-
-def doesLinkNameBelongToId(link_name, id=None):
+def doesLinkNameBelongToId(link_name, id):
   """Returns True if supplied link name belongs to supplied Google Account.
   
   Args:
     link_name: link name used in URLs to identify user
-    id: a Google Account object; optional, current logged-in user will
-      be used (or False will be returned if no user is logged in)
+    id: a Google Account object
   """
-  id = getIdIfMissing(id)
-    
+
   if not id:
-    # id not supplied and no Google Account logged in, so link name cannot
-    # belong to an unspecified User
+    # link name cannot belong to an unspecified User
     return False
 
-  user = getUserFromId(id)
+  user = soc.logic.user_logic.getFromFields(email=id.email())
 
   if not user:
     # no User corresponding to id Google Account, so no link name at all 
     return False
 
-  if user.link_name != link_name:
-    # User exists for id, but does not have this link name
-    return False
-
-  return True  # link_name does actually belong to this Google Account
-
-
-def updateOrCreateUserFromId(id, **user_properties):
-  """Update existing User entity, or create new one with supplied properties.
-
-  Args:
-    id: a Google Account object
-    **user_properties: keyword arguments that correspond to User entity
-      properties and their values
-      
-  Returns:
-    the User entity corresponding to the Google Account, with any supplied
-    properties changed, or a new User entity now associated with the Google
-    Account and with the supplied properties
-  """
-  # attempt to retrieve the existing User
-  user = getUserFromId(id)
-  
-  if not user:
-    # user did not exist, so create one in a transaction
-    key_name = getUserKeyNameFromId(id)
-    user = soc.models.user.User.get_or_insert(
-      key_name, id=id, **user_properties)
-
-  # there is no way to be sure if get_or_insert() returned a new User or
-  # got an existing one due to a race, so update with user_properties anyway,
-  # in a transaction
-  return updateUserProperties(user, **user_properties)
-
-
-def updateUserForKeyName(key_name, **user_properties):
-  """Update existing User entity for keyname with supplied properties.
-
-  Args:
-    key_name: key name of User entity
-    **user_properties: keyword arguments that correspond to User entity
-      properties and their values
-
-  Returns:
-    the User entity corresponding to the Google Account, with any supplied
-    properties changed, or a new User entity now associated with the Google
-    Account and with the supplied properties
-  """
-  # attempt to retrieve the existing User
-  user = getUserFromKeyName(key_name)
-
-  if not user:
-    return None
-  
-  # there is no way to be sure if get_or_insert() returned a new User or
-  # got an existing one due to a race, so update with user_properties anyway,
-  # in a transaction
-  return updateUserProperties(user, **user_properties)
-
-
-def updateUserProperties(user, **user_properties):
-  """Update existing User entity using supplied User properties.
-
-  Args:
-    user: a User entity
-    **user_properties: keyword arguments that correspond to User entity
-      properties and their values
-      
-  Returns:
-    the original User entity with any supplied properties changed 
-  """
-  def update():
-    return _unsafeUpdateUserProperties(user, **user_properties)
-
-  return db.run_in_transaction(update)
-
-
-def _unsafeUpdateUserProperties(user, **user_properties):
-  """(see updateUserProperties)
-  
-  Like updateUserProperties(), but not run within a transaction. 
-  """
-  properties = user.properties()
-  
-  for prop in properties.values():
-    if prop.name in user_properties:
-      if prop.name == 'former_ids':
-        # former_ids cannot be overwritten directly
-        continue
-
-      value = user_properties[prop.name]
-
-      if prop.name == 'id':
-        old_id = user.id
-
-        if value != old_id:
-          user.former_ids.append(old_id)
-
-      prop.__set__(user, value)
-        
-  user.put()
-  return user
+  return user.link_name == link_name
--- a/app/soc/logic/site/map.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/logic/site/map.py	Sun Oct 12 00:12:53 2008 +0000
@@ -30,7 +30,9 @@
 from django.conf.urls import defaults
 from django.utils import datastructures
 
-from soc.logic import path_link_name
+import soc.logic
+import soc.logic.path_link_name
+
 from soc.logic.site import page
 
 
@@ -82,7 +84,7 @@
 
 user_edit = page.Page(
   page.Url(
-    r'^user/profile/%s$' % path_link_name.LINKNAME_ARG_PATTERN,
+    r'^user/profile/%s$' % soc.logic.path_link_name.LINKNAME_ARG_PATTERN,
     'soc.views.user.profile.edit'),
   'User: Modify Existing User Profile',
   parent=user_signout)
@@ -123,7 +125,7 @@
 
 site_user_edit = page.Page(
   page.Url(
-    r'^site/user/profile/%s$' % path_link_name.LINKNAME_ARG_PATTERN,
+    r'^site/user/profile/%s$' % soc.logic.path_link_name.LINKNAME_ARG_PATTERN,
     'soc.views.site.user.profile.edit'),
   'Site: Modify Existing User Profile',
   short_name='Modify Site User',
@@ -140,7 +142,7 @@
 # Document views
 docs_show = page.Page(
   page.Url(
-    r'^docs/show/%s$' % path_link_name.PATH_LINKNAME_ARGS_PATTERN,
+    r'^docs/show/%s$' % soc.logic.path_link_name.PATH_LINKNAME_ARGS_PATTERN,
     'soc.views.docs.show.public'),
   'Show Document',
   parent=home)
@@ -156,7 +158,7 @@
 
 site_docs_edit = page.Page(
   page.Url(
-    r'^site/docs/edit/%s$' % path_link_name.PATH_LINKNAME_ARGS_PATTERN,
+    r'^site/docs/edit/%s$' % soc.logic.path_link_name.PATH_LINKNAME_ARGS_PATTERN,
     'soc.views.site.docs.edit.edit'),
   'Site: Modify Existing Document',
   short_name='Modify Site Document',
@@ -173,7 +175,7 @@
 # Sponsor Group public view
 sponsor_profile = page.Page(
   page.Url(
-    r'^sponsor/profile/%s' % path_link_name.LINKNAME_ARG_PATTERN,
+    r'^sponsor/profile/%s' % soc.logic.path_link_name.LINKNAME_ARG_PATTERN,
     'soc.views.sponsor.profile.public'),
   'Public Profile',
   parent=home)
@@ -189,7 +191,7 @@
 
 site_sponsor_delete = page.Page(
   page.Url(
-    r'^site/sponsor/profile/%s/delete$' % path_link_name.LINKNAME_ARG_PATTERN,
+    r'^site/sponsor/profile/%s/delete$' % soc.logic.path_link_name.LINKNAME_ARG_PATTERN,
     'soc.views.site.sponsor.profile.delete'),
   'Site: Delete Existing Sponsor',
   short_name='Delete Site Sponsor',
@@ -197,7 +199,7 @@
 
 site_sponsor_edit = page.Page(
   page.Url(
-    r'^site/sponsor/profile/%s' % path_link_name.LINKNAME_ARG_PATTERN,
+    r'^site/sponsor/profile/%s' % soc.logic.path_link_name.LINKNAME_ARG_PATTERN,
     'soc.views.site.sponsor.profile.edit'),
   'Site: Modify Existing Sponsor',
   short_name='Modify Site Sponsor',
--- a/app/soc/logic/site/settings.py	Sun Oct 12 00:08:54 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,74 +0,0 @@
-#!/usr/bin/python2.5
-#
-# Copyright 2008 the Melange authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""SiteSettings (Model) query functions.
-"""
-
-__authors__ = [
-  '"Pawel Solyga" <pawel.solyga@gmail.com>',
-  ]
-
-from google.appengine.ext import db
-
-from soc.logic import key_name
-
-import soc.models.site_settings
-import soc.logic.model
-
-
-def getSiteSettings(path):
-  """Returns SiteSettings entity for a given path, or None if not found.  
-    
-  Args:
-    path: a request path of the SiteSettings that uniquely identifies it
-  """
-  # lookup by Settings:path key name
-  name = key_name.nameSiteSettings(path)
-  
-  if name:
-    site_settings = soc.models.site_settings.SiteSettings.get_by_key_name(name)
-  else:
-    site_settings = None
-  
-  return site_settings
-
-
-def updateOrCreateSiteSettings(path, **site_settings_properties):
-  """Update existing SiteSettings entity, or create new one with supplied properties.
-
-  Args:
-    path: a request path of the SiteSettings that uniquely identifies it
-    **site_settings_properties: keyword arguments that correspond to Document entity
-      properties and their values
-
-  Returns:
-    the SiteSettings entity corresponding to the path, with any supplied
-    properties changed, or a new SiteSettings entity now associated with the 
-    supplied path and properties.
-  """
-  # attempt to retrieve the existing Site Settings
-  site_settings = getSiteSettings(path)
-
-  if not site_settings:
-    # site settings did not exist, so create one in a transaction
-    name = key_name.nameSiteSettings(path)
-    site_settings = soc.models.site_settings.SiteSettings.get_or_insert(
-      name, **site_settings_properties)
-
-  # there is no way to be sure if get_or_insert() returned a new SiteSettings or
-  # got an existing one due to a race, so update with site_settings_properties anyway,
-  # in a transaction
-  return soc.logic.model.updateModelProperties(site_settings, **site_settings_properties)
--- a/app/soc/logic/sponsor.py	Sun Oct 12 00:08:54 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,150 +0,0 @@
-#!/usr/bin/python2.5
-#
-# Copyright 2008 the Melange authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Sponsor (Model) query functions.
-"""
-
-__authors__ = [
-  '"Pawel Solyga" <pawel.solyga@gmail.com>',
-  ]
-
-
-from soc.logic import key_name
-from soc.logic import out_of_band
-
-import soc.models.sponsor
-import soc.logic.model
-
-
-def doesLinkNameExist(link_name=None):
-  """Returns True if link name exists in the Datastore.
-
-  Args:
-    link_name: link name used in URLs to identify Sponsor
-  """
-  if getSponsorFromLinkName(link_name):
-    return True
-  else:
-    return False
-
-
-def getSponsorFromLinkName(link_name):
-  """Returns Sponsor entity for a given link name, or None if not found.  
-    
-  Args:
-    link_name: a link name of the Sponsor that uniquely identifies it
-  """
-  # lookup by Sponsor key name
-  sponsor_key_name = getSponsorKeyNameForLinkName(link_name)
-  
-  if sponsor_key_name:
-    sponsor = soc.models.sponsor.Sponsor.get_by_key_name(sponsor_key_name)
-  else:
-    sponsor = None
-  
-  return sponsor
-
-
-def getSponsorIfLinkName(link_name=None):
-  """Returns Sponsor entity for supplied link name if one exists.
-
-  Args:
-    link_name: a link name of the Sponsor that uniquely identifies it
-
-  Returns:
-    * None if link name is false.
-    * Sponsor entity for supplied linkname
-
-  Raises:
-    out_of_band.ErrorResponse if link name is not false, but no Sponsor entity
-    with the supplied link name exists in the Datastore
-  """
-  if not link_name:
-    # exit without error, to let view know that link_name was not supplied
-    return None
-
-  linkname_sponsor = getSponsorFromLinkName(link_name=link_name)
-
-  if linkname_sponsor:
-    # a Sponsor exist for this linkname, so return that Sponsor entity
-    return linkname_sponsor
-
-  # else: a linkname was supplied, but there is no Sponsor that has it
-  raise out_of_band.ErrorResponse(
-      'There is no sponsor with a "link name" of "%s".' % link_name, status=404)
-
-
-def getSponsorKeyNameForLinkName(link_name):
-  """Return a Datastore key_name for a Sponsor from the link name.
-  
-  Args:
-    link_name: a link name of the Sponsor that uniquely identifies it
-  """
-  if not link_name:
-    return None
-
-  return key_name.nameSponsor(link_name)
-
-
-def getSponsorsForLimitAndOffset(limit, offset=0):
-  """Returns Sponsors entities for given offset and limit or None if not found.
-
-  Args:
-    limit: max amount of entities to return
-    offset: optional offset in entities list which defines first entity to
-      return; default is zero (first entity)
-  """
-  query = soc.models.sponsor.Sponsor.all()
-  return query.fetch(limit, offset)
-
-
-def updateOrCreateSponsorFromLinkName(sponsor_link_name, **sponsor_properties):
-  """Update existing Sponsor entity, or create new one with supplied properties.
-
-  Args:
-    sponsor_name: a linkname of the Sponsor that uniquely identifies it
-    **sponsor_properties: keyword arguments that correspond to Sponsor entity
-      properties and their values
-
-  Returns:
-    the Sponsor entity corresponding to the path, with any supplied
-    properties changed, or a new Sponsor entity now associated with the 
-    supplied path and properties.
-  """
-  # attempt to retrieve the existing Sponsor
-  sponsor = getSponsorFromLinkName(sponsor_link_name)
-
-  if not sponsor:
-    # sponsor did not exist, so create one in a transaction
-    sponsor_key_name = getSponsorKeyNameForLinkName(sponsor_link_name)
-    sponsor = soc.models.sponsor.Sponsor.get_or_insert(
-      sponsor_key_name, **sponsor_properties)
-
-  # there is no way to be sure if get_or_insert() returned a new Sponsor or
-  # got an existing one due to a race, so update with sponsor_properties anyway,
-  # in a transaction
-  return soc.logic.model.updateModelProperties(sponsor, **sponsor_properties)
-  
-  
-def deleteSponsor(sponsor):
-  """Delete Sponsor entity.
-  
-  Args:
-    sponsor: existing Sponsor entity
-  """
-  # TODO(pawel.solyga): check if Sponsor can be deleted
-  # If Sponsor has Hosts or Programs it cannot be deleted
-  sponsor.delete()
\ No newline at end of file
--- a/app/soc/logic/works.py	Sun Oct 12 00:08:54 2008 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,45 +0,0 @@
-#!/usr/bin/python2.5
-#
-# Copyright 2008 the Melange authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#   http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-"""Works (Model) query functions.
-"""
-
-__authors__ = [
-  '"Todd Larsen" <tlarsen@google.com>',
-  ]
-
-
-from google.appengine.ext import db
-
-from soc.logic import model
-
-import soc.models.work
-
-
-def getWorksForLimitAndOffset(limit, offset=0, cls=soc.models.work.Work):
-  """Returns Works for given offset and limit or None if not found.
-    
-  Args:
-    limit: max amount of entities to return
-    offset: optional offset in entities list which defines first entity to
-      return; default is zero (first entity)
-    cls: Model class of items to return (including sub-classes of that type);
-      default is Work
-  """
-  query = db.GqlQuery(model.buildOrderedQueryString(
-      soc.models.work.Work, derived_class=cls, order_by='title'))
- 
-  return query.fetch(limit, offset)  
--- a/app/soc/views/helper/responses.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/helper/responses.py	Sun Oct 12 00:12:53 2008 +0000
@@ -38,6 +38,7 @@
   # In the development server
   from google.appengine.runtime.apiproxy_errors import DeadlineExceededError
 
+import soc.logic
 from soc.logic import system
 from soc.logic.site import id_user
 from soc.logic.site import sidebar
@@ -64,7 +65,9 @@
     Any exceptions that django.template.loader.render_to_string() or
     django.http.HttpResponse() might raise.
   """
-  context = getUniversalContext(request, context=context)
+
+  if not context:
+    context = getUniversalContext(request)
 
   if response_args is None:
     response_args = {}
@@ -84,19 +87,14 @@
     return http.HttpResponse('AssertionError')
 
 
-def getUniversalContext(request, context=None):
+def getUniversalContext(request):
   """Constructs a template context dict will many common variables defined.
   
   Args:
     request: the Django HTTP request object
-    context: the template context dict to be updated in-place (pass in a copy
-      if the original must not be modified), or None if a new one is to be
-      created; any existing fields already present in the context dict passed
-      in by the caller are left unaltered 
-      
+
   Returns:
-    updated template context dict supplied by the caller, or a new context
-    dict if the caller supplied None
+    a new context dict containing:
     
     {
       'request': the Django HTTP request object passed in by the caller
@@ -110,26 +108,21 @@
       'sidebar_menu_html': an HTML string that renders the sidebar menu
     }
   """
-  if context is None:
-    context = {}
+
+  id = users.get_current_user()
+
+  context = {}
+  context['request'] = request
 
-  # set some universal values if caller did not already set them  
-  context['request'] = context.get('request', request)
-  context['id'] = id_user.getIdIfMissing(context.get('id', None))
-  context['user'] = id_user.getUserIfMissing(context.get('user', None),
-                                             context['id'])
-  context['is_admin'] = context.get(
-      'is_admin', id_user.isIdDeveloper(id=context['id']))
-  context['is_debug'] = context.get('is_debug', system.isDebug())
-  context['sign_in'] = context.get(
-      'sign_in', users.create_login_url(request.path))
-  context['sign_out'] = context.get(
-      'sign_out', users.create_logout_url(request.path))
+  if id:
+    context['id'] = id
+    context['user'] = soc.logic.user_logic.getFromFields(email=id.email())
+    context['is_admin'] = id_user.isIdDeveloper(id=id)
 
-  if not context.get('sidebar_menu_html'):
-    # pass the currently constructed context as keyword arguments to
-    # all of the sidebar builder functions
-    context['sidebar_menu_html'] = str(html_menu.UlMenu(
+  context['is_debug'] = system.isDebug()
+  context['sign_in'] = users.create_login_url(request.path)
+  context['sign_out'] = users.create_logout_url(request.path)
+  context['sidebar_menu_html'] = str(html_menu.UlMenu(
       sidebar.buildSidebar(**context)))
 
   return context
--- a/app/soc/views/person/profile.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/person/profile.py	Sun Oct 12 00:12:53 2008 +0000
@@ -52,7 +52,7 @@
     exclude = ['user']
 
 
-def edit(request, program=None, linkname=None,
+def edit(request, program=None, link_name=None,
          template='soc/person/profile/edit.html'):
   """View for a Person to modify the properties of a Person Model.
 
--- a/app/soc/views/simple.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/simple.py	Sun Oct 12 00:12:53 2008 +0000
@@ -22,6 +22,7 @@
   '"Pawel Solyga" <pawel.solyga@gmail.com>',
   ]
 
+from google.appengine.api import users
 
 from django.utils.translation import ugettext_lazy
 
@@ -32,54 +33,44 @@
 import soc.views.helper.templates
 
 
-def templateWithLinkName(request,
-                         template='soc/base.html', linkname=None,
+def public(request, template='soc/base.html', link_name=None,
                          context=None):
-  """A simple template view that expects a linkname extracted from the URL. 
+  """A simple template view that expects a link_name extracted from the URL.
 
   Args:
     request: the standard Django HTTP request object
     template: the template to use for rendering the view (or a search list
       of templates)
-    linkname: a site-unique "linkname" (usually extracted from the URL)
+    link_name: a site-unique "link_name" (usually extracted from the URL)
     context: the context dict supplied to the template, which is modified
         (so supply a copy if such modification is not acceptable)
-      linkname: the linkname parameter is added to the context
-      linkname_user: if the linkname exists for a User, that User
+      link_name: the link_name parameter is added to the context
+      link_name_user: if the link_name exists for a User, that User
         is added to the context
 
   Returns:
     A subclass of django.http.HttpResponse containing the generated page.
   """
-  context['linkname'] = linkname
-  context = helper.responses.getUniversalContext(request, context=context)
+
+  template = helper.templates.makeSiblingTemplatesList(template, 'public.html')
+
+  if not context:
+    context = helper.responses.getUniversalContext(request)
 
   try:
-    context['linkname_user'] = id_user.getUserIfLinkName(linkname)
+    if link_name:
+      user = id_user.getUserFromLinkNameOrDie(link_name)
   except out_of_band.ErrorResponse, error:
     return errorResponse(request, error, template, context)
 
+  context['link_name'] = link_name
+  context['link_name_user'] = user
+
   return helper.responses.respond(request, template, context)
 
 
-def public(request, template, linkname, context):
-  """A convenience wrapper around templateWithLinkName() using 'public.html'.
-
-  Args:
-    request, linkname, context: see templateWithLinkName()
-    template: the "sibling" template (or a search list of such templates)
-      from which to construct the public.html template name (or names)
+DEF_ERROR_TMPL = 'soc/error.html'
 
-  Returns:
-    A subclass of django.http.HttpResponse containing the generated page.
-  """
-  return templateWithLinkName(
-      request, linkname=linkname, context=context,
-      template=helper.templates.makeSiblingTemplatesList(
-          template, 'public.html'))
-
-
-DEF_ERROR_TMPL = 'soc/error.html'
 
 def errorResponse(request, error, template, context):
   """Displays an error page for an out_of_band.ErrorResponse exception.
@@ -95,8 +86,10 @@
       error_status: error.response_args['status'], or None if a status code
         was not supplied to the ErrorResponse
   """
-  context = helper.responses.getUniversalContext(request, context=context)
-  
+
+  if not context:
+    context = helper.responses.getUniversalContext(request)
+
   # make a list of possible "sibling" templates, then append a default
   error_templates = helper.templates.makeSiblingTemplatesList(
       template, 'error.html', default_template=DEF_ERROR_TMPL)
@@ -128,7 +121,9 @@
       login_message: the caller can completely construct the message supplied
         to the login template in lieu of using login_message_fmt
   """
-  context = helper.responses.getUniversalContext(request, context=context)
+
+  if not context:
+    context = helper.responses.getUniversalContext(request)
   
   # make a list of possible "sibling" templates, then append a default
   login_templates = helper.templates.makeSiblingTemplatesList(
--- a/app/soc/views/site/docs/edit.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/site/docs/edit.py	Sun Oct 12 00:12:53 2008 +0000
@@ -28,7 +28,7 @@
 from django import newforms as forms
 from django.utils.translation import ugettext_lazy
 
-from soc.logic import document
+import soc.logic
 from soc.logic import out_of_band
 from soc.logic import path_link_name
 from soc.logic.helper import access
@@ -76,7 +76,34 @@
  ugettext_lazy('Document saved.'),
 )
 
-def edit(request, partial_path=None, linkname=None,
+def getDocForForm(form):
+  """Extracts doc fields from a form and creates a new doc from it
+  """
+
+  user = users.get_current_user()
+  if user:
+    email = user.email()
+  else:
+    email = None
+
+  partial_path = form.cleaned_data.get('partial_path')
+  link_name = form.cleaned_data.get('link_name')
+
+  properties = {}
+  properties['partial_path'] = partial_path
+  properties['link_name'] = link_name
+  properties['title'] = form.cleaned_data.get('title')
+  properties['short_name'] = form.cleaned_data.get('short_name')
+  properties['abstract'] = form.cleaned_data.get('abstract')
+  properties['content'] = form.cleaned_data.get('content')
+  properties['user'] = soc.logic.user_logic.getFromFields(email=email)
+
+  doc = soc.logic.document_logic.updateOrCreateFromFields(properties,
+            partial_path=partial_path, link_name=link_name)
+
+  return doc
+
+def edit(request, partial_path=None, link_name=None,
          template=DEF_SITE_DOCS_EDIT_TMPL):
   """View for a Developer to modify the properties of a Document Model entity.
 
@@ -109,7 +136,9 @@
 
   # try to fetch Document entity corresponding to path if one exists    
   try:
-    doc = document.getDocumentIfPath(path)
+    if path:
+      doc = soc.logic.document_logic.getFromFields(partial_path=partial_path,
+                                                   link_name=link_name)
   except out_of_band.ErrorResponse, error:
     # show custom 404 page when path doesn't exist in Datastore
     error.message = error.message + DEF_CREATE_NEW_DOC_MSG
@@ -119,22 +148,12 @@
     form = EditForm(request.POST)
 
     if form.is_valid():
-      new_partial_path = form.cleaned_data.get('partial_path')
-      new_linkname = form.cleaned_data.get('link_name')
-      title = form.cleaned_data.get('title')
-      short_name = form.cleaned_data.get('short_name')
-      abstract = form.cleaned_data.get('abstract')
-      content = form.cleaned_data.get('content')
-      
-      doc = soc.logic.document.updateOrCreateDocument(
-          partial_path=new_partial_path, link_name=new_linkname,
-          title=title, short_name=short_name, abstract=abstract,
-          content=content, user=id_user.getUserFromId(logged_in_id))
+      doc = getDocForForm(form)
       
       if not doc:
         return http.HttpResponseRedirect('/')
 
-      new_path = path_link_name.combinePath([new_partial_path, new_link_name])
+      new_path = path_link_name.combinePath([doc.partial_path, doc.link_name])
         
       # redirect to new /site/docs/edit/new_path?s=0
       # (causes 'Profile saved' message to be displayed)
@@ -237,17 +256,7 @@
     form = CreateForm(request.POST)
 
     if form.is_valid():
-      new_partial_path = form.cleaned_data.get('partial_path')
-      new_linkname = form.cleaned_data.get('link_name')
-      title = form.cleaned_data.get('title')
-      short_name = form.cleaned_data.get('short_name')
-      abstract = form.cleaned_data.get('abstract')
-      content = form.cleaned_data.get('content')
-      
-      doc = soc.logic.document.updateOrCreateDocument(
-          partial_path=new_partial_path, link_name=new_linkname,
-          title=title, short_name=short_name, abstract=abstract,
-          content=content, user=id_user.getUserFromId(logged_in_id))
+      doc = getDocForForm(form)
 
       if not doc:
         return http.HttpResponseRedirect('/')
--- a/app/soc/views/site/docs/list.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/site/docs/list.py	Sun Oct 12 00:12:53 2008 +0000
@@ -22,7 +22,7 @@
   ]
 
 
-from soc.logic import works
+import soc.logic
 from soc.logic.helper import access
 from soc.views import simple
 from soc.views import helper
@@ -59,8 +59,7 @@
       offset=request.GET.get('offset'), limit=request.GET.get('limit'))
 
   # Fetch one more to see if there should be a 'next' link
-  docs = works.getWorksForLimitAndOffset(
-      limit + 1, offset=offset, cls=soc.models.document.Document)
+  docs = soc.logic.work_logic.getForLimitAndOffset(limit + 1, offset=offset)
 
   context['pagination_form'] = helper.lists.makePaginationForm(request, limit)
 
--- a/app/soc/views/site/home.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/site/home.py	Sun Oct 12 00:12:53 2008 +0000
@@ -33,6 +33,7 @@
 from django import shortcuts
 from django import newforms as forms
 
+import soc.logic
 from soc.logic import out_of_band
 from soc.logic import validate
 from soc.logic.site import id_user
@@ -46,8 +47,6 @@
 
 import soc.models.site_settings
 import soc.models.document
-import soc.logic.document
-import soc.logic.site.settings
 
 
 class DocumentForm(helper.forms.DbModelForm):
@@ -107,7 +106,7 @@
   # create default template context for use with any templates
   context = helper.responses.getUniversalContext(request)
   
-  site_settings = soc.logic.site.settings.getSiteSettings(DEF_SITE_SETTINGS_PATH)
+  site_settings = soc.logic.settings_logic.getFromFields(path=DEF_SITE_SETTINGS_PATH)
 
   if site_settings:
     context['site_settings'] = site_settings
@@ -117,7 +116,7 @@
       site_doc.content = helper.templates.unescape(site_doc.content)
       context['site_document'] = site_doc
 
-  return helper.responses.respond(request, template, context)
+  return helper.responses.respond(request, template, context=context)
 
 
 DEF_SITE_HOME_EDIT_TMPL = 'soc/site/home/edit.html'
@@ -149,29 +148,37 @@
     settings_form = SiteSettingsForm(request.POST)
 
     if document_form.is_valid() and settings_form.is_valid():
-      title = document_form.cleaned_data.get('title')
       link_name = DEF_SITE_HOME_DOC_LINK_NAME
-      short_name = document_form.cleaned_data.get('short_name')
-      abstract = document_form.cleaned_data.get('abstract')
-      content = document_form.cleaned_data.get('content')
-      
+      partial_path=DEF_SITE_SETTINGS_PATH
       logged_in_id = users.get_current_user()
+      user = soc.logic.user_logic.getFromFields(email=logged_in_id)
 
-      site_doc = soc.logic.document.updateOrCreateDocument(
-          partial_path=DEF_SITE_SETTINGS_PATH, link_name=link_name,
-          title=title, short_name=short_name, abstract=abstract,
-          content=content, user=id_user.getUserFromId(logged_in_id))
+      properties = {}
+      properties['title'] = document_form.cleaned_data.get('title')
+      properties['short_name'] = document_form.cleaned_data.get('short_name')
+      properties['abstract'] = document_form.cleaned_data.get('abstract')
+      properties['content'] = document_form.cleaned_data.get('content')
+      properties['link_name'] = link_name
+      properties['partial_path'] = partial_path
+      properties['id'] = logged_in_id
+      properties['user'] = user
+
+      #bla =  dir(logged_in_id)
+      #raise self
+
+      site_doc = soc.logic.document_logic.updateOrCreateFromFields(
+          properties, partial_path=partial_path, link_name=link_name)
       
       feed_url = settings_form.cleaned_data.get('feed_url')
 
-      site_settings = soc.logic.site.settings.updateOrCreateSiteSettings(
-          DEF_SITE_SETTINGS_PATH, home=site_doc, feed_url=feed_url)
+      site_settings = soc.logic.settings_logic.updateOrCreateFromFields(
+          {'feed_url' : feed_url, 'home' : site_doc}, path=DEF_SITE_SETTINGS_PATH)
       
       context['notice'] = 'Site Settings saved.'
   else: # request.method == 'GET'
     # try to fetch SiteSettings entity by unique key_name
-    site_settings = soc.logic.site.settings.getSiteSettings(
-        DEF_SITE_SETTINGS_PATH)
+    site_settings = soc.logic.settings_logic.getFromFields(
+        path=DEF_SITE_SETTINGS_PATH)
 
     if site_settings:
       # populate form with the existing SiteSettings entity
--- a/app/soc/views/site/sponsor/list.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/site/sponsor/list.py	Sun Oct 12 00:12:53 2008 +0000
@@ -22,7 +22,6 @@
   ]
 
 
-from soc.logic import sponsor
 from soc.logic.helper import access
 from soc.views import simple
 from soc.views import helper
@@ -48,7 +47,7 @@
       offset=request.GET.get('offset'), limit=request.GET.get('limit'))
   
   # Fetch one more to see if there should be a 'next' link
-  sponsors = sponsor.getSponsorsForLimitAndOffset(limit + 1, offset=offset)
+  sponsors = soc.logic.sponsor_logic.getForLimitAndOffset(limit + 1, offset=offset)
 
   context['pagination_form'] = helper.lists.makePaginationForm(request, limit)
   
--- a/app/soc/views/site/sponsor/profile.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/site/sponsor/profile.py	Sun Oct 12 00:12:53 2008 +0000
@@ -27,9 +27,9 @@
 from django import http
 from django import newforms as forms
 
+import soc.logic
 from soc.logic import validate
 from soc.logic import out_of_band
-from soc.logic import sponsor
 from soc.logic.helper import access
 from soc.logic.site import id_user
 from soc.views import helper
@@ -60,7 +60,7 @@
     link_name = self.cleaned_data.get('link_name')
     if not validate.isLinkNameFormatValid(link_name):
       raise forms.ValidationError("This link name is in wrong format.")
-    if sponsor.doesLinkNameExist(link_name):
+    if soc.logic.sponsor_logic.getFromFields(link_name=link_name):
       raise forms.ValidationError("This link name is already in use.")
     return link_name
 
@@ -106,13 +106,13 @@
   context = helper.responses.getUniversalContext(request)
 
   logged_in_id = users.get_current_user()
-  user = id_user.getUserFromId(logged_in_id)
+  user = soc.logic.user_logic.getFromFields(email=logged_in_id)
   sponsor_form = None
   existing_sponsor = None
 
   # try to fetch Sponsor entity corresponding to link_name if one exists
   try:
-    existing_sponsor = soc.logic.sponsor.getSponsorIfLinkName(linkname)
+    existing_sponsor = soc.logic.sponsor_logic.getIfFields(link_name=link_name)
   except out_of_band.ErrorResponse, error:
     # show custom 404 page when link name doesn't exist in Datastore
     error.message = error.message + DEF_CREATE_NEW_SPONSOR_MSG
@@ -144,8 +144,7 @@
       fields['founder'] = user
       
       form_ln = fields['link_name']
-      form_sponsor = sponsor.updateOrCreateSponsorFromLinkName(form_ln, 
-                                                               **fields)
+      form_sponsor = soc.logic.sponsor_logic.updateOrCreateFromFields(fields, link_name=form_ln)
       
       if not form_sponsor:
         return http.HttpResponseRedirect('/')
--- a/app/soc/views/site/user/list.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/site/user/list.py	Sun Oct 12 00:12:53 2008 +0000
@@ -22,6 +22,7 @@
   ]
 
 
+import soc.logic
 from soc.logic.helper import access
 from soc.logic.site import id_user
 from soc.views import simple
@@ -59,7 +60,7 @@
       offset=request.GET.get('offset'), limit=request.GET.get('limit'))
 
   # Fetch one more to see if there should be a 'next' link
-  users = id_user.getUsersForLimitAndOffset(limit + 1, offset=offset)
+  users = soc.logic.user_logic.getForLimitAndOffset(limit + 1, offset=offset)
 
   context['pagination_form'] = helper.lists.makePaginationForm(request, limit)
   
--- a/app/soc/views/site/user/profile.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/site/user/profile.py	Sun Oct 12 00:12:53 2008 +0000
@@ -28,6 +28,7 @@
 from django import newforms as forms
 from django.utils.translation import ugettext_lazy
 
+import soc.logic
 from soc.logic import validate
 from soc.logic import out_of_band
 from soc.logic.helper import access
@@ -126,7 +127,7 @@
       
       if form_id:
         # email provided, so attempt to look up user by email
-        user = id_user.getUserFromId(form_id)
+        user = soc.logic.user_logic.getFromFields(id=form_id)
 
         if user:
           lookup_message = ugettext_lazy('User found by email.')
@@ -166,7 +167,7 @@
   if user:
     # User entity found, so populate form with existing User information
     # context['found_user'] = user
-    form = LookupForm(initial={'id': user.id.email,
+    form = LookupForm(initial={'id': user.id.email(),
                                'link_name': user.link_name})
 
     if request.path.endswith('lookup'):
@@ -218,11 +219,12 @@
     link_name = self.cleaned_data.get('link_name')
     if not validate.isLinkNameFormatValid(link_name):
       raise forms.ValidationError("This link name is in wrong format.")
-    else:
-      key_name = self.data.get('key_name')
-      if not id_user.isLinkNameAvailableForId(
-          link_name, id=id_user.getUserFromKeyName(key_name).id) :
-        raise forms.ValidationError("This link name is already in use.")
+
+    user = soc.logic.user_logic.getFromKeyName(link_name)
+
+    if user and user.link_name != link_name:
+      raise forms.ValidationError("This link name is already in use.")
+
     return link_name
 
   def clean_id(self):
@@ -312,7 +314,7 @@
 
         # populate form with the existing User entity
         form = EditForm(initial={'key_name': user.key().name(),
-            'id': user.id.email, 'link_name': user.link_name,
+            'id': user.id.email(), 'link_name': user.link_name,
             'nick_name': user.nick_name, 'is_developer': user.is_developer})
       else:
         if request.GET.get(profile.SUBMIT_MSG_PARAM_NAME):
@@ -367,14 +369,14 @@
     if not validate.isLinkNameFormatValid(link_name):
       raise forms.ValidationError("This link name is in wrong format.")
     else:
-      if id_user.doesLinkNameExist(link_name):
+      if id_user.getUserFromLinkName(link_name):
         raise forms.ValidationError("This link name is already in use.")
     return link_name
 
   def clean_id(self):
     new_email = self.cleaned_data.get('id')
     form_id = users.User(email=new_email)
-    if id_user.isIdUser(form_id):
+    if soc.logic.user_logic.getFromFields(email=form_id):
         raise forms.ValidationError("This account is already in use.")
     return form_id
 
@@ -407,21 +409,23 @@
 
     if form.is_valid():
       form_id = form.cleaned_data.get('id')
-      new_linkname = form.cleaned_data.get('link_name')
-      nickname = form.cleaned_data.get('nick_name')
-      is_developer = form.cleaned_data.get('is_developer')
+      link_name = form.cleaned_data.get('link_name')
 
-      user = id_user.updateOrCreateUserFromId(id=form_id, 
-          link_name=new_linkname, nick_name=nickname, 
-          is_developer=is_developer)
+      properties = {}
+      properties['id'] = form_id
+      properties['link_name'] = link_name
+      properties['nick_name'] = form.cleaned_data.get('nick_name')
+      properties['is_developer'] = form.cleaned_data.get('is_developer')
+
+      user = soc.logic.user_logic.updateOrCreateFromFields(properties, email=form_id)
 
       if not user:
         return http.HttpResponseRedirect('/')
 
-      # redirect to new /site/user/profile/new_linkname?s=0
+      # redirect to new /site/user/profile/new_link_name?s=0
       # (causes 'Profile saved' message to be displayed)
       return helper.responses.redirectToChangedSuffix(
-          request, None, new_linkname,
+          request, None, link_name,
           params=profile.SUBMIT_PROFILE_SAVED_PARAMS)
   else: # method == 'GET':
     # no link name specified, so start with an empty form
--- a/app/soc/views/user/profile.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/user/profile.py	Sun Oct 12 00:12:53 2008 +0000
@@ -28,6 +28,7 @@
 from django import newforms as forms
 from django.utils.translation import ugettext_lazy
 
+import soc.logic
 from soc.logic import validate
 from soc.logic import out_of_band
 from soc.logic.site import id_user
@@ -56,8 +57,12 @@
     link_name = self.cleaned_data.get('link_name')
     if not validate.isLinkNameFormatValid(link_name):
       raise forms.ValidationError("This link name is in wrong format.")
-    elif not id_user.isLinkNameAvailableForId(link_name):
+
+    user = id_user.getUserFromLinkName(link_name)
+
+    if user and not id_user.doesLinkNameBelongToId(link_name, user.id):
       raise forms.ValidationError("This link name is already in use.")
+
     return link_name
 
 
@@ -109,7 +114,8 @@
 
   # try to fetch User entity corresponding to link_name if one exists
   try:
-    linkname_user = id_user.getUserIfLinkName(linkname)
+      if link_name:
+        link_name_user = id_user.getUserFromLinkNameOrDie(link_name)
   except out_of_band.ErrorResponse, error:
     # show custom 404 page when link name doesn't exist in Datastore
     return simple.errorResponse(request, error, template, context)
@@ -124,19 +130,21 @@
     form = UserForm(request.POST)
 
     if form.is_valid():
-      new_linkname = form.cleaned_data.get('link_name')
-      nickname = form.cleaned_data.get("nick_name")
+      new_link_name = form.cleaned_data.get('link_name')
+      properties = {}
+      properties['link_name'] = new_link_name
+      properties['nick_name'] = form.cleaned_data.get("nick_name")
+      properties['id'] = id
 
-      user = id_user.updateOrCreateUserFromId(
-          id, link_name=new_linkname, nick_name=nickname)
+      user = soc.logic.user_logic.updateOrCreateFromFields(properties, email=id)
 
       # redirect to new /user/profile/new_link_name?s=0
       # (causes 'Profile saved' message to be displayed)
       return helper.responses.redirectToChangedSuffix(
           request, link_name, new_link_name, params=SUBMIT_PROFILE_SAVED_PARAMS)
   else: # request.method == 'GET'
-    # try to fetch User entity corresponding to Google Account if one exists    
-    user = id_user.getUserFromId(id)
+    # try to fetch User entity corresponding to Google Account if one exists
+    user = soc.logic.user_logic.getFromFields(email=id)
 
     if user:
       # is 'Profile saved' parameter present, but referrer was not ourself?
--- a/app/soc/views/user/roles.py	Sun Oct 12 00:08:54 2008 +0000
+++ b/app/soc/views/user/roles.py	Sun Oct 12 00:12:53 2008 +0000
@@ -72,7 +72,7 @@
   """
   #TODO(tlarsen): this module is currently a placeholder for future work
   
-  # TODO: if linkname is empty or not a valid linkname on the site, display
+  # TODO: if link_name is empty or not a valid link_name on the site, display
   # some sort of "user does not exist" page (a custom 404 page, maybe?).
   
   return response_helpers.respond(request,