def test_2017scmb_sequence(self):
        event = Event(
            id='2017scmb',
            event_short='scmb',
            year=2017,
            event_type_enum=0,
            timezone_id='America/New_York'
        )
        event.put()

        event_code = 'scmb'

        file_prefix = 'frc-api-response/v2.0/2017/schedule/{}/playoff/hybrid/'.format(event_code)
        context = ndb.get_context()
        result = context.urlfetch('https://www.googleapis.com/storage/v1/b/bucket/o?bucket=tbatv-prod-hrd.appspot.com&prefix={}'.format(file_prefix)).get_result()

        for item in json.loads(result.content)['items']:
            filename = item['name']
            time_str = filename.replace(file_prefix, '').replace('.json', '').strip()
            file_time = datetime.datetime.strptime(time_str, "%Y-%m-%d %H:%M:%S.%f")
            query_time = file_time + datetime.timedelta(seconds=30)
            MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=query_time).getMatches('2017{}'.format(event_code)), run_post_update_hook=False)
        MatchHelper.deleteInvalidMatches(event.matches, event)

        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'), Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 11)

        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'), Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 4)

        f_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'), Match.comp_level == 'f').fetch()
        self.assertEqual(len(f_matches), 3)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']['totalPoints'], 305)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['red']['score'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['red']['totalPoints'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['blue']['totalPoints'], 305)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').alliances['red']['score'], 312)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').alliances['blue']['score'], 255)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').score_breakdown['red']['totalPoints'], 312)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').score_breakdown['blue']['totalPoints'], 255)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').alliances['red']['score'], 310)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').alliances['blue']['score'], 306)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').score_breakdown['red']['totalPoints'], 310)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').score_breakdown['blue']['totalPoints'], 306)
    def test_2017flwp(self):
        event = Event(id='2017flwp',
                      event_short='flwp',
                      year=2017,
                      event_type_enum=0,
                      timezone_id='America/New_York')
        event.put()

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 04, 21, 22)).getMatches('2017flwp'))
        MatchHelper.deleteInvalidMatches(event.matches)

        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017flwp'),
                                 Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 5)
        old_match = Match.get_by_id('2017flwp_sf1m3')
        self.assertNotEqual(old_match, None)
        self.assertEqual(old_match.alliances['red']['score'], 255)
        self.assertEqual(old_match.alliances['blue']['score'], 255)
        self.assertEqual(old_match.score_breakdown['red']['totalPoints'], 255)
        self.assertEqual(old_match.score_breakdown['blue']['totalPoints'], 255)

        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 04, 21, 35)).getMatches('2017flwp'))
        MatchHelper.deleteInvalidMatches(event.matches)

        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017flwp'),
                                 Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)
        new_match = Match.get_by_id('2017flwp_sf1m3')
        self.assertNotEqual(new_match, None)

        self.assertEqual(old_match.alliances, new_match.alliances)
        self.assertEqual(old_match.score_breakdown, new_match.score_breakdown)

        tiebreaker_match = Match.get_by_id('2017flwp_sf1m4')
        self.assertNotEqual(tiebreaker_match, None)

        self.assertEqual(tiebreaker_match.alliances['red']['score'], 165)
        self.assertEqual(tiebreaker_match.alliances['blue']['score'], 263)
        self.assertEqual(
            tiebreaker_match.score_breakdown['red']['totalPoints'], 165)
        self.assertEqual(
            tiebreaker_match.score_breakdown['blue']['totalPoints'], 263)
 def test_cleanup(self):
     matches = setupMatches('test_data/cleanup_matches.csv')
     cleaned_matches = MatchHelper.deleteInvalidMatches(matches)
     indices = [9, 12, 26]
     for index in sorted(indices, reverse=True): #need to delete in reverse order so indices don't get messed up
         del matches[index]
     self.assertEqual(matches, cleaned_matches)
