コード例 #1
0
ファイル: mixins.py プロジェクト: zengik/tabbycat
    def get_draw_or_panels_objects(self):
        selects = ('round__tournament', 'venue')
        prefetches = ()
        if self.prefetch_venues:
            prefetches += ('venue__venuecategory_set', )
        if self.prefetch_adjs:
            prefetches += (Prefetch(
                'debateadjudicator_set',
                queryset=DebateAdjudicator.objects.select_related(
                    'adjudicator')), )
        if self.prefetch_teams:
            prefetches += (Prefetch(
                'debateteam_set',
                queryset=DebateTeam.objects.select_related(
                    'team').prefetch_related(
                        Prefetch('team__speaker_set',
                                 queryset=Speaker.objects.order_by('name')),
                        'team__break_categories',
                    )), )
        else:
            prefetches += (Prefetch('debateteam_set',
                                    queryset=DebateTeam.objects.select_related(
                                        'team').prefetch_related(
                                            'team__break_categories', )), )

        draw = self.round.debate_set.select_related(*selects).prefetch_related(
            *prefetches)

        if self.prefetch_teams:
            populate_win_counts([
                dt.team for debate in draw
                for dt in debate.debateteam_set.all()
            ])
        return draw
コード例 #2
0
 def get_serialised_allocatable_items(self):
     # TODO: account for shared teams
     teams = Team.objects.filter(tournament=self.tournament).prefetch_related('speaker_set')
     teams = annotate_availability(teams, self.round)
     populate_win_counts(teams)
     serialized_teams = EditDebateTeamsTeamSerializer(teams, many=True)
     return self.json_render(serialized_teams.data)
コード例 #3
0
    def get_draw(self):
        round = self.get_round()

        # The use-case for prefetches here is so intense that we'll just implement
        # a separate one (as opposed to use Round.debate_set_with_prefetches())
        draw = round.debate_set.select_related(
            'round__tournament').prefetch_related(
                Prefetch('debateadjudicator_set',
                         queryset=DebateAdjudicator.objects.select_related(
                             'adjudicator__institution__region')),
                Prefetch(
                    'debateteam_set',
                    queryset=DebateTeam.objects.select_related(
                        'team__institution__region').prefetch_related(
                            Prefetch(
                                'team__speaker_set',
                                queryset=Speaker.objects.order_by('name')), )),
                'debateteam_set__team__break_categories',
            )
        populate_win_counts(
            [dt.team for debate in draw for dt in debate.debateteam_set.all()])
        populate_feedback_scores([
            da.adjudicator for debate in draw
            for da in debate.debateadjudicator_set.all()
        ])

        serialised_draw = [d.serialize() for d in draw]
        draw = self.annotate_draw(draw, serialised_draw)
        return json.dumps(serialised_draw)
コード例 #4
0
def standings_email_generator(to, url, round):
    emails = []
    to_ids = {p.id for p in to}

    context = {
        'TOURN': str(round.tournament),
        'ROUND': round.name,
        'URL': url,
    }

    teams = round.active_teams.filter(
        speaker__in=to).prefetch_related('speaker_set')
    populate_win_counts(teams)

    for team in teams:
        context_team = context.copy()
        context_team['POINTS'] = str(team.points_count)
        context_team['TEAM'] = team.short_name

        for speaker in team.speaker_set.all():
            if not _check_in_to(speaker.id, to_ids):
                continue

            context_user = context_team.copy()
            context_user['USER'] = speaker.name

            emails.append((context_user, speaker))

    return emails
コード例 #5
0
ファイル: utils.py プロジェクト: rishraj2000/tabbycat
def standings_email_generator(to, url, round_id):
    emails = []
    round = Round.objects.get(id=round_id)
    tournament = round.tournament

    teams = round.active_teams.prefetch_related('speaker_set')
    populate_win_counts(teams)

    context = {
        'TOURN': str(tournament),
        'ROUND': round.name,
        'URL': url if tournament.pref('public_team_standings') else ""
    }

    for team in teams:
        context_team = context.copy()
        context_team['POINTS'] = str(team.points_count)
        context_team['TEAM'] = team.short_name

        for speaker in team.speaker_set.all():
            try:
                to.remove(speaker.id)
            except ValueError:
                continue

            context_user = context_team.copy()
            context_user['USER'] = speaker.name

            emails.append((context_user, speaker))

    return emails
