def testAcceptNewKey(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm() form.set('accept_keys[]', suggestion_id) form.set('key-{}'.format(suggestion_id), '2016necmp_f1m2') response = form.submit().follow() self.assertEqual(response.status_int, 200) # Make sure we mark the Suggestion as REVIEWED suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.review_state, Suggestion.REVIEW_ACCEPTED) # Make sure the video gets associated match = Match.get_by_id(self.match2.key_name) self.assertIsNotNone(match) self.assertIsNotNone(match.youtube_videos) self.assertTrue('H-54KMwMKY0' in match.youtube_videos) # Make sure we don't add it to the first match match = Match.get_by_id(self.match.key_name) self.assertIsNotNone(match) self.assertIsNotNone(match.youtube_videos) self.assertFalse('H-54KMwMKY0' in match.youtube_videos)
def post(self, match_key): self._require_admin() alliances_json = self.request.get("alliances_json") alliances = json.loads(alliances_json) youtube_videos = json.loads(self.request.get("youtube_videos")) team_key_names = list() for alliance in alliances: team_key_names.extend(alliances[alliance].get('teams', None)) match = Match( id=match_key, event=Event.get_by_id(self.request.get("event_key_name")).key, set_number=int(self.request.get("set_number")), match_number=int(self.request.get("match_number")), comp_level=self.request.get("comp_level"), team_key_names=team_key_names, alliances_json=alliances_json, # no_auto_update = str(self.request.get("no_auto_update")).lower() == "true", #TODO ) match = MatchManipulator.createOrUpdate(match) match.youtube_videos = youtube_videos match.dirty = True # hacky MatchManipulator.createOrUpdate(match) self.redirect("/admin/match/" + match.key_name)
class TestDatafeedUsfirstTeams(unittest2.TestCase): def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() self.event = Event( id="2010sc", name="Palmetto Regional", event_type_enum=EventType.REGIONAL, short_name="Palmetto", event_short="sc", year=2010, end_date=datetime.datetime(2010, 03, 27), official=True, location='Clemson, SC', start_date=datetime.datetime(2010, 03, 24), ) self.event.put() self.match = Match( id="2010sc_qm1", alliances_json="""{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level="qm", event=self.event.key, year=2010, set_number=1, match_number=1, team_key_names=[u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073'] ) self.match.put() def tearDown(self): self.testbed.deactivate()
class TestEventMatchApiController(unittest2.TestCase): def setUp(self): app = webapp2.WSGIApplication([webapp2.Route(r'/<event_key:>', ApiEventMatchesController, methods=['GET'])], debug=True) self.testapp = webtest.TestApp(app) self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_urlfetch_stub() self.testbed.init_memcache_stub() self.testbed.init_taskqueue_stub(root_path=".") self.event = Event( id="2010sc", name="Palmetto Regional", event_type_enum=EventType.REGIONAL, short_name="Palmetto", event_short="sc", year=2010, end_date=datetime(2010, 03, 27), official=True, location='Clemson, SC', start_date=datetime(2010, 03, 24), ) self.event.put() self.match = Match( id="2010sc_qm1", alliances_json="""{"blue": {"score": 57, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": 74, "teams": ["frc281", "frc571", "frc176"]}}""", comp_level="qm", event=self.event.key, year=2010, set_number=1, match_number=1, team_key_names=[u'frc281', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073'], youtube_videos=["94UGXIq6jUA"], tba_videos=[".mp4"], time=datetime.fromtimestamp(1409527874) ) self.match.put() def tearDown(self): self.testbed.deactivate() def assertMatchJson(self, matches): match = matches[0] self.assertEqual(str(match["key"]), self.match.key.string_id()) self.assertEqual(match["comp_level"], self.match.comp_level) self.assertEqual(match["event_key"], self.match.event.string_id()) self.assertEqual(match["set_number"], self.match.set_number) self.assertEqual(match["match_number"], self.match.match_number) self.assertEqual(match["videos"], self.match.videos) self.assertEqual(match["time_string"], self.match.time_string) self.assertEqual(match["time"], 1409527874) def testEventMatchApi(self): response = self.testapp.get('/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"}) match_json = json.loads(response.body) self.assertMatchJson(match_json)
def deleteInvalidMatches(self, match_list): """ A match is invalid iff it is an elim match where the match number is 3 and the same alliance won in match numbers 1 and 2 of the same set. """ matches_by_key = {} for match in match_list: matches_by_key[match.key_name] = match return_list = [] for match in match_list: if match.comp_level in Match.ELIM_LEVELS and match.match_number == 3 and (not match.has_been_played): match_1 = matches_by_key.get( Match.renderKeyName(match.event.id(), match.comp_level, match.set_number, 1) ) match_2 = matches_by_key.get( Match.renderKeyName(match.event.id(), match.comp_level, match.set_number, 2) ) if ( match_1 != None and match_2 != None and match_1.has_been_played and match_2.has_been_played and match_1.winning_alliance == match_2.winning_alliance ): try: match.key.delete() logging.warning("Deleting invalid match: %s" % match.key_name) except: logging.warning("Tried to delete invalid match, but failed: %s" % match.key_name) continue return_list.append(match) return return_list
def get(self, year): year_event_keys = Event.query(Event.year == int(year)).fetch(1000, keys_only=True) final_match_keys = [] for event_key in year_event_keys: final_match_keys.extend(Match.query(Match.event == event_key, Match.comp_level == 'f').fetch(100, keys_only=True)) match_keys_to_repair = [] for match_key in final_match_keys: key_name = match_key.id() if '_f0m' in key_name: match_keys_to_repair.append(match_key) deleted_keys = [] matches_to_repair = ndb.get_multi(match_keys_to_repair) for match in matches_to_repair: deleted_keys.append(match.key) event = ndb.get_multi([match.event])[0] match.set_number = 1 match.key = ndb.Key(Match, Match.renderKeyName( event.key.id(), match.comp_level, match.set_number, match.match_number)) MatchManipulator.createOrUpdate(matches_to_repair) MatchManipulator.delete_keys(deleted_keys) template_values = {'deleted_keys': deleted_keys, 'new_matches': matches_to_repair} path = os.path.join(os.path.dirname(__file__), '../templates/math/final_matches_repair_do.html') self.response.out.write(template.render(path, template_values))
class TestSuggestMatchVideoYouTube(unittest2.TestCase): def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() ndb.get_context().clear_cache() # Prevent data from leaking between tests self.account = Account.get_or_insert( "123", email="*****@*****.**", registered=True) self.account.put() event = Event(id="2016test", name="Test Event", event_short="Test Event", year=2016, event_type_enum=EventType.OFFSEASON) event.put() self.match = Match(id="2016test_f1m1", event=ndb.Key(Event, "2016test"), year=2016, comp_level="f", set_number=1, match_number=1, alliances_json='') self.match.put() def tearDown(self): self.testbed.deactivate() def testBadMatch(self): status = SuggestionCreator.createMatchVideoYouTubeSuggestion(self.account.key, "37F5tbrFqJQ", "2016necmp_f1m2") self.assertEqual(status, 'bad_match') def testCreateSuggestion(self): status = SuggestionCreator.createMatchVideoYouTubeSuggestion(self.account.key, "37F5tbrFqJQ", "2016test_f1m1") self.assertEqual(status, 'success') suggestion_id = "media_2016_match_2016test_f1m1_youtube_37F5tbrFqJQ" suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.author, self.account.key) self.assertEqual(suggestion.target_key, '2016test_f1m1') self.assertEqual(suggestion.target_model, 'match') self.assertIsNotNone(suggestion.contents) self.assertIsNotNone(suggestion.contents.get('youtube_videos')) self.assertEqual(len(suggestion.contents.get('youtube_videos')), 1) self.assertEqual(suggestion.contents.get('youtube_videos')[0], "37F5tbrFqJQ") def testExistingVideo(self): self.match.youtube_videos = ["37F5tbrFqJQ"] self.match.put() status = SuggestionCreator.createMatchVideoYouTubeSuggestion(self.account.key, "37F5tbrFqJQ", "2016test_f1m1") self.assertEqual(status, 'video_exists') def testExistingSuggestion(self): status = SuggestionCreator.createMatchVideoYouTubeSuggestion(self.account.key, "37F5tbrFqJQ", "2016test_f1m1") self.assertEqual(status, 'success') status = SuggestionCreator.createMatchVideoYouTubeSuggestion(self.account.key, "37F5tbrFqJQ", "2016test_f1m1") self.assertEqual(status, 'suggestion_exists') def testBadYouTubeKey(self): status = SuggestionCreator.createMatchVideoYouTubeSuggestion(self.account.key, "", "2016test_f1m1") self.assertEqual(status, 'bad_url')
def test_createOrUpdate(self): MatchManipulator.createOrUpdate(self.old_match) self.assertOldMatch(Match.get_by_id("2012ct_qm1")) self.assertEqual(Match.get_by_id("2012ct_qm1").alliances_json, """{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""") MatchManipulator.createOrUpdate(self.new_match) self.assertMergedMatch(Match.get_by_id("2012ct_qm1"))
def getMatches(self, event): matches_url = self.YEAR_MATCH_RESULTS_URL_PATTERN.get( event.year, self.DEFAULT_MATCH_RESULTS_URL_PATTERN) % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) match_dicts, _ = self.parse(matches_url, self.YEAR_MATCH_PARSER.get(event.year, self.DEFAULT_MATCH_PARSER)) if not match_dicts: # Matches have not been played, but qual match schedule may be out # If this is run when there are already matches in the DB, it will overwrite scores! # Check to make sure event has no existing matches if len(Match.query(Match.event == event.key).fetch(1, keys_only=True)) == 0: logging.warning("No matches found for {}. Trying to parse qual match schedule.".format(event.key.id())) qual_match_sched_url = self.MATCH_SCHEDULE_QUAL_URL_PATTERN % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) match_dicts, _ = self.parse(qual_match_sched_url, self.MATCH_SCHEDULE_PARSER) for match_dict in match_dicts: alliances = json.loads(match_dict['alliances_json']) if (alliances['red']['score'] == -1 or alliances['blue']['score'] == -1 or match_dict['comp_level'] in Match.ELIM_LEVELS): break else: # Only qual matches have been played and they have all been played # If this is run when there are already elim matches in the DB, it will overwrite scores! # Check to make sure event has no existing elim matches if len(Match.query(Match.event == event.key, Match.comp_level.IN(Match.ELIM_LEVELS)).fetch(1, keys_only=True)) == 0: logging.warning("No elim matches found for {}. Trying to parse elim match schedule.".format(event.key.id())) elim_match_sched_url = self.MATCH_SCHEDULE_ELIMS_URL_PATTERN % ( event.year, self.EVENT_SHORT_EXCEPTIONS.get(event.event_short, event.event_short)) elim_match_dicts, _ = self.parse(elim_match_sched_url, self.MATCH_SCHEDULE_PARSER) match_dicts += elim_match_dicts matches = [Match( id=Match.renderKeyName( event.key.id(), match_dict.get("comp_level", None), match_dict.get("set_number", 0), match_dict.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match_dict.get("set_number", 0), match_number=match_dict.get("match_number", 0), comp_level=match_dict.get("comp_level", None), team_key_names=match_dict.get("team_key_names", None), time_string=match_dict.get("time_string", None), alliances_json=match_dict.get("alliances_json", None) ) for match_dict in match_dicts] MatchHelper.add_match_times(event, matches) return matches
class TestMatchSuggestionAccepter(unittest2.TestCase): def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() ndb.get_context().clear_cache() # Prevent data from leaking between tests self.testbed.init_taskqueue_stub(root_path=".") self.account = Account( email="*****@*****.**", ) self.account.put() self.suggestion = Suggestion( author=self.account.key, contents_json="{\"youtube_videos\":[\"123456\"]}", target_key="2012ct_qm1", target_model="match" ) self.suggestion.put() self.event = Event( id="2012ct", event_short="ct", year=2012, event_type_enum=EventType.REGIONAL, ) self.event.put() self.match = Match( id="2012ct_qm1", alliances_json="""{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level="qm", event=self.event.key, year=2012, set_number=1, match_number=1, team_key_names=[u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073'], youtube_videos=["abcdef"] ) self.match.put() def tearDown(self): self.testbed.deactivate() def test_accept_suggestions(self): MatchSuggestionAccepter.accept_suggestion(self.match, self.suggestion) match = Match.get_by_id("2012ct_qm1") self.assertTrue("abcdef" in match.youtube_videos) self.assertTrue("123456" in match.youtube_videos)
class TestDatafeedUsfirstTeams(unittest2.TestCase): def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() self.event = Event( id = "2010sc", name = "Palmetto Regional", event_type = "Regional", short_name = "Palmetto", event_short = "sc", year = 2010, end_date = datetime.datetime(2010, 03, 27), official = True, location = 'Clemson, SC', start_date = datetime.datetime(2010, 03, 24), ) self.event.put() self.match = Match( id = "2010sc_qm1", alliances_json = """{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level = "qm", event = self.event.key, game = "frc_2010_bkwy", set_number = 1, match_number = 1, team_key_names = [u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073'] ) self.match.put() def tearDown(self): self.testbed.deactivate() def test_doEventTeamUpdate(self): # call EventTeamUpdate with 2010sc eventteamupdate = EventTeamUpdate() eventteamupdate.response = Response() eventteamupdate.get("2010sc") # Teams were generated by EventTeamUpdate, make sure EventTeams # exist and feature Team Keys event_team_from_match_one = EventTeam.get_by_id("2010sc_frc69") self.assertEqual(event_team_from_match_one.event, self.event.key) self.assertEqual(event_team_from_match_one.team, ndb.Key(Team, "frc69")) event_team_from_match_two = EventTeam.get_by_id("2010sc_frc20") self.assertEqual(event_team_from_match_two.event, self.event.key) self.assertEqual(event_team_from_match_two.team, ndb.Key(Team, "frc20"))
def get_matches_async(event_keys): if event_keys == []: raise ndb.Return([]) match_keys = yield Match.query( Match.event.IN(event_keys), Match.team_key_names == team.key_name).fetch_async(500, keys_only=True) matches = yield ndb.get_multi_async(match_keys) raise ndb.Return(matches)
def _query_async(self): team_key = self._query_args[0] event_key = self._query_args[1] matches = yield Match.query( Match.team_key_names == team_key, Match.event == ndb.Key(Event, event_key)).fetch_async() raise ndb.Return(matches)
def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() ndb.get_context().clear_cache() # Prevent data from leaking between tests self.event = Event( id="2010sc", name="Palmetto Regional", event_type_enum=EventType.REGIONAL, short_name="Palmetto", event_short="sc", year=2010, end_date=datetime.datetime(2010, 03, 27), official=True, location="Clemson, SC", start_date=datetime.datetime(2010, 03, 24), ) self.event.put() self.match = Match( id="2010sc_qm1", alliances_json="""{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level="qm", event=self.event.key, year=2010, set_number=1, match_number=1, team_key_names=[u"frc69", u"frc571", u"frc176", u"frc3464", u"frc20", u"frc1073"], ) self.match.put()
def _render(self, team_number): team = Team.get_by_id("frc" + team_number) if not team: return self.redirect("/error/404") event_team_keys_future = EventTeam.query(EventTeam.team == team.key).fetch_async(1000, keys_only=True) award_keys_future = Award.query(Award.team == team.key).fetch_async(1000, keys_only=True) event_teams_futures = ndb.get_multi_async(event_team_keys_future.get_result()) awards_futures = ndb.get_multi_async(award_keys_future.get_result()) event_keys = [event_team_future.get_result().event for event_team_future in event_teams_futures] events_futures = ndb.get_multi_async(event_keys) awards_by_event = {} for award_future in awards_futures: award = award_future.get_result() if award.event.id() not in awards_by_event: awards_by_event[award.event.id()] = [award] else: awards_by_event[award.event.id()].append(award) event_awards = [] current_event = None matches_upcoming = None short_cache = False for event_future in events_futures: event = event_future.get_result() if event.now: current_event = event team_matches_future = Match.query(Match.event == event.key, Match.team_key_names == team.key_name)\ .fetch_async(500, keys_only=True) matches = ndb.get_multi(team_matches_future.get_result()) matches_upcoming = MatchHelper.upcomingMatches(matches) if event.within_a_day: short_cache = True if event.key_name in awards_by_event: sorted_awards = AwardHelper.organizeAwards(awards_by_event[event.key_name])['list'] else: sorted_awards = [] event_awards.append((event, sorted_awards)) event_awards = sorted(event_awards, key=lambda (e, _): e.start_date if e.start_date else datetime.datetime(e.year, 12, 31)) years = sorted(set([et.get_result().year for et in event_teams_futures if et.get_result().year != None])) template_values = {'team': team, 'event_awards': event_awards, 'years': years, 'current_event': current_event, 'matches_upcoming': matches_upcoming} if short_cache: self._cache_expiration = self.SHORT_CACHE_EXPIRATION path = os.path.join(os.path.dirname(__file__), '../templates/team_history.html') return template.render(path, template_values)
def parse(self, response): matches = response['MatchScores'] match_details_by_key = {} for match in matches: comp_level = get_comp_level(self.year, match['matchLevel'], match['matchNumber']) set_number, match_number = get_set_match_number(self.year, comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] for alliance in match['Alliances']: color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def parse(self, response): matches = response['MatchScores'] match_details_by_key = {} is_octofinals = len(matches) > 0 and matches[len(matches) - 1]['matchNumber'] > 23 # Hacky; this should be 24. Banking on the fact that 3 tiebreakers is rare for match in matches: comp_level = get_comp_level(self.year, match['matchLevel'], match['matchNumber'], is_octofinals) set_number, match_number = get_set_match_number(self.year, comp_level, match['matchNumber'], is_octofinals) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] for alliance in match['Alliances']: color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() self.event = Event( id = "2012ct", event_short = "ct", year = 2012 ) self.old_match = Match( id = "2012ct_qm1", alliances_json = """{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level = "qm", event = self.event.key, game = "frc_2012_rebr", set_number = 1, match_number = 1, team_key_names = [u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073'] ) self.new_match = Match( id = "2012ct_qm1", alliances_json = """{"blue": {"score": 57, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": 74, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level = "qm", event = self.event.key, game = "frc_2012_rebr", set_number = 1, match_number = 1, team_key_names = [u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073'] )
def post(self, match_key): self._require_login() self._require_registration() current_user_id = self.user_bundle.account.key.id() match = Match.get_by_id(match_key) if self.request.get('favorite'): favorite = Favorite( parent=ndb.Key(Account, current_user_id), user_id=current_user_id, model_type=ModelType.MATCH, model_key=match_key ) MyTBAHelper.add_favorite(favorite) else: MyTBAHelper.remove_favorite(current_user_id, match_key, ModelType.MATCH) subs = self.request.get_all('notification_types') if subs: subscription = Subscription( parent=ndb.Key(Account, current_user_id), user_id=current_user_id, model_type=ModelType.MATCH, model_key=match_key, notification_types=[int(s) for s in subs] ) MyTBAHelper.add_subscription(subscription) else: MyTBAHelper.remove_subscription(current_user_id, match_key, ModelType.MATCH) self.redirect('/account/mytba?status=match_updated#my-matches')
def post(self): self._require_admin() event_key = self.request.get('event_key') matches_csv = self.request.get('matches_csv') matches = OffseasonMatchesParser.parse(matches_csv) event = Event.get_by_id(event_key) matches = [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, game=Match.FRC_GAMES_BY_YEAR.get(event.year, "frc_unknown"), set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in matches] try: FirebasePusher.updated_event(event.key_name) except: logging.warning("Enqueuing Firebase push failed!") self.redirect('/admin/event/{}'.format(event_key))
def post(self): self._require_registration() event_key = self.request.get("event_key") if not event_key: self.response.out.write("No event key found") return event_future = Event.get_by_id_async(event_key) event = event_future.get_result() if not event: self.response.out.write("Invalid event key {}".format(event_key)) return match_futures = Match.query(Match.event == event.key).fetch_async(keys_only=True) valid_match_keys = [match.id() for match in match_futures.get_result()] num_videos = int(self.request.get("num_videos", 0)) suggestions_added = 0 for i in range(0, num_videos): yt_id = self.request.get("video_id_{}".format(i)) match_partial = self.request.get("match_partial_{}".format(i)) if not yt_id or not match_partial: continue match_key = "{}_{}".format(event_key, match_partial) if match_key not in valid_match_keys: continue status = SuggestionCreator.createMatchVideoYouTubeSuggestion(self.user_bundle.account.key, yt_id, match_key) if status == 'success': suggestions_added += 1 self.redirect('/suggest/event/video?event_key={}&num_added={}'.format(event_key, suggestions_added))
def get(self, match_key): self._require_login() self._require_registration() match = Match.get_by_id(match_key) if not match: self.abort(404) user = self.user_bundle.account.key favorite = Favorite.query(Favorite.model_key==match_key, Favorite.model_type==ModelType.MATCH, ancestor=user).get() subscription = Subscription.query(Favorite.model_key==match_key, Favorite.model_type==ModelType.MATCH, ancestor=user).get() if not favorite and not subscription: # New entry; default to being a favorite is_favorite = True else: is_favorite = favorite is not None enabled_notifications = [(en, NotificationType.render_names[en]) for en in NotificationType.enabled_match_notifications] self.template_values['match'] = match self.template_values['is_favorite'] = is_favorite self.template_values['subscription'] = subscription self.template_values['enabled_notifications'] = enabled_notifications self.response.out.write(jinja2_engine.render('mytba_match.html', self.template_values))
def get(self, event_key): event = Event.get_by_id(event_key) team_ids = set() # Add teams from Matches for match in Match.query(Match.event == event.key).fetch(1000): for team in match.team_key_names: team_ids.add(team) teams = TeamManipulator.createOrUpdate([Team( id = team_id, team_number = int(team_id[3:])) for team_id in team_ids]) if teams: event_teams = EventTeamManipulator.createOrUpdate([EventTeam( id = event_key + "_" + team.key.id(), event = event.key, team = team.key, year = event.year) for team in teams]) else: event_teams = None template_values = { 'event_teams': event_teams, } path = os.path.join(os.path.dirname(__file__), '../templates/math/eventteam_update_do.html') self.response.out.write(template.render(path, template_values))
def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() ndb.get_context().clear_cache() # Prevent data from leaking between tests self.account = Account.get_or_insert( "123", email="*****@*****.**", registered=True) self.account.put() self.account_banned = Account.get_or_insert( "456", email="*****@*****.**", registered=True, shadow_banned=True, ) self.account_banned.put() event = Event(id="2016test", name="Test Event", event_short="Test Event", year=2016, event_type_enum=EventType.OFFSEASON) event.put() self.match = Match(id="2016test_f1m1", event=ndb.Key(Event, "2016test"), year=2016, comp_level="f", set_number=1, match_number=1, alliances_json='') self.match.put()
def addTeamDetails(self, team_dict, year): """ Consume a Team dict, and return it with a year's Events filtered and Matches added """ # TODO Matches should live under Events - gregmarra 1 feb 2011 # TODO Filter Events by year - gregmarra 1 feb 2011 memcache_key = "api_team_details_%s_%s" % (team_dict["key"], year) matches_list = memcache.get(memcache_key) if matches_list is None: matches = list() team = Team.get_by_id(team_dict["key"]) for e in [a.event.get() for a in EventTeam.query(EventTeam.team == team.key).fetch(1000) if a.year == year]: match_list = Match.query(Match.event == event.key, Match.team_key_names == team.key_name).fetch(500) matches.extend(match_list) matches_list = list() for match in matches: match_dict = dict() match_dict["key"] = match.key_name match_dict["event"] = match.event match_dict["comp_level"] = match.comp_level match_dict["set_number"] = match.set_number match_dict["match_number"] = match.match_number match_dict["team_keys"] = match.team_key_names match_dict["alliances"] = json.loads(match.alliances_json) matches_list.append(match_dict) #TODO: Reduce caching time before 2013 season. 2592000 is one month -gregmarra if tba_config.CONFIG["memcache"]: memcache.set(memcache_key, matches_list, 2592000) team_dict["matches"] = matches_list return team_dict
def update(self, event_key): """ Updates EventTeams for an event. Returns a tuple of (teams, event_teams, event_team_keys_to_delete) An EventTeam is valid iff the team: a) played a match at the event, b) the team received an award at the event, c) or the event has not yet occurred. """ event = Event.get_by_id(event_key) # Add teams from Matches and Awards team_ids = set() match_key_futures = Match.query( Match.event == event.key).fetch_async(1000, keys_only=True) award_key_futures = Award.query( Award.event == event.key).fetch_async(1000, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) for match_future in match_futures: match = match_future.get_result() for team in match.team_key_names: team_ids.add(team) for award_future in award_futures: award = award_future.get_result() for team_key in award.team_list: team_ids.add(team_key.id()) # Create or update EventTeams teams = [Team(id=team_id, team_number=int(team_id[3:])) for team_id in team_ids] if teams: event_teams = [EventTeam(id=event_key + "_" + team.key.id(), event=event.key, team=team.key, year=event.year) for team in teams] else: event_teams = None # Delete EventTeams for teams who did not participate in the event # Only runs if event is over existing_event_teams_keys = EventTeam.query( EventTeam.event == event.key).fetch(1000, keys_only=True) existing_event_teams = ndb.get_multi(existing_event_teams_keys) existing_team_ids = set() for et in existing_event_teams: existing_team_ids.add(et.team.id()) et_keys_to_delete = set() if event.end_date is not None and event.end_date < datetime.datetime.now(): for team_id in existing_team_ids.difference(team_ids): et_key_name = "{}_{}".format(event.key_name, team_id) et_keys_to_delete.add(ndb.Key(EventTeam, et_key_name)) ndb.delete_multi(et_keys_to_delete) return teams, event_teams, et_keys_to_delete
def parse(self, response): """ This currently only works for the 2015 game. """ matches = response["MatchScores"] match_details_by_key = {} set_number = 1 for match in matches: comp_level = get_comp_level(match["matchLevel"], match["matchNumber"]) match_number = get_match_number(comp_level, match["matchNumber"]) breakdown = {"red": {}, "blue": {}} if "coopertition" in match: breakdown["coopertition"] = match["coopertition"] if "coopertitionPoints" in match: breakdown["coopertition_points"] = match["coopertitionPoints"] for alliance in match["Alliances"]: color = alliance["alliance"].lower() for key, value in alliance.items(): if key != "alliance": breakdown[color][camel_to_snake(key)] = value match_details_by_key[ Match.renderKeyName("{}{}".format(self.year, self.event_short), comp_level, set_number, match_number) ] = breakdown return match_details_by_key
def main(key, url): print "Configuring GAE Remote API on {} to import {}".format(url, key) if 'localhost' in url: remote_api_stub.ConfigureRemoteApi(None, '/_ah/remote_api', local_auth_func, url) else: remote_api_stub.ConfigureRemoteApiForOAuth(url, '/_ah/remote_api') print "Loading data from The Blue Alliance requires an API key" print "Please go to https://thebluealliance.com/account and generate a read API key" apiv3_key = raw_input("Enter your API key: ") global AUTH_TOKEN AUTH_TOKEN = apiv3_key if Match.validate_key_name(key): match_data = fetch_match(key) store_match(match_data) elif Event.validate_key_name(key): update_event(key) elif Team.validate_key_name(key): team_data = fetch_team(key) store_team(team_data) elif key.isdigit(): event_keys = [event['key'] for event in fetch_endpoint('events/{}'.format(key))] for event in event_keys: update_event(event) else: print "Unknown key :("
def post(self): self._require_admin() event_key = self.request.get('event_key') matches_csv = self.request.get('matches_csv') matches, _ = OffseasonMatchesParser.parse(matches_csv) event = Event.get_by_id(event_key) matches = [Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in matches] MatchManipulator.createOrUpdate(matches) self.redirect('/admin/event/{}'.format(event_key))
def _query_async(self): team_key = self._query_args[0] year = self._query_args[1] matches = yield Match.query( Match.team_key_names == team_key, Match.year == year).fetch_async() raise ndb.Return(matches)
def calculate_event_points(cls, event): match_key_futures = Match.query(Match.event == event.key).fetch_async( None, keys_only=True) award_key_futures = Award.query(Award.event == event.key).fetch_async( None, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) POINTS_MULTIPLIER = 3 if event.event_type_enum == EventType.DISTRICT_CMP else 1 district_points = { 'points': defaultdict(lambda: { 'qual_points': 0, 'elim_points': 0, 'alliance_points': 0, 'award_points': 0, 'total': 0, }), 'tiebreakers': defaultdict(lambda: { # for tiebreaker stats that can't be calculated with 'points' 'qual_wins': 0, 'highest_qual_scores': [], }), } # match points elim_num_wins = defaultdict(lambda: defaultdict(int)) elim_alliances = defaultdict(lambda: defaultdict(list)) for match_future in match_futures: match = match_future.get_result() if not match.has_been_played: continue if match.comp_level == 'qm': if match.winning_alliance == '': for team in match.team_key_names: district_points['points'][team][ 'qual_points'] += 1 * POINTS_MULTIPLIER else: for team in match.alliances[ match.winning_alliance]['teams']: district_points['points'][team][ 'qual_points'] += 2 * POINTS_MULTIPLIER district_points['tiebreakers'][team]['qual_wins'] += 1 for color in ['red', 'blue']: for team in match.alliances[color]['teams']: score = match.alliances[color]['score'] district_points['tiebreakers'][team][ 'highest_qual_scores'] = heapq.nlargest( 3, district_points['tiebreakers'][team] ['highest_qual_scores'] + [score]) else: if match.winning_alliance == '': continue match_set_key = '{}_{}{}'.format(match.event.id(), match.comp_level, match.set_number) elim_num_wins[match_set_key][match.winning_alliance] += 1 elim_alliances[match_set_key][ match.winning_alliance] += match.alliances[ match.winning_alliance]['teams'] if elim_num_wins[match_set_key][match.winning_alliance] >= 2: for team in elim_alliances[match_set_key][ match.winning_alliance]: district_points['points'][team][ 'elim_points'] += 5 * POINTS_MULTIPLIER # alliance points if event.alliance_selections: selection_points = EventHelper.alliance_selections_to_points( event.alliance_selections) for team, points in selection_points.items(): district_points['points'][team][ 'alliance_points'] += points * POINTS_MULTIPLIER else: logging.warning( "Event {} has no alliance selection district_points!".format( event.key.id())) # award points for award_future in award_futures: award = award_future.get_result() if award.award_type_enum not in AwardType.NON_JUDGED_NON_TEAM_AWARDS: if award.award_type_enum == AwardType.CHAIRMANS: point_value = 10 elif award.award_type_enum in { AwardType.ENGINEERING_INSPIRATION, AwardType.ROOKIE_ALL_STAR }: point_value = 8 else: point_value = 5 for team in award.team_list: district_points['points'][team.id( )]['award_points'] += point_value * POINTS_MULTIPLIER for team, point_breakdown in district_points['points'].items(): for p in point_breakdown.values(): district_points['points'][team]['total'] += p return district_points
def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() ndb.get_context().clear_cache( ) # Prevent data from leaking between tests app = webapp2.WSGIApplication([ RedirectRoute(r'/match/<match_key>', MatchDetail, 'match-detail'), ]) self.testapp = webtest.TestApp(app) self.match = Match(id="2014cc_f1m1", event=ndb.Key(Event, "2014cc"), year=2014, comp_level="f", set_number=1, match_number=1, team_key_names=[ u'frc846', u'frc2135', u'frc971', u'254', u'frc1678', u'frc973' ], time=datetime.fromtimestamp(1409527874), time_string="4:31 PM", youtube_videos=["JbwUzl3W9ug", "bHGyTjxbLz8"], tba_videos=[], alliances_json='{\ "blue": {\ "score": 270,\ "teams": [\ "frc846",\ "frc2135",\ "frc971"]},\ "red": {\ "score": 310,\ "teams": [\ "frc254",\ "frc1678",\ "frc973"]}}', score_breakdown_json='{\ "blue": {\ "auto": 70,\ "teleop_goal+foul": 40,\ "assist": 120,\ "truss+catch": 40\ },"red": {\ "auto": 70,\ "teleop_goal+foul": 50,\ "assist": 150,\ "truss+catch": 40}}') self.event = Event(id="2014cc", name="Cheesy Champs", event_type_enum=EventType.OFFSEASON, short_name="Cheesy Champs", event_short="cc", year=2014, end_date=datetime(2014, 03, 27), official=True, city='Hartford', state_prov='CT', country='USA', venue="Some Venue", venue_address="Some Venue, Hartford, CT, USA", timezone_id="America/New_York", start_date=datetime(2014, 03, 24)) self.match.put() self.event.put()
class TestMatchApiController(unittest2.TestCase): def setUp(self): app = webapp2.WSGIApplication([ webapp2.Route( r'/<match_key:>', ApiMatchController, methods=['GET']) ], debug=True) self.testapp = webtest.TestApp(app) self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_urlfetch_stub() self.testbed.init_memcache_stub() ndb.get_context().clear_cache( ) # Prevent data from leaking between tests self.testbed.init_taskqueue_stub(root_path=".") self.match = Match(id="2014cc_f1m1", event=ndb.Key(Event, "2014cc"), year=2014, comp_level="f", set_number=1, match_number=1, team_key_names=[ u'frc846', u'frc2135', u'frc971', u'254', u'frc1678', u'frc973' ], time=datetime.datetime.fromtimestamp(1409527874), time_string="4:31 PM", youtube_videos=["JbwUzl3W9ug", "bHGyTjxbLz8"], tba_videos=[], alliances_json='{\ "blue": {\ "score": 270,\ "teams": [\ "frc846",\ "frc2135",\ "frc971"]},\ "red": {\ "score": 310,\ "teams": [\ "frc254",\ "frc1678",\ "frc973"]}}', score_breakdown_json='{\ "blue": {\ "auto": 70,\ "teleop_goal+foul": 40,\ "assist": 120,\ "truss+catch": 40\ },"red": {\ "auto": 70,\ "teleop_goal+foul": 50,\ "assist": 150,\ "truss+catch": 40}}') self.match.put() def tearDown(self): self.testbed.deactivate() def assertMatchJson(self, match): self.assertEqual(str(match["key"]), self.match.key.string_id()) self.assertEqual(match["comp_level"], self.match.comp_level) self.assertEqual(match["event_key"], self.match.event.string_id()) self.assertEqual(match["set_number"], self.match.set_number) self.assertEqual(match["match_number"], self.match.match_number) self.assertEqual(match["alliances"], self.match.alliances) self.assertEqual(match["score_breakdown"], self.match.score_breakdown) self.assertEqual(match["videos"], self.match.videos) self.assertEqual(match["time_string"], self.match.time_string) if self.match.time is None: self.assertEqual(match["time"], None) else: self.assertEqual(match["time"], 1409527874) def testMatchApi(self): response = self.testapp.get( '/2014cc_f1m1', headers={"X-TBA-App-Id": "tba-tests:match-controller-test:v01"}) match_json = json.loads(response.body) self.assertMatchJson(match_json)
def get_matches_async(self): from models.match import Match match_keys = yield Match.query(Match.event == self.key).fetch_async( 500, keys_only=True) self._matches = yield ndb.get_multi_async(match_keys)
def post(self): self._require_admin() user_id = self.user_bundle.account.key.id() notification_type = self.request.get('type') if notification_type == "alliance_selection": event_key = self.request.get('event_key') event = Event.get_by_id(event_key) if not event: self.template_values.update({ 'error': 'No event for key {}'.format(event_key) }) return self.redirect('/admin/tbans') TBANSHelper.alliance_selection(event, user_id) elif notification_type == "awards": event_key = self.request.get('event_key') event = Event.get_by_id(event_key) if not event: self.template_values.update({ 'error': 'No event for key {}'.format(event_key) }) return self.redirect('/admin/tbans') TBANSHelper.awards(event, user_id) elif notification_type == "event_level": match_key = self.request.get('match_key') match = Match.get_by_id(match_key) if not match: self.template_values.update({ 'error': 'No match for key {}'.format(match_key) }) return self.redirect('/admin/tbans') TBANSHelper.event_level(match, user_id) elif notification_type == "event_schedule": event_key = self.request.get('event_key') event = Event.get_by_id(event_key) if not event: self.template_values.update({ 'error': 'No event for key {}'.format(event_key) }) return self.redirect('/admin/tbans') TBANSHelper.event_schedule(event, user_id) elif notification_type == "match_score": match_key = self.request.get('match_key') match = Match.get_by_id(match_key) if not match: self.template_values.update({ 'error': 'No match for key {}'.format(match_key) }) return self.redirect('/admin/tbans') TBANSHelper.match_score(match, user_id) elif notification_type == "match_upcoming": match_key = self.request.get('match_key') match = Match.get_by_id(match_key) if not match: self.template_values.update({ 'error': 'No match for key {}'.format(match_key) }) return self.redirect('/admin/tbans') TBANSHelper.match_upcoming(match, user_id) elif notification_type == "match_video": match_key = self.request.get('match_key') match = Match.get_by_id(match_key) if not match: self.template_values.update({ 'error': 'No match for key {}'.format(match_key) }) return self.redirect('/admin/tbans') TBANSHelper.match_video(match, user_id) elif notification_type == "ping": clients = MobileClient.clients([user_id]) for client in clients: TBANSHelper.ping(client) return self.redirect('/admin/tbans')
def getTeamWLT(self, team_key, event): """ Given a team_key, and an event, find the team's Win Loss Tie. """ match_keys = Match.query(Match.event == event.key, Match.team_key_names == team_key).fetch(500, keys_only=True) return self.calculateTeamWLTFromMatches(team_key, ndb.get_multi(match_keys))
def _query_async(self): match_key = self._query_args[0] match = yield Match.get_by_id_async(match_key) raise ndb.Return(match)
def test_accept_suggestions(self): MatchSuggestionAccepter.accept_suggestion(self.match, self.suggestion) match = Match.get_by_id("2012ct_qm1") self.assertTrue("abcdef" in match.youtube_videos) self.assertTrue("123456" in match.youtube_videos)
class TestSuggestEventWebcastController(unittest2.TestCase): def loginUser(self): self.testbed.setup_env(user_email="*****@*****.**", user_id="123", user_is_admin='0', overwrite=True) self.account = Account.get_or_insert("123", email="*****@*****.**", registered=True) def givePermission(self): self.account.permissions.append(AccountPermissions.REVIEW_MEDIA) self.account.put() def createSuggestion(self): status = SuggestionCreator.createMatchVideoYouTubeSuggestion( self.account.key, "H-54KMwMKY0", "2016necmp_f1m1") self.assertEqual(status, 'success') return Suggestion.render_media_key_name(2016, 'match', '2016necmp_f1m1', 'youtube', 'H-54KMwMKY0') def setUp(self): self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy( probability=1) self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub(consistency_policy=self.policy) self.testbed.init_memcache_stub() self.testbed.init_user_stub() self.testbed.init_urlfetch_stub() self.testbed.init_taskqueue_stub(_all_queues_valid=True) ndb.get_context().clear_cache( ) # Prevent data from leaking between tests app = webapp2.WSGIApplication([ RedirectRoute(r'/suggest/match/video/review', SuggestMatchVideoReviewController, 'suggest-video', strict_slash=True), ], debug=True) self.testapp = webtest.TestApp(app) self.event = Event( id="2016necmp", name="New England District Championship", event_type_enum=EventType.DISTRICT_CMP, event_district_enum=DistrictType.NEW_ENGLAND, short_name="New England", event_short="necmp", year=2016, end_date=datetime(2016, 03, 27), official=False, city='Hartford', state_prov='CT', country='USA', venue="Some Venue", venue_address="Some Venue, Hartford, CT, USA", timezone_id="America/New_York", start_date=datetime(2016, 03, 24), webcast_json="", website="http://www.firstsv.org", ) self.event.put() self.match = Match(id="2016necmp_f1m1", event=ndb.Key(Event, "2016necmp"), year=2016, comp_level="f", set_number=1, match_number=1, team_key_names=[ 'frc846', 'frc2135', 'frc971', 'frc254', 'frc1678', 'frc973' ], time=datetime.fromtimestamp(1409527874), time_string="4:31 PM", tba_videos=[], alliances_json='{\ "blue": {\ "score": 270,\ "teams": [\ "frc846",\ "frc2135",\ "frc971"]},\ "red": {\ "score": 310,\ "teams": [\ "frc254",\ "frc1678",\ "frc973"]}}', score_breakdown_json='{\ "blue": {\ "auto": 70,\ "teleop_goal+foul": 40,\ "assist": 120,\ "truss+catch": 40\ },"red": {\ "auto": 70,\ "teleop_goal+foul": 50,\ "assist": 150,\ "truss+catch": 40}}') self.match.put() self.match2 = Match(id="2016necmp_f1m2", event=ndb.Key(Event, "2016necmp"), year=2016, comp_level="f", set_number=1, match_number=2, team_key_names=[ 'frc846', 'frc2135', 'frc971', 'frc254', 'frc1678', 'frc973' ], time=datetime.fromtimestamp(1409527874), time_string="4:31 PM", tba_videos=[], alliances_json='{\ "blue": {\ "score": 270,\ "teams": [\ "frc846",\ "frc2135",\ "frc971"]},\ "red": {\ "score": 310,\ "teams": [\ "frc254",\ "frc1678",\ "frc973"]}}', score_breakdown_json='{\ "blue": {\ "auto": 70,\ "teleop_goal+foul": 40,\ "assist": 120,\ "truss+catch": 40\ },"red": {\ "auto": 70,\ "teleop_goal+foul": 50,\ "assist": 150,\ "truss+catch": 40}}') self.match2.put() def tearDown(self): self.testbed.deactivate() def getSuggestionForm(self): response = self.testapp.get('/suggest/match/video/review') self.assertEqual(response.status_int, 200) form = response.forms.get('review_videos', None) self.assertIsNotNone(form) return form def testLogInRedirect(self): response = self.testapp.get('/suggest/match/video/review', status='3*') response = response.follow(expect_errors=True) self.assertTrue( response.request.path.startswith("/account/login_required")) def testNoPermissions(self): self.loginUser() response = self.testapp.get('/suggest/match/video/review', status='3*') response = response.follow(expect_errors=True) self.assertEqual(response.request.path, '/') def testNothingToReview(self): self.loginUser() self.givePermission() response = self.testapp.get('/suggest/match/video/review') self.assertEqual(response.status_int, 200) def testAcceptSuggestion(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm() form.set('accept_keys[]', suggestion_id) response = form.submit().follow() self.assertEqual(response.status_int, 200) # Make sure we mark the Suggestion as REVIEWED suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.review_state, Suggestion.REVIEW_ACCEPTED) # Make sure the video gets associated match = Match.get_by_id(self.match.key_name) self.assertIsNotNone(match) self.assertIsNotNone(match.youtube_videos) self.assertTrue('H-54KMwMKY0' in match.youtube_videos) def testAcceptNewKey(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm() form.set('accept_keys[]', suggestion_id) form.set('key-{}'.format(suggestion_id), '2016necmp_f1m2') response = form.submit().follow() self.assertEqual(response.status_int, 200) # Make sure we mark the Suggestion as REVIEWED suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.review_state, Suggestion.REVIEW_ACCEPTED) # Make sure the video gets associated match = Match.get_by_id(self.match2.key_name) self.assertIsNotNone(match) self.assertIsNotNone(match.youtube_videos) self.assertTrue('H-54KMwMKY0' in match.youtube_videos) # Make sure we don't add it to the first match match = Match.get_by_id(self.match.key_name) self.assertIsNotNone(match) self.assertIsNotNone(match.youtube_videos) self.assertFalse('H-54KMwMKY0' in match.youtube_videos) def testAcceptBadKey(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm() form.set('accept_keys[]', suggestion_id) form.set('key-{}'.format(suggestion_id), '2016necmp_f1m3') # This match doesn't exist response = form.submit().follow() self.assertEqual(response.status_int, 200) # Make sure we don't mark the Suggestion as REVIEWED suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.review_state, Suggestion.REVIEW_PENDING) # Make sure the video doesn't get associated match = Match.get_by_id(self.match.key_name) self.assertIsNotNone(match) self.assertIsNotNone(match.youtube_videos) self.assertFalse('H-54KMwMKY0' in match.youtube_videos) def testRejectSuggestion(self): self.loginUser() self.givePermission() suggestion_id = self.createSuggestion() form = self.getSuggestionForm() form.set('reject_keys[]', suggestion_id) response = form.submit().follow() self.assertEqual(response.status_int, 200) # Make sure we mark the Suggestion as REVIEWED suggestion = Suggestion.get_by_id(suggestion_id) self.assertIsNotNone(suggestion) self.assertEqual(suggestion.review_state, Suggestion.REVIEW_REJECTED) # Make sure the video gets associated match = Match.get_by_id(self.match.key_name) self.assertIsNotNone(match) self.assertFalse(match.youtube_videos)
class TestEventMatchApiController(unittest2.TestCase): def setUp(self): app = webapp2.WSGIApplication([ webapp2.Route( r'/<event_key:>', ApiEventMatchesController, methods=['GET']) ], debug=True) self.testapp = webtest.TestApp(app) self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_urlfetch_stub() self.testbed.init_memcache_stub() ndb.get_context().clear_cache( ) # Prevent data from leaking between tests self.testbed.init_taskqueue_stub(root_path=".") self.event = Event( id="2010sc", name="Palmetto Regional", event_type_enum=EventType.REGIONAL, short_name="Palmetto", event_short="sc", year=2010, end_date=datetime(2010, 03, 27), official=True, city="Clemson", state_prov="SC", country="USA", start_date=datetime(2010, 03, 24), ) self.event.put() self.match = Match( id="2010sc_qm1", alliances_json= """{"blue": {"score": 57, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": 74, "teams": ["frc281", "frc571", "frc176"]}}""", comp_level="qm", event=self.event.key, year=2010, set_number=1, match_number=1, team_key_names=[ u'frc281', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073' ], youtube_videos=["94UGXIq6jUA"], tba_videos=[".mp4"], time=datetime.fromtimestamp(1409527874)) self.match.put() def tearDown(self): self.testbed.deactivate() def assertMatchJson(self, matches): match = matches[0] self.assertEqual(str(match["key"]), self.match.key.string_id()) self.assertEqual(match["comp_level"], self.match.comp_level) self.assertEqual(match["event_key"], self.match.event.string_id()) self.assertEqual(match["set_number"], self.match.set_number) self.assertEqual(match["match_number"], self.match.match_number) self.assertEqual(match["videos"], self.match.videos) self.assertEqual(match["time_string"], self.match.time_string) self.assertEqual(match["time"], 1409527874) def testEventMatchApi(self): response = self.testapp.get( '/2010sc', headers={"X-TBA-App-Id": "tba-tests:event-controller-test:v01"}) match_json = json.loads(response.body) self.assertMatchJson(match_json)
def setUp(self): self.policy = datastore_stub_util.PseudoRandomHRConsistencyPolicy( probability=1) self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub(consistency_policy=self.policy) self.testbed.init_memcache_stub() self.testbed.init_user_stub() self.testbed.init_urlfetch_stub() self.testbed.init_taskqueue_stub(_all_queues_valid=True) ndb.get_context().clear_cache( ) # Prevent data from leaking between tests app = webapp2.WSGIApplication([ RedirectRoute(r'/suggest/match/video/review', SuggestMatchVideoReviewController, 'suggest-video', strict_slash=True), ], debug=True) self.testapp = webtest.TestApp(app) self.event = Event( id="2016necmp", name="New England District Championship", event_type_enum=EventType.DISTRICT_CMP, event_district_enum=DistrictType.NEW_ENGLAND, short_name="New England", event_short="necmp", year=2016, end_date=datetime(2016, 03, 27), official=False, city='Hartford', state_prov='CT', country='USA', venue="Some Venue", venue_address="Some Venue, Hartford, CT, USA", timezone_id="America/New_York", start_date=datetime(2016, 03, 24), webcast_json="", website="http://www.firstsv.org", ) self.event.put() self.match = Match(id="2016necmp_f1m1", event=ndb.Key(Event, "2016necmp"), year=2016, comp_level="f", set_number=1, match_number=1, team_key_names=[ 'frc846', 'frc2135', 'frc971', 'frc254', 'frc1678', 'frc973' ], time=datetime.fromtimestamp(1409527874), time_string="4:31 PM", tba_videos=[], alliances_json='{\ "blue": {\ "score": 270,\ "teams": [\ "frc846",\ "frc2135",\ "frc971"]},\ "red": {\ "score": 310,\ "teams": [\ "frc254",\ "frc1678",\ "frc973"]}}', score_breakdown_json='{\ "blue": {\ "auto": 70,\ "teleop_goal+foul": 40,\ "assist": 120,\ "truss+catch": 40\ },"red": {\ "auto": 70,\ "teleop_goal+foul": 50,\ "assist": 150,\ "truss+catch": 40}}') self.match.put() self.match2 = Match(id="2016necmp_f1m2", event=ndb.Key(Event, "2016necmp"), year=2016, comp_level="f", set_number=1, match_number=2, team_key_names=[ 'frc846', 'frc2135', 'frc971', 'frc254', 'frc1678', 'frc973' ], time=datetime.fromtimestamp(1409527874), time_string="4:31 PM", tba_videos=[], alliances_json='{\ "blue": {\ "score": 270,\ "teams": [\ "frc846",\ "frc2135",\ "frc971"]},\ "red": {\ "score": 310,\ "teams": [\ "frc254",\ "frc1678",\ "frc973"]}}', score_breakdown_json='{\ "blue": {\ "auto": 70,\ "teleop_goal+foul": 40,\ "assist": 120,\ "truss+catch": 40\ },"red": {\ "auto": 70,\ "teleop_goal+foul": 50,\ "assist": 150,\ "truss+catch": 40}}') self.match2.put()
def _process_request(self, request, event_key): event = Event.get_by_id(event_key) year = int(event_key[:4]) matches = [] needs_time = [] for match in JSONMatchesParser.parse(request.body, year): match = Match( id=Match.renderKeyName(event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None), score_breakdown_json=match.get("score_breakdown_json", None), time_string=match.get("time_string", None), time=match.get("time", None), ) if (not match.time or match.time == "") and match.time_string: # We can calculate the real time from the time string needs_time.append(match) matches.append(match) if needs_time: try: logging.debug("Calculating time!") MatchHelper.add_match_times(event, needs_time) except Exception, e: logging.error("Failed to calculate match times")
def render_team_history(cls, handler, team, is_canonical): event_team_keys_future = EventTeam.query( EventTeam.team == team.key).fetch_async(1000, keys_only=True) award_keys_future = Award.query( Award.team_list == team.key).fetch_async(1000, keys_only=True) event_teams_futures = ndb.get_multi_async( event_team_keys_future.get_result()) awards_futures = ndb.get_multi_async(award_keys_future.get_result()) event_keys = [ event_team_future.get_result().event for event_team_future in event_teams_futures ] events_futures = ndb.get_multi_async(event_keys) awards_by_event = {} for award_future in awards_futures: award = award_future.get_result() if award.event.id() not in awards_by_event: awards_by_event[award.event.id()] = [award] else: awards_by_event[award.event.id()].append(award) event_awards = [] current_event = None matches_upcoming = None short_cache = False for event_future in events_futures: event = event_future.get_result() if event.now: current_event = event team_matches_future = Match.query(Match.event == event.key, Match.team_key_names == team.key_name)\ .fetch_async(500, keys_only=True) matches = ndb.get_multi(team_matches_future.get_result()) matches_upcoming = MatchHelper.upcomingMatches(matches) if event.within_a_day: short_cache = True if event.key_name in awards_by_event: sorted_awards = AwardHelper.organizeAwards( awards_by_event[event.key_name]) else: sorted_awards = [] event_awards.append((event, sorted_awards)) event_awards = sorted( event_awards, key=lambda (e, _): e.start_date if e.start_date else datetime.datetime(e.year, 12, 31)) years = sorted( set([ et.get_result().year for et in event_teams_futures if et.get_result().year is not None ])) handler.template_values.update({ 'is_canonical': is_canonical, 'team': team, 'event_awards': event_awards, 'years': years, 'current_event': current_event, 'matches_upcoming': matches_upcoming }) if short_cache: handler._cache_expiration = handler.SHORT_CACHE_EXPIRATION path = os.path.join(os.path.dirname(__file__), '../templates/team_history.html') return template.render(path, handler.template_values)
def get(self, event_key): if tba_config.CONFIG["env"] == "prod": # disable in prod for now logging.error("Tried to restore {} from CSV in prod! No can do.".format(event_key)) return event = Event.get_by_id(event_key) # alliances result = urlfetch.fetch(self.ALLIANCES_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.ALLIANCES_URL.format(event.year, event_key, event_key))) else: data = result.content.replace('frc', '') alliance_selections = CSVAllianceSelectionsParser.parse(data) event_details = EventDetails( id=event_key, alliance_selections=alliance_selections ) EventDetailsManipulator.createOrUpdate(event_details) # awards result = urlfetch.fetch(self.AWARDS_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.AWARDS_URL.format(event.year, event_key, event_key))) else: # convert into expected input format data = StringIO.StringIO() writer = csv.writer(data, delimiter=',') for row in csv.reader(StringIO.StringIO(result.content), delimiter=','): writer.writerow([event.year, event.event_short, row[1], row[2].replace('frc', ''), row[3]]) awards = [] for award in CSVAwardsParser.parse(data.getvalue()): awards.append(Award( id=Award.render_key_name(event.key_name, award['award_type_enum']), name_str=award['name_str'], award_type_enum=award['award_type_enum'], year=event.year, event=event.key, event_type_enum=event.event_type_enum, team_list=[ndb.Key(Team, 'frc{}'.format(team_number)) for team_number in award['team_number_list']], recipient_json_list=award['recipient_json_list'] )) AwardManipulator.createOrUpdate(awards) # matches result = urlfetch.fetch(self.MATCHES_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.MATCHES_URL.format(event.year, event_key, event_key))) else: data = result.content.replace('frc', '').replace('{}_'.format(event_key), '') match_dicts, _ = OffseasonMatchesParser.parse(data) matches = [ Match( id=Match.renderKeyName( event.key.id(), match.get("comp_level", None), match.get("set_number", 0), match.get("match_number", 0)), event=event.key, year=event.year, set_number=match.get("set_number", 0), match_number=match.get("match_number", 0), comp_level=match.get("comp_level", None), team_key_names=match.get("team_key_names", None), alliances_json=match.get("alliances_json", None) ) for match in match_dicts] MatchManipulator.createOrUpdate(matches) # rankings result = urlfetch.fetch(self.RANKINGS_URL.format(event.year, event_key, event_key)) if result.status_code != 200: logging.warning('Unable to retreive url: ' + (self.RANKINGS_URL.format(event.year, event_key, event_key))) else: # convert into expected input format rankings = list(csv.reader(StringIO.StringIO(result.content), delimiter=',')) event_details = EventDetails( id=event_key, rankings=rankings ) EventDetailsManipulator.createOrUpdate(event_details) self.response.out.write("Done restoring {}!".format(event_key))
class TestMatchManipulator(unittest2.TestCase): def setUp(self): self.testbed = testbed.Testbed() self.testbed.activate() self.testbed.init_datastore_v3_stub() self.testbed.init_memcache_stub() self.testbed.init_taskqueue_stub() self.event = Event(id="2012ct", event_short="ct", year=2012) self.old_match = Match( id="2012ct_qm1", alliances_json= """{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level="qm", event=self.event.key, game="frc_2012_rebr", set_number=1, match_number=1, team_key_names=[ u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073' ], youtube_videos=[u'P3C2BOtL7e8', u'tst1', u'tst2', u'tst3']) self.new_match = Match( id="2012ct_qm1", alliances_json= """{"blue": {"score": 57, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": 74, "teams": ["frc69", "frc571", "frc176"]}}""", comp_level="qm", event=self.event.key, game="frc_2012_rebr", set_number=1, match_number=1, team_key_names=[ u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073' ], youtube_videos=[u'TqY324xLU4s', u'tst1', u'tst3', u'tst4']) def tearDown(self): self.testbed.deactivate() def assertMergedMatch(self, match, is_auto_union): self.assertOldMatch(match) self.assertEqual( match.alliances_json, """{"blue": {"score": 57, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": 74, "teams": ["frc69", "frc571", "frc176"]}}""" ) if is_auto_union: self.assertEqual(set(match.youtube_videos), { u'P3C2BOtL7e8', u'TqY324xLU4s', u'tst1', u'tst2', u'tst3', u'tst4' }) else: self.assertEqual(match.youtube_videos, [u'TqY324xLU4s', u'tst1', u'tst3', u'tst4']) def assertOldMatch(self, match): self.assertEqual(match.comp_level, "qm") self.assertEqual(match.set_number, 1) self.assertEqual(match.match_number, 1) self.assertEqual( match.team_key_names, [u'frc69', u'frc571', u'frc176', u'frc3464', u'frc20', u'frc1073']) def test_createOrUpdate(self): MatchManipulator.createOrUpdate(self.old_match) self.assertOldMatch(Match.get_by_id("2012ct_qm1")) self.assertEqual( Match.get_by_id("2012ct_qm1").alliances_json, """{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""" ) MatchManipulator.createOrUpdate(self.new_match) self.assertMergedMatch(Match.get_by_id("2012ct_qm1"), True) def test_findOrSpawn(self): self.old_match.put() self.assertMergedMatch(MatchManipulator.findOrSpawn(self.new_match), True) def test_updateMerge(self): self.assertMergedMatch( MatchManipulator.updateMerge(self.new_match, self.old_match), True) def test_createOrUpdate_no_auto_union(self): MatchManipulator.createOrUpdate(self.old_match) self.assertOldMatch(Match.get_by_id("2012ct_qm1")) self.assertEqual( Match.get_by_id("2012ct_qm1").alliances_json, """{"blue": {"score": -1, "teams": ["frc3464", "frc20", "frc1073"]}, "red": {"score": -1, "teams": ["frc69", "frc571", "frc176"]}}""" ) MatchManipulator.createOrUpdate(self.new_match, auto_union=False) self.assertMergedMatch(Match.get_by_id("2012ct_qm1"), False) def test_findOrSpawn_no_auto_union(self): self.old_match.put() self.assertMergedMatch( MatchManipulator.findOrSpawn(self.new_match, auto_union=False), False) def test_updateMerge_no_auto_union(self): self.assertMergedMatch( MatchManipulator.updateMerge(self.new_match, self.old_match, auto_union=False), False)
def main(): pygame.init() screen = pygame.display.set_mode([400, 400]) pygame.display.set_caption("Xadrez") # defining Text font text_font = pygame.font.Font("font/FreeSansBold.ttf", 18) match = Match() ia = Ia(match) running = True ia_on = True ia_vs_ia = False playevent = pygame.USEREVENT + 1 my_event = pygame.event.Event(playevent) while running: match.is_checkmate = match.checkmate() for event in pygame.event.get(): mouse_x = pygame.mouse.get_pos()[0] mouse_y = pygame.mouse.get_pos()[1] if event.type == pygame.QUIT: running = False #IA vs IA if ia_vs_ia and ia_on and not match.is_checkmate and not match.get_is_stalemate( ): keys = pygame.key.get_pressed() if keys[pygame.K_ESCAPE]: screen = pygame.display.set_mode([400, 400]) match.button_manager() break if match.choice: pygame.event.post(my_event) ia.move() break #Player vs IA elif ia_on and match.get_turn( ) == BLACK and not match.is_checkmate and not match.get_is_stalemate( ): ia.move() if event.type == pygame.MOUSEBUTTONDOWN: if match.choice: # Match has already started if mouse_y <= 400: clicked_house = get_clicked_house(match) match.movement_manager(clicked_house, None) elif button_click_manager(screen): if not match.checked: screen = pygame.display.set_mode([400, 400]) match.button_manager() else: if has_clicked_on_p_vs_p(mouse_x, mouse_y): start_match(match, screen) ia_on = False ia_vs_ia = False elif has_clicked_on_ia(mouse_x, mouse_y): start_match(match, screen) ia_on = True ia_vs_ia = False elif has_clicked_on_credits(mouse_x, mouse_y): #show_credits_screen(match) show_menu_screen(match) elif has_clicked_on_go_to_menu(mouse_x, mouse_y): show_menu_screen(match) elif has_clicked_on_ia_vs_ia(mouse_x, mouse_y): start_match(match, screen) ia_vs_ia = True ia_on = True pygame.display.update() match.draw(screen, text_font, ia_vs_ia)
def test_matches_update(self): self.matches_auth.put() update_request_path = '/api/trusted/v1/event/2014casj/matches/update' delete_request_path = '/api/trusted/v1/event/2014casj/matches/delete' delete_all_request_path = '/api/trusted/v1/event/2014casj/matches/delete_all' # add one match matches = [{ 'comp_level': 'qm', 'set_number': 1, 'match_number': 1, 'alliances': { 'red': { 'teams': ['frc1', 'frc2', 'frc3'], 'score': 25 }, 'blue': { 'teams': ['frc4', 'frc5', 'frc6'], 'score': 26 }, }, 'time_string': '9:00 AM', 'time_utc': '2014-08-31T16:00:00', }] request_body = json.dumps(matches) sig = md5.new('{}{}{}'.format('321tEsTsEcReT', update_request_path, request_body)).hexdigest() response = self.testapp.post(update_request_path, request_body, headers={ 'X-TBA-Auth-Id': 'tEsT_id_1', 'X-TBA-Auth-Sig': sig }, expect_errors=True) self.assertEqual(response.status_code, 200) db_matches = Match.query(Match.event == self.event.key).fetch(None) self.assertEqual(len(db_matches), 1) self.assertTrue('2014casj_qm1' in [m.key.id() for m in db_matches]) # add another match matches = [{ 'comp_level': 'f', 'set_number': 1, 'match_number': 1, 'alliances': { 'red': { 'teams': ['frc1', 'frc2', 'frc3'], 'score': 250 }, 'blue': { 'teams': ['frc4', 'frc5', 'frc6'], 'score': 260 }, }, 'time_string': '10:00 AM', 'time_utc': '2014-08-31T17:00:00', }] request_body = json.dumps(matches) sig = md5.new('{}{}{}'.format('321tEsTsEcReT', update_request_path, request_body)).hexdigest() response = self.testapp.post(update_request_path, request_body, headers={ 'X-TBA-Auth-Id': 'tEsT_id_1', 'X-TBA-Auth-Sig': sig }, expect_errors=True) self.assertEqual(response.status_code, 200) db_matches = Match.query(Match.event == self.event.key).fetch(None) self.assertEqual(len(db_matches), 2) self.assertTrue('2014casj_qm1' in [m.key.id() for m in db_matches]) self.assertTrue('2014casj_f1m1' in [m.key.id() for m in db_matches]) # add a match and delete a match matches = [{ 'comp_level': 'f', 'set_number': 1, 'match_number': 2, 'alliances': { 'red': { 'teams': ['frc1', 'frc2', 'frc3'], 'score': 250 }, 'blue': { 'teams': ['frc4', 'frc5', 'frc6'], 'score': 260 }, }, 'score_breakdown': { 'red': { 'auto': 20, 'assist': 40, 'truss+catch': 20, 'teleop_goal+foul': 20 }, 'blue': { 'auto': 40, 'assist': 60, 'truss+catch': 10, 'teleop_goal+foul': 40 }, }, 'time_string': '11:00 AM', 'time_utc': '2014-08-31T18:00:00', }] request_body = json.dumps(matches) sig = md5.new('{}{}{}'.format('321tEsTsEcReT', update_request_path, request_body)).hexdigest() response = self.testapp.post(update_request_path, request_body, headers={ 'X-TBA-Auth-Id': 'tEsT_id_1', 'X-TBA-Auth-Sig': sig }, expect_errors=True) self.assertEqual(response.status_code, 200) keys_to_delete = ['qm1'] request_body = json.dumps(keys_to_delete) sig = md5.new('{}{}{}'.format('321tEsTsEcReT', delete_request_path, request_body)).hexdigest() response = self.testapp.post(delete_request_path, request_body, headers={ 'X-TBA-Auth-Id': 'tEsT_id_1', 'X-TBA-Auth-Sig': sig }, expect_errors=True) self.assertEqual(response.status_code, 200) self.assertEqual(response.json['keys_deleted'], ['qm1']) db_matches = Match.query(Match.event == self.event.key).fetch(None) self.assertEqual(len(db_matches), 2) self.assertTrue('2014casj_f1m1' in [m.key.id() for m in db_matches]) self.assertTrue('2014casj_f1m2' in [m.key.id() for m in db_matches]) db_matches = Match.query(Match.event == self.event.key).fetch(None) self.assertEqual(len(db_matches), 2) self.assertTrue('2014casj_f1m1' in [m.key.id() for m in db_matches]) self.assertTrue('2014casj_f1m2' in [m.key.id() for m in db_matches]) # verify match data match = Match.get_by_id('2014casj_f1m2') self.assertEqual(match.time, datetime.datetime(2014, 8, 31, 18, 0)) self.assertEqual(match.time_string, '11:00 AM') self.assertEqual(match.alliances['red']['score'], 250) self.assertEqual(match.score_breakdown['red']['truss+catch'], 20) # test delete all matches request_body = '' sig = md5.new('{}{}{}'.format('321tEsTsEcReT', delete_all_request_path, request_body)).hexdigest() response = self.testapp.post(delete_all_request_path, request_body, headers={ 'X-TBA-Auth-Id': 'tEsT_id_1', 'X-TBA-Auth-Sig': sig }, expect_errors=True) self.assertEqual(response.status_code, 400) request_body = '2014casj' sig = md5.new('{}{}{}'.format('321tEsTsEcReT', delete_all_request_path, request_body)).hexdigest() response = self.testapp.post(delete_all_request_path, request_body, headers={ 'X-TBA-Auth-Id': 'tEsT_id_1', 'X-TBA-Auth-Sig': sig }, expect_errors=True) self.assertEqual(response.status_code, 200) db_matches = Match.query(Match.event == self.event.key).fetch(None) self.assertEqual(len(db_matches), 0)
def parse(self, response): matches = response['MatchScores'] event_key = '{}{}'.format(self.year, self.event_short) event = Event.get_by_id(event_key) match_details_by_key = {} for match in matches: comp_level = PlayoffType.get_comp_level(event.playoff_type, match['matchLevel'], match['matchNumber']) set_number, match_number = PlayoffType.get_set_match_number( event.playoff_type, comp_level, match['matchNumber']) breakdown = { 'red': {}, 'blue': {}, } if 'coopertition' in match: breakdown['coopertition'] = match['coopertition'] if 'coopertitionPoints' in match: breakdown['coopertition_points'] = match['coopertitionPoints'] game_data = None if self.year == 2018: # Switches should be the same, but parse individually in case FIRST change things right_switch_red = match['switchRightNearColor'] == 'Red' scale_red = match['scaleNearColor'] == 'Red' left_switch_red = match['switchLeftNearColor'] == 'Red' game_data = '{}{}{}'.format( 'L' if right_switch_red else 'R', 'L' if scale_red else 'R', 'L' if left_switch_red else 'R', ) for alliance in match.get('alliances', match.get('Alliances', [])): color = alliance['alliance'].lower() for key, value in alliance.items(): if key != 'alliance': breakdown[color][key] = value if game_data is not None: breakdown[color]['tba_gameData'] = game_data if self.year == 2019: # Derive incorrect completedRocketFar and completedRocketNear returns from FIRST API for side1 in ['Near', 'Far']: completedRocket = True for side2 in ['Left', 'Right']: for level in ['low', 'mid', 'top']: if breakdown[color]['{}{}Rocket{}'.format( level, side2, side1)] != 'PanelAndCargo': completedRocket = False break if not completedRocket: break breakdown[color]['completedRocket{}'.format( side1)] = completedRocket match_details_by_key[Match.renderKeyName( '{}{}'.format(self.year, self.event_short), comp_level, set_number, match_number)] = breakdown return match_details_by_key
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)
def calculate_event_points(cls, event): match_key_futures = Match.query(Match.event == event.key).fetch_async(None, keys_only=True) award_key_futures = Award.query(Award.event == event.key).fetch_async(None, keys_only=True) match_futures = ndb.get_multi_async(match_key_futures.get_result()) award_futures = ndb.get_multi_async(award_key_futures.get_result()) POINTS_MULTIPLIER = 3 if event.event_type_enum == EventType.DISTRICT_CMP else 1 district_points = { 'points': defaultdict(lambda: { 'qual_points': 0, 'elim_points': 0, 'alliance_points': 0, 'award_points': 0, 'total': 0, }), 'tiebreakers': defaultdict(lambda: { # for tiebreaker stats that can't be calculated with 'points' 'qual_wins': 0, 'highest_qual_scores': [], }), } # match points if event.year == 2015: from helpers.match_helper import MatchHelper # circular import issue # qual match points are calculated by rank if event.rankings and len(event.rankings) > 1: rankings = event.rankings[1:] # skip title row num_teams = len(rankings) alpha = 1.07 for row in rankings: rank = int(row[0]) team = 'frc{}'.format(row[1]) qual_points = int(np.ceil(cls.inverf(float(num_teams - 2 * rank + 2) / (alpha * num_teams)) * (10.0 / cls.inverf(1.0 / alpha)) + 12)) district_points['points'][team]['qual_points'] = qual_points * POINTS_MULTIPLIER else: logging.warning("Event {} has no rankings for qual_points calculations!".format(event.key.id())) matches = MatchHelper.organizeMatches([mf.get_result() for mf in match_futures]) # qual match calculations. only used for tiebreaking for match in matches['qm']: for color in ['red', 'blue']: for team in match.alliances[color]['teams']: score = match.alliances[color]['score'] district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points['tiebreakers'][team]['highest_qual_scores'] + [score]) # elim match point calculations # count number of matches played per team per comp level num_played = defaultdict(lambda: defaultdict(int)) for level in ['qf', 'sf']: for match in matches[level]: if not match.has_been_played: continue for color in ['red', 'blue']: for team in match.alliances[color]['teams']: num_played[level][team] += 1 # qf and sf points advancement = MatchHelper.generatePlayoffAdvancement2015(matches) for last_level, level in [('qf', 'sf'), ('sf', 'f')]: for (teams, _, _) in advancement[last_level]: teams = ['frc{}'.format(t) for t in teams] done = False for match in matches[level]: for color in ['red', 'blue']: if set(teams).intersection(set(match.alliances[color]['teams'])) != set(): for team in teams: points = 5.0 if last_level == 'qf' else 3.3 district_points['points'][team]['elim_points'] += int(np.ceil(points * num_played[last_level][team])) * POINTS_MULTIPLIER done = True break if done: break if done: break # final points num_wins = {'red': 0, 'blue': 0} team_matches_played = {'red': [], 'blue': []} for match in matches['f']: if not match.has_been_played or match.winning_alliance == '': continue num_wins[match.winning_alliance] += 1 for team in match.alliances[match.winning_alliance]['teams']: team_matches_played[match.winning_alliance].append(team) if num_wins[match.winning_alliance] >= 2: for team in team_matches_played[match.winning_alliance]: district_points['points'][team]['elim_points'] += 5 * POINTS_MULTIPLIER else: elim_num_wins = defaultdict(lambda: defaultdict(int)) elim_alliances = defaultdict(lambda: defaultdict(list)) for match_future in match_futures: match = match_future.get_result() if not match.has_been_played: continue if match.comp_level == 'qm': if match.winning_alliance == '': for team in match.team_key_names: district_points['points'][team]['qual_points'] += 1 * POINTS_MULTIPLIER else: for team in match.alliances[match.winning_alliance]['teams']: district_points['points'][team]['qual_points'] += 2 * POINTS_MULTIPLIER district_points['tiebreakers'][team]['qual_wins'] += 1 for color in ['red', 'blue']: for team in match.alliances[color]['teams']: score = match.alliances[color]['score'] district_points['tiebreakers'][team]['highest_qual_scores'] = heapq.nlargest(3, district_points['tiebreakers'][team]['highest_qual_scores'] + [score]) else: if match.winning_alliance == '': continue match_set_key = '{}_{}{}'.format(match.event.id(), match.comp_level, match.set_number) elim_num_wins[match_set_key][match.winning_alliance] += 1 elim_alliances[match_set_key][match.winning_alliance] += match.alliances[match.winning_alliance]['teams'] if elim_num_wins[match_set_key][match.winning_alliance] >= 2: for team in elim_alliances[match_set_key][match.winning_alliance]: district_points['points'][team]['elim_points'] += 5* POINTS_MULTIPLIER # alliance points if event.alliance_selections: selection_points = EventHelper.alliance_selections_to_points(event.alliance_selections) for team, points in selection_points.items(): district_points['points'][team]['alliance_points'] += points * POINTS_MULTIPLIER else: logging.warning("Event {} has no alliance selection district_points!".format(event.key.id())) # award points for award_future in award_futures: award = award_future.get_result() if award.award_type_enum not in AwardType.NON_JUDGED_NON_TEAM_AWARDS: if award.award_type_enum == AwardType.CHAIRMANS: point_value = 10 elif award.award_type_enum in {AwardType.ENGINEERING_INSPIRATION, AwardType.ROOKIE_ALL_STAR}: point_value = 8 else: point_value = 5 for team in award.team_list: district_points['points'][team.id()]['award_points'] += point_value * POINTS_MULTIPLIER for team, point_breakdown in district_points['points'].items(): for p in point_breakdown.values(): district_points['points'][team]['total'] += p return district_points
def parse(self, response): matches = response['Schedule'] event_key = '{}{}'.format(self.year, self.event_short) event = Event.get_by_id(event_key) if event.timezone_id: event_tz = pytz.timezone(event.timezone_id) else: logging.warning( "Event {} has no timezone! Match times may be wrong.".format( event_key)) event_tz = None parsed_matches = [] remapped_matches = {} # If a key changes due to a tiebreaker is_octofinals = len( matches) > 0 and 'Octofinal' in matches[0]['description'] for match in matches: if 'tournamentLevel' in match: # 2016+ level = match['tournamentLevel'] else: # 2015 level = match['level'] comp_level = get_comp_level(self.year, level, match['matchNumber'], is_octofinals) set_number, match_number = get_set_match_number( self.year, comp_level, match['matchNumber'], is_octofinals) red_teams = [] blue_teams = [] red_surrogates = [] blue_surrogates = [] team_key_names = [] null_team = False sorted_teams = sorted( match['Teams'], key=lambda team: team['station'] ) # Sort by station to ensure correct ordering. Kind of hacky. for team in sorted_teams: if team['teamNumber'] is None: null_team = True team_key = 'frc{}'.format(team['teamNumber']) team_key_names.append(team_key) if 'Red' in team['station']: red_teams.append(team_key) if team['surrogate']: red_surrogates.append(team_key) elif 'Blue' in team['station']: blue_teams.append(team_key) if team['surrogate']: blue_surrogates.append(team_key) if null_team and match['scoreRedFinal'] is None and match[ 'scoreBlueFinal'] is None: continue alliances = { 'red': { 'teams': red_teams, 'surrogates': red_surrogates, 'score': match['scoreRedFinal'] }, 'blue': { 'teams': blue_teams, 'surrogates': blue_surrogates, 'score': match['scoreBlueFinal'] }, } if not match[ 'startTime']: # no startTime means it's an unneeded rubber match continue time = datetime.datetime.strptime(match['startTime'].split('.')[0], TIME_PATTERN) if event_tz is not None: time = time - event_tz.utcoffset(time) actual_time_raw = match[ 'actualStartTime'] if 'actualStartTime' in match else None actual_time = None if actual_time_raw is not None: actual_time = datetime.datetime.strptime( actual_time_raw.split('.')[0], TIME_PATTERN) if event_tz is not None: actual_time = actual_time - event_tz.utcoffset(actual_time) post_result_time_raw = match.get('postResultTime') post_result_time = None if post_result_time_raw is not None: post_result_time = datetime.datetime.strptime( post_result_time_raw.split('.')[0], TIME_PATTERN) if event_tz is not None: post_result_time = post_result_time - event_tz.utcoffset( post_result_time) key_name = Match.renderKeyName(event_key, comp_level, set_number, match_number) # Check for tiebreaker matches existing_match = Match.get_by_id(key_name) # Follow chain of existing matches while existing_match is not None and existing_match.tiebreak_match_key is not None: logging.info("Following Match {} to {}".format( existing_match.key.id(), existing_match.tiebreak_match_key.id())) existing_match = existing_match.tiebreak_match_key.get() # Check if last existing match needs to be tiebroken if existing_match and existing_match.comp_level != 'qm' and \ existing_match.has_been_played and \ existing_match.winning_alliance == '' and \ existing_match.actual_time != actual_time and \ not self.is_blank_match(existing_match): logging.warning("Match {} is tied!".format( existing_match.key.id())) # TODO: Only query within set if set_number ever gets indexed match_count = 0 for match_key in Match.query( Match.event == event.key, Match.comp_level == comp_level).fetch(keys_only=True): _, match_key = match_key.id().split('_') if match_key.startswith('{}{}'.format( comp_level, set_number)): match_count += 1 # Sanity check: Tiebreakers must be played after at least 3 matches, or 6 for finals if match_count < 3 or (match_count < 6 and comp_level == 'f'): logging.warning( "Match supposedly tied, but existing count is {}! Skipping match." .format(match_count)) continue match_number = match_count + 1 new_key_name = Match.renderKeyName(event_key, comp_level, set_number, match_number) remapped_matches[key_name] = new_key_name key_name = new_key_name # Point existing match to new tiebreaker match existing_match.tiebreak_match_key = ndb.Key(Match, key_name) parsed_matches.append(existing_match) logging.warning("Creating new match: {}".format(key_name)) elif existing_match: remapped_matches[key_name] = existing_match.key.id() key_name = existing_match.key.id() match_number = existing_match.match_number parsed_matches.append( Match( id=key_name, event=event.key, year=event.year, set_number=set_number, match_number=match_number, comp_level=comp_level, team_key_names=team_key_names, time=time, actual_time=actual_time, post_result_time=post_result_time, alliances_json=json.dumps(alliances), )) if self.year == 2015: # Fix null teams in elims (due to FMS API failure, some info not complete) # Should only happen for sf and f matches organized_matches = MatchHelper.organizeMatches(parsed_matches) for level in ['sf', 'f']: playoff_advancement = MatchHelper.generatePlayoffAdvancement2015( organized_matches) if playoff_advancement[LAST_LEVEL[level]] != []: for match in organized_matches[level]: if 'frcNone' in match.team_key_names: if level == 'sf': red_seed, blue_seed = QF_SF_MAP[ match.match_number] else: red_seed = 0 blue_seed = 1 red_teams = [ 'frc{}'.format(t) for t in playoff_advancement[ LAST_LEVEL[level]][red_seed][0] ] blue_teams = [ 'frc{}'.format(t) for t in playoff_advancement[ LAST_LEVEL[level]][blue_seed][0] ] alliances = match.alliances alliances['red']['teams'] = red_teams alliances['blue']['teams'] = blue_teams match.alliances_json = json.dumps(alliances) match.team_key_names = red_teams + blue_teams fixed_matches = [] for key, matches in organized_matches.items(): if key != 'num': for match in matches: if 'frcNone' not in match.team_key_names: fixed_matches.append(match) parsed_matches = fixed_matches return parsed_matches, remapped_matches
def parse(self, response): """ This currently only works for the 2015 game, where elims matches are all part of one set. """ matches = response['Schedule'] event_key = '{}{}'.format(self.year, self.event_short) event = Event.get_by_id(event_key) if event.timezone_id: event_tz = pytz.timezone(event.timezone_id) else: logging.warning( "Event {} has no timezone! Match times may be wrong.".format( event_key)) event_tz = None set_number = 1 parsed_matches = [] for match in matches: comp_level = get_comp_level(match['level'], match['matchNumber']) match_number = get_match_number(comp_level, match['matchNumber']) red_teams = [] blue_teams = [] team_key_names = [] null_team = False for team in match['Teams']: if team['teamNumber'] is None: null_team = True team_key = 'frc{}'.format(team['teamNumber']) team_key_names.append(team_key) if 'Red' in team['station']: red_teams.append(team_key) elif 'Blue' in team['station']: blue_teams.append(team_key) if null_team and match['scoreRedFinal'] is None and match[ 'scoreBlueFinal'] is None: continue alliances = { 'red': { 'teams': red_teams, 'score': match['scoreRedFinal'] }, 'blue': { 'teams': blue_teams, 'score': match['scoreBlueFinal'] } } score_breakdown = { 'red': { 'auto_points': match['scoreRedAuto'], 'foul_points': match['scoreRedFoul'] }, 'blue': { 'auto_points': match['scoreBlueAuto'], 'foul_points': match['scoreBlueFoul'] } } time = datetime.datetime.strptime(match['startTime'], TIME_PATTERN) actual_time_raw = match[ 'actualStartTime'] if 'actualStartTime' in match else None actual_time = None if event_tz is not None: time = time - event_tz.utcoffset(time) if actual_time_raw is not None: actual_time = datetime.datetime.strptime( actual_time_raw, TIME_PATTERN) if event_tz is not None: actual_time = actual_time - event_tz.utcoffset(actual_time) parsed_matches.append( Match(id=Match.renderKeyName(event_key, comp_level, set_number, match_number), event=event.key, year=event.year, set_number=set_number, match_number=match_number, comp_level=comp_level, team_key_names=team_key_names, time=time, actual_time=actual_time, alliances_json=json.dumps(alliances), score_breakdown_json=json.dumps(score_breakdown))) # Fix null teams in elims (due to FMS API failure, some info not complete) # Should only happen for sf and f matches organized_matches = MatchHelper.organizeMatches(parsed_matches) for level in ['sf', 'f']: playoff_advancement = MatchHelper.generatePlayoffAdvancement2015( organized_matches) if playoff_advancement[LAST_LEVEL[level]] != []: for match in organized_matches[level]: if 'frcNone' in match.team_key_names: if level == 'sf': red_seed, blue_seed = QF_SF_MAP[match.match_number] else: red_seed = 0 blue_seed = 1 red_teams = [ 'frc{}'.format(t) for t in playoff_advancement[ LAST_LEVEL[level]][red_seed][0] ] blue_teams = [ 'frc{}'.format(t) for t in playoff_advancement[ LAST_LEVEL[level]][blue_seed][0] ] alliances = match.alliances alliances['red']['teams'] = red_teams alliances['blue']['teams'] = blue_teams match.alliances_json = json.dumps(alliances) match.team_key_names = red_teams + blue_teams fixed_matches = [] for key, matches in organized_matches.items(): if key != 'num': for match in matches: if 'frcNone' not in match.team_key_names: fixed_matches.append(match) return fixed_matches
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 store_match(data): match = Match(id=data['key']) match.event = ndb.Key(Event, data['event_key']) match.year = int(data['key'][:4]) match.comp_level = data['comp_level'] match.set_number = data['set_number'] match.match_number = data['match_number'] if data.get('time'): match.time = datetime.datetime.fromtimestamp(int(data['time'])) if data.get('actual_time'): match.actual_time = datetime.datetime.fromtimestamp(int(data['actual_time'])) if data.get('predicted_time'): match.predicted_time = datetime.datetime.fromtimestamp(int(data['predicted_time'])) if data.get('post_result_time'): match.post_result_time = datetime.datetime.fromtimestamp(int(data['post_result_time'])) match.score_breakdown_json = json.dumps(data['score_breakdown']) for alliance in ['red', 'blue']: data['alliances'][alliance]['teams'] = data['alliances'][alliance].pop('team_keys') data['alliances'][alliance]['surrogates'] = data['alliances'][alliance].pop('surrogate_team_keys') match.alliances_json = json.dumps(data['alliances']) return MatchManipulator.createOrUpdate(match)
def store_match(data): match = Match(id=data['key']) match.event = ndb.Key(Event, data['event_key']) match.year = int(data['key'][:4]) match.comp_level = data['comp_level'] match.set_number = data['set_number'] match.match_number = data['match_number'] if data.get('time'): match.time = datetime.datetime.fromtimestamp(int(data['time'])) if data.get('actual_time'): match.actual_time = datetime.datetime.fromtimestamp( int(data['actual_time'])) if data.get('predicted_time'): match.predicted_time = datetime.datetime.fromtimestamp( int(data['predicted_time'])) if data.get('post_result_time'): match.post_result_time = datetime.datetime.fromtimestamp( int(data['post_result_time'])) match.score_breakdown_json = json.dumps(data['score_breakdown']) team_key_names = [] for alliance in ['red', 'blue']: team_key_names += data['alliances'][alliance]['team_keys'] data['alliances'][alliance]['teams'] = data['alliances'][alliance].pop( 'team_keys') data['alliances'][alliance]['surrogates'] = data['alliances'][ alliance].pop('surrogate_team_keys') match.alliances_json = json.dumps(data['alliances']) match.team_key_names = team_key_names youtube_videos = [] for video in data['videos']: if video['type'] == 'youtube': youtube_videos.append(video['key']) match.youtube_videos = youtube_videos return MatchManipulator.createOrUpdate(match)