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)
예제 #5
0
    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
예제 #6
0
    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))
예제 #7
0
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"))
예제 #9
0
    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)
예제 #13
0
 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))
예제 #23
0
    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()
예제 #25
0
    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
예제 #28
0
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))
예제 #30
0
 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)
예제 #31
0
    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)
예제 #34
0
 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')
예제 #36
0
 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))
예제 #37
0
 def _query_async(self):
     match_key = self._query_args[0]
     match = yield Match.get_by_id_async(match_key)
     raise ndb.Return(match)
예제 #38
0
    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)
예제 #39
0
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)
예제 #41
0
    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")
예제 #43
0
    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)
예제 #46
0
파일: main.py 프로젝트: yagoazedias/chess
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)
예제 #47
0
    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
예제 #49
0
    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)
예제 #50
0
    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
예제 #51
0
    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)
예제 #54
0
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)
예제 #55
0
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)