コード例 #6
0
ファイル: utils.py プロジェクト: czlee/tabbycat
def teams_to_json(teams, regions, categories, t, r):
    thresholds = {bc["id"]: calculate_live_thresholds(bc, t, r) for bc in categories}

    # populate team categories
    tbcs = Team.break_categories.through.objects.filter(team__in=teams)
    break_category_ids_by_team = {team.id: [] for team in teams}
    for tbc in tbcs:
        break_category_ids_by_team[tbc.team_id].append(tbc.breakcategory_id)

    populate_win_counts(teams)

    data = {}
    for team in teams:
        team_categories = break_category_ids_by_team[team.id]
        break_categories = [
            {
                "id": bc["id"],
                "name": bc["name"],
                "seq": bc["seq"],
                "will_break": determine_liveness(thresholds[bc["id"]], team.wins_count),
            }
            for bc in categories
            if bc["id"] in team_categories
        ]

        data[team.id] = {
            "type": "team",
            "id": team.id,
            "name": team.short_name,
            "long_name": team.long_name,
            "uses_prefix": team.use_institution_prefix,
            "speakers": [{"name": s.name, "gender": s.gender} for s in team.speakers],
            "gender_show": False,
            "wins": team.wins_count,
            "region": [r for r in regions if r["id"] is team.institution.region_id][0]
            if team.institution.region_id
            else "",
            "region_show": False,
            # TODO: Searching for break cats here incurs extra queries; should be done earlier
            "categories": break_categories,
            "category_show": False,
            "institution": {
                "id": team.institution.id,
                "name": team.institution.code,
                "code": team.institution.code,
                "abbreviation": team.institution.abbreviation,
            },
            "histories": team.histories,
            "conflicts": {
                "teams": [],  # No team-team conflicts
                "institutions": team.institutional_institutions,
                "adjudicators": team.personal_adjudicators,
            },
            "conflicted": {
                "hover": {"personal": False, "institutional": False, "history": False, "history_ago": 99},
                "panel": {"personal": False, "institutional": False, "history": False, "history_ago": 99},
            },
        }
    return json.dumps(data)
コード例 #7
0
ファイル: views.py プロジェクト: czlee/tabbycat
    def post(self, request, *args, **kwargs):
        active_teams = Team.objects.filter(debateteam__debate__round=self.round).prefetch_related('speaker_set')
        populate_win_counts(active_teams)

        try:
            send_standings_emails(self.tournament, active_teams, request, self.round)
        except (ConnectionError, SMTPException):
            messages.error(request, _("Team point emails could not be sent."))
        else:
            messages.success(request, _("Team point emails have been sent to the speakers."))

        return redirect_round('tournament-advance-round-check', self.round)
コード例 #8
0
ファイル: views.py プロジェクト: molins/tabbycat
    def post(self, request, *args, **kwargs):
        active_teams = Team.objects.filter(debateteam__debate__round=self.round
                                           ).prefetch_related('speaker_set')
        populate_win_counts(active_teams)

        try:
            send_standings_emails(self.tournament, active_teams, request,
                                  self.round)
        except (ConnectionError, SMTPException):
            messages.error(request, _("Team point emails could not be sent."))
        else:
            messages.success(
                request,
                _("Team point emails have been sent to the speakers."))

        return redirect_round('tournament-advance-round-check', self.round)
コード例 #9
0
    def prioritise_debates(self, event):
        # TODO: Debates and panels should really be unified in a single function
        round = Round.objects.get(pk=event['extra']['round_id'])
        debates = round.debate_set_with_prefetches(teams=True,
                                                   adjudicators=False,
                                                   speakers=False,
                                                   divisions=False,
                                                   venues=False)

        priority_method = event['extra']['settings']['type']
        if priority_method == 'liveness':
            populate_win_counts(
                [team for debate in debates for team in debate.teams],
                round.prev)
            open_category = round.tournament.breakcategory_set.filter(
                is_general=True).first()
            if open_category:
                safe, dead = calculate_live_thresholds(open_category,
                                                       round.tournament, round)
                for debate in debates:
                    points_now = [team.points_count for team in debate.teams]
                    highest = max(points_now)
                    lowest = min(points_now)
                    if lowest >= safe:
                        debate.importance = 0
                    elif highest <= dead:
                        debate.importance = -2
                    else:
                        debate.importance = 1
                    debate.save()
            else:
                self.return_error(
                    event['extra']['group_name'],
                    _("You have no break category set as 'is general' so debate importances can't be calculated."
                      ))
                return

        elif priority_method == 'bracket':
            self._prioritise_by_bracket(debates, 'bracket')

        self.log_action(event['extra'], round,
                        ActionLogEntry.ACTION_TYPE_DEBATE_IMPORTANCE_AUTO)
        content = self.reserialize_debates(SimpleDebateImportanceSerializer,
                                           round, debates)
        msg = _("Succesfully auto-prioritised debates.")
        self.return_response(content, event['extra']['group_name'], msg,
                             'success')
