blob: 05cacc749b61b3af6f7702fa503efef67ed6bcaa [file] [log] [blame]
# 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)