| # 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 melange.request import access |
| from melange.templates import readonly |
| from melange.views import profile as profile_view |
| |
| from soc.views.helper import url_patterns |
| 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.templates import tabs |
| from summerofcode.views.helper import urls as soc_urls |
| |
| |
| class SocProfileFormFactory(profile_view.ProfileFormFactory): |
| """Implementation of profile_view.ProfileFormFactory to be used |
| for Summer Of Code programs. |
| """ |
| |
| def create(self, program, 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, program, terms_of_service=terms_of_service, |
| has_student_data=include_student_fields, |
| template_path=gsoc_forms.TEMPLATE_PATH, **kwargs) |
| |
| if not include_user_fields: |
| del form.fields['user_id'] |
| |
| # Summer Of Code programs do not collect grade level |
| form.fields.pop('grade', None) |
| |
| return form |
| |
| SOC_PROFILE_FORM_FACTORY = SocProfileFormFactory() |
| |
| |
| 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', |
| 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) |
| |
| |
| class ProfileShowPage(base.GSoCRequestHandler): |
| """View to display the read-only profile page.""" |
| |
| access_checker = access.HAS_PROFILE_ACCESS_CHECKER |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| soc_url_patterns.url( |
| r'profile/show/%s$' % url_patterns.PROGRAM, |
| self, name=soc_urls.UrlNames.PROFILE_SHOW)] |
| |
| def templatePath(self): |
| """See base.RequestHandler.templatePath for specification.""" |
| return 'summerofcode/profile/profile_show.html' |
| |
| def context(self, data, check, mutator): |
| """See soc.views.base.RequestHandler.context for specification.""" |
| profile_template = _getShowProfileTemplate(data, data.ndb_profile) |
| |
| return { |
| 'page_name': '%s Profile - %s' % ( |
| data.program.short_name, data.ndb_profile.public_name), |
| 'program_name': data.program.name, |
| 'profile_template': profile_template, |
| 'tabs': tabs.profileTabs( |
| data, selected_tab_id=tabs.VIEW_PROFILE_TAB_ID) |
| } |
| |
| |
| class ProfileAdminPage(base.GSoCRequestHandler): |
| """View to display the read-only profile page to program administrators.""" |
| |
| access_checker = access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| soc_url_patterns.url( |
| r'profile/admin/%s$' % url_patterns.PROFILE, |
| self, name=soc_urls.UrlNames.PROFILE_ADMIN)] |
| |
| def templatePath(self): |
| """See base.RequestHandler.templatePath for specification.""" |
| return 'summerofcode/profile/profile_show.html' |
| |
| def context(self, data, check, mutator): |
| """See soc.views.base.RequestHandler.context for specification.""" |
| profile_template = _getShowProfileTemplate(data, data.url_ndb_profile) |
| |
| return { |
| 'page_name': '%s Profile - %s' % ( |
| data.program.short_name, data.url_ndb_profile.public_name), |
| 'program_name': data.program.name, |
| 'profile_template': profile_template, |
| 'submit_tax_link': links.SOC_LINKER.profile( |
| data.url_ndb_profile, 'gsoc_tax_form_admin'), |
| 'submit_enrollment_link': links.SOC_LINKER.profile( |
| data.url_ndb_profile, 'gsoc_enrollment_form_admin') |
| } |
| |
| |
| def _getShowProfileTemplate(data, profile): |
| """Returns a template to show the specified profile. |
| |
| Args: |
| data: request_data.RequestData object for the current request. |
| profile: Profile entity. |
| |
| Returns: |
| Instance of readonly.Readonly to show the specified project. |
| """ |
| groups = [] |
| |
| fields = collections.OrderedDict() |
| fields[profile_view.USER_ID_LABEL] = profile.key.parent().id() |
| fields[profile_view.PUBLIC_NAME_LABEL] = profile.public_name |
| fields[profile_view.WEB_PAGE_LABEL] = profile.contact.web_page |
| fields[profile_view.BLOG_LABEL] = profile.contact.blog |
| fields[profile_view.PHOTO_URL_LABEL] = profile.photo_url |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._PUBLIC_INFORMATION_GROUP, |
| fields.items())) |
| |
| 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.items())) |
| |
| fields = collections.OrderedDict() |
| fields[profile_view.RESIDENTIAL_STREET_LABEL] = ( |
| _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.items())) |
| |
| if profile.shipping_address: |
| fields = collections.OrderedDict() |
| fields[profile_view.SHIPPING_STREET_LABEL] = ( |
| _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.items())) |
| |
| 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]) |
| fields[profile_view.PROGRAM_KNOWLEDGE_LABEL] = profile.program_knowledge |
| groups.append( |
| readonly.Group( |
| data, 'summerofcode/readonly/_group.html', |
| profile_view._OTHER_INFORMATION_GROUP, |
| fields.items())) |
| |
| 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.items())) |
| |
| return readonly.Readonly( |
| data, 'summerofcode/_readonly_template.html', groups) |
| |
| |
| 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 data.timeline.programActive() |
| 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 data.timeline.programActive() |
| 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 _streetValue(address): |
| if not address.street_extra: |
| return address.street |
| else: |
| return html.format_html( |
| profile_view._STREET_VALUE % (address.street, address.street_extra)) |
| |
| |
| 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 |