# HG changeset patch # User Lennard de Rijk # Date 1233157410 0 # Node ID 5e15994b2033061c71eb29a2299a2b2611687bc8 # Parent edd125206703d4837d46c45d5735af45ac4e26f2 Redone the user's profile page. A user can now create his profile on /user/create_profile. A user can edit his profile on /user/edit_profile. Created new access checks to correctly allow access to the new profile page. Changed the /user/edit_self.html template to /user/edit_profile.html. Patch by: Lennard de Rijk Reviewed by: to-be-reviewed diff -r edd125206703 -r 5e15994b2033 app/soc/templates/soc/user/edit_profile.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/app/soc/templates/soc/user/edit_profile.html Wed Jan 28 15:43:30 2009 +0000 @@ -0,0 +1,88 @@ +{% extends "soc/base.html" %} +{% comment %} +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +{% endcomment %} +{% load forms_helpers %} +{% block page_title %}User Profile{% endblock %} +{% block header_title %} +{% if user %} +Modify Existing User Profile for {{ user.name }} <{{ account.email }}> +{% else %} +Create a New User Profile for <{{ account.email }}> +{% endif %} +{% endblock %} +{% block body %} +

+

+{% block instructions %} +Please use this form to set basic site-wide settings for your participation in Google Open Source Programs. +{% endblock %} +

+
+ + {% field_as_table_row form.name %} + + + + + + {% field_as_table_row form.link_id %} + + + + + +{% if tos_link %} + {% field_as_table_row form.agrees_to_tos %} + + + + +{% endif %} + +
+While you can use your real name, like First Last, please +keep in mind that this public name will be used as your alias +throughout the site, displayed to all users, for comments, +document ownership, and the like. You can change this public name at any +time.
+
+Please do not use your real name if you are a minor (not an +adult) where you live. +
 
+This Link ID is used throughout the site when creating various URL +links related to you and content you create. As a result, it may only +consist of lower ASCII characters, digits, and underscores. Also, it must +be unique and not in use by any other user of the site. +
 
+In order to participate on this site, you must agree to the +site-wide Terms of Service.

+(There may also be additional Terms of Service specific to participation +in certain Programs or Groups. Those are agreed to elsewhere on the site, +when signing up for the specific participation Roles.) +
 
+ + + {% block submit_buttons %} + + + {% endblock %} + +
+ + + +
+
+

+{% endblock %} diff -r edd125206703 -r 5e15994b2033 app/soc/templates/soc/user/edit_self.html --- a/app/soc/templates/soc/user/edit_self.html Wed Jan 28 15:40:44 2009 +0000 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -{% extends "soc/base.html" %} -{% comment %} -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -{% endcomment %} -{% load forms_helpers %} -{% block page_title %}User Profile{% endblock %} -{% block header_title %} -{% if user %} -Modify Existing User Profile for {{ user.name }} <{{ account.email }}> -{% else %} -Create a New User Profile for <{{ account.email }}> -{% endif %} -{% endblock %} -{% block body %} -

-

-{% block instructions %} -Please use this form to set basic site-wide settings for your participation in Google Open Source Programs. -{% endblock %} -

-
- - {% field_as_table_row form.name %} - - - - - - {% field_as_table_row form.link_id %} - - - - - -{% if tos_link %} - {% field_as_table_row form.agrees_to_tos %} - - - - -{% endif %} - -
-While you can use your real name, like First Last, please -keep in mind that this public name will be used as your alias -throughout the site, displayed to all users, for comments, -document ownership, and the like. You can change this public name at any -time.
-
-Please do not use your real name if you are a minor (not an -adult) where you live. -
 
-This Link ID is used throughout the site when creating various URL -links related to you and content you create. As a result, it may only -consist of lower ASCII characters, digits, and underscores. Also, it must -be unique and not in use by any other user of the site. -
 
-In order to participate on this site, you must agree to the -site-wide Terms of Service.

-(There may also be additional Terms of Service specific to participation -in certain Programs or Groups. Those are agreed to elsewhere on the site, -when signing up for the specific participation Roles.) -
 
