def _render(self, team_number): self.response.headers['content-type'] = 'text/plain; charset="utf-8"' user = self.request.get('user') if user: user_str = '@{}, '.format(user) else: user_str = '' team_event_or_error = validate_team(user_str, team_number) if type(team_event_or_error) == str: return team_event_or_error _, event = team_event_or_error event_code_upper = event.event_short.upper() matches_future = TeamEventMatchesQuery('frc{}'.format(team_number), event.key.id()).fetch_async() matches = MatchHelper.play_order_sort_matches(matches_future.get_result()) # No match schedule yet if not matches: return "{}[{}] Team {} has no scheduled matches yet.".format(user_str, event_code_upper, team_number) next_match = None for match in matches: if not match.has_been_played: next_match = match break if next_match is None: return "{}[{}] Team {} has no more scheduled matches.".format(user_str, event_code_upper, team_number) return "{}[{}] Team {} will be playing in match {}.".format(user_str, event_code_upper, team_number, match.short_name)
def _render(self, team_number, tz_str=None): import pytz from pytz.exceptions import UnknownTimeZoneError user = self.request.get('user') if user: user_str = '@{}, '.format(user) else: user_str = '' try: arg_tz = pytz.timezone(tz_str) if tz_str else None except UnknownTimeZoneError: arg_tz = None team_event_or_error = validate_team(user_str, team_number) if type(team_event_or_error) == str: return team_event_or_error _, event = team_event_or_error event_code_upper = event.event_short.upper() matches_future = TeamEventMatchesQuery('frc{}'.format(team_number), event.key.id()).fetch_async() matches = MatchHelper.play_order_sort_matches( matches_future.get_result()) # No match schedule yet if not matches: return "{}[{}] Team {} has no scheduled matches yet.".format( user_str, event_code_upper, team_number) next_match = None for match in matches: if not match.has_been_played: next_match = match break if next_match is None: return "{}[{}] Team {} has no more scheduled matches.".format( user_str, event_code_upper, team_number) predicted_str = "predicted" if next_match.predicted_time else "scheduled" match_time = next_match.predicted_time if next_match.predicted_time else next_match.time timezone = arg_tz if arg_tz else pytz.timezone(event.timezone_id) predicted_time_local = pytz.utc.localize(match_time).astimezone( timezone) if timezone else match_time time_string = ", {} to start at {}".format( predicted_str, predicted_time_local.strftime("%a %H:%M %Z")) if match_time else "" return "{}[{}] Team {} will be playing in match {}{}".format( user_str, event_code_upper, team_number, next_match.short_name, time_string)
def test_match_updated(self): affected_refs = { 'key': {ndb.Key(Match, '2015casj_qm1'), ndb.Key(Match, '2015casj_qm2')}, 'event': {ndb.Key(Event, '2015casj'), ndb.Key(Event, '2015cama')}, 'team_keys': {ndb.Key(Team, 'frc254'), ndb.Key(Team, 'frc604')}, 'year': {2014, 2015}, } cache_keys = [ q.cache_key for q in get_affected_queries.match_updated(affected_refs) ] self.assertEqual(len(cache_keys), 16) self.assertTrue(MatchQuery('2015casj_qm1').cache_key in cache_keys) self.assertTrue(MatchQuery('2015casj_qm2').cache_key in cache_keys) self.assertTrue( MatchGdcvDataQuery('2015casj_qm1').cache_key in cache_keys) self.assertTrue( MatchGdcvDataQuery('2015casj_qm2').cache_key in cache_keys) self.assertTrue(EventMatchesQuery('2015casj').cache_key in cache_keys) self.assertTrue(EventMatchesQuery('2015cama').cache_key in cache_keys) self.assertTrue( EventMatchesGdcvDataQuery('2015casj').cache_key in cache_keys) self.assertTrue( EventMatchesGdcvDataQuery('2015cama').cache_key in cache_keys) self.assertTrue( TeamEventMatchesQuery('frc254', '2015casj').cache_key in cache_keys) self.assertTrue( TeamEventMatchesQuery('frc254', '2015cama').cache_key in cache_keys) self.assertTrue( TeamEventMatchesQuery('frc604', '2015casj').cache_key in cache_keys) self.assertTrue( TeamEventMatchesQuery('frc604', '2015cama').cache_key in cache_keys) self.assertTrue( TeamYearMatchesQuery('frc254', 2014).cache_key in cache_keys) self.assertTrue( TeamYearMatchesQuery('frc254', 2015).cache_key in cache_keys) self.assertTrue( TeamYearMatchesQuery('frc604', 2014).cache_key in cache_keys) self.assertTrue( TeamYearMatchesQuery('frc604', 2015).cache_key in cache_keys)
def _render(self, team_key, event_key, model_type=None): matches, self._last_modified = TeamEventMatchesQuery( team_key, event_key).fetch(dict_version=3, return_updated=True) if model_type is not None: matches = filter_match_properties(matches, model_type) return json.dumps(matches, ensure_ascii=True, indent=2, sort_keys=True)
def _render(self, team_number, tz_str=None): import pytz from pytz.exceptions import UnknownTimeZoneError user = self.request.get('user') if user: user_str = '@{}, '.format(user) else: user_str = '' try: arg_tz = pytz.timezone(tz_str) if tz_str else None except UnknownTimeZoneError: arg_tz = None team_event_or_error = validate_team(user_str, team_number) if type(team_event_or_error) == str: return team_event_or_error _, event = team_event_or_error event_code_upper = event.event_short.upper() matches_future = TeamEventMatchesQuery('frc{}'.format(team_number), event.key.id()).fetch_async() matches = MatchHelper.play_order_sort_matches(matches_future.get_result()) # No match schedule yet if not matches: return "{}[{}] Team {} has no scheduled matches yet.".format(user_str, event_code_upper, team_number) next_match = None for match in matches: if not match.has_been_played: next_match = match break if next_match is None: return "{}[{}] Team {} has no more scheduled matches.".format(user_str, event_code_upper, team_number) predicted_str = "predicted" if next_match.predicted_time else "scheduled" match_time = next_match.predicted_time if next_match.predicted_time else next_match.time timezone = arg_tz if arg_tz else pytz.timezone(event.timezone_id) predicted_time_local = pytz.utc.localize(match_time).astimezone(timezone) if timezone else match_time time_string = ", {} to start at {}".format(predicted_str, predicted_time_local.strftime("%a %H:%M %Z")) if match_time else "" return "{}[{}] Team {} will be playing in match {}{}".format(user_str, event_code_upper, team_number, next_match.short_name, time_string)
def generateTeamAtEventStatus(cls, team_key, event): """ Generate Team@Event status items :return: a tuple <long summary string, qual record, qual ranking, playoff status> """ team_number = team_key[3:] matches_future = TeamEventMatchesQuery(team_key, event.key.id()).fetch_async() matches = MatchHelper.organizeMatches(matches_future.get_result()) # Compute alliances alliance_number = cls._get_alliance_number(team_key, event) # Playoff Status status, short_playoff_status = cls._get_playoff_status(team_key, matches, alliance_number) # Still in quals or team did not make it to elims # Compute qual W-L-T wins, losses, ties, unplayed_qual = cls._get_qual_wlt(team_key, matches) if wins == 0 and losses == 0 and ties == 0: # No matches played yet status = "Team {} has not played any matches yet.".format(team_number) if not status else status # Compute rank & num_teams # Gets record from ranking data to account for surrogate matches rank, ranking_points, record, num_teams = cls._get_rank(team_number, event) rank_str = "Rank {} with {} RP".format(rank, ranking_points) # Compute final long status for nightbot, if one isn't already there if unplayed_qual > 0 and not status: if rank is not None: status = "Team {} is currently rank {}/{} with a record of {} and {} ranking points.".format(team_number, rank, num_teams, record, ranking_points) else: status = "Team {} currently has a record of {}.".format(team_number, record) elif not status: if alliance_number is None: status = "Team {} ended qualification matches at rank {}/{} with a record of {}.".format(team_number, rank, num_teams, record) elif alliance_number == 0: status = "Team {} ended qualification matches at rank {}/{} with a record of {} and was not picked for playoff matches.".format(team_number, rank, num_teams, record) else: status = "Team {} will be competing in the playoff matches on alliance #{}.".format(team_number, alliance_number) return status, record, rank_str, short_playoff_status
def match_updated(affected_refs): event_keys = filter(None, affected_refs['event']) team_keys = filter(None, affected_refs['team_keys']) years = filter(None, affected_refs['year']) queries_and_keys = [] for event_key in event_keys: queries_and_keys.append((EventMatchesQuery(event_key.id()))) for team_key in team_keys: queries_and_keys.append((TeamEventMatchesQuery(team_key.id(), event_key.id()))) for team_key in team_keys: for year in years: queries_and_keys.append((TeamYearMatchesQuery(team_key.id(), year))) return queries_and_keys
def match_updated(affected_refs): match_keys = _filter(affected_refs['key']) event_keys = _filter(affected_refs['event']) team_keys = _filter(affected_refs['team_keys']) years = _filter(affected_refs['year']) queries_and_keys = [] for match_key in match_keys: queries_and_keys.append((MatchQuery(match_key.id()))) queries_and_keys.append((MatchGdcvDataQuery(match_key.id()))) for event_key in event_keys: queries_and_keys.append((EventMatchesQuery(event_key.id()))) queries_and_keys.append((EventMatchesGdcvDataQuery(event_key.id()))) for team_key in team_keys: queries_and_keys.append( (TeamEventMatchesQuery(team_key.id(), event_key.id()))) for team_key in team_keys: for year in years: queries_and_keys.append((TeamYearMatchesQuery(team_key.id(), year))) return queries_and_keys
def _render(self, team_number): self.response.headers['content-type'] = 'text/plain; charset="utf-8"' team_event_or_error = validate_team(team_number) if type(team_event_or_error) == str: return team_event_or_error _, event = team_event_or_error event_code_upper = event.event_short.upper() team_key = 'frc{}'.format(team_number) matches_future = TeamEventMatchesQuery(team_key, event.key.id()).fetch_async() matches = MatchHelper.organizeMatches(matches_future.get_result()) # Compute alliances alliance_number = None if event.alliance_selections: for i, alliance in enumerate(event.alliance_selections): if team_key in alliance['picks']: alliance_number = i + 1 break else: alliance_number = 0 # Team didn't make it to elims level_map = { 'qf': 'quarters', 'sf': 'semis', 'f': 'the finals', } for comp_level in ['f', 'sf', 'qf']: # playoffs level_str = level_map[comp_level] if matches[comp_level]: wins = 0 losses = 0 for match in matches[comp_level]: if match.has_been_played: if team_key in match.alliances[match.winning_alliance]['teams']: wins += 1 else: losses += 1 if wins == 2: if comp_level == 'f': return "[{}]: Team {} won the event on alliance #{}.".format(event_code_upper, team_number, alliance_number) else: return "[{}]: Team {} won {} on alliance #{}.".format(event_code_upper, team_number, level_str, alliance_number) elif losses == 2: return "[{}]: Team {} got knocked out in {} on alliance #{}.".format(event_code_upper, team_number, level_str, alliance_number) else: return "[{}]: Team {} is currently {}-{} in {} on alliance #{}.".format(event_code_upper, team_number, wins, losses, level_str, alliance_number) # Still in quals or team did not make it to elims # Compute qual W-L-T wins = 0 losses = 0 ties = 0 unplayed_qual = 0 for match in matches['qm']: if match.has_been_played: if match.winning_alliance == '': ties += 1 elif team_key in match.alliances[match.winning_alliance]['teams']: wins += 1 else: losses += 1 else: unplayed_qual += 1 # Compute rank & num_teams rank = None if event.rankings: num_teams = len(event.rankings) - 1 for i, row in enumerate(event.rankings): if row[1] == team_number: rank = i if unplayed_qual > 0: if rank is not None: return "[{}]: Team {} is currently rank {}/{} with a record of {}-{}-{}.".format(event_code_upper, team_number, rank, num_teams, wins, losses, ties) else: return "[{}]: Team {} currently has a record of {}-{}-{} at [{}].".format(event_code_upper, team_number, wins, losses, ties) else: if alliance_number is None: return "[{}]: Team {} ended qualification matches at rank {}/{} with a record of {}-{}-{}.".format(event_code_upper, team_number, rank, num_teams, wins, losses, ties) elif alliance_number == 0: return "[{}]: Team {} ended qualification matches at rank {}/{} with a record of {}-{}-{} and was not picked for playoff matches.".format(event_code_upper, team_number, rank, num_teams, wins, losses, ties) else: return "[{}]: Team {} will be competing in the playoff matches on alliance #{}.".format(event_code_upper, team_number, alliance_number)
def _render(self, team_number): self.response.headers['content-type'] = 'text/plain; charset="utf-8"' user = self.request.get('user') if user: user_str = '@{}, '.format(user) else: user_str = '' team_event_or_error = validate_team(user_str, team_number) if type(team_event_or_error) == str: return team_event_or_error _, event = team_event_or_error event_code_upper = event.event_short.upper() team_key = 'frc{}'.format(team_number) matches_future = TeamEventMatchesQuery(team_key, event.key.id()).fetch_async() matches = MatchHelper.organizeMatches(matches_future.get_result()) # Compute alliances alliance_number = None if event.alliance_selections: for i, alliance in enumerate(event.alliance_selections): if team_key in alliance['picks']: alliance_number = i + 1 break else: alliance_number = 0 # Team didn't make it to elims level_map = { 'qf': 'quarters', 'sf': 'semis', 'f': 'the finals', } for comp_level in ['f', 'sf', 'qf']: # playoffs level_str = level_map[comp_level] if matches[comp_level]: wins = 0 losses = 0 for match in matches[comp_level]: if match.has_been_played: if team_key in match.alliances[match.winning_alliance]['teams']: wins += 1 else: losses += 1 if wins == 2: if comp_level == 'f': return "{}[{}] Team {} won the event on alliance #{}.".format(user_str, event_code_upper, team_number, alliance_number) else: return "{}[{}] Team {} won {} on alliance #{}.".format(user_str, event_code_upper, team_number, level_str, alliance_number) elif losses == 2: return "{}[{}] Team {} got knocked out in {} on alliance #{}.".format(user_str, event_code_upper, team_number, level_str, alliance_number) else: return "{}[{}] Team {} is currently {}-{} in {} on alliance #{}.".format(user_str, event_code_upper, team_number, wins, losses, level_str, alliance_number) # Still in quals or team did not make it to elims # Compute qual W-L-T wins = 0 losses = 0 ties = 0 unplayed_qual = 0 for match in matches['qm']: if match.has_been_played: if match.winning_alliance == '': ties += 1 elif team_key in match.alliances[match.winning_alliance]['teams']: wins += 1 else: losses += 1 else: unplayed_qual += 1 if wins == 0 and losses == 0 and ties == 0: # No matches played yet return "{}[{}] Team {} has not played any matches yet.".format(user_str, event_code_upper, team_number) # Compute rank & num_teams rank = None ranking_points = None if event.rankings: num_teams = len(event.rankings) - 1 for i, row in enumerate(event.rankings): if row[1] == team_number: rank = i ranking_points = int(float(row[2])) break if unplayed_qual > 0: if rank is not None: return "{}[{}] Team {} is currently rank {}/{} with a record of {}-{}-{} and {} ranking points.".format(user_str, event_code_upper, team_number, rank, num_teams, wins, losses, ties, ranking_points) else: return "{}[{}] Team {} currently has a record of {}-{}-{}.".format(user_str, event_code_upper, team_number, wins, losses, ties) else: if alliance_number is None: return "{}[{}] Team {} ended qualification matches at rank {}/{} with a record of {}-{}-{}.".format(user_str, event_code_upper, team_number, rank, num_teams, wins, losses, ties) elif alliance_number == 0: return "{}[{}] Team {} ended qualification matches at rank {}/{} with a record of {}-{}-{} and was not picked for playoff matches.".format(user_str, event_code_upper, team_number, rank, num_teams, wins, losses, ties) else: return "{}[{}] Team {} will be competing in the playoff matches on alliance #{}.".format(user_str, event_code_upper, team_number, alliance_number)
def _getteam_nextmatch(cls, request): team_number = request['result']['parameters']['team_number'] team_key = 'frc{}'.format(team_number) team = Team.get_by_id(team_key) if team: events = TeamYearEventsQuery(team_key, datetime.datetime.now().year).fetch() EventHelper.sort_events(events) # Find first current or future event for event in events: if event.now: matches = TeamEventMatchesQuery(team_key, event.key.id()).fetch() matches = MatchHelper.play_order_sort_matches(matches) if matches: next_match = None for match in matches: if not match.has_been_played: next_match = match break if next_match is not None: if match.predicted_time: eta = match.predicted_time - datetime.datetime.now( ) eta_str = None if eta < datetime.timedelta(minutes=5): fmt = 'Team {0} will be playing in {1} soon at the {3}.' else: eta_str = '' days = eta.days hours, rem = divmod(eta.seconds, 3600) minutes, _ = divmod(rem, 60) if days: eta_str += ' {} day{}'.format( days, '' if days == 1 else 's') if hours: eta_str += ' {} hour{}'.format( hours, '' if hours == 1 else 's') if minutes: eta_str += ' {} minute{}'.format( minutes, '' if minutes == 1 else 's') fmt = 'Team {0} will be playing in {1} in about{2} at the {3}.' text = fmt.format(team_number, match.verbose_name, eta_str, event.normalized_name) tts = fmt.format( cls._team_number_tts(team_number), match.verbose_name, eta_str, event.normalized_name) else: fmt = 'Team {0} will be playing in {1} at the {2}.' text = fmt.format(team_number, match.verbose_name, event.normalized_name) tts = fmt.format( cls._team_number_tts(team_number), match.verbose_name, event.normalized_name) add_messages = cls._create_link_chip( match.verbose_name, 'https://www.thebluealliance.com/match/{}'. format(match.key.id())) else: fmt = 'Team {0} has no more scheduled matches at the {1}.' text = fmt.format(team_number, event.normalized_name) tts = fmt.format(cls._team_number_tts(team_number), event.normalized_name) add_messages = [] else: fmt = 'Team {0} has no scheduled matches at the {1}.' text = fmt.format(team_number, event.normalized_name) tts = fmt.format(cls._team_number_tts(team_number), event.normalized_name) add_messages = [] break elif event.future: fmt = 'Team {0} will be competing at the {1} which begins on {2}.' event_date = event.start_date.strftime("%B %d") text = fmt.format(team_number, event.normalized_name, event_date) tts = fmt.format(cls._team_number_tts(team_number), event.normalized_name, event_date) add_messages = cls._create_link_chip( 'event page', 'https://www.thebluealliance.com/event/{}'.format( event.key.id())) break else: fmt = 'Team {0} is not registered for any more events this season.' text = fmt.format(team_number) tts = fmt.format(cls._team_number_tts(team_number)) add_messages = [] fmt = ' Would you like to know more about {} or another team?' text += fmt.format(team_number) tts += fmt.format(cls._team_number_tts(team_number)) add_messages += cls._create_suggestion_chips([ 'Current status', 'Location', 'Rookie year', 'Another team', 'No thanks', ]) else: fmt = 'Team {0} does not exist. Please ask about another team.' text = fmt.format(team_number) tts = fmt.format(cls._team_number_tts(team_number)) add_messages = [] return { 'speech': text, 'messages': cls._create_simple_response(text, tts=tts) + add_messages, }
def _render(self, team_key, event_key): matches = TeamEventMatchesQuery(self.team_key, self.event_key).fetch() matches = [ModelToDict.matchConverter(match) for match in matches] return json.dumps(matches, ensure_ascii=True)