예제 #4
0
    def get(self, event_key):
        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)

        event_future = EventQuery(event_key).fetch_async(return_updated=True)
        matches_future = EventMatchesQuery(event_key).fetch_async(
            return_updated=True)

        event, _ = event_future.get_result()
        matches, _ = matches_future.get_result()

        cleaned_matches = MatchHelper.deleteInvalidMatches(matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        bracket_table, playoff_advancement, _, _ = PlayoffAdvancementHelper.generatePlayoffAdvancement(
            event, matches)

        event_details = EventDetails(
            id=event.key_name,
            playoff_advancement={
                'advancement': playoff_advancement,
                'bracket': bracket_table,
            },
        )
        EventDetailsManipulator.createOrUpdate(event_details)

        self.response.out.write("New playoff advancement for {}\n{}".format(
            event.key_name,
            json.dumps(event_details.playoff_advancement,
                       indent=2,
                       sort_keys=True)))
    def _render(self, event_key):
        event_future = EventQuery(event_key).fetch_async(return_updated=True)
        matches_future = EventMatchesQuery(event_key).fetch_async(return_updated=True)

        event, event_updated = event_future.get_result()
        matches, matches_updated = matches_future.get_result()
        self._last_modified = max(event_updated, matches_updated)

        cleaned_matches = MatchHelper.deleteInvalidMatches(matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        bracket_table, playoff_advancement, _, _ = PlayoffAdvancementHelper.generatePlayoffAdvancement(event, matches)

        output = []
        for level in Match.ELIM_LEVELS:
            level_ranks = []
            if playoff_advancement and playoff_advancement.get(level):
                if event.playoff_type == PlayoffType.AVG_SCORE_8_TEAM:
                    level_ranks = PlayoffAdvancementHelper.transform2015AdvancementLevelForApi(event, playoff_advancement, level)
                else:
                    level_ranks = PlayoffAdvancementHelper.transformRoundRobinAdvancementLevelForApi(event, playoff_advancement, level)
            elif bracket_table and bracket_table.get(level):
                level_ranks = PlayoffAdvancementHelper.transformBracketLevelForApi(event, bracket_table, level)
            output.extend(level_ranks)

        return json.dumps(output, ensure_ascii=True, indent=2, sort_keys=True)
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        num_teams = len(teams)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = teams[:middle_value], teams[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.within_a_day:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = {}
        qf_matches = matches['qf']
        sf_matches = matches['sf']
        f_matches = matches['f']
        if qf_matches:
            bracket_table['qf'] = MatchHelper.generateBracket(qf_matches)
        if sf_matches:
            bracket_table['sf'] = MatchHelper.generateBracket(sf_matches)
        if f_matches:
            bracket_table['f'] = MatchHelper.generateBracket(f_matches)

        template_values = {
            "event": event,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
        }

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        path = os.path.join(os.path.dirname(__file__), '../templates/event_details.html')
        return template.render(path, template_values)
 def test_cleanup(self):
     matches = self.setupMatches("test_data/cleanup_matches.csv")
     cleaned_matches = MatchHelper.deleteInvalidMatches(matches)
     indices = {9, 12, 26}
     correct_matches = []
     for i, match in enumerate(matches):
         if i not in indices:
             correct_matches.append(match)
     self.assertEqual(correct_matches, cleaned_matches)
예제 #8
0
 def test_cleanup(self):
     matches = self.setupMatches('test_data/cleanup_matches.csv')
     cleaned_matches = MatchHelper.deleteInvalidMatches(matches)
     indices = {9, 12, 26}
     correct_matches = []
     for i, match in enumerate(matches):
         if i not in indices:
             correct_matches.append(match)
     self.assertEqual(correct_matches, cleaned_matches)
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        num_teams = len(teams)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = teams[:middle_value], teams[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.within_a_day:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event.alliance_selections)

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        self.template_values.update({
            "event": event,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "district_points_sorted": district_points_sorted,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        path = os.path.join(os.path.dirname(__file__), '../templates/event_details.html')
        return template.render(path, self.template_values)
    def test_2017flwp(self):
        event = Event(
            id='2017flwp',
            event_short='flwp',
            year=2017,
            event_type_enum=0,
            timezone_id='America/New_York'
        )
        event.put()

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 04, 21, 22)).getMatches('2017flwp'))
        MatchHelper.deleteInvalidMatches(event.matches, event)

        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017flwp'), Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 5)
        old_match = Match.get_by_id('2017flwp_sf1m3')
        self.assertNotEqual(old_match, None)
        self.assertEqual(old_match.alliances['red']['score'], 255)
        self.assertEqual(old_match.alliances['blue']['score'], 255)
        self.assertEqual(old_match.score_breakdown['red']['totalPoints'], 255)
        self.assertEqual(old_match.score_breakdown['blue']['totalPoints'], 255)

        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 04, 21, 35)).getMatches('2017flwp'))
        MatchHelper.deleteInvalidMatches(event.matches, event)

        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017flwp'), Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)
        new_match = Match.get_by_id('2017flwp_sf1m3')
        self.assertNotEqual(new_match, None)

        self.assertEqual(old_match.alliances, new_match.alliances)
        self.assertEqual(old_match.score_breakdown, new_match.score_breakdown)

        tiebreaker_match = Match.get_by_id('2017flwp_sf1m4')
        self.assertNotEqual(tiebreaker_match, None)

        self.assertEqual(tiebreaker_match.alliances['red']['score'], 165)
        self.assertEqual(tiebreaker_match.alliances['blue']['score'], 263)
        self.assertEqual(tiebreaker_match.score_breakdown['red']['totalPoints'], 165)
        self.assertEqual(tiebreaker_match.score_breakdown['blue']['totalPoints'], 263)
    def post(self):
        self._require_admin()

        event_key = self.request.get("event_key").strip()
        event = Event.get_by_id(event_key)
        if not event:
            self.redirect("/admin/event/" + event.key_name)
            return

        if event.playoff_type != PlayoffType.ROUND_ROBIN_6_TEAM:
            logging.warning("Can't set advancement for non-round robin events")
            self.redirect("/admin/event/" + event.key_name)
            return

        advancement_csv = self.request.get("advancement_csv")
        comp_level = self.request.get("comp_level")
        matches_per_team = int(self.request.get("num_matches"))
        if comp_level not in Match.ELIM_LEVELS:
            logging.warning("Bad comp level: {}".format(comp_level))
            self.redirect("/admin/event/" + event.key_name)
            return
        parsed_advancement = CSVAdvancementParser.parse(
            advancement_csv, matches_per_team)
        advancement = PlayoffAdvancementHelper.generatePlayoffAdvancementFromCSV(
            event, parsed_advancement, comp_level)

        cleaned_matches = MatchHelper.deleteInvalidMatches(
            event.matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        bracket_table = PlayoffAdvancementHelper.generateBracket(
            matches, event, event.alliance_selections)
        comp_levels = bracket_table.keys()
        for comp_level in comp_levels:
            if comp_level != 'f':
                del bracket_table[comp_level]

        existing_details = EventDetails.get_by_id(event.key_name)
        new_advancement = existing_details.playoff_advancement if existing_details and existing_details.playoff_advancement else {}
        new_advancement.update(advancement)
        event_details = EventDetails(
            id=event.key_name,
            playoff_advancement={
                'advancement': new_advancement,
                'bracket': bracket_table,
            },
        )
        EventDetailsManipulator.createOrUpdate(event_details)

        self.redirect("/admin/event/" + event.key_name)
        return
    def get(self, event_key):
        df = DatafeedFMSAPI('v2.0', save_response=True)

        new_matches = MatchManipulator.createOrUpdate(
            MatchHelper.deleteInvalidMatches(df.getMatches(event_key),
                                             Event.get_by_id(event_key)))

        template_values = {
            'matches': new_matches,
        }

        if 'X-Appengine-Taskname' not in self.request.headers:  # Only write out if not in taskqueue
            path = os.path.join(
                os.path.dirname(__file__),
                '../templates/datafeeds/usfirst_matches_get.html')
            self.response.out.write(template.render(path, template_values))
    def get(self, event_key):
        df = DatafeedFMSAPI('v2.0', save_response=True)

        new_matches = MatchManipulator.createOrUpdate(
            MatchHelper.deleteInvalidMatches(
                df.getMatches(event_key),
                Event.get_by_id(event_key)
            )
        )

        template_values = {
            'matches': new_matches,
        }

        if 'X-Appengine-Taskname' not in self.request.headers:  # Only write out if not in taskqueue
            path = os.path.join(os.path.dirname(__file__), '../templates/datafeeds/usfirst_matches_get.html')
            self.response.out.write(template.render(path, template_values))
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event or event.year < 2016 or not event.details.predictions:
            self.abort(404)

        event.get_matches_async()

        match_predictions = event.details.predictions.get('match_predictions', None)
        match_prediction_stats = event.details.predictions.get('match_prediction_stats', None)

        ranking_predictions = event.details.predictions.get('ranking_predictions', None)
        ranking_prediction_stats = event.details.predictions.get('ranking_prediction_stats', None)

        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)

        # If no matches but there are match predictions, create fake matches
        # For cases where FIRST doesn't allow posting of match schedule
        fake_matches = False
        if not matches['qm'] and match_predictions['qual']:
            fake_matches = True
            for i in xrange(len(match_predictions.keys())):
                match_number = i + 1
                alliances = {
                    'red': {
                        'score': -1,
                        'teams': ['frc?', 'frc?', 'frc?']
                    },
                    'blue': {
                        'score': -1,
                        'teams': ['frc?', 'frc?', 'frc?']
                    }
                }
                matches['qm'].append(Match(
                    id=Match.renderKeyName(
                        event_key,
                        'qm',
                        1,
                        match_number),
                    event=event.key,
                    year=event.year,
                    set_number=1,
                    match_number=match_number,
                    comp_level='qm',
                    alliances_json=json.dumps(alliances),
                ))

        # Add actual scores to predictions
        distribution_info = {}
        for comp_level in Match.COMP_LEVELS:
            level = 'qual' if comp_level == 'qm' else 'playoff'
            for match in matches[comp_level]:
                distribution_info[match.key.id()] = {
                    'level': level,
                    'red_actual_score': match.alliances['red']['score'],
                    'blue_actual_score': match.alliances['blue']['score'],
                    'red_mean': match_predictions[level][match.key.id()]['red']['score'],
                    'blue_mean': match_predictions[level][match.key.id()]['blue']['score'],
                    'red_var': match_predictions[level][match.key.id()]['red']['score_var'],
                    'blue_var': match_predictions[level][match.key.id()]['blue']['score_var'],
            }

        last_played_match_num = None
        if ranking_prediction_stats:
            last_played_match_key = ranking_prediction_stats.get('last_played_match', None)
            if last_played_match_key:
                last_played_match_num = last_played_match_key.split('_qm')[1]

        self.template_values.update({
            "event": event,
            "matches": matches,
            "fake_matches": fake_matches,
            "match_predictions": match_predictions,
            "distribution_info_json": json.dumps(distribution_info),
            "match_prediction_stats": match_prediction_stats,
            "ranking_predictions": ranking_predictions,
            "ranking_prediction_stats": ranking_prediction_stats,
            "last_played_match_num": last_played_match_num,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_insights.html', self.template_values)
    def _render(self, event_key):
        event = EventQuery(event_key).fetch()

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        event.prep_details()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()
        district_future = DistrictQuery(event.district_key.id()).fetch_async() if event.district_key else None
        event_medias_future = media_query.EventMediasQuery(event_key).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = event.details.insights if event.details else None
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        district = district_future.get_result() if district_future else None

        medias_by_slugname = MediaHelper.group_by_slugname([media for media in event_medias_future.get_result()])

        self.template_values.update({
            "event": event,
            "district_name": district.display_name if district else None,
            "district_abbrev": district.abbreviation if district else None,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "district_points_sorted": district_points_sorted,
            "is_2015_playoff": is_2015_playoff,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
            "medias_by_slugname": medias_by_slugname,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
    def test_2017ncwin(self):
        event = Event(id='2017ncwin',
                      event_short='ncwin',
                      year=2017,
                      event_type_enum=0,
                      timezone_id='America/New_York')
        event.put()

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 05, 21, 2)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'),
                                 Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)

        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']
            ['totalPoints'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']
            ['totalPoints'], 150)

        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 05, 21, 30)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'),
                                 Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)

        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']
            ['totalPoints'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']
            ['totalPoints'], 150)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').alliances['red']['score'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').alliances['blue']['score'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').score_breakdown['red']
            ['totalPoints'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').score_breakdown['blue']
            ['totalPoints'], 205)

        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 05, 21, 35)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'),
                                 Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)

        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']
            ['totalPoints'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']
            ['totalPoints'], 150)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').alliances['red']['score'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').alliances['blue']['score'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').score_breakdown['red']
            ['totalPoints'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').score_breakdown['blue']
            ['totalPoints'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').alliances['red']['score'], 145)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').alliances['blue']['score'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').score_breakdown['red']
            ['totalPoints'], 145)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').score_breakdown['blue']
            ['totalPoints'], 265)

        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 05, 21, 51)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'),
                                 Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 7)

        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']
            ['totalPoints'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']
            ['totalPoints'], 150)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').alliances['red']['score'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').alliances['blue']['score'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').score_breakdown['red']
            ['totalPoints'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m2').score_breakdown['blue']
            ['totalPoints'], 205)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').alliances['red']['score'], 145)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').alliances['blue']['score'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').score_breakdown['red']
            ['totalPoints'], 145)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m3').score_breakdown['blue']
            ['totalPoints'], 265)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m4').alliances['red']['score'], 180)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m4').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m4').score_breakdown['red']
            ['totalPoints'], 180)
        self.assertEqual(
            Match.get_by_id('2017ncwin_sf2m4').score_breakdown['blue']
            ['totalPoints'], 305)
    def test_2017scmb(self):
        event = Event(id='2017scmb',
                      event_short='scmb',
                      year=2017,
                      event_type_enum=0,
                      timezone_id='America/New_York')
        event.put()

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 04, 19, 17)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'),
                                 Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 12)

        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']
            ['totalPoints'], 305)

        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 04, 19, 50)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'),
                                 Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 12)

        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').alliances['red']['score'], 213)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').score_breakdown['red']
            ['totalPoints'], 213)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').score_breakdown['blue']
            ['totalPoints'], 305)

        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 04, 20, 12)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'),
                                 Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 12)

        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').alliances['red']['score'], 213)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').score_breakdown['red']
            ['totalPoints'], 213)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').score_breakdown['blue']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').alliances['red']['score'], 312)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').alliances['blue']['score'], 255)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').score_breakdown['red']
            ['totalPoints'], 312)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').score_breakdown['blue']
            ['totalPoints'], 255)

        ndb.get_context().clear_cache(
        )  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(
            DatafeedFMSAPI('v2.0',
                           sim_time=datetime.datetime(
                               2017, 3, 04, 20, 48)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'),
                                 Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 13)

        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').alliances['red']['score'], 213)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').alliances['blue']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').score_breakdown['red']
            ['totalPoints'], 213)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m2').score_breakdown['blue']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').alliances['red']['score'], 312)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').alliances['blue']['score'], 255)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').score_breakdown['red']
            ['totalPoints'], 312)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m3').score_breakdown['blue']
            ['totalPoints'], 255)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m4').alliances['red']['score'], 310)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m4').alliances['blue']['score'], 306)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m4').score_breakdown['red']
            ['totalPoints'], 310)
        self.assertEqual(
            Match.get_by_id('2017scmb_qf4m4').score_breakdown['blue']
            ['totalPoints'], 306)
    def test_2017flwp_sequence(self):
        event = Event(id='2017flwp',
                      event_short='flwp',
                      year=2017,
                      event_type_enum=0,
                      timezone_id='America/New_York')
        event.put()

        event_code = 'flwp'

        file_prefix = 'frc-api-response/v2.0/2017/schedule/{}/playoff/hybrid/'.format(
            event_code)
        context = ndb.get_context()
        result = context.urlfetch(
            'https://www.googleapis.com/storage/v1/b/bucket/o?bucket=tbatv-prod-hrd.appspot.com&prefix={}'
            .format(file_prefix)).get_result()

        for item in json.loads(result.content)['items']:
            filename = item['name']
            time_str = filename.replace(file_prefix, '').replace('.json',
                                                                 '').strip()
            file_time = datetime.datetime.strptime(time_str,
                                                   "%Y-%m-%d %H:%M:%S.%f")
            query_time = file_time + datetime.timedelta(seconds=30)
            MatchManipulator.createOrUpdate(DatafeedFMSAPI(
                'v2.0',
                sim_time=query_time).getMatches('2017{}'.format(event_code)),
                                            run_post_update_hook=False)
        MatchHelper.deleteInvalidMatches(event.matches)

        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017flwp'),
                                 Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 7)

        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m1').alliances['red']['score'], 305)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m1').alliances['blue']['score'], 255)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m1').score_breakdown['red']
            ['totalPoints'], 305)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m1').score_breakdown['blue']
            ['totalPoints'], 255)

        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m2').alliances['red']['score'], 165)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m2').alliances['blue']['score'], 258)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m2').score_breakdown['red']
            ['totalPoints'], 165)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m2').score_breakdown['blue']
            ['totalPoints'], 258)

        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m3').alliances['red']['score'], 255)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m3').alliances['blue']['score'], 255)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m3').score_breakdown['red']
            ['totalPoints'], 255)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m3').score_breakdown['blue']
            ['totalPoints'], 255)

        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m4').alliances['red']['score'], 255)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m4').alliances['blue']['score'], 255)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m4').score_breakdown['red']
            ['totalPoints'], 255)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m4').score_breakdown['blue']
            ['totalPoints'], 255)

        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m5').alliances['red']['score'], 165)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m5').alliances['blue']['score'], 263)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m5').score_breakdown['red']
            ['totalPoints'], 165)
        self.assertEqual(
            Match.get_by_id('2017flwp_sf1m5').score_breakdown['blue']
            ['totalPoints'], 263)
    def test_2017scmb(self):
        event = Event(
            id='2017scmb',
            event_short='scmb',
            year=2017,
            event_type_enum=0,
            timezone_id='America/New_York'
        )
        event.put()

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 04, 19, 17)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'), Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 12)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']['totalPoints'], 305)

        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 04, 19, 50)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'), Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 12)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['red']['score'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['red']['totalPoints'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['blue']['totalPoints'], 305)

        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 04, 20, 12)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'), Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 12)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['red']['score'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['red']['totalPoints'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['blue']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').alliances['red']['score'], 312)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').alliances['blue']['score'], 255)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').score_breakdown['red']['totalPoints'], 312)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').score_breakdown['blue']['totalPoints'], 255)

        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 04, 20, 48)).getMatches('2017scmb'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        qf_matches = Match.query(Match.event == ndb.Key(Event, '2017scmb'), Match.comp_level == 'qf').fetch()
        self.assertEqual(len(qf_matches), 13)

        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['red']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['red']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m1').score_breakdown['blue']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['red']['score'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['red']['totalPoints'], 213)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m2').score_breakdown['blue']['totalPoints'], 305)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').alliances['red']['score'], 312)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').alliances['blue']['score'], 255)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').score_breakdown['red']['totalPoints'], 312)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m3').score_breakdown['blue']['totalPoints'], 255)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').alliances['red']['score'], 310)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').alliances['blue']['score'], 306)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').score_breakdown['red']['totalPoints'], 310)
        self.assertEqual(Match.get_by_id('2017scmb_qf4m4').score_breakdown['blue']['totalPoints'], 306)
