Add /site/user/profile Developer view for editing arbitrary User entities.
Update /user/profile edit() view to fix TODO about updating the URL when a
POST of the form changes the link_name of the User. Add a Create New User
link to the base.html sidebar mock-up.
--- a/app/soc/templates/soc/base.html Fri Sep 19 05:12:35 2008 +0000
+++ b/app/soc/templates/soc/base.html Fri Sep 19 05:15:20 2008 +0000
@@ -89,6 +89,9 @@
<li>
<a href="/site/user/lookup">Look Up User</a>
</li>
+ <li>
+ <a href="/site/user/profile">Create New User</a>
+ </li>
</ul>
</li>
</ul>
--- a/app/soc/templates/soc/site/user/profile/edit.html Fri Sep 19 05:12:35 2008 +0000
+++ b/app/soc/templates/soc/site/user/profile/edit.html Fri Sep 19 05:15:20 2008 +0000
@@ -14,16 +14,16 @@
{% endcomment %}
{% load forms_helpers %}
{% block page_title %}
- {% if linkname_user %}
+ {% if existing_user %}
Developer: Modify Existing User Profile
{% else %}
Developer: Create New User Profile
{% endif %}
{% endblock %}
{% block header_title %}
- {% if linkname_user %}
- Modify Existing User Profile for {{ linkname_user.nick_name }}
- <a href="mailto:{{ linkname_user.id }} "><{{ linkname_user.id }}></a>
+ {% if existing_user %}
+ Modify Existing User Profile for {{ existing_user.nick_name }}
+ <a href="mailto:{{ existing_user.id }} "><{{ existing_user.id }}></a>
{% else %}
Create a New User Profile
{% endif %}
@@ -38,19 +38,20 @@
<form method="POST">
<table>
{% field_as_table_row form.id %}
+{% if lookup_error %}
+<tr>
+ <td> </td>
+ <td colspan="3" class="formfielderror">
+ {{ lookup_error }}
+ </td>
+</tr>
+{% endif %}
{% field_as_table_row form.link_name %}
+ {% field_as_table_row form.nick_name %}
+ {% field_as_table_row form.is_developer %}
<tr>
- <td>
- <input type="submit" style="font-weight: bold" name="lookup" value="Look up User"/></span>
- </td>
- <td> </td>
- <td> </td>
- <td>
- {% if lookup_message %}<b><i>{{ lookup_message }}</i></b>{% endif %}
- </td>
- <tr><td colspan="4"> </td></tr>
+ <td colspan="4"> </td>
</tr>
- {% field_as_table_row form.nick_name %}
<tr>
<td>
<input type="submit" style="font-weight: bold" name="save" value="Save Changes"/></span>
@@ -58,9 +59,16 @@
<td>
<input type="button" onclick="location.href='/'" value="Cancel"/>
</td>
+ <td> </td>
+{% if submit_error %}
+ <td class="formfielderror">
+ {{ submit_error }}
+ </td>
+{% else %}
<td>
- {% if submit_message %}<b><i>{{ submit_message }}</i></b>{% endif %}
+ {% if submit_message %}<b><i>{{ submit_message }}</i></b>{% else %} {% endif %}
</td>
+{% endif %}
</tr>
</table>
</form>
--- a/app/soc/templates/soc/site/user/profile/lookup.html Fri Sep 19 05:12:35 2008 +0000
+++ b/app/soc/templates/soc/site/user/profile/lookup.html Fri Sep 19 05:15:20 2008 +0000
@@ -28,19 +28,35 @@
</p>
<form method="POST">
<table>
+{% if email_error %}
+<tr>
+ <td> </td>
+ <td colspan="3" class="formfielderror">
+ {{ email_error }}
+ </td>
+</tr>
+{% endif %}
{% field_as_table_row form.id %}
+{% if linkname_error %}
+<tr>
+ <td> </td>
+ <td colspan="3" class="formfielderror">
+ {{ linkname_error }}
+ </td>
+</tr>
+{% endif %}
{% field_as_table_row form.link_name %}
{% if found_user %}
<tr>
<td class="formfieldlabel">Nick name</td>
+ <td>{{ found_user.nick_name }}</td>
<td class="formfieldrequired"> </td>
- <td>{{ found_user.nick_name }}</td>
<td class="formfieldhelptext"> </td>
</tr>
<tr>
<td class="formfieldlabel">Is Developer</td>
+ <td>{{ found_user.is_developer }}</td>
<td class="formfieldrequired"> </td>
- <td>{{ found_user.is_developer }}</td>
<td class="formfieldhelptext"> </td>
</tr>
{% endif %}
@@ -51,16 +67,10 @@
<td>
<input type="submit" style="font-weight: bold" name="lookup" value="Look up User"/></span>
</td>
- <td> </td>
-{% if lookup_error %}
- <td colspan="2" class="formfielderror">
- {{ lookup_error }}
+ <td colspan="2"> </td>
+ <td>
+ {% if lookup_message %}<b><i>{{ lookup_message }}</i></b>{% else %} {% endif %}
</td>
-{% else %}
- <td colspan="2">
- {% if lookup_message %}<b><i>{{ lookup_message }}</i></b>{% else %}%nbsp;{% endif %}
- </td>
-{% endif %}
</tr>
{% if edit_link %}
<tr>
--- a/app/soc/views/site/user/profile.py Fri Sep 19 05:12:35 2008 +0000
+++ b/app/soc/views/site/user/profile.py Fri Sep 19 05:15:20 2008 +0000
@@ -21,13 +21,12 @@
'"Todd Larsen" <tlarsen@google.com>',
]
-import re
-import logging
from google.appengine.api import users
+
from django import http
-from django import shortcuts
from django import newforms as forms
+from django.utils.translation import ugettext_lazy
from soc.logic import out_of_band
from soc.logic.site import id_user
@@ -35,15 +34,29 @@
from soc.views.helpers import forms_helpers
from soc.views.helpers import response_helpers
from soc.views.helpers import template_helpers
+from soc.views.user import profile
import soc.models.user
class LookupForm(forms_helpers.DbModelForm):
"""Django form displayed for a Developer to look up a User.
+
+ This form is manually specified, instead of using
+ model = soc.models.user.User
+ in the Meta class, because the form behavior is unusual and normally
+ required Properties of the User model need to sometimes be omitted.
+
+ Also, this form only permits entry and editing of some of the User entity
+ Properties, not all of them.
"""
- id = forms.EmailField(required=False)
- link_name = forms.CharField(required=False)
+ id = forms.EmailField(required=False,
+ label=soc.models.user.User.id.verbose_name,
+ help_text=soc.models.user.User.id.help_text)
+
+ link_name = forms.CharField(required=False,
+ label=soc.models.user.User.link_name.verbose_name,
+ help_text=soc.models.user.User.link_name.help_text)
class Meta:
model = None
@@ -90,25 +103,15 @@
# create default template context for use with any templates
context = response_helpers.getUniversalContext(request)
- logged_in_id = users.get_current_user()
-
- alt_response = simple.getAltResponseIfNotDeveloper(request, context,
- id = logged_in_id)
+ alt_response = simple.getAltResponseIfNotDeveloper(request,
+ context=context)
if alt_response:
- # not a developer
- return alt_response
-
- alt_response = simple.getAltResponseIfNotLoggedIn(request, context,
- id = logged_in_id)
- if alt_response:
- # not logged in
return alt_response
user = None # assume that no User entity will be found
form = None # assume blank form needs to be displayed
- lookup_message = 'Enter information to look up a User.'
- lookup_error = None # assume no look-up errors
- edit_link = None # assume no User entity found to be edited
+ lookup_message = ugettext_lazy('Enter information to look up a User.')
+ email_error = None # assume no email look-up errors
if request.method == 'POST':
form = LookupForm(request.POST)
@@ -121,9 +124,9 @@
user = id_user.getUserFromId(form_id)
if user:
- lookup_message = 'User found by email.'
+ lookup_message = ugettext_lazy('User found by email.')
else:
- lookup_error = 'User with that email not found.'
+ email_error = ugettext_lazy('User with that email not found.')
if not user:
# user not found yet, so see if link name was provided
@@ -134,15 +137,11 @@
user = id_user.getUserFromLinkName(linkname)
if user:
- lookup_message = 'User found by link name.'
- lookup_error = None # clear previous error, now that User was found
+ lookup_message = ugettext_lazy('User found by link name.')
+ email_error = None # clear previous error, since User was found
else:
- if form_id:
- # email was provided, so look up failure is due to both
- lookup_error = 'User with that email or link name not found.'
- else:
- # email was not provided, so look up failure is due to link name
- lookup_error = 'User with that link name not found.'
+ context['linkname_error'] = ugettext_lazy(
+ 'User with that link name not found.')
# else: form was not valid
# else: # method == 'GET'
@@ -154,17 +153,149 @@
if request.path.endswith('lookup'):
# convert /lookup path into /profile/link_name path
- edit_link = '%sprofile/%s' % (request.path[:-len('lookup')],
- user.link_name)
+ context['edit_link'] = response_helpers.replaceSuffix(
+ request.path, 'lookup', 'profile/%s' % user.link_name)
# else: URL is not one that was expected, so do not display edit link
elif not form:
# no pre-populated form was constructed, so show the empty look-up form
form = LookupForm()
context.update({'form': form,
- 'edit_link': edit_link,
'found_user': user,
- 'lookup_error': lookup_error,
+ 'email_error': email_error,
'lookup_message': lookup_message})
return response_helpers.respond(request, template, context)
+
+
+class EditForm(forms_helpers.DbModelForm):
+ """Django form displayed when Developer creates or edits a User.
+
+ This form is manually specified, instead of using
+ model = soc.models.user.User
+ in the Meta class, because the form behavior is unusual and normally
+ required Properties of the User model need to sometimes be omitted.
+ """
+ id = forms.EmailField(
+ label=soc.models.user.User.id.verbose_name,
+ help_text=soc.models.user.User.id.help_text)
+
+ link_name = forms.CharField(
+ label=soc.models.user.User.link_name.verbose_name,
+ help_text=soc.models.user.User.link_name.help_text)
+
+ nick_name = forms.CharField(
+ label=soc.models.user.User.nick_name.verbose_name)
+
+ is_developer = forms.BooleanField(required=False,
+ label=soc.models.user.User.is_developer.verbose_name,
+ help_text=soc.models.user.User.is_developer.help_text)
+
+ class Meta:
+ model = None
+
+ def clean_link_name(self):
+ link_name = self.cleaned_data.get('link_name')
+ if not id_user.isLinkNameFormatValid(link_name):
+ raise forms.ValidationError("This link name is in wrong format.")
+ else:
+ if not id_user.isLinkNameAvailableForId(
+ link_name, id=self.cleaned_data.get('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.')
+
+
+DEF_SITE_USER_PROFILE_EDIT_TMPL = 'soc/site/user/profile/edit.html'
+
+def edit(request, linkname=None, template=DEF_SITE_USER_PROFILE_EDIT_TMPL):
+ """View for a Developer to modify the properties of a User Model entity.
+
+ Args:
+ request: the standard django request object
+ linkname: the User's site-unique "linkname" extracted from the URL
+ template: the "sibling" template (or a search list of such templates)
+ from which to construct the public.html template name (or names)
+
+ Returns:
+ A subclass of django.http.HttpResponse which either contains the form to
+ be filled out, or a redirect to the correct view in the interface.
+ """
+ # create default template context for use with any templates
+ context = response_helpers.getUniversalContext(request)
+
+ alt_response = simple.getAltResponseIfNotDeveloper(request,
+ context=context)
+ if alt_response:
+ return alt_response
+
+ user = None # assume that no User entity will be found
+
+ if request.method == 'POST':
+ form = EditForm(request.POST)
+
+ 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')
+
+ user = id_user.updateOrCreateUserFromId(
+ form_id, link_name=new_linkname, nick_name=nickname,
+ is_developer=is_developer)
+
+ # redirect to new /site/user/profile/new_linkname&s=0
+ # (causes 'Profile saved' message to be displayed)
+ return response_helpers.redirectToChangedSuffix(
+ request, linkname, new_linkname,
+ params=profile.SUBMIT_PROFILE_SAVED_PARAMS)
+ else: # method == 'GET':
+ # try to fetch User entity corresponding to link name if one exists
+ if linkname:
+ user = id_user.getUserFromLinkName(linkname)
+
+ if user:
+ # is 'Profile saved' parameter present, but referrer was not ourself?
+ # (e.g. someone bookmarked the GET that followed the POST submit)
+ if (request.GET.get(profile.SUBMIT_MSG_PARAM_NAME)
+ and (not response_helpers.isReferrerSelf(request,
+ suffix=linkname))):
+ # redirect to aggressively remove 'Profile saved' query parameter
+ return http.HttpResponseRedirect(request.path)
+
+ # referrer was us, so select which submit message to display
+ # (may display no message if ?s=0 parameter is not present)
+ context['submit_message'] = (
+ template_helpers.getSingleIndexedParamValue(
+ request, profile.SUBMIT_MSG_PARAM_NAME,
+ values=profile.SUBMIT_MESSAGES))
+
+ # populate form with the existing User entity
+ form = EditForm(initial={
+ 'id': user.id, '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):
+ # redirect to aggressively remove 'Profile saved' query parameter
+ return http.HttpResponseRedirect(request.path)
+
+ context['lookup_error'] = ugettext_lazy(
+ 'User with that link name not found.')
+ form = EditForm(initial={'link_name': linkname})
+ else: # no link name specified in the URL
+ if request.GET.get(profile.SUBMIT_MSG_PARAM_NAME):
+ # redirect to aggressively remove 'Profile saved' query parameter
+ return http.HttpResponseRedirect(request.path)
+
+ # no link name specified, so start with an empty form
+ form = EditForm()
+
+ context.update({'form': form,
+ 'existing_user': user})
+
+ return response_helpers.respond(request, template, context)
--- a/app/soc/views/user/profile.py Fri Sep 19 05:12:35 2008 +0000
+++ b/app/soc/views/user/profile.py Fri Sep 19 05:15:20 2008 +0000
@@ -21,13 +21,12 @@
'"Pawel Solyga" <pawel.solyga@gmail.com>',
]
-import re
-import logging
from google.appengine.api import users
from django import http
from django import shortcuts
from django import newforms as forms
+from django.utils.translation import ugettext_lazy
from soc.logic import out_of_band
from soc.logic.site import id_user
@@ -62,6 +61,18 @@
DEF_USER_PROFILE_EDIT_TMPL = 'soc/user/profile/edit.html'
+SUBMIT_MSG_PARAM_NAME = 's'
+
+SUBMIT_MESSAGES = (
+ ugettext_lazy('Profile saved.'),
+)
+
+SUBMIT_MSG_PROFILE_SAVED = 0
+
+SUBMIT_PROFILE_SAVED_PARAMS = {
+ SUBMIT_MSG_PARAM_NAME: SUBMIT_MSG_PROFILE_SAVED,
+}
+
def edit(request, linkname=None, template=DEF_USER_PROFILE_EDIT_TMPL):
"""View for a User to modify the properties of a User Model entity.
@@ -96,10 +107,10 @@
try:
linkname_user = id_user.getUserIfLinkName(linkname)
except out_of_band.ErrorResponse, error:
- # show custom 404 page when linkname doesn't exist in Datastore
+ # show custom 404 page when link name doesn't exist in Datastore
return simple.errorResponse(request, error, template, context)
- # linkname_user will be None here if linkname was already None...
+ # linkname_user will be None here if link name was already None...
if linkname_user and (linkname_user.id != id):
# linkname_user exists but is not the currently logged in Google Account,
# so show public view for that (other) User entity
@@ -109,24 +120,42 @@
form = UserForm(request.POST)
if form.is_valid():
- linkname = form.cleaned_data.get('link_name')
+ new_linkname = form.cleaned_data.get('link_name')
nickname = form.cleaned_data.get("nick_name")
user = id_user.updateOrCreateUserFromId(
- id, link_name=linkname, nick_name=nickname)
+ id, link_name=new_linkname, nick_name=nickname)
- # TODO(tlarsen):
- # if old_linkname: redirect to new /user/profile/new_linkname
- # (how to preserve displaying the "Profile saved" message?)
- context.update({'submit_message': 'Profile saved.'})
+ # 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)
else: # request.method == 'GET'
# try to fetch User entity corresponding to Google Account if one exists
user = id_user.getUserFromId(id)
if user:
+ # is 'Profile saved' parameter present, but referrer was not ourself?
+ # (e.g. someone bookmarked the GET that followed the POST submit)
+ if (request.GET.get(SUBMIT_MSG_PARAM_NAME)
+ and (not response_helpers.isReferrerSelf(request,
+ suffix=linkname))):
+ # redirect to aggressively remove 'Profile saved' query parameter
+ return http.HttpResponseRedirect(request.path)
+
+ # referrer was us, so select which submit message to display
+ # (may display no message if ?s=0 parameter is not present)
+ context['submit_message'] = (
+ template_helpers.getSingleIndexedParamValue(
+ request, SUBMIT_MSG_PARAM_NAME, values=SUBMIT_MESSAGES))
+
# populate form with the existing User entity
form = UserForm(instance=user)
else:
+ if request.GET.get(SUBMIT_MSG_PARAM_NAME):
+ # redirect to aggressively remove 'Profile saved' query parameter
+ return http.HttpResponseRedirect(request.path)
+
# no User entity exists for this Google Account, so show a blank form
form = UserForm()
--- a/app/urls.py Fri Sep 19 05:12:35 2008 +0000
+++ b/app/urls.py Fri Sep 19 05:15:20 2008 +0000
@@ -37,13 +37,9 @@
# 'soc.views.user.roles.dashboard'),
(r'^site/user/lookup$', 'soc.views.site.user.profile.lookup'),
+ (r'^site/user/profile$', 'soc.views.site.user.profile.edit'),
(r'^site/user/profile/(?P<linkname>[_0-9a-z]+)$',
'soc.views.site.user.profile.edit'),
-
- # TODO(tlarsen): uncomment these when the view functions are committed
- # (r'^site/user/profile$', 'soc.views.site.user.profile.create'),
- # (r'^site/user/profile/(?P<linkname>[_0-9a-z]+)$',
- # 'soc.views.site.user.profile.edit'),
(r'^user/profile$', 'soc.views.user.profile.edit'),
(r'^user/profile/(?P<linkname>[_0-9a-z]+)$',