blob: a00dfdb57febff2f41d95ad52fdb5ff3b5969170 [file] [log] [blame]
# Copyright 2011 the Melange authors.
# 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
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# See the License for the specific language governing permissions and
# limitations under the License.
"""Module for the profile page."""
from google.appengine.ext import db
from django.forms import fields
from soc.logic import accounts
from soc.logic import cleaning
from soc.views import forms
from soc.views.helper import url_patterns
class EmptyForm(forms.ModelForm):
"""Empty form that is always valid.
def __init__(self, *args, **kwargs):
super(EmptyForm, self).__init__(forms.BoundField, *args, **kwargs)
def render(self):
return ''
def is_valid(self):
return True
# identification fields
'link_id', 'user', 'scope', 'scope_path', 'status',
'agreed_to_tos_on', 'name_on_documents',
# notification fields
'notify_new_requests', 'notify_new_invites',
'notify_invite_handled', 'notify_request_handled',
# role data fields
'student_info', 'mentor_for', 'org_admin_for',
'is_student', 'is_mentor', 'is_org_admin',
class ProfileForm(forms.ModelForm):
"""Django form for profile page.
TWO_LETTER_STATE_REQ = ['United States', 'Canada']
def __init__(self, bound_field_class=None, request_data=None,
*args, **kwargs):
super(ProfileForm, self).__init__(bound_field_class, *args, **kwargs)
self.fields['given_name'].group = "2. Contact Info (Private)"
self.fields['surname'].group = "2. Contact Info (Private)"
self.request_data = request_data
self.program = request_data.program if request_data else None
public_name = fields.CharField(required=True)
clean_public_name = cleaning.clean_html_content('public_name')
clean_name_on_documents = cleaning.clean_html_content('name_on_documents')
clean_im_network = cleaning.clean_html_content('im_network')
clean_im_handle = cleaning.clean_html_content('im_handle')
clean_program_knowledge = cleaning.clean_html_content('program_knowledge')
clean_given_name = cleaning.clean_valid_shipping_chars('given_name')
clean_surname = cleaning.clean_valid_shipping_chars('surname')
clean_email = cleaning.clean_email('email')
clean_phone = cleaning.clean_phone_number('phone')
clean_res_street = cleaning.clean_valid_shipping_chars('res_street')
clean_res_street_extra = cleaning.clean_valid_shipping_chars(
clean_res_city = cleaning.clean_valid_shipping_chars('res_city')
clean_res_state = cleaning.clean_valid_shipping_chars('res_state')
clean_res_postalcode = cleaning.clean_valid_shipping_chars(
clean_ship_name = cleaning.clean_valid_shipping_chars('ship_name')
clean_ship_street = cleaning.clean_valid_shipping_chars('ship_street')
clean_ship_street_extra = cleaning.clean_valid_shipping_chars(
clean_ship_city = cleaning.clean_valid_shipping_chars('ship_city')
clean_ship_state = cleaning.clean_valid_shipping_chars('ship_state')
clean_ship_postalcode = cleaning.clean_valid_shipping_chars(
clean_home_page = cleaning.clean_url('home_page')
clean_blog = cleaning.clean_url('blog')
clean_photo_url = cleaning.clean_url('photo_url')
def clean(self):
country = self.cleaned_data.get('res_country')
state = self.cleaned_data.get('res_state')
if country in self.TWO_LETTER_STATE_REQ and (not state or len(state) != 2):
self._errors['res_state'] = ["Please use a 2-letter state/province name"]
country = self.cleaned_data.get('ship_country')
state = self.cleaned_data.get('ship_state')
if country in self.TWO_LETTER_STATE_REQ and (not state or len(state) != 2):
self._errors['ship_state'] = ["Please use a 2-letter state/province name"]
return self.cleaned_data
class ProfilePage(object):
"""View for the participant profile.
def djangoURLPatterns(self):
return [
r'profile/%s$' % self._getEditProfileURLPattern(),
self, name=self._getEditProfileURLName()),
r'profile/%s$' % self._getCreateProfileURLPattern(),
self, name=self._getCreateProfileURLName()),
def _getTOSContent(self, data):
"""Convenience method to obtain the relevant Terms of Service content
for the role in the program.
tos_content = None
role = data.kwargs.get('role')
program = data.program
if role == 'student' and program.student_agreement:
tos_content = program.student_agreement.content
elif role == 'mentor' and program.mentor_agreement:
tos_content = program.mentor_agreement.content
elif role == 'org_admin' and program.org_admin_agreement:
tos_content = program.org_admin_agreement.content
return tos_content
def isCreateProfileRequest(self, data):
"""Returns True if the current request is supposed to create a new profile.
Otherwise, the result is false.
return data.kwargs.get('role') is not None
def isStudentRequest(self, data):
"""Returns True if the current request refers to a student which means it
is either Create or Edit Student Profile.
return data.student_info or data.kwargs.get('role') == 'student'
def prefilledProfileData(self, data):
if not data.user:
return None
profile = self._getProfileForCurrentUser(data)
if not profile:
return None
properties = {}
for property_name in
if property_name in self._getFieldsToExcludeInPrefill():
properties[property_name] = getattr(profile, property_name)
return properties
def context(self, data, check, mutator):
"""See soc.views.base.RequestHandler.context for specification."""
role = data.kwargs.get('role')
if data.student_info or role == 'student':
student_info_form = self._getStudentInfoForm(data)
# student's age should be checked
is_student = True
student_info_form = EmptyForm()
is_student = False
if not role:
page_name = 'Edit your Profile'
elif role == 'student':
page_name = 'Register as a Student'
elif role == 'mentor':
page_name = 'Register as a Mentor'
elif role == 'org_admin':
page_name = 'Register as an Org Admin'
if data.user:
user_form = EmptyForm(data.POST or None, instance=data.user)
user_form = self._getCreateUserForm(data)
if data.profile:
profile_form = self._getEditProfileForm(data, is_student)
profile_form = self._getCreateProfileForm(
data, is_student, prefill_data=True)
error = user_form.errors or profile_form.errors or student_info_form.errors
form = self._getNotificationForm(data)
notification_form = form(data.POST or None,
forms = [user_form, profile_form, notification_form, student_info_form]
context = {
'page_name': page_name,
'forms': forms,
'error': error,
return context
def validateUser(self, data, dirty):
if data.user:
return EmptyForm(), data.user
user_form = self._getCreateUserForm(data)
if not user_form.is_valid():
return user_form, None
key_name = user_form.cleaned_data['link_id']
account = data.gae_user
norm_account = accounts.normalizeAccount(account)
user_form.cleaned_data['account'] = norm_account
user_form.cleaned_data['user_id'] = account.user_id()
user = user_form.create(commit=False, key_name=key_name)
return user_form, user
def validateProfile(self, data, dirty, user):
check_age = data.student_info or data.kwargs.get('role') == 'student'
if data.profile:
profile_form = self._getEditProfileForm(data, check_age)
profile_form = self._getCreateProfileForm(data, check_age, save=True)
if not profile_form.is_valid() or not user:
return profile_form, None
key_name = '%s/%s' % (data.program.key().name(), user.link_id)
profile_form.cleaned_data['user'] = user
profile_form.cleaned_data['link_id'] = user.link_id
profile_form.cleaned_data['scope'] = data.program
if data.profile:
profile =
profile = profile_form.create(commit=False, key_name=key_name,
# synchronize the public name in the profile with the one in user = profile_form.cleaned_data['public_name']
return profile_form, profile
def validateNotifications(self, data, dirty, profile):
if not profile:
return EmptyForm(data.POST)
form = self._getNotificationForm(data)
notification_form = form(data.POST, instance=profile)
if not notification_form.is_valid():
return notification_form
if profile not in dirty:
return notification_form
def validateStudent(self, data, dirty, profile):
if not data.student_info or data.kwargs.get('role') == 'student':
return EmptyForm(data.POST)
student_form = self._getStudentInfoForm(data)
if not profile or not student_form.is_valid():
return student_form
key_name = profile.key().name()
if data.student_info:
student_info =
student_info = student_form.create(
commit=False, key_name=key_name, parent=profile)
student_info.program = data.program
profile.is_student = True
profile.student_info = student_info
return student_form
def validate(self, data):
dirty = []
user_form, user = self.validateUser(data, dirty)
if not user_form.is_valid():
return False
profile_form, profile = self.validateProfile(data, dirty, user)
notification_form = self.validateNotifications(data, dirty, profile)
student_form = self.validateStudent(data, dirty, profile)
if (user_form.is_valid() and profile_form.is_valid() and
notification_form.is_valid() and student_form.is_valid()):
db.run_in_transaction(db.put, dirty)
return True
return False
def _getModulePrefix(self):
raise NotImplementedError
def _getEditProfileURLName(self):
raise NotImplementedError
def _getCreateProfileURLName(self):
raise NotImplementedError
def _getEditProfileURLPattern(self):
raise NotImplementedError
def _getCreateProfileURLPattern(self):
raise NotImplementedError
def _getEditProfileForm(self, data, check_age):
raise NotImplementedError
def _getCreateProfileForm(
self, data, check_age, save=False, prefill_data=False):
raise NotImplementedError
def _getNotificationForm(self, data):
raise NotImplementedError
def _getStudentInfoForm(self, data):
raise NotImplementedError
def _getProfileForCurrentUser(self, data):
raise NotImplementedError
def _getFieldsToExcludeInPrefill(self):
raise NotImplementedError