| # Copyright 2013 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 |
| # |
| # 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. |
| |
| """Module containing the profile related views for Summer Of Code.""" |
| |
| import collections |
| |
| from google.appengine.ext import blobstore |
| |
| from django.utils import html |
| from django.utils import translation |
| |
| from melange.logic import timeline as timeline_logic |
| from melange.request import access |
| from melange.templates import readonly |
| from melange.views import profile as profile_view |
| |
| from soc.modules.gsoc.views import base |
| from soc.modules.gsoc.views import forms as gsoc_forms |
| from soc.modules.gsoc.views.helper import url_patterns as soc_url_patterns |
| |
| from summerofcode.logic import profile as soc_profile_logic |
| from summerofcode.request import error |
| from summerofcode.request import links |
| from summerofcode.request import render |
| from summerofcode.views.helper import urls as soc_urls |
| |
| |
| # Summer Of Code programs do not collect these fields: |
| _SKIP_FIELDS = ['grade', 'blog', 'web_page', 'photo_url'] |
| |
| TEE_SIZE_HELP_TEXT = translation.ugettext( |
| 'Size of a T-Shirt that may be sent to you upon program completion.' |
| '<br>' |
| '<a href="' |
| 'https://docs.google.com/file/d/0B7BZHIBakF7POVIwWXJHYmkwOTg/edit">' |
| 'Men\'s</a> and <a href="' |
| 'https://docs.google.com/file/d/0B7BZHIBakF7PWUZmWjAxYnVFQmc/edit">' |
| 'Women\'s</a> size charts are available to help you choose.' |
| ) |
| |
| |
| class SocProfileFormFactory(profile_view.ProfileFormFactory): |
| """Implementation of profile_view.ProfileFormFactory to be used |
| for Summer Of Code programs. |
| """ |
| |
| def create(self, request_data, terms_of_service, include_user_fields=None, |
| include_student_fields=None, **kwargs): |
| """See profile_view.ProfileFormFactory.create for specification.""" |
| form = profile_view._UserProfileForm( |
| gsoc_forms.GSoCBoundField, request_data, |
| terms_of_service=terms_of_service, |
| has_student_data=include_student_fields, |
| template_path=gsoc_forms.TEMPLATE_PATH, skip_fields=_SKIP_FIELDS, |
| **kwargs) |
| |
| if not include_user_fields: |
| del form.fields['user_id'] |
| |
| # override help_text |
| form.fields['tee_size'].help_text = TEE_SIZE_HELP_TEXT |
| |
| return form |
| |
| SOC_PROFILE_FORM_FACTORY = SocProfileFormFactory() |
| |
| |
| class SOCProfileReadonlyFactory(profile_view.ProfileReadonlyFactory): |
| """Implementation of profile_view.ProfileReadonlyFactory to be used for |
| Summer Of Code programs. |
| """ |
| |
| def create(self, data, profile): |
| """See profile_view.ProfileReadonlyFactory.create for specification.""" |
| groups = [] |
| |
| fields = collections.OrderedDict() |
| fields[profile_view.USER_ID_LABEL] = profile.key.parent().id() |
| fields[profile_view.PUBLIC_NAME_LABEL] = profile.public_name |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._BASIC_INFORMATION_GROUP, fields)) |
| |
| fields = collections.OrderedDict() |
| fields[profile_view.FIRST_NAME_LABEL] = profile.first_name |
| fields[profile_view.LAST_NAME_LABEL] = profile.last_name |
| fields[profile_view.EMAIL_LABEL] = profile.contact.email |
| fields[profile_view.PHONE_LABEL] = profile.contact.phone |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._CONTACT_GROUP, fields)) |
| |
| fields = collections.OrderedDict() |
| fields[profile_view.RESIDENTIAL_STREET_LABEL] = ( |
| profile_view.streetValue(profile.residential_address)) |
| fields[profile_view.RESIDENTIAL_CITY_LABEL] = ( |
| profile.residential_address.city) |
| fields[profile_view.RESIDENTIAL_PROVINCE_LABEL] = ( |
| profile.residential_address.province) |
| fields[profile_view.RESIDENTIAL_POSTAL_CODE_LABEL] = ( |
| profile.residential_address.postal_code) |
| fields[profile_view.RESIDENTIAL_COUNTRY_LABEL] = ( |
| profile.residential_address.country) |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._RESIDENTIAL_ADDRESS_GROUP, fields)) |
| |
| if profile.shipping_address: |
| fields = collections.OrderedDict() |
| fields[profile_view.SHIPPING_STREET_LABEL] = ( |
| profile_view.streetValue(profile.shipping_address)) |
| fields[profile_view.SHIPPING_CITY_LABEL] = profile.shipping_address.city |
| fields[profile_view.SHIPPING_PROVINCE_LABEL] = ( |
| profile.shipping_address.province) |
| fields[profile_view.SHIPPING_POSTAL_CODE_LABEL] = ( |
| profile.shipping_address.postal_code) |
| fields[profile_view.SHIPPING_COUNTRY_LABEL] = ( |
| profile.shipping_address.country) |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._SHIPPING_ADDRESS_GROUP, fields)) |
| |
| fields = collections.OrderedDict() |
| fields[profile_view.BIRTH_DATE_LABEL] = profile.birth_date |
| fields[profile_view.TEE_STYLE_LABEL] = profile.tee_style |
| fields[profile_view.TEE_SIZE_LABEL] = profile.tee_size |
| fields[profile_view.GENDER_LABEL] = ( |
| profile_view._GENDER_ENUM_TO_VERBOSE_MAP[profile.gender]) |
| |
| if profile.program_knowledge not in ( |
| [choice_id for choice_id, _ in profile_view.PROGRAM_KNOWLEDGE_CHOICES]): |
| fields[profile_view.PROGRAM_KNOWLEDGE_LABEL] = profile.program_knowledge |
| else: |
| fields[profile_view.PROGRAM_KNOWLEDGE_LABEL] = ( |
| profile_view._PROGRAM_KNOWLEDGE_ENUM_TO_VERBOSE_MAP[( |
| profile.program_knowledge)]) |
| |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._OTHER_INFORMATION_GROUP, fields)) |
| |
| if profile.is_student: |
| fields = collections.OrderedDict() |
| fields[profile_view.ENROLLMENT_FORM_LABEL] = ( |
| _getEnrollmentFormItemValue(data, profile)) |
| fields[profile_view.TAX_FORM_LABEL] = _getTaxFormItemValue(data, profile) |
| |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._FORMS_GROUP, fields)) |
| |
| return readonly.Readonly( |
| data, 'summerofcode/_readonly_template.html', groups) |
| |
| SOC_PROFILE_READONLY_FACTORY = SOCProfileReadonlyFactory() |
| |
| |
| PROFILE_REGISTER_AS_STUDENT_ACCESS_CHECKER = access.ConjuctionAccessChecker([ |
| access.HAS_NO_PROFILE_ACCESS_CHECKER, |
| access.STUDENT_SIGNUP_ACTIVE_ACCESS_CHECKER]) |
| |
| |
| PROFILE_REGISTER_AS_ORG_MEMBER_PAGE = ( |
| profile_view.ProfileRegisterAsOrgMemberPage( |
| base._GSOC_INITIALIZER, links.SOC_LINKER, render.SOC_RENDERER, |
| error.SOC_ERROR_HANDLER, soc_url_patterns.SOC_URL_PATTERN_CONSTRUCTOR, |
| soc_urls.UrlNames, 'summerofcode/profile/profile_edit.html', |
| SOC_PROFILE_FORM_FACTORY)) |
| |
| PROFILE_REGISTER_AS_STUDENT_PAGE = profile_view.ProfileRegisterAsStudentPage( |
| base._GSOC_INITIALIZER, links.SOC_LINKER, render.SOC_RENDERER, |
| error.SOC_ERROR_HANDLER, soc_url_patterns.SOC_URL_PATTERN_CONSTRUCTOR, |
| soc_urls.UrlNames, 'summerofcode/profile/profile_edit.html', |
| PROFILE_REGISTER_AS_STUDENT_ACCESS_CHECKER, SOC_PROFILE_FORM_FACTORY) |
| |
| PROFILE_EDIT_PAGE = profile_view.ProfileEditPage( |
| base._GSOC_INITIALIZER, links.SOC_LINKER, render.SOC_RENDERER, |
| error.SOC_ERROR_HANDLER, soc_url_patterns.SOC_URL_PATTERN_CONSTRUCTOR, |
| soc_urls.UrlNames, 'summerofcode/profile/profile_edit.html', |
| SOC_PROFILE_FORM_FACTORY) |
| |
| PROFILE_SHOW_PAGE = profile_view.ProfileShowPage( |
| base._GSOC_INITIALIZER, links.SOC_LINKER, render.SOC_RENDERER, |
| error.SOC_ERROR_HANDLER, soc_url_patterns.SOC_URL_PATTERN_CONSTRUCTOR, |
| soc_urls.UrlNames, 'summerofcode/profile/profile_show.html', |
| SOC_PROFILE_READONLY_FACTORY) |
| |
| PROFILE_ADMIN_PAGE = profile_view.ProfileAdminPage( |
| base._GSOC_INITIALIZER, links.SOC_LINKER, render.SOC_RENDERER, |
| error.SOC_ERROR_HANDLER, soc_url_patterns.SOC_URL_PATTERN_CONSTRUCTOR, |
| soc_urls.UrlNames, 'summerofcode/profile/profile_show.html', |
| SOC_PROFILE_READONLY_FACTORY) |
| |
| |
| def _getEnrollmentFormItemValue(data, profile): |
| """Returns a value to be displayed for Enrollment Form item in readonly |
| views for profiles. |
| |
| Args: |
| data: request_data.RequestData object for the current request. |
| profile: Profile entity. |
| |
| Returns: |
| A string to be rendered for Enrollment Form item. |
| """ |
| if data.ndb_profile.key == profile.key: |
| # the form may be still re-uploaded provided the program has not ended. |
| upload_url = ( |
| links.ABSOLUTE_LINKER.program( |
| data.program, 'gsoc_enrollment_form', secure=True) |
| if timeline_logic.isProgramActive(data.program_timeline) |
| else None) |
| download_url = links.ABSOLUTE_LINKER.program( |
| data.program, 'gsoc_enrollment_form_download') |
| else: |
| upload_url = links.ABSOLUTE_LINKER.profile( |
| profile, 'gsoc_enrollment_form_admin', secure=True) |
| download_url = links.ABSOLUTE_LINKER.profile( |
| profile, 'gsoc_enrollment_form_download_admin') |
| |
| if profile.student_data.enrollment_form: |
| blob_info = blobstore.BlobInfo.get(profile.student_data.enrollment_form) |
| return _formSubmittedValue(blob_info.filename, download_url, upload_url) |
| else: |
| return _formNotSubmittedValue(upload_url) |
| |
| |
| def _getTaxFormItemValue(data, profile): |
| """Returns a value to be displayed for Tax Form item in readonly |
| views for profiles. |
| |
| Args: |
| data: request_data.RequestData object for the current request. |
| profile: Profile entity. |
| |
| Returns: |
| A string to be rendered for Tax Form item. |
| """ |
| if data.is_host: |
| upload_url = links.ABSOLUTE_LINKER.profile( |
| profile, 'gsoc_tax_form_admin', secure=True) |
| download_url = links.ABSOLUTE_LINKER.profile( |
| profile, 'gsoc_tax_form_download_admin') |
| else: |
| # the form may be still re-uploaded provided the program has not ended. |
| upload_url = ( |
| links.ABSOLUTE_LINKER.program( |
| data.program, 'gsoc_tax_form', secure=True) |
| if timeline_logic.isProgramActive(data.program_timeline) |
| and data.timeline.afterFormSubmissionStart() |
| else None) |
| download_url = links.ABSOLUTE_LINKER.program( |
| data.program, 'gsoc_tax_form_download') |
| |
| if profile.student_data.tax_form: |
| blob_info = blobstore.BlobInfo.get(profile.student_data.tax_form) |
| return _formSubmittedValue(blob_info.filename, download_url, upload_url) |
| elif (not data.timeline.afterFormSubmissionStart() |
| or not soc_profile_logic.hasProject(profile)): |
| return _formNotRequired() |
| else: |
| return _formNotSubmittedValue(upload_url) |
| |
| |
| def _formSubmittedValue(filename, download_url, upload_url): |
| """Returns a value to be displayed for a form which has already |
| been submitted. |
| |
| Args: |
| filename: A string containing name of the uploaded file. |
| download_url: A string containing URL to download the uploaded file. |
| upload_url: An string containing URL to re-upload the form. A link |
| is not included, if this parameter is set to None. |
| |
| Returns: |
| A string to be displayed for the form. |
| """ |
| return ( |
| html.format_html( |
| profile_view._FORM_SUBMITTED_UPLOAD_FORM_OPTION % ( |
| filename, html.mark_safe(upload_url), |
| html.mark_safe(download_url))) |
| if upload_url |
| else html.format_html( |
| profile_view._FORM_SUBMITTED_NO_UPLOAD_FORM_OPTION % ( |
| filename, html.mark_safe(download_url)))) |
| |
| |
| def _formNotSubmittedValue(upload_url=None): |
| """Returns a value to be displayed for a form which has not been submitted. |
| |
| Args: |
| upload_url: A string containing URL to upload the form. A link is not |
| included, if this parameter is set to None. |
| |
| Returns: |
| A string to be displayed for the form. |
| """ |
| return ( |
| html.format_html( |
| profile_view._NO_FORM_SUBMITTED_UPLOAD_FORM_OPTION % |
| html.mark_safe(upload_url)) |
| if upload_url |
| else profile_view._NO_FORM_SUBMITTED) |
| |
| |
| def _formNotRequired(): |
| """Returns a value to be displayed for a form when it is not required |
| at this time. |
| |
| Returns: |
| A string to be displayed for the form. |
| """ |
| return profile_view._NO_FORM_REQUIRED |