# HG changeset patch # User Todd Larsen # Date 1221801320 0 # Node ID 1fadf6e0348d45cdeb009f70efda6c024c67d8a2 # Parent a9b3d6c9d4f9b8c87c955bfff4d559d2d6c06a69 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. diff -r a9b3d6c9d4f9 -r 1fadf6e0348d app/soc/templates/soc/base.html --- 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 @@
  • Look Up User
  • +
  • + Create New User +
  • diff -r a9b3d6c9d4f9 -r 1fadf6e0348d app/soc/templates/soc/site/user/profile/edit.html --- 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 }} - <{{ linkname_user.id }}> + {% if existing_user %} + Modify Existing User Profile for {{ existing_user.nick_name }} + <{{ existing_user.id }}> {% else %} Create a New User Profile {% endif %} @@ -38,19 +38,20 @@
    {% field_as_table_row form.id %} +{% if lookup_error %} + + + + +{% endif %} {% field_as_table_row form.link_name %} + {% field_as_table_row form.nick_name %} + {% field_as_table_row form.is_developer %} - - - - - + - {% field_as_table_row form.nick_name %} + +{% if submit_error %} + +{% else %} +{% endif %}
      + {{ lookup_error }} +
    - -    - {% if lookup_message %}{{ lookup_message }}{% endif %} -
     
     
    @@ -58,9 +59,16 @@   + {{ submit_error }} + - {% if submit_message %}{{ submit_message }}{% endif %} + {% if submit_message %}{{ submit_message }}{% else %} {% endif %}
    diff -r a9b3d6c9d4f9 -r 1fadf6e0348d app/soc/templates/soc/site/user/profile/lookup.html --- 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 @@

    +{% if email_error %} + + + + +{% endif %} {% field_as_table_row form.id %} +{% if linkname_error %} + + + + +{% endif %} {% field_as_table_row form.link_name %} {% if found_user %} + - + - {% endif %} @@ -51,16 +67,10 @@ - -{% if lookup_error %} - + -{% else %} - -{% endif %} {% if edit_link %} diff -r a9b3d6c9d4f9 -r 1fadf6e0348d app/soc/views/site/user/profile.py --- 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" ', ] -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) diff -r a9b3d6c9d4f9 -r 1fadf6e0348d app/soc/views/user/profile.py --- 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" ', ] -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() diff -r a9b3d6c9d4f9 -r 1fadf6e0348d app/urls.py --- 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[_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[_0-9a-z]+)$', - # 'soc.views.site.user.profile.edit'), (r'^user/profile$', 'soc.views.user.profile.edit'), (r'^user/profile/(?P[_0-9a-z]+)$',
      + {{ email_error }} +
      + {{ linkname_error }} +
    Nick name{{ found_user.nick_name }}  {{ found_user.nick_name }}  
    Is Developer{{ found_user.is_developer }}  {{ found_user.is_developer }}  
      - {{ lookup_error }} +   + {% if lookup_message %}{{ lookup_message }}{% else %} {% endif %} - {% if lookup_message %}{{ lookup_message }}{% else %}%nbsp;{% endif %} -