Add support for changing User id (Google Account email) in User Profile Developer view. Now user profile developer edit view includes hidden key_name field. Fix typo in user/profile.py. Show former user ids in lookup and edit User Profile Developer views.
authorPawel Solyga <Pawel.Solyga@gmail.com>
Mon, 22 Sep 2008 13:42:53 +0000
changeset 184 7c0b42aecd9b
parent 183 37d98c3cefa5
child 185 2f3bd84bb106
Add support for changing User id (Google Account email) in User Profile Developer view. Now user profile developer edit view includes hidden key_name field. Fix typo in user/profile.py. Show former user ids in lookup and edit User Profile Developer views. Patch by: Pawel Solyga Reviewed by: to-be-reviewed
app/soc/logic/site/id_user.py
app/soc/templates/soc/site/user/profile/edit.html
app/soc/templates/soc/site/user/profile/lookup.html
app/soc/views/site/user/profile.py
app/soc/views/user/profile.py
--- a/app/soc/logic/site/id_user.py	Sun Sep 21 08:59:11 2008 +0000
+++ b/app/soc/logic/site/id_user.py	Mon Sep 22 13:42:53 2008 +0000
@@ -44,7 +44,7 @@
   return 'User:%s' % id.email()
 
 
-def getIdIfMissing(id):
+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
@@ -66,6 +66,17 @@
 
   return id
 
+def getUsersForOffsetAndLimit(offset=0, limit=0):
+  """Returns Users entities for given offset and limit or None if not found.
+    
+  Args:
+    offset: offset in entities list which defines first entity to return
+    limit: max amount of entities to return
+  """
+  query = db.GqlQuery('SELECT * FROM User ORDER BY id')
+
+  # Fetch one more to see if there should be a 'next' link
+  return query.fetch(limit+1, offset)  
 
 def getUserFromId(id):
   """Returns User entity for a Google Account, or None if not found.  
@@ -73,29 +84,8 @@
   Args:
     id: a Google Account (users.User) object
   """
-  # first, attempt a lookup by User:id key name
-  key_name = getUserKeyNameFromId(id)
-  
-  if key_name:
-    user = soc.models.user.User.get_by_key_name(key_name)
-  else:
-    user = None
-  
-  if user:
-    return user
+  return soc.models.user.User.gql('WHERE id = :1', id).get()
 
-  # email address may have changed, so query the id property
-  user = soc.models.user.User.gql('WHERE id = :1', id).get()
-
-  if user:
-    return user
-
-  # last chance: perhaps the User changed their email address at some point
-  user = soc.models.user.User.gql('WHERE former_ids = :1', id).get()
-
-  return user
-
-  
 def getUserIfMissing(user, id):
   """Conditionally returns User entity for a Google Account.
   
@@ -227,6 +217,13 @@
   """
   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.
@@ -349,6 +346,29 @@
   # 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.
--- a/app/soc/templates/soc/site/user/profile/edit.html	Sun Sep 21 08:59:11 2008 +0000
+++ b/app/soc/templates/soc/site/user/profile/edit.html	Mon Sep 22 13:42:53 2008 +0000
@@ -36,6 +36,7 @@
 {% endblock %}
 </p>
 <form method="POST">
+  {{ form.key_name }}
  <table>
   {% field_as_table_row form.id %}
 {% if lookup_error %}
@@ -49,6 +50,18 @@
   {% field_as_table_row form.link_name %}
   {% field_as_table_row form.nick_name %}
   {% field_as_table_row form.is_developer %}
+  {% if existing_user.former_ids %}
+  <tr>
+   <td class="formfieldlabel">Former ids</td>
+   <td>
+       {% for former_id in existing_user.former_ids %}
+       {{ former_id }}<br />
+       {% endfor %}
+   </td>
+   <td class="formfieldrequired">&nbsp;</td>
+   <td class="formfieldhelptext">&nbsp;</td>
+  </tr>
+  {% endif %}
   <tr>
    <td colspan="4">&nbsp;</td>
   </tr>