コード例 #10
0
    def handle_tournament(self, tournament, **options):
        for slug in options["slug"]:
            try:
                break_category = tournament.breakcategory_set.get(slug=slug)
            except ObjectDoesNotExist:
                raise CommandError("There's no break category with slug '%s'" %
                                   slug)

            self.stdout.write("\n==== %s Teams ====" % (break_category.name, ))

            teams = break_category.team_set.all()
            populate_win_counts(teams)

            writer = csv.writer(self.stdout)

            for team in sorted(teams, key=lambda x: -x.points_count):
                row = [team.short_name, team.code_name, team.points_count]
                writer.writerow(row)
コード例 #11
0
ファイル: mixins.py プロジェクト: czlee/tabbycat
    def get_draw(self):
        # The use-case for prefetches here is so intense that we'll just implement
        # a separate one (as opposed to use Round.debate_set_with_prefetches())
        draw = self.round.debate_set.select_related('round__tournament', 'venue').prefetch_related(
            Prefetch('debateadjudicator_set',
                queryset=DebateAdjudicator.objects.select_related('adjudicator__institution__region')),
            Prefetch('debateteam_set',
                queryset=DebateTeam.objects.select_related(
                    'team__institution__region'
                ).prefetch_related(
                    Prefetch('team__speaker_set', queryset=Speaker.objects.order_by('name')),
                )),
            'debateteam_set__team__break_categories',
            'venue__venuecategory_set',
        )
        populate_win_counts([dt.team for debate in draw for dt in debate.debateteam_set.all()])
        populate_feedback_scores([da.adjudicator for debate in draw for da in debate.debateadjudicator_set.all()])

        serialised_draw = [d.serialize() for d in draw]
        draw = self.annotate_draw(draw, serialised_draw)
        return json.dumps(serialised_draw)
