app/soc/views/user/profile.py
changeset 517 661ab830e921
parent 516 ec1dcd70b97e
child 518 d9d31d316a74
equal deleted inserted replaced
516:ec1dcd70b97e 517:661ab830e921
     1 #!/usr/bin/python2.5
       
     2 #
       
     3 # Copyright 2008 the Melange authors.
       
     4 #
       
     5 # Licensed under the Apache License, Version 2.0 (the "License");
       
     6 # you may not use this file except in compliance with the License.
       
     7 # You may obtain a copy of the License at
       
     8 #
       
     9 #   http://www.apache.org/licenses/LICENSE-2.0
       
    10 #
       
    11 # Unless required by applicable law or agreed to in writing, software
       
    12 # distributed under the License is distributed on an "AS IS" BASIS,
       
    13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
       
    14 # See the License for the specific language governing permissions and
       
    15 # limitations under the License.
       
    16 
       
    17 """Views for editing and examining User profiles.
       
    18 """
       
    19 
       
    20 __authors__ = [
       
    21   '"Pawel Solyga" <pawel.solyga@gmail.com>',
       
    22   ]
       
    23 
       
    24 
       
    25 from google.appengine.api import users
       
    26 
       
    27 from django import forms
       
    28 from django import http
       
    29 from django.utils.translation import ugettext_lazy
       
    30 
       
    31 from soc.logic import accounts
       
    32 from soc.logic import models
       
    33 from soc.logic import out_of_band
       
    34 from soc.logic import validate
       
    35 from soc.views import helper
       
    36 from soc.views import simple
       
    37 from soc.views.helper import decorators
       
    38 
       
    39 import soc.logic
       
    40 import soc.models.user
       
    41 import soc.views.helper.forms
       
    42 import soc.views.helper.requests
       
    43 import soc.views.helper.responses
       
    44 
       
    45 
       
    46 class UserForm(helper.forms.BaseForm):
       
    47   """Django form displayed when creating or editing a User.
       
    48   """
       
    49   class Meta:
       
    50     """Inner Meta class that defines some behavior for the form.
       
    51     """
       
    52     #: db.Model subclass for which the form will gather information
       
    53     model = soc.models.user.User
       
    54     
       
    55     #: list of model fields which will *not* be gathered by the form
       
    56     exclude = ['account', 'former_accounts', 'is_developer']
       
    57   
       
    58   def clean_link_id(self):
       
    59     link_id = self.cleaned_data.get('link_id')
       
    60     if not validate.isLinkIdFormatValid(link_id):
       
    61       raise forms.ValidationError("This link ID is in wrong format.")
       
    62 
       
    63     user = models.user.logic.getForFields({'link_id': link_id},
       
    64                                           unique=True)
       
    65     
       
    66     # Get the currently logged in user account
       
    67     current_account = users.get_current_user()
       
    68     
       
    69     if user:
       
    70       if current_account != user.account:
       
    71         raise forms.ValidationError("This link ID is already in use.")
       
    72 
       
    73     return link_id
       
    74 
       
    75 
       
    76 DEF_USER_PROFILE_EDIT_TMPL = 'soc/user/edit_self.html'
       
    77 DEF_USER_ACCOUNT_INVALID_MSG = 'This account is invalid.'
       
    78 
       
    79 SUBMIT_MSG_PARAM_NAME = 's'
       
    80 
       
    81 SUBMIT_MESSAGES = (
       
    82   ugettext_lazy('Profile saved.'),
       
    83 )
       
    84 
       
    85 SUBMIT_MSG_PROFILE_SAVED = 0
       
    86 
       
    87 SUBMIT_PROFILE_SAVED_PARAMS = {
       
    88   SUBMIT_MSG_PARAM_NAME: SUBMIT_MSG_PROFILE_SAVED,
       
    89 }
       
    90 
       
    91 @decorators.view
       
    92 def edit(request, page_name=None, link_id=None, 
       
    93          template=DEF_USER_PROFILE_EDIT_TMPL):
       
    94   """View for a User to modify the properties of a User Model entity.
       
    95 
       
    96   Args:
       
    97     request: the standard django request object
       
    98     page_name: the page name displayed in templates as page and header title
       
    99     link_id: the User's site-unique "link_id" extracted from the URL
       
   100     template: the template path to use for rendering the template
       
   101 
       
   102   Returns:
       
   103     A subclass of django.http.HttpResponse which either contains the form to
       
   104     be filled out, or a redirect to the correct view in the interface.
       
   105   """
       
   106   account = users.get_current_user()
       
   107   
       
   108   # create default template context for use with any templates
       
   109   context = helper.responses.getUniversalContext(request)
       
   110 
       
   111   if (not account) and (not link_id):
       
   112     # not logged in, and no link ID, so request that the user sign in 
       
   113     return simple.requestLogin(request, page_name, template, context,
       
   114         # TODO(tlarsen): /user/profile could be a link to a help page instead
       
   115         login_message_fmt=ugettext_lazy(
       
   116             'To create a new <a href="/user/profile">User Profile</a>'
       
   117             ' or modify an existing one, you must first'
       
   118             ' <a href="%(sign_in)s">sign in</a>.'))
       
   119 
       
   120   if (not account) and link_id:
       
   121     # not logged in, so show read-only public profile for link_id user
       
   122     return simple.public(request, page_name=page_name, template=template, 
       
   123                          link_id=link_id, context=context)
       
   124 
       
   125   link_id_user = None
       
   126 
       
   127   # try to fetch User entity corresponding to link_id if one exists
       
   128   try:
       
   129     if link_id:
       
   130       link_id_user = accounts.getUserFromLinkIdOr404(link_id)
       
   131   except out_of_band.ErrorResponse, error:
       
   132     # show custom 404 page when link ID doesn't exist in Datastore
       
   133     return simple.errorResponse(request, page_name, error, template, context)
       
   134   
       
   135   # link_id_user will be None here if link ID was already None...
       
   136   if link_id_user and (link_id_user.account != account):
       
   137     # link_id_user exists but is not the currently logged in Google Account,
       
   138     # so show public view for that (other) User entity
       
   139     return simple.public(request, page_name=page_name, template=template, 
       
   140                          link_id=link_id, context=context)
       
   141 
       
   142   if request.method == 'POST':
       
   143     form = UserForm(request.POST)
       
   144 
       
   145     if form.is_valid():
       
   146       new_link_id = form.cleaned_data.get('link_id')
       
   147       properties = {
       
   148         'link_id': new_link_id,
       
   149         'nick_name': form.cleaned_data.get("nick_name"),
       
   150         'account': account,
       
   151       }
       
   152 
       
   153       # check if user account is not in former_accounts
       
   154       # if it is show error message that account is invalid
       
   155       if models.user.logic.isFormerAccount(account):
       
   156         msg = DEF_USER_ACCOUNT_INVALID_MSG
       
   157         error = out_of_band.ErrorResponse(msg)
       
   158         return simple.errorResponse(request, page_name, error, template, context)
       
   159       
       
   160       user = models.user.logic.updateOrCreateFromFields(properties, {'link_id': new_link_id})
       
   161       
       
   162       # redirect to /user/profile?s=0
       
   163       # (causes 'Profile saved' message to be displayed)
       
   164       return helper.responses.redirectToChangedSuffix(
       
   165           request, None, params=SUBMIT_PROFILE_SAVED_PARAMS)
       
   166   else: # request.method == 'GET'
       
   167     # try to fetch User entity corresponding to Google Account if one exists
       
   168     user = models.user.logic.getForFields({'account': account}, unique=True)
       
   169 
       
   170     if user:
       
   171       # is 'Profile saved' parameter present, but referrer was not ourself?
       
   172       # (e.g. someone bookmarked the GET that followed the POST submit) 
       
   173       if (request.GET.get(SUBMIT_MSG_PARAM_NAME)
       
   174           and (not helper.requests.isReferrerSelf(request,
       
   175                                                   suffix=link_id))):
       
   176         # redirect to aggressively remove 'Profile saved' query parameter
       
   177         return http.HttpResponseRedirect(request.path)
       
   178     
       
   179       # referrer was us, so select which submit message to display
       
   180       # (may display no message if ?s=0 parameter is not present)
       
   181       context['notice'] = (
       
   182           helper.requests.getSingleIndexedParamValue(
       
   183               request, SUBMIT_MSG_PARAM_NAME, values=SUBMIT_MESSAGES))
       
   184 
       
   185       # populate form with the existing User entity
       
   186       form = UserForm(instance=user)
       
   187     else:
       
   188       if request.GET.get(SUBMIT_MSG_PARAM_NAME):
       
   189         # redirect to aggressively remove 'Profile saved' query parameter
       
   190         return http.HttpResponseRedirect(request.path)
       
   191 
       
   192       # no User entity exists for this Google Account, so show a blank form
       
   193       form = UserForm()
       
   194 
       
   195   context['form'] = form
       
   196   return helper.responses.respond(request, template, context)
       
   197 
       
   198 
       
   199 @decorators.view
       
   200 def create(request, page_name=None, template=DEF_USER_PROFILE_EDIT_TMPL):
       
   201   """create() view is same as edit() view, but with no link_id supplied.
       
   202   """
       
   203   return edit(request, page_name=page_name, link_id=None, template=template)