--- a/app/soc/templates/soc/site/user/profile/lookup.html	Sun Sep 21 08:59:11 2008 +0000
+++ b/app/soc/templates/soc/site/user/profile/lookup.html	Mon Sep 22 13:42:53 2008 +0000
@@ -59,6 +59,19 @@
   <td class="formfieldrequired">&nbsp;</td>
   <td class="formfieldhelptext">&nbsp;</td>
  </tr>
+ 
+ {% if found_user.former_ids %}
+ <tr>
+  <td class="formfieldlabel">Former ids</td>
+  <td>
+      {% for former_id in found_user.former_ids %}
+      {{ former_id }}<br />
+      {% endfor %}
+  </td>
+  <td class="formfieldrequired">&nbsp;</td>
+  <td class="formfieldhelptext">&nbsp;</td>
+ </tr>
+ {% endif %}
 {% endif %}
   <tr>
    <td colspan="4">&nbsp;</td>
--- a/app/soc/views/site/user/profile.py	Sun Sep 21 08:59:11 2008 +0000
+++ b/app/soc/views/site/user/profile.py	Mon Sep 22 13:42:53 2008 +0000
@@ -191,6 +191,8 @@
       label=soc.models.user.User.is_developer.verbose_name,
       help_text=soc.models.user.User.is_developer.help_text)
 
+  key_name = forms.CharField(widget=forms.HiddenInput)
+  
   class Meta:
     model = None
  
@@ -199,17 +201,22 @@
     if not id_user.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=self.cleaned_data.get('id')):
+          link_name, id=id_user.getUserFromKeyName(key_name).id) :
         raise forms.ValidationError("This link name is already in use.")
     return link_name
 
   def clean_id(self):
-    try:
-      return users.User(email=self.cleaned_data.get('id'))
-    except users.UserNotFoundError:
-      raise forms.ValidationError('Account not found.')
-    
+    new_email = self.cleaned_data.get('id')
+    form_id = users.User(email=new_email)
+    key_name = self.data.get('key_name')
+    old_email = id_user.getUserFromKeyName(key_name).id.email()
+    if new_email != old_email:
+      if id_user.isIdUser(form_id):
+        raise forms.ValidationError("This account is already in use.")
+    return form_id
+
 
 DEF_SITE_USER_PROFILE_EDIT_TMPL = 'soc/site/user/profile/edit.html'
 DEF_CREATE_NEW_USER_MSG = ' You can create a new user by visiting' \
@@ -255,11 +262,15 @@
       new_linkname = form.cleaned_data.get('link_name')
       nickname = form.cleaned_data.get('nick_name')
       is_developer = form.cleaned_data.get('is_developer')
+      key_name = form.cleaned_data.get('key_name')
       
-      user = id_user.updateOrCreateUserFromId(
-        form_id, link_name=new_linkname, nick_name=nickname,
-        is_developer=is_developer)
+      user = id_user.updateUserForKeyName(key_name=key_name, id=form_id, 
+          link_name=new_linkname, nick_name=nickname, 
+          is_developer=is_developer)
 
+      if not user:
+        return http.HttpResponseRedirect('/')
+        
       # redirect to new /site/user/profile/new_linkname?s=0
       # (causes 'Profile saved' message to be displayed)
       return response_helpers.redirectToChangedSuffix(
@@ -285,7 +296,7 @@
                 values=profile.SUBMIT_MESSAGES))
 
         # populate form with the existing User entity
-        form = EditForm(initial={
+        form = EditForm(initial={ 'key_name': user.key().name(),
             'id': user.id.email, 'link_name': user.link_name,
             'nick_name': user.nick_name, 'is_developer': user.is_developer})       
       else:
--- a/app/soc/views/user/profile.py	Sun Sep 21 08:59:11 2008 +0000
+++ b/app/soc/views/user/profile.py	Mon Sep 22 13:42:53 2008 +0000
@@ -126,7 +126,7 @@
       user = id_user.updateOrCreateUserFromId(
           id, link_name=new_linkname, nick_name=nickname)
 
-      # redirect to new /user/profile/new_linkname&s=0
+      # redirect to new /user/profile/new_linkname?s=0
       # (causes 'Profile saved' message to be displayed)
       return response_helpers.redirectToChangedSuffix(
           request, linkname, new_linkname, params=SUBMIT_PROFILE_SAVED_PARAMS)