| # Copyright 2014 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 for organization administrators to nominate winners.""" |
| |
| import collections |
| import logging |
| |
| from google.appengine.ext import ndb |
| |
| from django import forms |
| from django import http |
| from django.utils import translation |
| |
| from codein.logic import profile as ci_profile_logic |
| from codein.logic import task_counts as task_counts_logic |
| from codein.logic import winners as winners_logic |
| from codein.request import access as ci_access |
| from codein.request import error |
| from codein.request import render |
| from codein.views.helper import urls as ci_urls |
| |
| from melange.logic import organization as org_logic |
| from melange.logic import profile as profile_logic |
| from melange.models import organization as org_model |
| from melange.request import access |
| from melange.request import exception |
| from melange.request import links |
| from melange.templates.helper import select |
| |
| from soc.modules.gci.views import base as gci_base |
| from soc.modules.gci.views import forms as gci_forms |
| from soc.views import base |
| from soc.views.helper import lists |
| from soc.views.helper import url_patterns |
| from soc.modules.gci.templates import org_list |
| from soc.modules.gci.views.helper import url_patterns as ci_url_patterns |
| |
| |
| # Winners and finalists for an organization can be nominated among the first |
| # ten students who completed most tasks for the given organization. |
| _PLACE_LIMIT = 10 |
| |
| _NUMBER_OF_WINNERS = 2 |
| _NUMBER_OF_FINALISTS = 2 |
| |
| BACKUP_WINNER_LABEL = translation.ugettext('Backup winner') |
| |
| FINALIST_LABEL = translation.ugettext('Finalist') |
| |
| WINNER_LABEL = translation.ugettext('Grand Prize Winner') |
| |
| NOMINATE_WINNERS_PAGE_NAME = translation.ugettext('Nominate winners') |
| |
| WRONG_NUMBER_OF_WINNERS = translation.ugettext( |
| 'You need to choose exactly %s different winners.' % _NUMBER_OF_WINNERS) |
| |
| WRONG_NUMBER_OF_FINALISTS = translation.ugettext( |
| 'You need to choose exactly %s different finalists.' % _NUMBER_OF_FINALISTS) |
| |
| NO_BACKUP_WINNER = translation.ugettext('You need to specify a backup winner.') |
| |
| NOT_UNIQUE_CHOICES = translation.ugettext( |
| 'You need to specify different users.') |
| |
| _FINALIST_NOT_ELIGIBLE_NOT_STUDENT = translation.ugettext( |
| 'User %s is not eligible to become a finalist because he or she does not ' |
| 'participate as a student in the program.') |
| |
| _FINALIST_NOT_ELIGIBLE_ALREADY_FINALIST = translation.ugettext( |
| 'User %s is not eligible to become a finalist because he or she is already ' |
| 'selected as a finalist for %s.') |
| |
| _FINALIST_NOT_ELIGIBLE_ALREADY_WINNER = translation.ugettext( |
| 'User %s is not eligible to become a finalist because he or she is already ' |
| 'selected as a winner for %s.') |
| |
| _WINNERS_NOT_ELIGIBLE_NOT_STUDENT = translation.ugettext( |
| 'User %s is not eligible to become a winner because he or she does not ' |
| 'participate as a student in the program.') |
| |
| _WINNER_NOT_ELIGIBLE_ALREADY_FINALIST = translation.ugettext( |
| 'User %s is not eligible to become a winner because he or she is already ' |
| 'selected as a finalist for %s.') |
| |
| _WINNER_NOT_ELIGIBLE_ALREADY_WINNER = translation.ugettext( |
| 'User %s is not eligible to become a winner because he or she is already ' |
| 'selected as a winner for %s.') |
| |
| _NOMINATION_WARNING_MESSAGE_MAP = { |
| winners_logic.WinnerNominationWarning.not_enough_winners: |
| translation.ugettext('Not all winners have been nominated so far.'), |
| winners_logic.WinnerNominationWarning.too_many_winners: |
| translation.ugettext('Too many winners have been nominated.'), |
| winners_logic.WinnerNominationWarning.not_enough_finalists: |
| translation.ugettext('Not all finalists have been nominated so far.'), |
| winners_logic.WinnerNominationWarning.too_many_finalists: |
| translation.ugettext('Too many finalists have been nominated.'), |
| winners_logic.WinnerNominationWarning.no_backup_winner: |
| translation.ugettext('Backup winner has not been nominated.'), |
| } |
| |
| NominateWinnersFormData = collections.namedtuple( |
| 'NominateWinnersFormData', ['winners', 'backup_winner', 'finalists']) |
| |
| |
| def _getWinnerFieldId(index): |
| """Returns identifier for a form field to choose a winner with the specified |
| index. |
| |
| Args: |
| index: An int specifying index of the winner field. |
| |
| Returns: |
| A string containing identifier for a form field. |
| """ |
| return 'winner-%s' % index |
| |
| |
| def _getFinalistFieldId(index): |
| """Returns identifier for a form field to choose a finalist with the specified |
| index. |
| |
| Args: |
| index: An int specifying index of the finalist field. |
| |
| Returns: |
| A string containing identifier for a form field. |
| """ |
| return 'finalist-%s' % index |
| |
| |
| class NominateWinnersForm(gci_forms.GCIModelForm): |
| """Form to nominate the grand prize winners and finalists.""" |
| |
| EMPTY_CHOICE = '' |
| |
| def __init__(self, request_data, **kwargs): |
| super(NominateWinnersForm, self).__init__(**kwargs) |
| self.request_data = request_data |
| |
| choices = [(NominateWinnersForm.EMPTY_CHOICE, '---')] |
| |
| task_counts = task_counts_logic.getStudentsByTaskCountForOrg( |
| self.request_data.url_ndb_org.key, limit=_PLACE_LIMIT) |
| students = ndb.get_multi(task_counts.keys()) |
| for student in students: |
| choices.append(self._getChoiceOption(student)) |
| |
| for i in range(_NUMBER_OF_WINNERS): |
| self.fields[_getWinnerFieldId(i)] = ( |
| forms.ChoiceField(label=WINNER_LABEL, choices=choices)) |
| if len(self.request_data.url_ndb_org.nominated_winners) > i: |
| self.fields[_getWinnerFieldId(i)].initial = ( |
| self.request_data.url_ndb_org.nominated_winners[i].urlsafe()) |
| |
| self.fields['backup-winner'] = ( |
| forms.ChoiceField(label=BACKUP_WINNER_LABEL, choices=choices)) |
| if self.request_data.url_ndb_org.nominated_backup_winner: |
| self.fields['backup-winner'].initial = ( |
| self.request_data.url_ndb_org.nominated_backup_winner.urlsafe()) |
| |
| for i in range(_NUMBER_OF_FINALISTS): |
| self.fields[_getFinalistFieldId(i)] = ( |
| forms.ChoiceField(label=FINALIST_LABEL, choices=choices)) |
| if len(self.request_data.url_ndb_org.nominated_finalists) > i: |
| self.fields[_getFinalistFieldId(i)].initial = ( |
| self.request_data.url_ndb_org.nominated_finalists[i].urlsafe()) |
| |
| def clean(self): |
| """See forms.Form.clean for specification.""" |
| winners = set() |
| backup_winner = None |
| finalists = set() |
| |
| for field_id, value in self.cleaned_data.iteritems(): |
| if field_id.startswith('winner'): |
| winners.add(ndb.Key(urlsafe=value)) |
| elif field_id == 'backup-winner': |
| backup_winner = ndb.Key(urlsafe=value) |
| elif field_id.startswith('finalist'): |
| finalists.add(ndb.Key(urlsafe=value)) |
| |
| if len(winners) != _NUMBER_OF_WINNERS: |
| self.addGlobalFormError(WRONG_NUMBER_OF_WINNERS) |
| |
| if len(finalists) != _NUMBER_OF_FINALISTS: |
| self.addGlobalFormError(WRONG_NUMBER_OF_FINALISTS) |
| |
| if not backup_winner: |
| self.addGlobalFormError(NO_BACKUP_WINNER) |
| |
| if winners & finalists or backup_winner in winners | finalists: |
| self.addGlobalFormError(NOT_UNIQUE_CHOICES) |
| |
| return NominateWinnersFormData( |
| winners=winners, backup_winner=backup_winner, finalists=finalists) |
| |
| def addGlobalFormError(self, message): |
| """Adds the specified message to the dictionary of global errors for |
| the form. |
| |
| Args: |
| message: A string that contains the error message. |
| """ |
| if '__all__' not in self._errors: |
| self._errors['__all__'] = [message] |
| else: |
| self._errors['__all__'].append(message) |
| |
| def _getChoiceOption(self, student): |
| """Returns a choice for ChoiceField for the specified student. |
| |
| Args: |
| student: profile_model.Profile entity of the student. |
| |
| Returns: |
| A tupe which is an option for ChoiceField. |
| """ |
| return (student.key.urlsafe(), self._formatChoice(student)) |
| |
| def _formatChoice(self, student): |
| """Format the possible choice to be displayed to users. |
| |
| Args: |
| student: profile_model.Profile entity of the student. |
| |
| Returns: |
| A string to be used for the choice. |
| """ |
| return student.public_name |
| |
| |
| class NominateWinnersPage(base.RequestHandler): |
| """Page for organization administrators to nominate winners and finalists.""" |
| |
| access_checker = access.ConjuctionAccessChecker( |
| [ci_access.WORK_REVIEWED_ACCESS_CHECKER, |
| access.IS_USER_ORG_ADMIN_FOR_NDB_ORG]) |
| |
| def __init__(self, initializer, linker, renderer, error_handler, |
| url_pattern_constructor, url_names, template_path): |
| """Initializes a new instance of the request handler for the specified |
| parameters. |
| |
| Args: |
| initializer: Implementation of initialize.Initializer interface. |
| linker: Instance of links.Linker class. |
| renderer: Implementation of render.Renderer interface. |
| error_handler: Implementation of error.ErrorHandler interface. |
| url_pattern_constructor: |
| Implementation of url_patterns.UrlPatternConstructor. |
| url_names: Instance of url_names.UrlNames. |
| template_path: The path of the template to be used. |
| form_factory: Implementation of ProfileFormFactory interface. |
| """ |
| super(NominateWinnersPage, self).__init__( |
| initializer, linker, renderer, error_handler) |
| self.url_pattern_constructor = url_pattern_constructor |
| self.url_names = url_names |
| self.template_path = template_path |
| |
| def templatePath(self): |
| """See base.RequestHandler.templatePath for specification.""" |
| return self.template_path |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| self.url_pattern_constructor.construct( |
| r'org/nominate_winners/%s$' % url_patterns.ORG, |
| self, name=self.url_names.ORG_NOMINATE_WINNERS)] |
| |
| def context(self, data, check, mutator): |
| """See base.RequestHandler.context for specification.""" |
| form = NominateWinnersForm(data, data=data.POST) |
| return { |
| 'error': bool(form.errors), |
| 'forms': [form], |
| 'page_name': NOMINATE_WINNERS_PAGE_NAME |
| } |
| |
| def post(self, data, check, mutator): |
| """See base.RequestHandler.post for specification.""" |
| form = NominateWinnersForm(data, data=data.POST) |
| |
| if not form.is_valid(): |
| return self.get(data, check, mutator) |
| else: |
| updateNominatedWinners( |
| data.url_ndb_org.key, form.cleaned_data.winners, |
| form.cleaned_data.backup_winner, form.cleaned_data.finalists) |
| |
| url = links.LINKER.organization( |
| data.url_ndb_org.key, self.url_names.ORG_NOMINATE_WINNERS) |
| return http.HttpResponseRedirect(url) |
| |
| NOMINATE_WINNERS_PAGE = NominateWinnersPage( |
| gci_base._GCI_INITIALIZER, links.LINKER, render.CI_RENDERER, |
| error.CI_ERROR_HANDLER, ci_url_patterns.CI_URL_PATTERN_CONSTRUCTOR, |
| ci_urls.UrlNames, 'codein/winners/nominate_winners.html') |
| |
| |
| @ndb.transactional |
| def updateNominatedWinners(org_key, winners, backup_winner, finalists): |
| """Updates nominated winners for the specified organization. |
| |
| Args: |
| org_key: ndb.Key of the organization. |
| winners: List of ndb.Key of profiles of the nominated winners. |
| backup_winners: ndb.Key of profile of the nominated backup winner. |
| finalists: List of ndb.Key of profiles of the nominated finalists. |
| """ |
| org = org_key.get() |
| org_properties = { |
| 'nominated_winners': winners, |
| 'nominated_backup_winner': backup_winner, |
| 'nominated_finalists': finalists, |
| } |
| org_logic.updateOrganization(org, org_properties=org_properties) |
| |
| |
| class NominateWinnersOrganizationsList(org_list.OrgList): |
| """Lists all organizations for which the current user may nominate winners |
| and the row action takes them to Nominate Winners page for the corresponding |
| organization. |
| """ |
| |
| def _getDescription(self): |
| return translation.ugettext( |
| 'Choose an organization for which to nominate winners and finalists') |
| |
| def getListData(self): |
| """Returns the list data as requested by the current request. |
| |
| If the lists as requested is not supported by this component None is |
| returned. |
| """ |
| if lists.getListIndex(self.data.request) != 0: |
| return None |
| |
| orgs = ndb.get_multi(self.data.ndb_profile.admin_for) |
| |
| response = lists.ListContentResponse(self.data.request, self._list_config) |
| |
| for org in orgs: |
| response.addRow(org) |
| response.next = 'done' |
| |
| return response |
| |
| def _getListConfig(self): |
| """Returns ListConfiguration object for the list.""" |
| list_config = lists.ListConfiguration() |
| list_config.addPlainTextColumn('name', 'Name', |
| lambda e, *args: e.name.strip()) |
| list_config.addSimpleColumn('org_id', 'Organization ID', hidden=True) |
| list_config.setRowAction( |
| lambda e, *args: links.LINKER.organization( |
| e.key, ci_urls.UrlNames.ORG_NOMINATE_WINNERS)) |
| return list_config |
| |
| |
| class NominateWinnersPickOrganizationPage(base.RequestHandler): |
| """Page with a list of organizations. When a user clicks on one of them, |
| he or she is moved to the propose winner page for this organization. |
| """ |
| |
| access_checker = access.NON_STUDENT_PROFILE_ACCESS_CHECKER |
| |
| def __init__(self, initializer, linker, renderer, error_handler, |
| url_pattern_constructor, url_names, template_path): |
| """Initializes a new instance of the request handler for the specified |
| parameters. |
| |
| Args: |
| initializer: Implementation of initialize.Initializer interface. |
| linker: Instance of links.Linker class. |
| renderer: Implementation of render.Renderer interface. |
| error_handler: Implementation of error.ErrorHandler interface. |
| url_pattern_constructor: |
| Implementation of url_patterns.UrlPatternConstructor. |
| url_names: Instance of url_names.UrlNames. |
| template_path: The path of the template to be used. |
| form_factory: Implementation of ProfileFormFactory interface. |
| """ |
| super(NominateWinnersPickOrganizationPage, self).__init__( |
| initializer, linker, renderer, error_handler) |
| self.url_pattern_constructor = url_pattern_constructor |
| self.url_names = url_names |
| self.template_path = template_path |
| |
| def templatePath(self): |
| """See base.RequestHandler.templatePath for specification.""" |
| return self.template_path |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| self.url_pattern_constructor.construct( |
| r'org/pick_org_to_nominate_winners/%s$' % url_patterns.PROGRAM, |
| self, name=self.url_names.ORG_NOMINATE_WINNERS_PICK_ORG)] |
| |
| def jsonContext(self, data, check, mutator): |
| list_content = NominateWinnersOrganizationsList(data).getListData() |
| if list_content: |
| return list_content.content() |
| else: |
| raise exception.Forbidden(message='You do not have access to this data') |
| |
| def context(self, data, check, mutator): |
| return { |
| 'page_name': 'Choose an organization for which to nominate winners.', |
| 'org_list': NominateWinnersOrganizationsList(data), |
| } |
| |
| NOMINAGE_WINNERS_PICK_ORGANIZATION_PAGE = NominateWinnersPickOrganizationPage( |
| gci_base._GCI_INITIALIZER, links.LINKER, render.CI_RENDERER, |
| error.CI_ERROR_HANDLER, ci_url_patterns.CI_URL_PATTERN_CONSTRUCTOR, |
| ci_urls.UrlNames, 'modules/gci/org_list/base.html') |
| |
| |
| SelectedProfile = collections.namedtuple( |
| 'SelectedProfile', ['profile', 'name', 'unselect_url']) |
| |
| OrgWinnerSelection = collections.namedtuple( |
| 'OrgWinnerSelection', |
| ['organization', 'nominated_winners', 'nominated_backup_winner', |
| 'nominated_finalists', 'selected_winners', 'selected_finalists', |
| 'add_winner_url', 'add_finalist_url', 'selectable_options', |
| 'warning_messages']) |
| |
| class WinnersManageSelectionPage(base.RequestHandler): |
| """Page for program administrators to manage and finalize selection of |
| winners and finalists for the program.""" |
| |
| access_checker = access.ConjuctionAccessChecker( |
| [ci_access.WORK_REVIEWED_ACCESS_CHECKER, |
| access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER]) |
| |
| def __init__(self, initializer, linker, renderer, error_handler, |
| url_pattern_constructor, url_names, template_path): |
| """Initializes a new instance of the request handler for the specified |
| parameters. |
| |
| Args: |
| initializer: Implementation of initialize.Initializer interface. |
| linker: Instance of links.Linker class. |
| renderer: Implementation of render.Renderer interface. |
| error_handler: Implementation of error.ErrorHandler interface. |
| url_pattern_constructor: |
| Implementation of url_patterns.UrlPatternConstructor. |
| url_names: Instance of url_names.UrlNames. |
| template_path: The path of the template to be used. |
| """ |
| super(WinnersManageSelectionPage, self).__init__( |
| initializer, linker, renderer, error_handler) |
| self.url_pattern_constructor = url_pattern_constructor |
| self.url_names = url_names |
| self.template_path = template_path |
| |
| def templatePath(self): |
| """See base.RequestHandler.templatePath for specification.""" |
| return self.template_path |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| self.url_pattern_constructor.construct( |
| r'winners/manage_selection/%s$' % url_patterns.PROGRAM, |
| self, name=self.url_names.WINNERS_MANAGE_SELECTION)] |
| |
| def context(self, data, check, mutator): |
| """See base.RequestHandler.context for specification.""" |
| winner_selections = [] |
| |
| orgs = data.models.ndb_org_model.query( |
| org_model.Organization.program == |
| ndb.Key.from_old_key(data.program.key()), |
| org_model.Organization.status == org_model.Status.ACCEPTED).fetch(1000) |
| for org in orgs: |
| profile_keys = [] |
| profile_keys.extend(org.nominated_winners) |
| if org.nominated_backup_winner: |
| profile_keys.append(org.nominated_backup_winner) |
| profile_keys.extend(org.nominated_finalists) |
| profiles = ndb.get_multi(profile_keys) |
| |
| nominated_winners = [] |
| nominated_backup_winner = None |
| nominated_finalists = [] |
| for profile in profiles: |
| if profile.key in org.nominated_winners: |
| nominated_winners.append(profile) |
| elif profile.key == org.nominated_backup_winner: |
| nominated_backup_winner = profile |
| elif profile.key in org.nominated_finalists: |
| nominated_finalists.append(profile) |
| |
| add_winner_url = links.LINKER.organization( |
| org.key, self.url_names.WINNERS_ADD_WINNER) |
| add_finalist_url = links.LINKER.organization( |
| org.key, self.url_names.WINNERS_ADD_FINALIST) |
| |
| selected_winners = [] |
| for profile in ci_profile_logic.getWinnersForOrg(org.key): |
| selected_winners.append( |
| SelectedProfile( |
| profile, |
| profile.public_name, |
| links.LINKER.profile( |
| profile, self.url_names.WINNERS_UNSELECT, |
| category='winner'))) |
| |
| selected_finalists = [] |
| for profile in ci_profile_logic.getFinalistsForOrg(org.key): |
| selected_finalists.append( |
| SelectedProfile( |
| profile, |
| profile.public_name, |
| links.LINKER.profile( |
| profile, self.url_names.WINNERS_UNSELECT, |
| category='finalist'))) |
| |
| # list of all students that can still be selected as winners or finalists |
| selectable_options = [] |
| |
| student_keys = set( |
| task_counts_logic.getStudentsByTaskCountForOrg( |
| org.key, limit=_PLACE_LIMIT).keys()) |
| |
| # remove students who are already selected as winners or finalists |
| student_keys.difference_update( |
| set(winner.profile.key for winner in selected_winners)) |
| student_keys.difference_update( |
| set(finalist.profile.key for finalist in selected_finalists)) |
| |
| students = ndb.get_multi(student_keys) |
| for student in students: |
| student_name = "%s / %s (%s)" % ( |
| student.public_name, student.legal_name, student.profile_id) |
| selectable_options.append( |
| select.SelectOption(student.key.urlsafe(), student_name)) |
| |
| warning_messages = [] |
| for warning in winners_logic.getWinnerNominationWarnings(org): |
| warning_messages.append(_NOMINATION_WARNING_MESSAGE_MAP[warning]) |
| |
| # this is supposed to be prevented by the logic; |
| # log a warning if it happens so that it can be spotted |
| if warning == winners_logic.WinnerNominationWarning.too_many_finalists: |
| logging.warning('Too many winners nominated by %r.', org.key) |
| |
| if warning == winners_logic.WinnerNominationWarning.too_many_finalists: |
| logging.warning('Too many finalists nominated by %r.', org.key) |
| |
| winner_selections.append( |
| OrgWinnerSelection( |
| org, nominated_winners, nominated_backup_winner, |
| nominated_finalists, selected_winners, selected_finalists, |
| add_winner_url, add_finalist_url, selectable_options, |
| warning_messages)) |
| |
| return { |
| 'org_selection_panels': winner_selections, |
| 'page_name': NOMINATE_WINNERS_PAGE_NAME |
| } |
| |
| WINNERS_MANAGE_SELECTION_PAGE = WinnersManageSelectionPage( |
| gci_base._GCI_INITIALIZER, links.LINKER, render.CI_RENDERER, |
| error.CI_ERROR_HANDLER, ci_url_patterns.CI_URL_PATTERN_CONSTRUCTOR, |
| ci_urls.UrlNames, 'codein/winners/manage_winner_selection.html') |
| |
| |
| class WinnersAddWinnerForOrg(base.RequestHandler): |
| """Handler to add a winner for the specified organization by program |
| administrators. |
| """ |
| |
| access_checker = access.ConjuctionAccessChecker( |
| [ci_access.WORK_REVIEWED_ACCESS_CHECKER, |
| access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER]) |
| |
| def __init__(self, initializer, linker, renderer, error_handler, |
| url_pattern_constructor, url_names): |
| """Initializes a new instance of the request handler for the specified |
| parameters. |
| |
| Args: |
| initializer: Implementation of initialize.Initializer interface. |
| linker: Instance of links.Linker class. |
| renderer: Implementation of render.Renderer interface. |
| error_handler: Implementation of error.ErrorHandler interface. |
| url_pattern_constructor: |
| Implementation of url_patterns.UrlPatternConstructor. |
| url_names: Instance of url_names.UrlNames. |
| """ |
| super(WinnersAddWinnerForOrg, self).__init__( |
| initializer, linker, renderer, error_handler) |
| self.url_pattern_constructor = url_pattern_constructor |
| self.url_names = url_names |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| self.url_pattern_constructor.construct( |
| r'winners/add_winner/%s$' % url_patterns.ORG, |
| self, name=self.url_names.WINNERS_ADD_WINNER)] |
| |
| def post(self, data, check, mutator): |
| """See base.RequestHandler.post for specification.""" |
| if 'winner' not in data.POST: |
| raise exception.BadRequest('winner not found in POST data.') |
| else: |
| profile_key = ndb.Key(urlsafe=data.POST['winner']) |
| result = ci_profile_logic.setWinnerForOrg( |
| profile_key, data.url_ndb_org.key) |
| if result: |
| url = links.LINKER.program( |
| data.program, self.url_names.WINNERS_MANAGE_SELECTION) |
| return http.HttpResponseRedirect(url) |
| elif result.extra == ci_profile_logic.ALREADY_WINNER: |
| profile = profile_key.get() |
| raise exception.BadRequest( |
| message=_WINNER_NOT_ELIGIBLE_ALREADY_WINNER % ( |
| profile.key.id(), profile.student_data.winner_for.get().name)) |
| elif result.extra == ci_profile_logic.ALREADY_FINALIST: |
| profile = profile_key.get() |
| raise exception.BadRequest( |
| message=_WINNER_NOT_ELIGIBLE_ALREADY_FINALIST % ( |
| profile_key.id(), |
| profile.student_data.finalist_for.get().name)) |
| elif result.extra == ci_profile_logic.NOT_STUDENT: |
| profile = profile_key.get() |
| raise exception.BadRequest( |
| message=_WINNERS_NOT_ELIGIBLE_NOT_STUDENT % profile_key.id()) |
| else: |
| raise exception.BadRequest(messsage='Unknown error') |
| |
| WINNERS_ADD_WINNER_FOR_ORG = WinnersAddWinnerForOrg( |
| gci_base._GCI_INITIALIZER, links.LINKER, render.CI_RENDERER, |
| error.CI_ERROR_HANDLER, ci_url_patterns.CI_URL_PATTERN_CONSTRUCTOR, |
| ci_urls.UrlNames) |
| |
| |
| class WinnersAddFinalist(base.RequestHandler): |
| """Handler to add a finalist for the specified organization by program |
| administrators. |
| """ |
| |
| access_checker = access.ConjuctionAccessChecker( |
| [ci_access.WORK_REVIEWED_ACCESS_CHECKER, |
| access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER]) |
| |
| def __init__(self, initializer, linker, renderer, error_handler, |
| url_pattern_constructor, url_names): |
| """Initializes a new instance of the request handler for the specified |
| parameters. |
| |
| Args: |
| initializer: Implementation of initialize.Initializer interface. |
| linker: Instance of links.Linker class. |
| renderer: Implementation of render.Renderer interface. |
| error_handler: Implementation of error.ErrorHandler interface. |
| url_pattern_constructor: |
| Implementation of url_patterns.UrlPatternConstructor. |
| url_names: Instance of url_names.UrlNames. |
| """ |
| super(WinnersAddFinalist, self).__init__( |
| initializer, linker, renderer, error_handler) |
| self.url_pattern_constructor = url_pattern_constructor |
| self.url_names = url_names |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| self.url_pattern_constructor.construct( |
| r'winners/add_finalist/%s$' % url_patterns.ORG, |
| self, name=self.url_names.WINNERS_ADD_FINALIST)] |
| |
| def post(self, data, check, mutator): |
| """See base.RequestHandler.post for specification.""" |
| if 'finalist' not in data.POST: |
| raise exception.BadRequest('finalist not found in POST data.') |
| else: |
| profile_key = ndb.Key(urlsafe=data.POST['finalist']) |
| result = ci_profile_logic.setFinalistForOrg( |
| profile_key, data.url_ndb_org.key) |
| if result: |
| url = links.LINKER.program( |
| data.program, self.url_names.WINNERS_MANAGE_SELECTION) |
| return http.HttpResponseRedirect(url) |
| elif result.extra == ci_profile_logic.ALREADY_WINNER: |
| profile = profile_key.get() |
| raise exception.BadRequest( |
| message=_FINALIST_NOT_ELIGIBLE_ALREADY_WINNER % ( |
| profile.profile_id, profile.student_data.winner_for.get().name)) |
| elif result.extra == ci_profile_logic.ALREADY_FINALIST: |
| profile = profile_key.get() |
| raise exception.BadRequest( |
| message=_FINALIST_NOT_ELIGIBLE_ALREADY_FINALIST % ( |
| profile.profile_id, |
| profile.student_data.finalist_for.get().name)) |
| elif result.extra == ci_profile_logic.NOT_STUDENT: |
| profile = profile_key.get() |
| raise exception.BadRequest( |
| message=_FINALIST_NOT_ELIGIBLE_NOT_STUDENT % profile_key.id()) |
| else: |
| raise exception.BadRequest(messsage='Unknown error') |
| |
| WINNERS_ADD_FINALIST = WinnersAddFinalist( |
| gci_base._GCI_INITIALIZER, links.LINKER, render.CI_RENDERER, |
| error.CI_ERROR_HANDLER, ci_url_patterns.CI_URL_PATTERN_CONSTRUCTOR, |
| ci_urls.UrlNames) |
| |
| |
| class WinnersUnselect(base.RequestHandler): |
| """Handler to unselect winners and finalists by program administrators.""" |
| |
| access_checker = access.ConjuctionAccessChecker( |
| [ci_access.WORK_REVIEWED_ACCESS_CHECKER, |
| access.PROGRAM_ADMINISTRATOR_ACCESS_CHECKER]) |
| |
| def __init__(self, initializer, linker, renderer, error_handler, |
| url_pattern_constructor, url_names): |
| """Initializes a new instance of the request handler for the specified |
| parameters. |
| |
| Args: |
| initializer: Implementation of initialize.Initializer interface. |
| linker: Instance of links.Linker class. |
| renderer: Implementation of render.Renderer interface. |
| error_handler: Implementation of error.ErrorHandler interface. |
| url_pattern_constructor: |
| Implementation of url_patterns.UrlPatternConstructor. |
| url_names: Instance of url_names.UrlNames. |
| """ |
| super(WinnersUnselect, self).__init__( |
| initializer, linker, renderer, error_handler) |
| self.url_pattern_constructor = url_pattern_constructor |
| self.url_names = url_names |
| |
| def djangoURLPatterns(self): |
| """See base.RequestHandler.djangoURLPatterns for specification.""" |
| return [ |
| self.url_pattern_constructor.construct( |
| r'winners/unselect/(?P<category>winner|finalist)/%s$' % |
| url_patterns.PROFILE, |
| self, name=self.url_names.WINNERS_UNSELECT)] |
| |
| def post(self, data, check, mutator): |
| """See base.RequestHandler.post for specification.""" |
| category = data.kwargs['category'] |
| if category == 'winner': |
| result = profile_logic.editProfile( |
| data.url_ndb_profile.key, {'student_data': {'winner_for': None}}) |
| else: # category == 'finalist' |
| result = profile_logic.editProfile( |
| data.url_ndb_profile.key, {'student_data': {'finalist_for': None}}) |
| |
| if result: |
| url = links.LINKER.program( |
| data.program, self.url_names.WINNERS_MANAGE_SELECTION) |
| return http.HttpResponseRedirect(url) |
| else: |
| raise exception.BadRequest(message=result.extra) |
| |
| WINNERS_UNSELECT = WinnersUnselect( |
| gci_base._GCI_INITIALIZER, links.LINKER, render.CI_RENDERER, |
| error.CI_ERROR_HANDLER, ci_url_patterns.CI_URL_PATTERN_CONSTRUCTOR, |
| ci_urls.UrlNames) |