def get_round_info(self): round_info = self.round.serialize() if hasattr(self, 'auto_url'): round_info['autoUrl'] = reverse_round(self.auto_url, self.round) if hasattr(self, 'save_url'): round_info['saveUrl'] = reverse_round(self.save_url, self.round) return round_info
def get_round_info(self): round = self.get_round() t = self.get_tournament() adjudicator_positions = ["C"] if not t.pref('no_panellist_position'): adjudicator_positions += "P" if not t.pref('no_trainee_position'): adjudicator_positions += "T" round_info = { 'adjudicatorPositions': adjudicator_positions, # Depends on prefs 'adjudicatorDoubling': t.pref('duplicate_adjs'), 'teamsInDebate': t.pref('teams_in_debate'), 'teamPositions': t.sides, 'backUrl': reverse_round('draw', round), 'autoUrl': reverse_round(self.auto_url, round) if hasattr(self, 'auto_url') else None, 'saveUrl': reverse_round(self.save_url, round) if hasattr(self, 'save_url') else None, 'roundName': round.abbreviation, 'roundIsPrelim': not round.is_break_round, } round_info = self.annotate_round_info(round_info) return json.dumps(round_info)
def post(self, request, *args, **kwargs): if self.round.draw_status != Round.STATUS_NONE: messages.error(request, _("Could not create draw for %(round)s, there was already a draw!") % {'round': self.round.name}) return super().post(request, *args, **kwargs) try: manager = DrawManager(self.round) manager.create() except DrawUserError as e: messages.error(request, mark_safe(_( "<p>The draw could not be created, for the following reason: " "<em>%(message)s</em></p>\n" "<p>Please fix this issue before attempting to create the draw.</p>", ) % {'message': str(e)})) logger.warning("User error creating draw: " + str(e), exc_info=True) return HttpResponseRedirect(reverse_round('availability-index', self.round)) except DrawFatalError as e: messages.error(request, mark_safe(_( "<p>The draw could not be created, because the following error occurred: " "<em>%(message)s</em></p>\n" "<p>If this issue persists and you're not sure how to resolve it, please " "contact the developers.</p>", ) % {'message': str(e)})) logger.exception("Fatal error creating draw: " + str(e)) return HttpResponseRedirect(reverse_round('availability-index', self.round)) except StandingsError as e: message = _( "<p>The team standings could not be generated, because the following error occurred: " "<em>%(message)s</em></p>\n" "<p>Because generating the draw uses the current team standings, this " "prevents the draw from being generated.</p>", ) % {'message': str(e)} standings_options_url = reverse_tournament('options-tournament-section', self.tournament, kwargs={'section': 'standings'}) instructions = BaseStandingsView.admin_standings_error_instructions % {'standings_options_url': standings_options_url} messages.error(request, mark_safe(message + instructions)) logger.exception("Error generating standings for draw: " + str(e)) return HttpResponseRedirect(reverse_round('availability-index', self.round)) relevant_adj_venue_constraints = VenueConstraint.objects.filter( adjudicator__in=self.tournament.relevant_adjudicators) if not relevant_adj_venue_constraints.exists(): allocate_venues(self.round) else: messages.warning(request, _("Rooms were not auto-allocated because there are one or more adjudicator room constraints. " "You should run room allocations after allocating adjudicators.")) self.log_action() return super().post(request, *args, **kwargs)
def post(self, request, *args, **kwargs): if self.round.draw_status != Round.STATUS_NONE: messages.error(request, _("Could not create draw for %(round)s, there was already a draw!") % {'round': self.round.name}) return super().post(request, *args, **kwargs) try: manager = DrawManager(self.round) manager.create() except DrawUserError as e: messages.error(request, mark_safe(_( "<p>The draw could not be created, for the following reason: " "<em>%(message)s</em></p>\n" "<p>Please fix this issue before attempting to create the draw.</p>" ) % {'message': str(e)})) logger.warning("User error creating draw: " + str(e), exc_info=True) return HttpResponseRedirect(reverse_round('availability-index', self.round)) except DrawFatalError as e: messages.error(request, mark_safe(_( "The draw could not be created, because the following error occurred: " "<em>%(message)s</em></p>\n" "<p>If this issue persists and you're not sure how to resolve it, please " "contact the developers.</p>" ) % {'message': str(e)})) logger.exception("Fatal error creating draw: " + str(e)) return HttpResponseRedirect(reverse_round('availability-index', self.round)) except StandingsError as e: message = _( "<p>The team standings could not be generated, because the following error occurred: " "<em>%(message)s</em></p>\n" "<p>Because generating the draw uses the current team standings, this " "prevents the draw from being generated.</p>" ) % {'message': str(e)} standings_options_url = reverse_tournament('options-tournament-section', self.tournament, kwargs={'section': 'standings'}) instructions = BaseStandingsView.admin_standings_error_instructions % {'standings_options_url': standings_options_url} messages.error(request, mark_safe(message + instructions)) logger.exception("Error generating standings for draw: " + str(e)) return HttpResponseRedirect(reverse_round('availability-index', self.round)) relevant_adj_venue_constraints = VenueConstraint.objects.filter( adjudicator__in=self.tournament.relevant_adjudicators) if not relevant_adj_venue_constraints.exists(): allocate_venues(self.round) else: messages.warning(request, _("Venues were not auto-allocated because there are one or more adjudicator venue constraints. " "You should run venue allocations after allocating adjudicators.")) self.log_action() return super().post(request, *args, **kwargs)
def get_context_data(self, **kwargs): prior_rounds_not_completed = self.tournament.round_set.filter( Q(break_category=self.round.break_category) | Q(break_category__isnull=True), completed=False, seq__lt=self.round.seq, ) kwargs[ 'number_of_prior_rounds_not_completed'] = prior_rounds_not_completed.count( ) kwargs['prior_rounds_not_completed'] = format_html_join( ", ", "<a href=\"{}\" class=\"alert-link\">{}</a>", ((reverse_round('tournament-complete-round-check', r), r.name) for r in prior_rounds_not_completed), ) kwargs['num_unconfirmed'] = self.round.debate_set.filter( result_status__in=[Debate.STATUS_NONE, Debate.STATUS_DRAFT ]).count() kwargs['increment_ok'] = kwargs['num_unconfirmed'] == 0 kwargs['emails_sent'] = BulkNotification.objects.filter( tournament=self.tournament, round=self.round, event=BulkNotification.EVENT_TYPE_POINTS).exists() return super().get_context_data(**kwargs)
def post(self, request, *args, **kwargs): round = self.get_round() if round.draw_status != round.STATUS_NONE: messages.error(request, "Could not create draw for {}, there was already a draw!".format(round.name)) return super().post(request, *args, **kwargs) manager = DrawManager(round) try: manager.create() except DrawError as e: messages.error(request, "There was a problem creating the draw: " + str(e) + " If this " " issue persists and you're not sure how to resolve it, please contact the developers.") logger.critical(str(e), exc_info=True) return HttpResponseRedirect(reverse_round('availability-index', round)) relevant_adj_venue_constraints = AdjudicatorVenueConstraint.objects.filter( Q(adjudicator__tournament=self.get_tournament()) | Q(adjudicator__tournament__isnull=True) ) if not relevant_adj_venue_constraints.exists(): allocate_venues(round) else: messages.warning(request, "Venues were not auto-allocated because there are one or more adjudicator venue constraints. " "You should run venue allocations after allocating adjudicators.") self.log_action() return super().post(request, *args, **kwargs)
def get_extra_info(self): """ Unlike meta_info everything under extra info is json serialised automatically. Designed for simple key/value pairs""" extra_info = {} # Set by view for top bar toggles extra_info['codeNames'] = self.tournament.pref('team_code_names') extra_info['highlights'] = {} bcs = self.tournament.breakcategory_set.all() serialised_bcs = [] for bc in bcs: safe, dead = calculate_live_thresholds(bc, self.tournament, self.round) serialised_bc = { 'pk': bc.id, 'fields': { 'name': bc.name, 'safe': safe, 'dead': dead }, } serialised_bcs.append(serialised_bc) extra_info['highlights']['break'] = serialised_bcs extra_info['backUrl'] = reverse_round('draw', self.round) extra_info['backLabel'] = _("Return to Draw") return extra_info
def get_table(self): if not self.is_draw_released(): return None debateadjs = DebateAdjudicator.objects.filter( debate__round=self.round, ).select_related( 'adjudicator', 'debate__venue', ).prefetch_related('debate__venue__venuecategory_set', ).order_by( 'adjudicator__name') table = TabbycatTableBuilder(view=self, sort_key='adj') data = [{ 'text': _("Add result from %(adjudicator)s") % { 'adjudicator': da.adjudicator.name }, 'link': reverse_round('old-results-public-ballotset-new-pk', self.round, kwargs={'adjudicator_pk': da.adjudicator_id}), } for da in debateadjs] header = {'key': 'adj', 'title': _("Adjudicator")} table.add_column(header, data) debates = [da.debate for da in debateadjs] table.add_debate_venue_columns(debates) return table
def add_debate_ballot_link_column(self, debates, show_ballot=False): ballot_links_header = { 'key': "ballot", 'icon': 'search', 'tooltip': _("The ballot you submitted") } if self.admin: ballot_links_data = [{ 'text': _("View/Edit Ballot"), 'link': reverse_tournament('old-results-ballotset-edit', self.tournament, kwargs={'pk': debate.confirmed_ballot.id}), } if debate.confirmed_ballot else "" for debate in debates] self.add_column(ballot_links_header, ballot_links_data) elif self.private_url: ballot_links_data = [] for debate in debates: if not debate.ballotsubmission_set.exclude( discarded=True).exists(): ballot_links_data.append(_("No ballot")) elif self.tournament.pref( 'teams_in_debate' ) == 'bp' and debate.round.is_break_round: ballot_links_data.append(_("Elimination")) else: ballot_links_data.append({ 'text': _("View Ballot"), 'link': reverse_round('results-privateurl-scoresheet-view', debate.round, kwargs={'url_key': self.private_url_key}), }) self.add_column(ballot_links_header, ballot_links_data) elif self.tournament.pref('ballots_released'): ballot_links_data = [] for debate in debates: if self.tournament.pref( 'teams_in_debate' ) == 'bp' and debate.round.is_break_round: ballot_links_data.append("") else: ballot_links_data.append({ 'text': _("View Ballot"), 'link': reverse_tournament('results-public-scoresheet-view', self.tournament, kwargs={'pk': debate.id}), }) self.add_column(ballot_links_header, ballot_links_data)
def get_round_info(self): round_info = super().get_round_info() round_info['updateImportanceURL'] = reverse_round('adjallocation-save-debate-importance', self.round) round_info['scoreMin'] = self.tournament.pref('adj_min_score') round_info['scoreMax'] = self.tournament.pref('adj_max_score') round_info['scoreForVote'] = self.tournament.pref('adj_min_voting_score') round_info['allowDuplicateAllocations'] = self.tournament.pref('duplicate_adjs') round_info['regions'] = self.get_regions_info() round_info['categories'] = self.get_categories_info() return round_info
def get_redirect_url(self, *args, **kwargs): # Override if self.round_redirect_pattern_name is specified, # otherwise just pass down the chain if self.round_redirect_pattern_name: try: return reverse_round(self.round_redirect_pattern_name, self.round, args=args, kwargs=kwargs) except NoReverseMatch: pass return super().get_redirect_url(*args, **kwargs)
def get_context_data(self, **kwargs): unused = [t for t in self.round.unused_teams()] serialized_unused = [t.serialize() for t in unused] break_thresholds = self.break_thresholds for t, serialt in zip(unused, serialized_unused): serialt = self.annotate_break_classes(serialt, break_thresholds) serialt = self.annotate_region_classes(serialt) kwargs['vueUnusedTeams'] = json.dumps(serialized_unused) kwargs['saveSidesStatusUrl'] = reverse_round('save-debate-sides-status', self.round) return super().get_context_data(**kwargs)
def annotate_round_info(self, round_info): t = self.get_tournament() r = self.get_round() round_info['updateImportanceURL'] = reverse_round( 'save-debate-importance', r) round_info['scoreMin'] = t.pref('adj_min_score') round_info['scoreMax'] = t.pref('adj_max_score') round_info['scoreForVote'] = t.pref('adj_min_voting_score') round_info['allowDuplicateAllocations'] = t.pref('duplicate_adjs') round_info['regions'] = self.get_regions_info() round_info['categories'] = self.get_categories_info() return round_info
def add_speaker_debate_ballot_link_column(self, debates): ballot_links_header = {'key': "ballot", 'icon': 'search', 'tooltip': _("The confirmed ballot")} ballot_links_data = [] for debate in debates: if not debate.confirmed_ballot: ballot_links_data.append(_("No ballot")) elif not debate.confirmed_ballot.result.uses_speakers: ballot_links_data.append(_("No scores")) else: ballot_links_data.append({ 'text': _("View Ballot"), 'link': reverse_round( 'speaker-results-privateurl-scoresheet', debate.round, kwargs={'url_key': self.private_url_key}), }) self.add_column(ballot_links_header, ballot_links_data)
def serialize(self): adjudicator_positions = ["C"] if not self.tournament.pref('no_panellist_position'): adjudicator_positions += "P" if not self.tournament.pref('no_trainee_position'): adjudicator_positions += "T" round_info = { 'adjudicatorPositions': adjudicator_positions, # Depends on prefs 'adjudicatorDoubling': self.tournament.pref('duplicate_adjs'), 'teamsInDebate': self.tournament.pref('teams_in_debate'), 'teamPositions': self.tournament.sides, 'backUrl': reverse_round('draw', self), 'roundName' : self.abbreviation, 'roundSeq' : self.seq, 'roundIsPrelim' : not self.is_break_round, } return round_info
def serialize(self): adjudicator_positions = ["C"] if not self.tournament.pref('no_panellist_position'): adjudicator_positions += "P" if not self.tournament.pref('no_trainee_position'): adjudicator_positions += "T" round_info = { 'adjudicatorPositions': adjudicator_positions, # Depends on prefs 'adjudicatorDoubling': self.tournament.pref('duplicate_adjs'), 'teamsInDebate': self.tournament.pref('teams_in_debate'), 'teamPositions': self.tournament.sides, 'backUrl': reverse_round('draw', self), 'roundName': self.abbreviation, 'roundSeq': self.seq, 'roundIsPrelim': not self.is_break_round, } return round_info
def add_debate_ballot_link_column(self, debates, show_ballot=False): ballot_links_header = {'key': "ballot", 'icon': 'search', 'tooltip': _("The ballot you submitted")} if self.admin: ballot_links_data = [{ 'text': _("View/Edit Ballot"), 'link': reverse_tournament('old-results-ballotset-edit', self.tournament, kwargs={'pk': debate.confirmed_ballot.id}), } if debate.confirmed_ballot else "" for debate in debates] self.add_column(ballot_links_header, ballot_links_data) elif self.private_url: debates = Debate.objects.filter(pk__in=[d.pk for d in debates]).select_related('round').annotate( has_ballot=Exists(BallotSubmission.objects.filter(debate_id=OuterRef('id')).exclude(discarded=True)), ).prefetch_related( Prefetch('ballotsubmission_set', queryset=BallotSubmission.objects.exclude(discarded=True), to_attr='nondiscard_ballots')) ballot_links_data = [] for debate in debates: if not debate.has_ballot: ballot_links_data.append(_("No ballot")) elif not get_result_class(debate.nondiscard_ballots[0], debate.round, self.tournament).uses_speakers: ballot_links_data.append(_("No scores")) else: ballot_links_data.append({ 'text': _("View Ballot"), 'link': reverse_round( 'results-privateurl-scoresheet-view', debate.round, kwargs={'url_key': self.private_url_key}), }) self.add_column(ballot_links_header, ballot_links_data) elif self.tournament.pref('ballots_released'): ballot_links_data = [] for debate in debates: if self.tournament.pref('teams_in_debate') == 'bp' and debate.round.is_break_round: ballot_links_data.append("") else: ballot_links_data.append({ 'text': _("View Ballot"), 'link': reverse_tournament('results-public-scoresheet-view', self.tournament, kwargs={'pk': debate.id}), }) self.add_column(ballot_links_header, ballot_links_data)
def post(self, request, *args, **kwargs): round = self.get_round() if round.draw_status != round.STATUS_NONE: messages.error( request, "Could not create draw for {}, there was already a draw!". format(round.name)) return super().post(request, *args, **kwargs) manager = DrawManager(round) try: manager.create() except DrawError as e: messages.error( request, "There was a problem creating the draw: " + str(e) + " If this " " issue persists and you're not sure how to resolve it, please contact the developers." ) logger.error(str(e), exc_info=True) return HttpResponseRedirect( reverse_round('availability-index', round)) relevant_adj_venue_constraints = VenueConstraint.objects.filter( adjudicator__in=self.get_tournament().relevant_adjudicators) if not relevant_adj_venue_constraints.exists(): allocate_venues(round) else: messages.warning( request, "Venues were not auto-allocated because there are one or more adjudicator venue constraints. " "You should run venue allocations after allocating adjudicators." ) self.log_action() return super().post(request, *args, **kwargs)
def get_context_data(self, **kwargs): kwargs['update_url'] = reverse_round(self.update_view, self.get_round()) return super().get_context_data(**kwargs)
def get_success_url(self): return reverse_round('tournament-complete-round-check', self.round)
def get_success_url(self): return reverse_round('results-round-list', self.ballotsub.debate.round)
def get_success_url(self): return reverse_round('draw-display', self.round)
def populate_objects(self, prefill=True): super().populate_objects() use_code_names = use_team_code_names_data_entry(self.tournament, True) bses = BallotSubmission.objects.filter( debate=self.debate, participant_submitter__isnull=False, discarded=False, single_adj=True, ).distinct('participant_submitter').select_related( 'participant_submitter').order_by('participant_submitter', '-version') populate_results(bses, self.tournament) self.merged_ballots = bses # Handle result conflicts self.result = DebateResult(self.ballotsub, tournament=self.tournament) try: self.result.populate_from_merge(*[b.result for b in bses]) except ResultError as e: msg, t, adj, bs, side, speaker = e.args args = { 'ballot_url': reverse_tournament(self.edit_ballot_url, self.tournament, kwargs={'pk': bs.id}), 'adjudicator': adj.name, 'speaker': speaker.name, 'team': team_name_for_data_entry(self.debate.get_team(side), use_code_names), } if t == 'speaker': msg = _( "The speaking order in the ballots is inconsistent, so could not be merged." ) elif t == 'ghost': msg = _( "Duplicate speeches are marked inconsistently, so could not be merged." ) msg += _( " This error was caught in <a href='%(ballot_url)s'>%(adjudicator)s's ballot</a> for %(speaker)s (%(team)s)." ) messages.error(self.request, msg % args) return HttpResponseRedirect( reverse_round(self.ballot_list_url, self.debate.round)) # Handle motion conflicts bs_motions = BallotSubmission.objects.filter( id__in=[b.id for b in bses], motion__isnull=False, ).prefetch_related('debateteammotionpreference_set__debate_team') if self.tournament.pref('enable_motions'): try: merge_motions(self.ballotsub, bs_motions) except ValidationError as e: messages.error(self.request, e) return HttpResponseRedirect( reverse_round(self.ballot_list_url, self.debate.round)) # Vetos try: self.vetos = merge_motion_vetos(self.ballotsub, bs_motions) except ValidationError as e: messages.error(self.request, e) return HttpResponseRedirect( reverse_round(self.ballot_list_url, self.debate.round))
def get_context_data(self, **kwargs): kwargs["update_url"] = reverse_round(self.update_view, self.get_round()) return super().get_context_data(**kwargs)
def get_list_url(self): return reverse_round('results-round-list', self.round)
def get_redirect_url(self): return reverse_round('venues-edit', self.get_round())
def reverse_round(self, view_name): return reverse_round(view_name, self.round)
def get_context_data(self, **kwargs): kwargs['model'] = self.model._meta.label # does not get translated kwargs['saveURL'] = reverse_round(self.update_view, self.round) return super().get_context_data(**kwargs)
def get_redirect_url(self): return reverse_round('draw', self.get_round())
def get_back_url(self, obj): return reverse_round('draw', obj)