app/soc/views/site/user/profile.py
changeset 170 1fadf6e0348d
parent 141 e120c24b89e2
child 171 b62f1cf5e878
equal deleted inserted replaced
169:a9b3d6c9d4f9 170:1fadf6e0348d
    19 
    19 
    20 __authors__ = [
    20 __authors__ = [
    21   '"Todd Larsen" <tlarsen@google.com>',
    21   '"Todd Larsen" <tlarsen@google.com>',
    22   ]
    22   ]
    23 
    23 
    24 import re
       
    25 import logging
       
    26 
    24 
    27 from google.appengine.api import users
    25 from google.appengine.api import users
       
    26 
    28 from django import http
    27 from django import http
    29 from django import shortcuts
       
    30 from django import newforms as forms
    28 from django import newforms as forms
       
    29 from django.utils.translation import ugettext_lazy
    31 
    30 
    32 from soc.logic import out_of_band
    31 from soc.logic import out_of_band
    33 from soc.logic.site import id_user
    32 from soc.logic.site import id_user
    34 from soc.views import simple
    33 from soc.views import simple
    35 from soc.views.helpers import forms_helpers
    34 from soc.views.helpers import forms_helpers
    36 from soc.views.helpers import response_helpers
    35 from soc.views.helpers import response_helpers
    37 from soc.views.helpers import template_helpers
    36 from soc.views.helpers import template_helpers
       
    37 from soc.views.user import profile
    38 
    38 
    39 import soc.models.user
    39 import soc.models.user
    40 
    40 
    41 
    41 
    42 class LookupForm(forms_helpers.DbModelForm):
    42 class LookupForm(forms_helpers.DbModelForm):
    43   """Django form displayed for a Developer to look up a User.
    43   """Django form displayed for a Developer to look up a User.
       
    44   
       
    45   This form is manually specified, instead of using
       
    46     model = soc.models.user.User
       
    47   in the Meta class, because the form behavior is unusual and normally
       
    48   required Properties of the User model need to sometimes be omitted.
       
    49   
       
    50   Also, this form only permits entry and editing  of some of the User entity
       
    51   Properties, not all of them.
    44   """
    52   """
    45   id = forms.EmailField(required=False)
    53   id = forms.EmailField(required=False,
    46   link_name = forms.CharField(required=False)
    54       label=soc.models.user.User.id.verbose_name,
       
    55       help_text=soc.models.user.User.id.help_text)
       
    56 
       
    57   link_name = forms.CharField(required=False,
       
    58       label=soc.models.user.User.link_name.verbose_name,
       
    59       help_text=soc.models.user.User.link_name.help_text)
    47 
    60 
    48   class Meta:
    61   class Meta:
    49     model = None
    62     model = None
    50 
    63 
    51   def clean_link_name(self):
    64   def clean_link_name(self):
    88     be filled out, or a redirect to the correct view in the interface.
   101     be filled out, or a redirect to the correct view in the interface.
    89   """
   102   """
    90   # create default template context for use with any templates
   103   # create default template context for use with any templates
    91   context = response_helpers.getUniversalContext(request)
   104   context = response_helpers.getUniversalContext(request)
    92 
   105 
    93   logged_in_id = users.get_current_user()
   106   alt_response = simple.getAltResponseIfNotDeveloper(request,
    94 
   107                                                      context=context)
    95   alt_response = simple.getAltResponseIfNotDeveloper(request, context, 
       
    96                                                         id = logged_in_id)
       
    97   if alt_response:
   108   if alt_response:
    98     # not a developer
       
    99     return alt_response
       
   100   
       
   101   alt_response = simple.getAltResponseIfNotLoggedIn(request, context, 
       
   102                                                         id = logged_in_id)
       
   103   if alt_response:
       
   104     # not logged in
       
   105     return alt_response
   109     return alt_response
   106 
   110 
   107   user = None  # assume that no User entity will be found
   111   user = None  # assume that no User entity will be found
   108   form = None  # assume blank form needs to be displayed
   112   form = None  # assume blank form needs to be displayed
   109   lookup_message = 'Enter information to look up a User.'
   113   lookup_message = ugettext_lazy('Enter information to look up a User.')
   110   lookup_error = None  # assume no look-up errors
   114   email_error = None  # assume no email look-up errors
   111   edit_link = None  # assume no User entity found to be edited
       
   112 
   115 
   113   if request.method == 'POST':
   116   if request.method == 'POST':
   114     form = LookupForm(request.POST)
   117     form = LookupForm(request.POST)
   115 
   118 
   116     if form.is_valid():
   119     if form.is_valid():
   119       if form_id:
   122       if form_id:
   120         # email provided, so attempt to look up user by email
   123         # email provided, so attempt to look up user by email
   121         user = id_user.getUserFromId(form_id)
   124         user = id_user.getUserFromId(form_id)
   122 
   125 
   123         if user:
   126         if user:
   124           lookup_message = 'User found by email.'
   127           lookup_message = ugettext_lazy('User found by email.')
   125         else:
   128         else:
   126           lookup_error = 'User with that email not found.'
   129           email_error = ugettext_lazy('User with that email not found.')
   127 
   130 
   128       if not user:
   131       if not user:
   129         # user not found yet, so see if link name was provided
   132         # user not found yet, so see if link name was provided
   130         linkname = form.cleaned_data.get('link_name')
   133         linkname = form.cleaned_data.get('link_name')
   131         
   134         
   132         if linkname:
   135         if linkname:
   133           # link name provided, so try to look up by link name 
   136           # link name provided, so try to look up by link name 
   134           user = id_user.getUserFromLinkName(linkname)
   137           user = id_user.getUserFromLinkName(linkname)
   135         
   138         
   136           if user:
   139           if user:
   137             lookup_message = 'User found by link name.'
   140             lookup_message = ugettext_lazy('User found by link name.')
   138             lookup_error = None  # clear previous error, now that User was found
   141             email_error = None  # clear previous error, since User was found
   139           else:
   142           else:
   140             if form_id:
   143             context['linkname_error'] = ugettext_lazy(
   141               # email was provided, so look up failure is due to both            
   144                 'User with that link name not found.')            
   142               lookup_error = 'User with that email or link name not found.'            
       
   143             else:
       
   144               # email was not provided, so look up failure is due to link name            
       
   145               lookup_error = 'User with that link name not found.'            
       
   146     # else: form was not valid
   145     # else: form was not valid
   147   # else:  # method == 'GET'
   146   # else:  # method == 'GET'
   148 
   147 
   149   if user:
   148   if user:
   150     # User entity found, so populate form with existing User information            
   149     # User entity found, so populate form with existing User information            
   152     form = LookupForm(initial={'id': user.id,
   151     form = LookupForm(initial={'id': user.id,
   153                                'link_name': user.link_name})
   152                                'link_name': user.link_name})
   154 
   153 
   155     if request.path.endswith('lookup'):
   154     if request.path.endswith('lookup'):
   156       # convert /lookup path into /profile/link_name path
   155       # convert /lookup path into /profile/link_name path
   157       edit_link = '%sprofile/%s' % (request.path[:-len('lookup')],
   156       context['edit_link'] = response_helpers.replaceSuffix(
   158                                     user.link_name) 
   157           request.path, 'lookup', 'profile/%s' % user.link_name)
   159     # else: URL is not one that was expected, so do not display edit link
   158     # else: URL is not one that was expected, so do not display edit link
   160   elif not form:
   159   elif not form:
   161     # no pre-populated form was constructed, so show the empty look-up form
   160     # no pre-populated form was constructed, so show the empty look-up form
   162     form = LookupForm()
   161     form = LookupForm()
   163 
   162 
   164   context.update({'form': form,
   163   context.update({'form': form,
   165                   'edit_link': edit_link,
       
   166                   'found_user': user,
   164                   'found_user': user,
   167                   'lookup_error': lookup_error,
   165                   'email_error': email_error,
   168                   'lookup_message': lookup_message})
   166                   'lookup_message': lookup_message})
   169 
   167 
   170   return response_helpers.respond(request, template, context)
   168   return response_helpers.respond(request, template, context)
       
   169 
       
   170 
       
   171 class EditForm(forms_helpers.DbModelForm):
       
   172   """Django form displayed when Developer creates or edits a User.
       
   173   
       
   174   This form is manually specified, instead of using
       
   175     model = soc.models.user.User
       
   176   in the Meta class, because the form behavior is unusual and normally
       
   177   required Properties of the User model need to sometimes be omitted.
       
   178   """
       
   179   id = forms.EmailField(
       
   180       label=soc.models.user.User.id.verbose_name,
       
   181       help_text=soc.models.user.User.id.help_text)
       
   182 
       
   183   link_name = forms.CharField(
       
   184       label=soc.models.user.User.link_name.verbose_name,
       
   185       help_text=soc.models.user.User.link_name.help_text)
       
   186 
       
   187   nick_name = forms.CharField(
       
   188       label=soc.models.user.User.nick_name.verbose_name)
       
   189 
       
   190   is_developer = forms.BooleanField(required=False,
       
   191       label=soc.models.user.User.is_developer.verbose_name,
       
   192       help_text=soc.models.user.User.is_developer.help_text)
       
   193 
       
   194   class Meta:
       
   195     model = None
       
   196  
       
   197   def clean_link_name(self):
       
   198     link_name = self.cleaned_data.get('link_name')
       
   199     if not id_user.isLinkNameFormatValid(link_name):
       
   200       raise forms.ValidationError("This link name is in wrong format.")
       
   201     else:
       
   202       if not id_user.isLinkNameAvailableForId(
       
   203           link_name, id=self.cleaned_data.get('id')):
       
   204         raise forms.ValidationError("This link name is already in use.")
       
   205     return link_name
       
   206 
       
   207   def clean_id(self):
       
   208     try:
       
   209       return users.User(email=self.cleaned_data.get('id'))
       
   210     except users.UserNotFoundError:
       
   211       raise forms.ValidationError('Account not found.')
       
   212     
       
   213 
       
   214 DEF_SITE_USER_PROFILE_EDIT_TMPL = 'soc/site/user/profile/edit.html'
       
   215 
       
   216 def edit(request, linkname=None, template=DEF_SITE_USER_PROFILE_EDIT_TMPL):
       
   217   """View for a Developer to modify the properties of a User Model entity.
       
   218 
       
   219   Args:
       
   220     request: the standard django request object
       
   221     linkname: the User's site-unique "linkname" extracted from the URL
       
   222     template: the "sibling" template (or a search list of such templates)
       
   223       from which to construct the public.html template name (or names)
       
   224 
       
   225   Returns:
       
   226     A subclass of django.http.HttpResponse which either contains the form to
       
   227     be filled out, or a redirect to the correct view in the interface.
       
   228   """
       
   229   # create default template context for use with any templates
       
   230   context = response_helpers.getUniversalContext(request)
       
   231 
       
   232   alt_response = simple.getAltResponseIfNotDeveloper(request,
       
   233                                                      context=context)
       
   234   if alt_response:
       
   235     return alt_response
       
   236 
       
   237   user = None  # assume that no User entity will be found
       
   238 
       
   239   if request.method == 'POST':
       
   240     form = EditForm(request.POST)
       
   241 
       
   242     if form.is_valid():
       
   243       form_id = form.cleaned_data.get('id')
       
   244       new_linkname = form.cleaned_data.get('link_name')
       
   245       nickname = form.cleaned_data.get('nick_name')
       
   246       is_developer = form.cleaned_data.get('is_developer')
       
   247       
       
   248       user = id_user.updateOrCreateUserFromId(
       
   249         form_id, link_name=new_linkname, nick_name=nickname,
       
   250         is_developer=is_developer)
       
   251 
       
   252       # redirect to new /site/user/profile/new_linkname&s=0
       
   253       # (causes 'Profile saved' message to be displayed)
       
   254       return response_helpers.redirectToChangedSuffix(
       
   255           request, linkname, new_linkname,
       
   256           params=profile.SUBMIT_PROFILE_SAVED_PARAMS)
       
   257   else: # method == 'GET':
       
   258     # try to fetch User entity corresponding to link name if one exists
       
   259     if linkname:
       
   260       user = id_user.getUserFromLinkName(linkname)
       
   261 
       
   262       if user:
       
   263         # is 'Profile saved' parameter present, but referrer was not ourself?
       
   264         # (e.g. someone bookmarked the GET that followed the POST submit) 
       
   265         if (request.GET.get(profile.SUBMIT_MSG_PARAM_NAME)
       
   266             and (not response_helpers.isReferrerSelf(request,
       
   267                                                     suffix=linkname))):
       
   268           # redirect to aggressively remove 'Profile saved' query parameter
       
   269           return http.HttpResponseRedirect(request.path)
       
   270     
       
   271         # referrer was us, so select which submit message to display
       
   272         # (may display no message if ?s=0 parameter is not present)
       
   273         context['submit_message'] = (
       
   274             template_helpers.getSingleIndexedParamValue(
       
   275                 request, profile.SUBMIT_MSG_PARAM_NAME,
       
   276                 values=profile.SUBMIT_MESSAGES))
       
   277 
       
   278         # populate form with the existing User entity
       
   279         form = EditForm(initial={
       
   280             'id': user.id, 'link_name': user.link_name,
       
   281             'nick_name': user.nick_name, 'is_developer': user.is_developer})       
       
   282       else:
       
   283         if request.GET.get(profile.SUBMIT_MSG_PARAM_NAME):
       
   284           # redirect to aggressively remove 'Profile saved' query parameter
       
   285           return http.HttpResponseRedirect(request.path)
       
   286           
       
   287         context['lookup_error'] = ugettext_lazy(
       
   288             'User with that link name not found.')
       
   289         form = EditForm(initial={'link_name': linkname})
       
   290     else:  # no link name specified in the URL
       
   291       if request.GET.get(profile.SUBMIT_MSG_PARAM_NAME):
       
   292         # redirect to aggressively remove 'Profile saved' query parameter
       
   293         return http.HttpResponseRedirect(request.path)
       
   294 
       
   295       # no link name specified, so start with an empty form
       
   296       form = EditForm()
       
   297 
       
   298   context.update({'form': form,
       
   299                   'existing_user': user})
       
   300 
       
   301   return response_helpers.respond(request, template, context)