- - - {% block submit_buttons %} - - - {% endblock %} - -
- - - -
-
-

-{% endblock %} diff -r edd125206703 -r 5e15994b2033 app/soc/views/helper/access.py --- a/app/soc/views/helper/access.py Wed Jan 28 15:40:44 2009 +0000 +++ b/app/soc/views/helper/access.py Wed Jan 28 15:43:30 2009 +0000 @@ -51,13 +51,13 @@ from soc.views.helper import redirects -DEF_NO_USER_LOGIN_MSG_FMT = ugettext( - 'Please create User Profile' +DEF_NO_USER_LOGIN_MSG= ugettext( + 'Please create User Profile' ' in order to view this page.') DEF_AGREE_TO_TOS_MSG_FMT = ugettext( 'You must agree to the site-wide Terms of' - ' Service in your User Profile' + ' Service in your User Profile' ' in order to view this page.') DEF_DEV_LOGOUT_LOGIN_MSG_FMT = ugettext( @@ -74,6 +74,15 @@ DEF_GROUP_NOT_FOUND_MSG = ugettext( 'The requested Group can not be found') +DEF_USER_ACCOUNT_INVALID_MSG_FMT = ugettext( + 'The %(email)s account cannot be used with this site, for' + ' one or more of the following reasons:' + '') def denySidebar(fun): """Decorator that denies access if the sidebar is calling. @@ -323,7 +332,7 @@ self.checkIsLoggedIn(django_args) if not self.user: - raise out_of_band.LoginRequest(message_fmt=DEF_NO_USER_LOGIN_MSG_FMT) + raise out_of_band.LoginRequest(message_fmt=DEF_NO_USER_LOGIN_MSG) if user_logic.agreesToSiteToS(self.user): return @@ -334,6 +343,47 @@ 'tos_link': redirects.getToSRedirect(site_logic.getSingleton())} raise out_of_band.LoginRequest(message_fmt=login_msg_fmt) + + def checkIsUnusedAccount(self, django_args): + """Raises an alternate HTTP response if Google Account has a User entity. + + Args: + django_args: a dictionary with django's arguments + + Raises: + AccessViolationResponse: + * if a User exists for the logged-in Google Account, or + * if a User has this Gooogle Account in their formerAccounts list + """ + + self.checkIsLoggedIn(django_args) + + if self.user or user_logic.isFormerAccount(self.id): + message_fmt = DEF_USER_ACCOUNT_INVALID_MSG_FMT % { + 'email' : self.id.email()} + raise out_of_band.LoginRequest(message_fmt=message_fmt) + + return + + def checkHasUserEntity(self, django_args): + """Raises an alternate HTTP response if Google Account has no User entity. + + Args: + django_args: a dictionary with django's arguments + + Raises: + AccessViolationResponse: + * if no User exists for the logged-in Google Account, or + * if no Google Account is logged in at all + """ + + self.checkIsLoggedIn(django_args) + + if not self.user: + raise out_of_band.LoginRequest(message_fmt=DEF_NO_USER_LOGIN_MSG) + + return + def checkIsDeveloper(self, django_args): """Raises an alternate HTTP response if Google Account is not a Developer. diff -r edd125206703 -r 5e15994b2033 app/soc/views/models/user_self.py --- a/app/soc/views/models/user_self.py Wed Jan 28 15:40:44 2009 +0000 +++ b/app/soc/views/models/user_self.py Wed Jan 28 15:43:30 2009 +0000 @@ -19,91 +19,36 @@ __authors__ = [ '"Sverre Rabbelier" ', + '"Lennard de Rijk" ', '"Pawel Solyga" ', ] from google.appengine.api import users -from django import forms from django import http from django.utils.encoding import force_unicode from django.utils.safestring import mark_safe from django.utils.translation import ugettext +from soc.logic import cleaning from soc.logic import dicts -from soc.logic import validate from soc.logic import models as model_logic -from soc.logic.models.site import logic as site_logic from soc.logic.models.user import logic as user_logic from soc.views import helper -from soc.views import out_of_band from soc.views.helper import access from soc.views.helper import decorators +from soc.views.helper import widgets from soc.views.models import base - -import soc.models.linkable -import soc.models.user -import soc.views.helper - - -class UserForm(helper.forms.BaseForm): - """Django form displayed when creating or editing a User. - """ - class Meta: - """Inner Meta class that defines some behavior for the form. - """ - #: db.Model subclass for which the form will gather information - model = soc.models.user.User - - #: list of model fields which will *not* be gathered by the form - exclude = ['account', 'former_accounts', 'is_developer'] - - def clean_link_id(self): - link_id = self.cleaned_data.get('link_id').lower() - if not validate.isLinkIdFormatValid(link_id): - raise forms.ValidationError("This link ID is in wrong format.") +from soc.views.models import user as user_view - user = user_logic.getForFields({'link_id': link_id}, unique=True) - - # Get the currently logged in user account - current_account = users.get_current_user() - - if user: - if current_account != user.account: - raise forms.ValidationError("This link ID is already in use.") - - return link_id - - def clean_agrees_to_tos(self): - agrees_to_tos = self.cleaned_data.get('agrees_to_tos') - - if not site_logic.getToS(site_logic.getSingleton()): - return agrees_to_tos - - # Site settings specify a site-wide ToS, so agreement is *required* - if agrees_to_tos: - return True - - raise forms.ValidationError( - 'The site-wide Terms of Service must be accepted to participate' - ' on this site.') +import soc.models.user class View(base.View): - """View methods for the User model. + """Views for User own profiles. """ - DEF_USER_ACCOUNT_INVALID_MSG_FMT = ugettext( - 'The %(email)s account cannot be used with this site, for' - ' one or more of the following reasons:' - '
    ' - '
  • the account is invalid
  • ' - '
  • the account is already attached to a User profile and cannot be' - ' used to create another one
  • ' - '
  • the account is a former account that cannot be used again
  • ' - '
') - def __init__(self, params=None): """Defines the fields and methods required for the base View class to provide the user with list, public, create, edit and delete views. @@ -115,7 +60,8 @@ rights = access.Checker(params) rights['unspecified'] = ['deny'] rights['any_access'] = ['allow'] - rights['edit'] = ['checkIsLoggedIn'] + rights['create_profile'] = ['checkIsUnusedAccount'] + rights['edit_profile'] = ['checkHasUserEntity'] rights['roles'] = ['checkIsUser'] rights['signIn'] = ['checkNotLoggedIn'] rights['notification'] = ['checkIsUser'] @@ -128,22 +74,41 @@ new_params['module_name'] = "user_self" new_params['url_name'] = "user" - new_params['edit_template'] = 'soc/user/edit_self.html' + new_params['create_template'] = 'soc/user/edit_profile.html' + new_params['edit_template'] = 'soc/user/edit_profile.html' + new_params['save_message'] = [ugettext('Profile saved.')] + new_params['edit_redirect'] = '/%(url_name)s/edit_profile' + + # set the specific fields for the users profile page + new_params['extra_dynaexclude'] = ['former_accounts', + 'account', 'is_developer'] + new_params['create_extra_dynafields'] = { + 'clean_agrees_to_tos' : cleaning.clean_agrees_to_tos('agrees_to_tos'), + 'clean_link_id': cleaning.clean_user_not_exist('link_id'),} + + new_params['edit_extra_dynafields'] = { + 'clean_link_id': cleaning.clean_link_id + } new_params['sidebar_heading'] = 'User (self)' new_params['sidebar'] = [ - (users.create_login_url("/user/edit"), 'Sign In', 'signIn'), - ('/' + new_params['url_name'] + '/edit', 'Profile', 'edit'), + (users.create_login_url("/"), 'Sign In', 'signIn'), + ('/' + new_params['url_name'] + '/create_profile', 'Create Profile', 'create_profile'), + ('/' + new_params['url_name'] + '/edit_profile', 'Edit Profile', 'edit_profile'), ('/' + new_params['url_name'] + '/roles', 'Roles', 'roles'), ] patterns = [] - page_name = "Profile" - patterns += [(r'^%(url_name)s/(?Pedit)$', + page_name = ugettext("Create your profile") + patterns += [(r'^%(url_name)s/(?Pcreate_profile)$', + 'soc.views.models.%(module_name)s.create', page_name)] + + page_name = ugettext("Edit your profile") + patterns += [(r'^%(url_name)s/(?Pedit_profile)$', 'soc.views.models.%(module_name)s.edit', page_name)] - page_name = "Requests Overview" + page_name = ugettext("List of your roles") patterns += [(r'^%(url_name)s/(?Proles)$', 'soc.views.models.request.list_self', page_name)] @@ -153,11 +118,12 @@ super(View, self).__init__(params=params) + @decorators.merge_params @decorators.check_access - def edit(self, request, access_type, + def editProfile(self, request, access_type, page_name=None, params=None, seed=None, **kwargs): - """Displays User self edit page for the entity specified by **kwargs. + """Displays User profile edit page for the current user. Args: request: the standard Django HTTP request object @@ -166,80 +132,21 @@ kwargs: The Key Fields for the specified entity """ - account = users.get_current_user() - properties = {'account': account} - - user = user_logic.getForFields(properties, unique=True) - - # create default template context for use with any templates - context = helper.responses.getUniversalContext(request) - - if request.method == 'POST': - form = UserForm(request.POST) - - if form.is_valid(): - new_link_id = form.cleaned_data.get('link_id') - properties = { - 'link_id': new_link_id, - 'name': form.cleaned_data.get('name'), - 'account': account, - 'agrees_to_tos': form.cleaned_data.get('agrees_to_tos'), - } - - # check if user account is not in former_accounts - # if it is show error message that account is invalid - if user_logic.isFormerAccount(account): - msg = self.DEF_USER_ACCOUNT_INVALID_MSG_FMT % { - 'email': account.email()} - error = out_of_band.Error(msg) - return helper.responses.errorResponse( - error, request, template=params['edit_template'], context=context) - - user = user_logic.updateOrCreateFromFields( - properties, {'link_id': new_link_id}) + # set the link_id to the current user's link_id + user_entity = user_logic.getForCurrentAccount() + link_id = user_entity.link_id - # redirect to /user/profile?s=0 - # (causes 'Profile saved' message to be displayed) - return helper.responses.redirectToChangedSuffix( - request, None, params=params['edit_params']) - else: # request.method == 'GET' - 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(params['submit_msg_param_name']) - and (not helper.requests.isReferrerSelf(request))): - # redirect to aggressively remove 'Profile saved' query parameter - return http.HttpResponseRedirect(request.path) + return self.edit(request, access_type, + page_name=page_name, params=params, seed=seed, link_id=link_id, **kwargs) - # referrer was us, so select which submit message to display - # (may display no message if ?s=0 parameter is not present) - context['notice'] = ( - helper.requests.getSingleIndexedParamValue( - request, params['submit_msg_param_name'], - values=params['save_message'])) - # populate form with the existing User entity - form = UserForm(instance=user) - else: - if request.GET.get(params['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() - - context['form'] = form - - template = params['edit_template'] - - return helper.responses.respond(request, template, context) - def _editGet(self, request, entity, form): """See base.View._editGet(). """ - # fill in the email field with the data from the entity - form.fields['email'].initial = entity.account.email() + # set the ToS example text + form.fields['agrees_to_tos'].example_text = user_view.view.getToSExampleText() + form.fields['link_id'].initial = entity.link_id super(View, self)._editGet(request, entity, form) @@ -247,11 +154,12 @@ """See base.View._editPost(). """ - # fill in the account field with the user created from email - fields['account'] = users.User(fields['email']) + # fill in the account field with the current User + fields['account'] = users.User() super(View, self)._editPost(request, entity, fields) + def getSidebarMenus(self, id, user, params=None): """See base.View.getSidebarMenus(). """ @@ -282,6 +190,7 @@ view = View() -edit = view.edit +create = view.create +edit = view.editProfile export = view.export