예제 #20
0
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event or event.year < 2016 or not event.details or not event.details.predictions:
            self.abort(404)

        event.get_matches_async()

        match_predictions = event.details.predictions.get('match_predictions', None)
        match_prediction_stats = event.details.predictions.get('match_prediction_stats', None)

        ranking_predictions = event.details.predictions.get('ranking_predictions', None)
        ranking_prediction_stats = event.details.predictions.get('ranking_prediction_stats', None)

        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)

        # If no matches but there are match predictions, create fake matches
        # For cases where FIRST doesn't allow posting of match schedule
        fake_matches = False
        if match_predictions and (not matches['qm'] and match_predictions['qual']):
            fake_matches = True
            for i in xrange(len(match_predictions['qual'].keys())):
                match_number = i + 1
                alliances = {
                    'red': {
                        'score': -1,
                        'teams': ['frc?', 'frc?', 'frc?']
                    },
                    'blue': {
                        'score': -1,
                        'teams': ['frc?', 'frc?', 'frc?']
                    }
                }
                matches['qm'].append(Match(
                    id=Match.renderKeyName(
                        event_key,
                        'qm',
                        1,
                        match_number),
                    event=event.key,
                    year=event.year,
                    set_number=1,
                    match_number=match_number,
                    comp_level='qm',
                    alliances_json=json.dumps(alliances),
                ))

        # Add actual scores to predictions
        distribution_info = {}
        for comp_level in Match.COMP_LEVELS:
            level = 'qual' if comp_level == 'qm' else 'playoff'
            for match in matches[comp_level]:
                distribution_info[match.key.id()] = {
                    'level': level,
                    'red_actual_score': match.alliances['red']['score'],
                    'blue_actual_score': match.alliances['blue']['score'],
                    'red_mean': match_predictions[level][match.key.id()]['red']['score'],
                    'blue_mean': match_predictions[level][match.key.id()]['blue']['score'],
                    'red_var': match_predictions[level][match.key.id()]['red']['score_var'],
                    'blue_var': match_predictions[level][match.key.id()]['blue']['score_var'],
            }

        last_played_match_num = None
        if ranking_prediction_stats:
            last_played_match_key = ranking_prediction_stats.get('last_played_match', None)
            if last_played_match_key:
                last_played_match_num = last_played_match_key.split('_qm')[1]

        self.template_values.update({
            "event": event,
            "matches": matches,
            "fake_matches": fake_matches,
            "match_predictions": match_predictions,
            "distribution_info_json": json.dumps(distribution_info),
            "match_prediction_stats": match_prediction_stats,
            "ranking_predictions": ranking_predictions,
            "ranking_prediction_stats": ranking_prediction_stats,
            "last_played_match_num": last_played_match_num,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_insights.html', self.template_values)
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = EventInsightsHelper.calculate_event_insights(cleaned_matches, event.year)
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        # rankings processing for ranking score per match
        full_rankings = event.rankings
        rankings_enhanced = event.rankings_enhanced
        if rankings_enhanced is not None:
            rp_index = RankingIndexes.CUMULATIVE_RANKING_SCORE[event.year]
            matches_index = RankingIndexes.MATCHES_PLAYED[event.year]
            ranking_criterion_name = full_rankings[0][rp_index]
            full_rankings[0].append(ranking_criterion_name + "/Match*")

            for row in full_rankings[1:]:
                team = row[1]
                if rankings_enhanced["ranking_score_per_match"] is not None:
                    rp_per_match = rankings_enhanced['ranking_score_per_match'][team]
                    row.append(rp_per_match)
                if rankings_enhanced["match_offset"] is not None:
                    match_offset = rankings_enhanced["match_offset"][team]
                    if match_offset != 0:
                        row[matches_index] = "{} ({})".format(row[matches_index], match_offset)

        self.template_values.update({
            "event": event,
            "district_name": DistrictType.type_names.get(event.event_district_enum, None),
            "district_abbrev": DistrictType.type_abbrevs.get(event.event_district_enum, None),
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "district_points_sorted": district_points_sorted,
            "is_2015_playoff": is_2015_playoff,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
    def test_2017ncwin(self):
        event = Event(
            id='2017ncwin',
            event_short='ncwin',
            year=2017,
            event_type_enum=0,
            timezone_id='America/New_York'
        )
        event.put()

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 05, 21, 2)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'), Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)

        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']['totalPoints'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']['totalPoints'], 150)

        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 05, 21, 30)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'), Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)

        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']['totalPoints'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']['totalPoints'], 150)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').alliances['red']['score'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').alliances['blue']['score'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').score_breakdown['red']['totalPoints'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').score_breakdown['blue']['totalPoints'], 205)

        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 05, 21, 35)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'), Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 6)

        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']['totalPoints'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']['totalPoints'], 150)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').alliances['red']['score'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').alliances['blue']['score'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').score_breakdown['red']['totalPoints'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').score_breakdown['blue']['totalPoints'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').alliances['red']['score'], 145)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').alliances['blue']['score'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').score_breakdown['red']['totalPoints'], 145)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').score_breakdown['blue']['totalPoints'], 265)

        ndb.get_context().clear_cache()  # Prevent data from leaking between tests

        MatchManipulator.createOrUpdate(DatafeedFMSAPI('v2.0', sim_time=datetime.datetime(2017, 3, 05, 21, 51)).getMatches('2017ncwin'))
        MatchHelper.deleteInvalidMatches(event.matches, event)
        sf_matches = Match.query(Match.event == ndb.Key(Event, '2017ncwin'), Match.comp_level == 'sf').fetch()
        self.assertEqual(len(sf_matches), 7)

        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['red']['score'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').alliances['blue']['score'], 150)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['red']['totalPoints'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m1').score_breakdown['blue']['totalPoints'], 150)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').alliances['red']['score'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').alliances['blue']['score'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').score_breakdown['red']['totalPoints'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m2').score_breakdown['blue']['totalPoints'], 205)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').alliances['red']['score'], 145)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').alliances['blue']['score'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').score_breakdown['red']['totalPoints'], 145)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m3').score_breakdown['blue']['totalPoints'], 265)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m4').alliances['red']['score'], 180)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m4').alliances['blue']['score'], 305)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m4').score_breakdown['red']['totalPoints'], 180)
        self.assertEqual(Match.get_by_id('2017ncwin_sf2m4').score_breakdown['blue']['totalPoints'], 305)