コード例 #12
0
ファイル: anticipated.py プロジェクト: vicbab/tabbycat
def calculate_anticipated_draw(round):
    """Calculates an anticipated draw for the next round, based on the draw for
    the last round. Returns a list of tuples
        `(bracket_min, bracket_max, liveness)`,
    being the minimum and maximum brackets possible for that room, and the
    maximum number of teams that might be live in it. If the previous round's
    draw doesn't exist, it will just return an empty list.

    Procedure:
      1. Take the (actual) draw of the last round, with team points
      2. For each room, compute a (min, max) of outcomes for each team.
      3. Take the min, divide into rooms to make the `bracket_min` for each room.
      4. Take the max, divide into rooms to make the `bracket_max` for each room.

    `round` should be the round for which you want an anticipated draw (the
    "next round").
    """

    nteamsindebate = 4 if round.tournament.pref(
        'teams_in_debate') == 'bp' else 2

    if round.prev is None or not round.prev.debate_set.exists():
        # Special case: If this is the first round, everyone will be on zero.
        # Just take all teams, rounded down -- if this is done, it'll typically
        # be done before availability is locked down. Also do this if the last
        # round hasn't yet been drawn, since that's premature for bracket
        # predictions.
        npanels = round.tournament.team_set.count() // nteamsindebate
        return [(0, 0, 0) for i in range(npanels)]

    # 1. Take the (actual) draw of the last round, with team points
    debates = round.prev.debate_set_with_prefetches(ordering=('room_rank', ),
                                                    teams=True,
                                                    adjudicators=False,
                                                    speakers=False,
                                                    divisions=False,
                                                    venues=False)
    if round.prev.prev:
        populate_win_counts(
            [team for debate in debates for team in debate.teams],
            round=round.prev.prev)
    else:
        # just say everyone is on zero (since no rounds have finished yet)
        for debate in debates:
            for team in debate.teams:
                team._points = 0

    # 2. Compute a (min, max) of outcomes for each team
    team_points_after = []
    for debate in debates:
        points_now = [team.points_count for team in debate.teams]
        highest = max(points_now)
        lowest = min(points_now)

        # Most cases will be single-point rooms or rooms with pull-ups from only
        # one bracket; in these cases it's easy to prove this closed-form
        # guarantee for what the teams in that room will look like afterwards.
        if highest - lowest <= 1:
            points_after = [(lowest + i, highest + i)
                            for i in range(nteamsindebate)]

        # For more complicated rooms (e.g. [9, 8, 8, 7]), it gets harder; just
        # use brute force. For few enough rooms this won't be too bad a hit.
        else:
            possible_outcomes = []
            for result in itertools.permutations(range(nteamsindebate)):
                outcome = [n + r for n, r in zip(points_now, result)]
                outcome.sort(reverse=True)
                possible_outcomes.append(outcome)
            points_after = [(min(team_after), max(team_after))
                            for team_after in zip(*possible_outcomes)]

        team_points_after.extend(points_after)

    # 3. Take the min, divide into rooms to make the `bracket_min` for each room.
    # 4. Take the max, divide into rooms to make the `bracket_max` for each room.
    lowers, uppers = [sorted(x, reverse=True) for x in zip(*team_points_after)]
    brackets_min = [max(r) for r in zip(*([iter(lowers)] * nteamsindebate))]
    brackets_max = [max(r) for r in zip(*([iter(uppers)] * nteamsindebate))]

    open_category = round.tournament.breakcategory_set.filter(
        is_general=True).first()
    if open_category:
        live_thresholds = calculate_live_thresholds(open_category,
                                                    round.tournament, round)
        liveness_by_lower = [
            determine_liveness(live_thresholds, x) for x in lowers
        ]
        liveness_by_upper = [
            determine_liveness(live_thresholds, x) for x in uppers
        ]
        liveness_by_team = [
            x == 'live' or y == 'live'
            for x, y in zip(liveness_by_lower, liveness_by_upper)
        ]
        liveness = [
            x.count(True)
            for x in zip(*([iter(liveness_by_team)] * nteamsindebate))
        ]
    else:
        liveness = [0] * len(debates)

    return zip(brackets_min, brackets_max, liveness)
コード例 #13
0
ファイル: utils.py プロジェクト: modale/tabbycat
def teams_to_json(teams, regions, categories, t, r):
    thresholds = {
        bc['id']: calculate_live_thresholds(bc, t, r)
        for bc in categories
    }

    # populate team categories
    tbcs = Team.break_categories.through.objects.filter(team__in=teams)
    break_category_ids_by_team = {team.id: [] for team in teams}
    for tbc in tbcs:
        break_category_ids_by_team[tbc.team_id].append(tbc.breakcategory_id)

    populate_win_counts(teams)

    data = {}
    for team in teams:
        team_categories = break_category_ids_by_team[team.id]
        break_categories = [{
            'id':
            bc['id'],
            'name':
            bc['name'],
            'seq':
            bc['seq'],
            'will_break':
            determine_liveness(thresholds[bc['id']], team.wins_count)
        } for bc in categories if bc['id'] in team_categories]

        data[team.id] = {
            'type':
            'team',
            'id':
            team.id,
            'name':
            team.short_name,
            'long_name':
            team.long_name,
            'uses_prefix':
            team.use_institution_prefix,
            'speakers': [{
                'name': s.name,
                'gender': s.gender
            } for s in team.speakers],
            'gender_show':
            False,
            'wins':
            team.wins_count,
            'region':
            [r for r in regions if r['id'] is team.institution.region_id][0]
            if team.institution.region_id else '',
            'region_show':
            False,
            # TODO: Searching for break cats here incurs extra queries; should be done earlier
            'categories':
            break_categories,
            'category_show':
            False,
            'institution': {
                'id': team.institution.id,
                'name': team.institution.code,
                'code': team.institution.code,
                'abbreviation': team.institution.abbreviation
            },
            'histories':
            team.histories,
            'conflicts': {
                'teams': [],  # No team-team conflicts
                'institutions': team.institutional_institutions,
                'adjudicators': team.personal_adjudicators
            },
            'conflicted': {
                'hover': {
                    'personal': False,
                    'institutional': False,
                    'history': False,
                    'history_ago': 99
                },
                'panel': {
                    'personal': False,
                    'institutional': False,
                    'history': False,
                    'history_ago': 99
                }
            }
        }
    return json.dumps(data)