예제 #23
0
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        num_teams = len(teams)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = teams[:middle_value], teams[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        self.template_values.update({
            "event": event,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "district_points_sorted": district_points_sorted,
            "is_2015_playoff": is_2015_playoff,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        path = os.path.join(os.path.dirname(__file__), '../templates/event_details.html')
        return template.render(path, self.template_values)
예제 #24
0
    def _render(self, event_key):
        event = EventQuery(event_key).fetch()

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        event.prep_details()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()
        district_future = DistrictQuery(event.district_key.id()).fetch_async() if event.district_key else None
        event_medias_future = media_query.EventMediasQuery(event_key).fetch_async()
        status_sitevar_future = Sitevar.get_by_id_async('apistatus.down_events')

        event_divisions_future = None
        event_codivisions_future = None
        parent_event_future = None
        if event.divisions:
            event_divisions_future = ndb.get_multi_async(event.divisions)
        elif event.parent_event:
            parent_event_future = event.parent_event.get_async()
            event_codivisions_future = EventDivisionsQuery(event.parent_event.id()).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event, event.alliance_selections)

        playoff_advancement = None
        playoff_template = None
        double_elim_matches = None
        if EventHelper.is_2015_playoff(event_key):
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            playoff_template = 'playoff_table'
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.ROUND_ROBIN_6_TEAM:
            playoff_advancement = MatchHelper.generatePlayoffAdvancementRoundRobin(matches, event.year, event.alliance_selections)
            playoff_template = 'playoff_round_robin_6_team'
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.BO3_FINALS or event.playoff_type == PlayoffType.BO5_FINALS:
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.DOUBLE_ELIM_8_TEAM:
            double_elim_matches = MatchHelper.organizeDoubleElimMatches(matches)

        district_points_sorted = None
        if event.district_key and event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = event.details.insights if event.details else None
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        district = district_future.get_result() if district_future else None
        event_divisions = None
        if event_divisions_future:
            event_divisions = [e.get_result() for e in event_divisions_future]
        elif event_codivisions_future:
            event_divisions = event_codivisions_future.get_result()

        medias_by_slugname = MediaHelper.group_by_slugname([media for media in event_medias_future.get_result()])
        has_time_predictions = matches_upcoming and any(match.predicted_time for match in matches_upcoming)

        status_sitevar = status_sitevar_future.get_result()

        self.template_values.update({
            "event": event,
            "event_down": status_sitevar and event_key in status_sitevar.contents,
            "district_name": district.display_name if district else None,
            "district_abbrev": district.abbreviation if district else None,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            'has_time_predictions': has_time_predictions,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "playoff_template": playoff_template,
            "district_points_sorted": district_points_sorted,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
            "medias_by_slugname": medias_by_slugname,
            "event_divisions": event_divisions,
            'parent_event': parent_event_future.get_result() if parent_event_future else None,
            'double_elim_matches': double_elim_matches,
            'double_elim_playoff_types': PlayoffType.DOUBLE_ELIM_TYPES,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
예제 #25
0
    def _render(self, event_key):
        event = EventQuery(event_key).fetch()

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        event.prep_details()
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()
        district_future = DistrictQuery(event.district_key.id()).fetch_async() if event.district_key else None
        event_medias_future = media_query.EventMediasQuery(event_key).fetch_async()
        status_sitevar_future = Sitevar.get_by_id_async('apistatus.down_events')

        event_divisions_future = None
        event_codivisions_future = None
        parent_event_future = None
        if event.divisions:
            event_divisions_future = ndb.get_multi_async(event.divisions)
        elif event.parent_event:
            parent_event_future = event.parent_event.get_async()
            event_codivisions_future = EventDivisionsQuery(event.parent_event.id()).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches, event)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()] if (event.matchstats is not None and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches, event, event.alliance_selections)

        playoff_advancement = None
        playoff_template = None
        double_elim_matches = None
        if EventHelper.is_2015_playoff(event_key):
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(matches, event.alliance_selections)
            playoff_template = 'playoff_table'
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.ROUND_ROBIN_6_TEAM:
            playoff_advancement = MatchHelper.generatePlayoffAdvancementRoundRobin(matches, event.year, event.alliance_selections)
            playoff_template = 'playoff_round_robin_6_team'
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.BO3_FINALS or event.playoff_type == PlayoffType.BO5_FINALS:
            comp_levels = bracket_table.keys()
            for comp_level in comp_levels:
                if comp_level != 'f':
                    del bracket_table[comp_level]
        elif event.playoff_type == PlayoffType.DOUBLE_ELIM_8_TEAM:
            double_elim_matches = MatchHelper.organizeDoubleElimMatches(matches)

        district_points_sorted = None
        if event.district_key and event.district_points:
            district_points_sorted = sorted(event.district_points['points'].items(), key=lambda (team, points): -points['total'])

        event_insights = event.details.insights if event.details else None
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(event.year)

        district = district_future.get_result() if district_future else None
        event_divisions = None
        if event_divisions_future:
            event_divisions = [e.get_result() for e in event_divisions_future]
        elif event_codivisions_future:
            event_divisions = event_codivisions_future.get_result()

        medias_by_slugname = MediaHelper.group_by_slugname([media for media in event_medias_future.get_result()])
        has_time_predictions = matches_upcoming and any(match.predicted_time for match in matches_upcoming)

        status_sitevar = status_sitevar_future.get_result()

        self.template_values.update({
            "event": event,
            "event_down": status_sitevar and event_key in status_sitevar.contents,
            "district_name": district.display_name if district else None,
            "district_abbrev": district.abbreviation if district else None,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            'has_time_predictions': has_time_predictions,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "playoff_template": playoff_template,
            "district_points_sorted": district_points_sorted,
            "event_insights_qual": event_insights['qual'] if event_insights else None,
            "event_insights_playoff": event_insights['playoff'] if event_insights else None,
            "event_insights_template": event_insights_template,
            "medias_by_slugname": medias_by_slugname,
            "event_divisions": event_divisions,
            'parent_event': parent_event_future.get_result() if parent_event_future else None,
            'double_elim_matches': double_elim_matches,
            'double_elim_playoff_types': PlayoffType.DOUBLE_ELIM_TYPES,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
예제 #26
0
    def step(self):
        event = Event.get_by_id('2016nytr')

        if self._step == 0:  # Qual match schedule added
            for match in copy.deepcopy(self._all_matches['qm']):
                for alliance in ['red', 'blue']:
                    match.alliances[alliance]['score'] = -1
                match.alliances_json = json.dumps(match.alliances)
                match.score_breakdown_json = None
                match.actual_time = None
                MatchManipulator.createOrUpdate(match)

            self._step += 1
        elif self._step == 1:  # After each qual match
            MatchManipulator.createOrUpdate(self._played_matches['qm'][self._substep])
            if self._substep < len(self._played_matches['qm']) - 1:
                self._substep += 1
            else:
                self._step += 1
                self._substep = 0
            EventDetailsManipulator.createOrUpdate(EventDetails(id='2016nytr'))
        elif self._step == 2:  # After alliance selections
            EventDetailsManipulator.createOrUpdate(EventDetails(
                id='2016nytr',
                alliance_selections=self._alliance_selections_without_backup
            ))
            self._step += 1
        elif self._step == 3:  # QF schedule added
            for match in copy.deepcopy(self._all_matches['qf']):
                for alliance in ['red', 'blue']:
                    match.alliances[alliance]['score'] = -1
                match.alliances_json = json.dumps(match.alliances)
                match.score_breakdown_json = None
                match.actual_time = None
                MatchManipulator.createOrUpdate(match)
            self._step += 1
        elif self._step == 4:  # After each QF match
            new_match = MatchHelper.play_order_sort_matches(self._played_matches['qf'])[self._substep]
            MatchManipulator.createOrUpdate(new_match)

            if not self._batch_advance:
                win_counts = {
                    'red': 0,
                    'blue': 0,
                }
                for i in xrange(new_match.match_number):
                    win_counts[Match.get_by_id(
                        Match.renderKeyName(
                            new_match.event.id(),
                            new_match.comp_level,
                            new_match.set_number,
                            i+1)).winning_alliance] += 1
                for alliance, wins in win_counts.items():
                    if wins == 2:
                        s = new_match.set_number
                        if s in {1, 2}:
                            self._advancement_alliances['sf1']['red' if s == 1 else 'blue'] = new_match.alliances[alliance]['teams']
                        elif s in {3, 4}:
                            self._advancement_alliances['sf2']['red' if s == 3 else 'blue'] = new_match.alliances[alliance]['teams']
                        else:
                            raise Exception("Invalid set number: {}".format(s))

                        for match_set, alliances in self._advancement_alliances.items():
                            if match_set.startswith('sf'):
                                for i in xrange(3):
                                    for match in copy.deepcopy(self._all_matches['sf']):
                                        key = '2016nytr_{}m{}'.format(match_set, i+1)
                                        if match.key.id() == key:
                                            for color in ['red', 'blue']:
                                                match.alliances[color]['score'] = -1
                                                match.alliances[color]['teams'] = alliances.get(color, [])
                                            match.alliances_json = json.dumps(match.alliances)
                                            match.score_breakdown_json = None
                                            match.actual_time = None
                                            MatchManipulator.createOrUpdate(match)

            if self._substep < len(self._played_matches['qf']) - 1:
                self._substep += 1
            else:
                self._step += 1 if self._batch_advance else 2
                self._substep = 0
        elif self._step == 5:  # SF schedule added
            if self._batch_advance:
                for match in copy.deepcopy(self._all_matches['sf']):
                    for alliance in ['red', 'blue']:
                        match.alliances[alliance]['score'] = -1
                    match.alliances_json = json.dumps(match.alliances)
                    match.score_breakdown_json = None
                    match.actual_time = None
                    MatchManipulator.createOrUpdate(match)
                self._step += 1
        elif self._step == 6:  # After each SF match
            new_match = MatchHelper.play_order_sort_matches(self._played_matches['sf'])[self._substep]
            MatchManipulator.createOrUpdate(new_match)

            if not self._batch_advance:
                win_counts = {
                    'red': 0,
                    'blue': 0,
                }
                for i in xrange(new_match.match_number):
                    win_counts[Match.get_by_id(
                        Match.renderKeyName(
                            new_match.event.id(),
                            new_match.comp_level,
                            new_match.set_number,
                            i+1)).winning_alliance] += 1
                for alliance, wins in win_counts.items():
                    if wins == 2:
                        self._advancement_alliances['f1']['red' if new_match.set_number == 1 else 'blue'] = new_match.alliances[alliance]['teams']

                        for match_set, alliances in self._advancement_alliances.items():
                            if match_set.startswith('f'):
                                for i in xrange(3):
                                    for match in copy.deepcopy(self._all_matches['f']):
                                        key = '2016nytr_{}m{}'.format(match_set, i+1)
                                        if match.key.id() == key:
                                            for color in ['red', 'blue']:
                                                match.alliances[color]['score'] = -1
                                                match.alliances[color]['teams'] = alliances.get(color, [])
                                            match.alliances_json = json.dumps(match.alliances)
                                            match.score_breakdown_json = None
                                            match.actual_time = None
                                            MatchManipulator.createOrUpdate(match)

            # Backup robot introduced
            if self._substep == 3:
                EventDetailsManipulator.createOrUpdate(EventDetails(
                    id='2016nytr',
                    alliance_selections=self._event_details.alliance_selections
                ))
            if self._substep < len(self._played_matches['sf']) - 1:
                self._substep += 1
            else:
                self._step += 1 if self._batch_advance else 2
                self._substep = 0
        elif self._step == 7:  # F schedule added
            if self._batch_advance:
                for match in copy.deepcopy(self._all_matches['f']):
                    for alliance in ['red', 'blue']:
                        match.alliances[alliance]['score'] = -1
                    match.alliances_json = json.dumps(match.alliances)
                    match.score_breakdown_json = None
                    match.actual_time = None
                    MatchManipulator.createOrUpdate(match)
                self._step += 1
        elif self._step == 8:  # After each F match
            MatchManipulator.createOrUpdate(
                MatchHelper.play_order_sort_matches(
                    self._played_matches['f'])[self._substep])
            if self._substep < len(self._played_matches['f']) - 1:
                self._substep += 1
            else:
                self._step += 1
                self._substep = 0

        ndb.get_context().clear_cache()
        # Re fetch event matches
        event = Event.get_by_id('2016nytr')
        MatchHelper.deleteInvalidMatches(event.matches, event)
        ndb.get_context().clear_cache()
        self._update_rankings()
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event or event.year != 2016:
            self.abort(404)

        event.get_matches_async()

        match_predictions = event.details.predictions.get('match_predictions', None)
        match_prediction_stats = event.details.predictions.get('match_prediction_stats', None)

        ranking_predictions = event.details.predictions.get('ranking_predictions', None)
        ranking_prediction_stats = event.details.predictions.get('ranking_prediction_stats', None)

        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)

        # If no matches but there are match predictions, create fake matches
        # For cases where FIRST doesn't allow posting of match schedule
        fake_matches = False
        if not matches['qm'] and match_predictions:
            fake_matches = True
            for i in xrange(len(match_predictions.keys())):
                match_number = i + 1
                alliances = {
                    'red': {
                        'score': -1,
                        'teams': ['frc?', 'frc?', 'frc?']
                    },
                    'blue': {
                        'score': -1,
                        'teams': ['frc?', 'frc?', 'frc?']
                    }
                }
                matches['qm'].append(Match(
                    id=Match.renderKeyName(
                        event_key,
                        'qm',
                        1,
                        match_number),
                    event=event.key,
                    year=event.year,
                    set_number=1,
                    match_number=match_number,
                    comp_level='qm',
                    alliances_json=json.dumps(alliances),
                ))

        last_played_match_num = None
        if ranking_prediction_stats:
            last_played_match_key = ranking_prediction_stats.get('last_played_match', None)
            if last_played_match_key:
                last_played_match_num = last_played_match_key.split('_qm')[1]

        self.template_values.update({
            "event": event,
            "matches": matches,
            "fake_matches": fake_matches,
            "match_predictions": match_predictions,
            "match_prediction_stats": match_prediction_stats,
            "ranking_predictions": ranking_predictions,
            "ranking_prediction_stats": ranking_prediction_stats,
            "last_played_match_num": last_played_match_num,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_insights.html', self.template_values)
예제 #28
0
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()
        medias_future = media_query.EventTeamsPreferredMediasQuery(
            event_key).fetch_async()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        # Organize medias by team
        image_medias = MediaHelper.get_images(
            [media for media in medias_future.get_result()])
        team_medias = defaultdict(list)
        for image_media in image_medias:
            for reference in image_media.references:
                team_medias[reference].append(image_media)
        team_and_medias = []
        for team in teams:
            team_and_medias.append((team, team_medias.get(team.key, [])))

        num_teams = len(team_and_medias)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = team_and_medias[:middle_value], team_and_medias[
            middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()
                ] if (event.matchstats is not None
                      and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches,
                                                    event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(
                matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(
                event.district_points['points'].items(),
                key=lambda (team, points): -points['total'])

        event_insights = EventInsightsHelper.calculate_event_insights(
            cleaned_matches, event.year)
        event_insights_template = None
        if event_insights:
            event_insights_template = 'event_partials/event_insights_{}.html'.format(
                event.year)

        self.template_values.update({
            "event":
            event,
            "district_name":
            DistrictType.type_names.get(event.event_district_enum, None),
            "district_abbrev":
            DistrictType.type_abbrevs.get(event.event_district_enum, None),
            "matches":
            matches,
            "matches_recent":
            matches_recent,
            "matches_upcoming":
            matches_upcoming,
            "awards":
            awards,
            "teams_a":
            teams_a,
            "teams_b":
            teams_b,
            "num_teams":
            num_teams,
            "oprs":
            oprs,
            "bracket_table":
            bracket_table,
            "playoff_advancement":
            playoff_advancement,
            "district_points_sorted":
            district_points_sorted,
            "is_2015_playoff":
            is_2015_playoff,
            "event_insights_qual":
            event_insights['qual'] if event_insights else None,
            "event_insights_playoff":
            event_insights['playoff'] if event_insights else None,
            "event_insights_template":
            event_insights_template,
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)
    def _render(self, event_key):
        event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        event.prepAwardsMatchesTeams()

        awards = AwardHelper.organizeAwards(event.awards)
        cleaned_matches = MatchHelper.deleteInvalidMatches(event.matches)
        matches = MatchHelper.organizeMatches(cleaned_matches)
        teams = TeamHelper.sortTeams(event.teams)

        num_teams = len(teams)
        middle_value = num_teams / 2
        if num_teams % 2 != 0:
            middle_value += 1
        teams_a, teams_b = teams[:middle_value], teams[middle_value:]

        oprs = [i for i in event.matchstats['oprs'].items()
                ] if (event.matchstats is not None
                      and 'oprs' in event.matchstats) else []
        oprs = sorted(oprs, key=lambda t: t[1], reverse=True)  # sort by OPR
        oprs = oprs[:15]  # get the top 15 OPRs

        if event.now:
            matches_recent = MatchHelper.recentMatches(cleaned_matches)
            matches_upcoming = MatchHelper.upcomingMatches(cleaned_matches)
        else:
            matches_recent = None
            matches_upcoming = None

        bracket_table = MatchHelper.generateBracket(matches,
                                                    event.alliance_selections)
        is_2015_playoff = EventHelper.is_2015_playoff(event_key)
        if is_2015_playoff:
            playoff_advancement = MatchHelper.generatePlayoffAdvancement2015(
                matches, event.alliance_selections)
            for comp_level in ['qf', 'sf']:
                if comp_level in bracket_table:
                    del bracket_table[comp_level]
        else:
            playoff_advancement = None

        district_points_sorted = None
        if event.district_points:
            district_points_sorted = sorted(
                event.district_points['points'].items(),
                key=lambda (team, points): -points['total'])

        event_insights = EventInsightsHelper.calculate_event_insights(
            cleaned_matches, event.year)

        self.template_values.update({
            "event": event,
            "matches": matches,
            "matches_recent": matches_recent,
            "matches_upcoming": matches_upcoming,
            "awards": awards,
            "teams_a": teams_a,
            "teams_b": teams_b,
            "num_teams": num_teams,
            "oprs": oprs,
            "bracket_table": bracket_table,
            "playoff_advancement": playoff_advancement,
            "district_points_sorted": district_points_sorted,
            "is_2015_playoff": is_2015_playoff,
            "event_insights": event_insights
        })

        if event.within_a_day:
            self._cache_expiration = self.SHORT_CACHE_EXPIRATION

        return jinja2_engine.render('event_details.html', self.template_values)