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 get(self):
        suggestions = Suggestion.query().filter(
            Suggestion.review_state == Suggestion.REVIEW_PENDING).filter(
            Suggestion.target_model == "event")

        suggestions_by_event_key = {}
        for suggestion in suggestions:
            if 'webcast_dict' in suggestion.contents:
                suggestion.webcast_template = 'webcast/{}.html'.format(suggestion.contents['webcast_dict']['type'])
            suggestions_by_event_key.setdefault(suggestion.target_key, []).append(suggestion)

        suggestion_sets = []
        for event_key, suggestions in suggestions_by_event_key.items():
            suggestion_sets.append({
                "event": Event.get_by_id(event_key),
                "suggestions": suggestions
                })

        self.template_values.update({
            "event_key": self.request.get("event_key"),
            "success": self.request.get("success"),
            "suggestion_sets": suggestion_sets
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/suggest_event_webcast_review_list.html')
        self.response.out.write(template.render(path, self.template_values))
    def get(self, event_key):
        df = DatafeedUsfirst()

        event = Event.get_by_id(event_key)
        new_matches = MatchManipulator.createOrUpdate(df.getMatches(event))

        if new_matches:
            for match in new_matches:
                if hasattr(match, 'dirty') and match.dirty:
                    # Enqueue push notification
                    try:
                        FirebasePusher.updated_event(event.key_name)
                    except:
                        logging.warning("Enqueuing Firebase push failed!")
                    # Enqueue task to calculate matchstats
                    taskqueue.add(
                            url='/tasks/math/do/event_matchstats/' + event.key_name,
                            method='GET')
                    break


        template_values = {
            'matches': new_matches,
        }

        path = os.path.join(os.path.dirname(__file__), '../templates/datafeeds/usfirst_matches_get.html')
        self.response.out.write(template.render(path, template_values))
    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)
    def _render(self, event_key):
        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)
            return
        medias_future = media_query.EventTeamsPreferredMediasQuery(event_key).fetch_async()
        next_match = MatchHelper.upcomingMatches(event.matches, num=1)
        next_match = next_match[0] if next_match else None
        team_and_medias = []
        if next_match:
            # Organize medias by team
            teams = ndb.get_multi([ndb.Key(Team, team_key) for team_key in next_match.alliances['red']['teams'] + next_match.alliances['blue']['teams']])
            image_medias = MediaHelper.get_images([media for media in medias_future.get_result()])
            team_medias = defaultdict(list)
            for image_media in image_medias:
                for reference in image_media.references:
                    team_medias[reference].append(image_media)

            stations = ['Red 1', 'Red 2', 'Red 3', 'Blue 1', 'Blue 2', 'Blue 3']
            for i, team in enumerate(teams):
                team_and_medias.append((team, stations[i], team_medias.get(team.key, [])))

        self.template_values.update({
            'event': event,
            'next_match': next_match,
            'teams_and_media': team_and_medias,
        })
        return jinja2_engine.render('nextmatch.html', self.template_values)
    def get(self, event_key):
        event = Event.get_by_id(event_key)
        matchstats_dict = MatchstatsHelper.calculate_matchstats(event.matches, event.year)

        if event.year == 2016:
            organized_matches = MatchHelper.organizeMatches(event.matches)
            match_predictions, match_prediction_stats = PredictionHelper.get_match_predictions(organized_matches['qm'])
            ranking_predictions, ranking_prediction_stats = PredictionHelper.get_ranking_predictions(organized_matches['qm'], match_predictions)

            matchstats_dict['match_predictions'] = match_predictions
            matchstats_dict['match_prediction_stats'] = match_prediction_stats
            matchstats_dict['ranking_predictions'] = ranking_predictions
            matchstats_dict['ranking_prediction_stats'] = ranking_prediction_stats

        if any([v != {} for v in matchstats_dict.values()]):
            event.matchstats_json = json.dumps(matchstats_dict)
            EventManipulator.createOrUpdate(event)
        else:
            logging.warn("Matchstat calculation for {} failed!".format(event_key))

        template_values = {
            'matchstats_dict': matchstats_dict,
        }

        path = os.path.join(os.path.dirname(__file__), '../templates/math/event_matchstats_do.html')
        self.response.out.write(template.render(path, template_values))
    def post(self, event_key):
        self._require_login()
        self._require_registration()

        current_user_id = self.user_bundle.account.key.id()

        event = Event.get_by_id(event_key)
        subscribed_matches = set(self.request.get_all('subscribed_matches'))

        for match in event.matches:
            if not match.has_been_played:
                match_key = match.key.id()
                if match.key.id() in subscribed_matches:
                    sub = Subscription(
                        parent=ndb.Key(Account, current_user_id),
                        user_id=current_user_id,
                        model_type=ModelType.MATCH,
                        model_key=match_key,
                        notification_types=[NotificationType.UPCOMING_MATCH]
                    )
                    MyTBAHelper.add_subscription(sub)
                else:
                    MyTBAHelper.remove_subscription(current_user_id, match_key, ModelType.MATCH)

        self.redirect('/account/mytba?status=match_updated#my-matches'.format(event_key))
    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']
            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 post(self, event_key_id):
        self._require_admin()

        event = Event.get_by_id(event_key_id)
        if not event:
            self.abort(404)

        place_id = self.request.get('place_id')
        if not place_id:
            self.abort(400)

        # Construct a mostly empty input struct that'll get filled in
        location_input = {
            'place_id': place_id,
            'geometry': {
                'location': {
                    'lat': '',
                    'lng': '',
                },
            },
            'name': '',
            'types': [],
        }

        location_info = LocationHelper.construct_location_info_async(location_input).get_result()
        event.normalized_location = LocationHelper.build_normalized_location(location_info)
        EventManipulator.createOrUpdate(event)
        self.redirect('/admin/event/{}'.format(event_key_id))
示例#10
0
    def get(self, event_key):
        df = DatafeedTba()

        event = Event.get_by_id(event_key)
        match_filetypes = df.getVideos(event)
        if match_filetypes:
            matches_to_put = []
            for match in event.matches:
                if match.tba_videos != match_filetypes.get(match.key_name, []):
                    match.tba_videos = match_filetypes.get(match.key_name, [])
                    match.dirty = True
                    matches_to_put.append(match)

            MatchManipulator.createOrUpdate(matches_to_put)

            tbavideos = match_filetypes.items()
        else:
            logging.info("No tbavideos found for event " + event.key_name)
            tbavideos = []

        template_values = {
            'tbavideos': tbavideos,
        }

        if 'X-Appengine-Taskname' not in self.request.headers:  # Only write out if not in taskqueue
            path = os.path.join(os.path.dirname(__file__), '../templates/datafeeds/tba_videos_get.html')
            self.response.out.write(template.render(path, template_values))
    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))
示例#12
0
    def _render(self, event_key):
        self.response.headers.add_header('content-type', 'application/json', charset='utf-8')
        event = Event.get_by_id(event_key)
        if not event:
            return json.dumps(None)

        return json.dumps(event.remap_teams)
    def get(self, event_key=None):
        self._require_login()
        self._require_registration()

        if event_key is None:
            events = EventHelper.getEventsWithinADay()
            EventHelper.sort_events(events)
            self.template_values['events'] = events
            self.response.out.write(jinja2_engine.render('mytba_add_hot_matches_base.html', self.template_values))
            return

        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)

        subscriptions_future = Subscription.query(
            Subscription.model_type==ModelType.MATCH,
            Subscription.notification_types==NotificationType.UPCOMING_MATCH,
            ancestor=self.user_bundle.account.key).fetch_async(projection=[Subscription.model_key])

        matches = []
        if event.matchstats and 'match_predictions' in event.matchstats:
            match_predictions = event.matchstats['match_predictions']
            max_hotness = 0
            min_hotness = float('inf')
            for match in event.matches:
                if not match.has_been_played and match.key.id() in match_predictions:
                    prediction = match_predictions[match.key.id()]
                    red_score = prediction['red']['score']
                    blue_score = prediction['blue']['score']
                    if red_score > blue_score:
                        winner_score = red_score
                        loser_score = blue_score
                    else:
                        winner_score = blue_score
                        loser_score = red_score

                    hotness = winner_score + 2.0*loser_score  # Favor close high scoring matches

                    max_hotness = max(max_hotness, hotness)
                    min_hotness = min(min_hotness, hotness)
                    match.hotness = hotness
                    matches.append(match)

        existing_subscriptions = set()
        for sub in subscriptions_future.get_result():
            existing_subscriptions.add(sub.model_key)

        hot_matches = []
        for match in matches:
            match.hotness = 100 * (match.hotness - min_hotness) / (max_hotness - min_hotness)
            match.already_subscribed = match.key.id() in existing_subscriptions
            hot_matches.append(match)
        hot_matches = sorted(hot_matches, key=lambda match: -match.hotness)
        matches_dict = {'qm': hot_matches[:25]}

        self.template_values['event'] = event
        self.template_values['matches'] = matches_dict

        self.response.out.write(jinja2_engine.render('mytba_add_hot_matches.html', self.template_values))
示例#14
0
    def get(self, alias):
        special_webcasts_future = Sitevar.get_by_id_async('gameday.special_webcasts')
        special_webcasts = special_webcasts_future.get_result()
        aliases = special_webcasts.contents.get("aliases", {}) if special_webcasts else {}

        if alias in aliases:
            self.redirect("/gameday{}".format(aliases[alias]))
            return

        # Allow an alias to be an event key
        if not ValidationHelper.event_id_validator(alias):
            event = Event.get_by_id(alias)
            if event and event.webcast and event.within_a_day:
                params = self.get_param_string_for_event(event)
                self.redirect("/gameday{}".format(params))
                return

        # Allow an alias to be a team number
        team_key = "frc{}".format(alias)
        if not ValidationHelper.team_id_validator(team_key):
            now = datetime.datetime.now()
            team_events_future = TeamYearEventsQuery(team_key, now.year).fetch_async()
            team_events = team_events_future.get_result()
            for event in team_events:
                if event and event.webcast and event.within_a_day:
                    params = self.get_param_string_for_event(event)
                    self.redirect("/gameday{}".format(params))
                    return

        self.redirect("/gameday")
        return
    def _process_request(self, request, event_key):
        alliance_selections = JSONAllianceSelectionsParser.parse(request.body)

        event = Event.get_by_id(event_key)
        event.alliance_selections_json = json.dumps(alliance_selections)
        event.dirty = True  # TODO: hacky
        EventManipulator.createOrUpdate(event)
    def post(self, event_key_id):
        self._require_admin()
        event = Event.get_by_id(event_key_id)
        if not event:
            self.redirect("/admin/event/" + event.key_name)
            return
        event_details = event.details
        if not event_details or not event_details.alliance_selections:
            # No alliance data to modify
            self.redirect("/admin/event/" + event.key_name)
            return

        team_in = "frc{}".format(self.request.get("backup_in"))
        team_out = "frc{}".format(self.request.get("backup_out"))

        # Make sure both teams are attending the event
        et_in = EventTeam.get_by_id("{}_{}".format(event.key_name, team_in))
        et_out = EventTeam.get_by_id("{}_{}".format(event.key_name, team_out))
        if not et_in and et_out:
            # Bad teams supplied
            self.redirect("/admin/event/" + event.key_name)
            return

        for alliance in event_details.alliance_selections:
            if team_out in alliance.get('picks', []):
                alliance['backup'] = {}
                alliance['backup']['in'] = team_in
                alliance['backup']['out'] = team_out
                EventDetailsManipulator.createOrUpdate(event_details)
                break

        self.redirect("/admin/event/" + event.key_name)
        return
    def _process_request(self, request, event_key):
        event = Event.get_by_id(event_key)
        year = int(event_key[:4])

        matches = []
        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
                logging.debug("Calculating time!")
                MatchHelper.add_match_times(event, [match])

            matches.append(match)

        MatchManipulator.createOrUpdate(matches)

        self.response.out.write(json.dumps({'Success': "Matches successfully updated"}))
    def getEventAlliances(self, event_key):
        year = int(event_key[:4])
        event_short = event_key[4:]

        event = Event.get_by_id(event_key)
        alliances = self._parse(self.FMS_API_EVENT_ALLIANCES_URL_PATTERN % (year, self._get_event_short(event_short, event)), FMSAPIEventAlliancesParser())
        return alliances
    def getMatches(self, event_key):
        year = int(event_key[:4])
        event_short = event_key[4:]

        event = Event.get_by_id(event_key)
        hs_parser = FMSAPIHybridScheduleParser(year, event_short)
        detail_parser = FMSAPIMatchDetailsParser(year, event_short)
        qual_matches_future = self._parse_async(self.FMS_API_HYBRID_SCHEDULE_QUAL_URL_PATTERN % (year, self._get_event_short(event_short, event)), hs_parser)
        playoff_matches_future = self._parse_async(self.FMS_API_HYBRID_SCHEDULE_PLAYOFF_URL_PATTERN % (year, self._get_event_short(event_short, event)), hs_parser)
        qual_details_future = self._parse_async(self.FMS_API_MATCH_DETAILS_QUAL_URL_PATTERN % (year, self._get_event_short(event_short, event)), detail_parser)
        playoff_details_future = self._parse_async(self.FMS_API_MATCH_DETAILS_PLAYOFF_URL_PATTERN % (year, self._get_event_short(event_short, event)), detail_parser)

        matches_by_key = {}
        qual_matches = qual_matches_future.get_result()
        if qual_matches is not None:
            for match in qual_matches[0]:
                matches_by_key[match.key.id()] = match
        playoff_matches = playoff_matches_future.get_result()
        if playoff_matches is not None:
            for match in playoff_matches[0]:
                matches_by_key[match.key.id()] = match

        qual_details = qual_details_future.get_result()
        qual_details_items = qual_details.items() if qual_details is not None else []
        playoff_details = playoff_details_future.get_result()
        playoff_details_items = playoff_details.items() if playoff_details is not None else []
        for match_key, match_details in qual_details_items + playoff_details_items:
            match_key = playoff_matches[1].get(match_key, match_key)
            if match_key in matches_by_key:
                matches_by_key[match_key].score_breakdown_json = json.dumps(match_details)

        return filter(
            lambda m: not FMSAPIHybridScheduleParser.is_blank_match(m),
            matches_by_key.values())
 def post(self):
     event_key = self.request.get('event_key')
     awards_json = self.request.get('awards_json')
     awards = json.loads(awards_json)
     
     event = Event.get_by_id(event_key)
     
     def _getTeamKey(award):
         team = Team.get_by_id('frc' + str(award.get('team_number', None)))
         if team is not None:
             return team.key
         else:
             return None
    
     awards = [Award(
         id = Award.renderKeyName(event.key_name, award.get('name')),
         name = award.get('name', None),
         team = _getTeamKey(award),
         awardee = award.get('awardee', None),
         year = event.year,
         official_name = award.get('official_name', None),
         event = event.key)
         for award in awards]
     
     AwardManipulator.createOrUpdate(awards)
     self.redirect('/admin/event/{}'.format(event_key))
示例#21
0
    def get(self, event_key):
        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)

        if not event.remap_teams:
            return

        event.prepAwardsMatchesTeams()

        # Remap matches
        EventHelper.remapteams_matches(event.matches, event.remap_teams)
        MatchManipulator.createOrUpdate(event.matches)

        # Remap alliance selections
        if event.alliance_selections:
            EventHelper.remapteams_alliances(event.alliance_selections, event.remap_teams)
        # Remap rankings
        if event.rankings:
            EventHelper.remapteams_rankings(event.rankings, event.remap_teams)
        if event.details and event.details.rankings2:
            EventHelper.remapteams_rankings2(event.details.rankings2, event.remap_teams)
        EventDetailsManipulator.createOrUpdate(event.details)

        # Remap awards
        EventHelper.remapteams_awards(event.awards, event.remap_teams)
        AwardManipulator.createOrUpdate(event.awards, auto_union=False)
    def create_target_model(self, suggestion):
        event_id = self.request.get("event_short", None)
        event_key = str(self.request.get("year")) + str.lower(str(self.request.get("event_short")))
        if not event_id:
            # Need to supply a key :(
            return 'missing_key', None
        if not Event.validate_key_name(event_key):
            # Bad event key generated
            return 'bad_key', None

        start_date = None
        if self.request.get("start_date"):
            start_date = datetime.strptime(self.request.get("start_date"), "%Y-%m-%d")

        end_date = None
        if self.request.get("end_date"):
            end_date = datetime.strptime(self.request.get("end_date"), "%Y-%m-%d")

        existing_event = Event.get_by_id(event_key)
        if existing_event:
            return 'duplicate_key', None

        first_code = self.request.get("first_code", '')
        event = Event(
            id=event_key,
            end_date=end_date,
            event_short=self.request.get("event_short"),
            event_type_enum=EventType.OFFSEASON,
            district_key=None,
            venue=self.request.get("venue"),
            venue_address=self.request.get("venue_address"),
            city=self.request.get("city"),
            state_prov=self.request.get("state"),
            country=self.request.get("country"),
            name=self.request.get("name"),
            short_name=self.request.get("short_name"),
            start_date=start_date,
            website=self.request.get("website"),
            year=int(self.request.get("year")),
            first_code=first_code,
            official=(not first_code == ''),
        )
        EventManipulator.createOrUpdate(event)

        author = suggestion.author.get()
        OutgoingNotificationHelper.send_suggestion_result_email(
            to=author.email,
            subject="[TBA] Offseason Event Suggestion: {}".format(event.name),
            email_body="""Dear {},

Thank you for suggesting an offseason event to The Blue Alliance. Your suggestion has been approved and you can find the event at https://thebluealliance.com/event/{}

If you are the event's organizer and would like to upload teams attending, match videos, or real-time match results to TBA before or during the event, you can do so using the TBA EventWizard - request auth keys here: https://www.thebluealliance.com/request/apiwrite

Thanks for helping make TBA better,
The Blue Alliance Admins
            """.format(author.nickname, event_key)
        )

        return 'success', event_key
    def _render(self, event_key, webcast_number):
        self.response.headers.add_header('content-type', 'application/json', charset='utf-8')

        output = {}
        if not webcast_number.isdigit():
            return json.dumps(output)
        webcast_number = int(webcast_number) - 1

        event = Event.get_by_id(event_key)
        if event and event.webcast:
            webcast = event.webcast[webcast_number]
            if 'type' in webcast and 'channel' in webcast:
                output['player'] = self._renderPlayer(webcast)
        else:
            special_webcasts_future = Sitevar.get_by_id_async('gameday.special_webcasts')
            special_webcasts = special_webcasts_future.get_result()
            if special_webcasts:
                special_webcasts = special_webcasts.contents
            else:
                special_webcasts = {}
            if event_key in special_webcasts:
                webcast = special_webcasts[event_key]
                if 'type' in webcast and 'channel' in webcast:
                    output['player'] = self._renderPlayer(webcast)

        return json.dumps(output)
    def _process_request(self, request, event_key):
        rankings = JSONRankingsParser.parse(request.body)

        event = Event.get_by_id(event_key)
        event.rankings_json = json.dumps(rankings)
        event.dirty = True  # TODO: hacky
        EventManipulator.createOrUpdate(event)
示例#25
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 get(self, event_key):
        self._require_admin()

        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)
        event.prepAwardsMatchesTeams()

        reg_sitevar = Sitevar.get_by_id("cmp_registration_hacks")
        api_keys = ApiAuthAccess.query(ApiAuthAccess.event_list == ndb.Key(Event, event_key)).fetch()
        event_medias = Media.query(Media.references == event.key).fetch(500)

        self.template_values.update({
            "event": event,
            "medias": event_medias,
            "cache_key": event_controller.EventDetail('2016nyny').cache_key.format(event.key_name),
            "flushed": self.request.get("flushed"),
            "playoff_types": PlayoffType.type_names,
            "write_auths": api_keys,
            "event_sync_disable": reg_sitevar and event_key in reg_sitevar.contents.get('divisions_to_skip', []),
            "set_start_day_to_last": reg_sitevar and event_key in reg_sitevar.contents.get('set_start_to_last_day', []),
            "skip_eventteams": reg_sitevar and event_key in reg_sitevar.contents.get('skip_eventteams', []),
            "event_name_override": next(iter(filter(lambda e: e.get("event") == event_key, reg_sitevar.contents.get("event_name_override", []))), {}).get("name", "")
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_details.html')
        self.response.out.write(template.render(path, self.template_values))
示例#27
0
    def getEventInfo(self, event_key):
        """
        Return an Event dict with basic information
        """
        
        memcache_key = "api_event_info_%s" % event_key
        event_dict = memcache.get(memcache_key)
        if event_dict is None:
            event = Event.get_by_id(event_key)
            if event is not None:
                event_dict = dict()
                event_dict["key"] = event.key_name
                event_dict["year"] = event.year
                event_dict["event_code"] = event.event_short
                event_dict["name"] = event.name
                event_dict["short_name"] = event.short_name
                event_dict["location"] = event.location
                event_dict["official"] = event.official
                event_dict["facebook_eid"] = event.facebook_eid

                if event.start_date:
                    event_dict["start_date"] = event.start_date.isoformat()
                else:
                    event_dict["start_date"] = None
                if event.end_date:
                    event_dict["end_date"] = event.end_date.isoformat()
                else:
                    event_dict["end_date"] = None

                event.prepTeams()
                event_dict["teams"] = [team.key_name for team in event.teams]

                #TODO: Reduce caching time before 2013 season. 2592000 is one month -gregmarra
                if tba_config.CONFIG["memcache"]: memcache.set(memcache_key, event_dict, 2592000)
        return event_dict
    def get(self, event_key):
        datafeed = DatafeedUsfirst()

        event = Event.get_by_id(event_key)
        new_awards = AwardManipulator.createOrUpdate(datafeed.getEventAwards(event))
        if type(new_awards) != list:
            new_awards = [new_awards]

        # create EventTeams
        team_ids = set()
        for award in new_awards:
            for team in award.team_list:
                team_ids.add(team.id())
        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])

        template_values = {
            'awards': new_awards,
        }

        path = os.path.join(os.path.dirname(__file__), '../templates/datafeeds/usfirst_awards_get.html')
        self.response.out.write(template.render(path, template_values))
    def post(self):
        self._require_admin()
        event_key = self.request.get('event_key')
        matches_csv = self.request.get('matches_csv')
        matches, _ = OffseasonMatchesParser.parse(matches_csv)

        event = Event.get_by_id(event_key)
        matches = [Match(
            id=Match.renderKeyName(
                event.key.id(),
                match.get("comp_level", None),
                match.get("set_number", 0),
                match.get("match_number", 0)),
            event=event.key,
            year=event.year,
            set_number=match.get("set_number", 0),
            match_number=match.get("match_number", 0),
            comp_level=match.get("comp_level", None),
            team_key_names=match.get("team_key_names", None),
            alliances_json=match.get("alliances_json", None)
            )
            for match in matches]
        MatchManipulator.createOrUpdate(matches)

        self.redirect('/admin/event/{}'.format(event_key))
    def post(self):
        self.verify_permissions()
        suggestion_id = int(self.request.get("suggestion_id"))
        verdict = self.request.get("verdict")
        message = self.request.get("user_message")

        admin_email_body = None
        email_body = None
        user = None
        event_key = None
        status = ''
        if verdict == "accept":
            status = 'accept'
            auth_id, user, event_key, email_body = self._process_accepted(suggestion_id, message)
            admin_email_body = """{} ({}) has accepted the request with the following message:
{}

View the key: https://www.thebluealliance.com/admin/api_auth/edit/{}

""".format(self.user_bundle.account.display_name, self.user_bundle.account.email, message, auth_id)

        elif verdict == "reject":
            suggestion = Suggestion.get_by_id(suggestion_id)
            event_key = suggestion.contents['event_key']
            user = suggestion.author.get()
            event = Event.get_by_id(event_key)
            suggestion.review_state = Suggestion.REVIEW_REJECTED
            suggestion.reviewer = self.user_bundle.account.key
            suggestion.reviewed_at = datetime.now()
            suggestion.put()

            status = 'reject'
            email_body = """Hi {},

We have reviewer your request for auth tokens for {} {} and have regretfully declined with the following message:

{}

If you have any questions, please don't hesitate to reach out to us at [email protected]

Thanks,
TBA Admins
""".format(user.display_name, event.year, event.name, message)

            admin_email_body = """{} ({}) has rejected this request with the following reason:
{}
""".format(self.user_bundle.account.display_name, self.user_bundle.account.email, message)

        # Notify the user their keys are available
        if email_body:
            mail.send_mail(sender="The Blue Alliance Contact <*****@*****.**>",
                           to=user.email,
                           subject="The Blue Alliance Auth Tokens for {}".format(event_key),
                           body=email_body)
        if admin_email_body:
            # Subject should match the one in suggest_apiwrite_controller
            subject = "Trusted API Key Request for {}".format(event_key)
            SuggestionNotifier.send_admin_alert_email(subject, admin_email_body)

        self.redirect("/suggest/apiwrite/review?success={}".format(status))
    def get(self, event_key):
        event = Event.get_by_id(event_key)
        if event.event_district_enum == DistrictType.NO_DISTRICT:
            self.response.out.write(
                "Can't calculate district points for a non-district event!")
            return

        district_points = DistrictHelper.calculate_event_points(event)

        event.district_points_json = json.dumps(district_points)
        EventManipulator.createOrUpdate(event)

        self.response.out.write(event.district_points)
示例#32
0
    def get(self, event_key):
        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)
            return

        taskqueue.add(
            url='/tasks/math/do/playoff_advancement_update/{}'.format(
                event.key_name),
            method='GET')

        self.response.out.write("Enqueued time prediction for {}".format(
            event.key_name))
    def get(self, event_key_id):
        self._require_admin()

        event = Event.get_by_id(event_key_id)
        if not event:
            self.abort(404)

        event.normalized_location = None
        LocationHelper.update_event_location(event)
        event = EventManipulator.createOrUpdate(event)

        self.response.out.write("New location: {}".format(
            event.normalized_location))
    def post(self, event_key_id):
        self._require_admin()
        event = Event.get_by_id(event_key_id)

        alliance_selections_csv = self.request.get('alliance_selections_csv')
        alliance_selections = CSVAllianceSelectionsParser.parse(
            alliance_selections_csv)

        event_details = EventDetails(id=event_key_id,
                                     alliance_selections=alliance_selections)
        EventDetailsManipulator.createOrUpdate(event_details)

        self.redirect("/admin/event/" + event.key_name)
    def post(self, event_key_id):
        self._require_admin()

        webcast = dict()
        webcast["type"] = self.request.get("webcast_type")
        webcast["channel"] = self.request.get("webcast_channel")
        if self.request.get("webcast_file"):
            webcast["file"] = self.request.get("webcast_file")

        event = Event.get_by_id(event_key_id)
        EventWebcastAdder.add_webcast(event, webcast)

        self.redirect("/admin/event/" + event.key_name)
    def _process_request(self, request, event_key):
        rankings = JSONRankingsParser.parse(request.body)

        event = Event.get_by_id(event_key)

        event_details = EventDetails(id=event_key, rankings=rankings)
        if event_details.year == 2017:  # TODO: Temporary fix. Should directly parse request into rankings2
            event_details.rankings2 = RankingsHelper.convert_rankings(
                event_details)
        EventDetailsManipulator.createOrUpdate(event_details)

        self.response.out.write(
            json.dumps({'Success': "Rankings successfully updated"}))
示例#37
0
    def get(self, event_key):
        self._require_admin()
        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)
            return
        existing_event_team_keys = set(
            EventTeam.query(EventTeam.event == event.key).fetch(
                1000, keys_only=True))
        EventTeamManipulator.delete_keys(existing_event_team_keys)

        self.response.out.write("Deleted {} EventTeams from {}".format(
            len(existing_event_team_keys), event_key))
    def getEventDetails(self, event_key):
        year = int(event_key[:4])
        event_short = event_key[4:]

        event = Event.get_by_id(event_key)
        api_event_short = self._get_event_short(event_short, event)
        result = self._parse(
            self.FMS_API_EVENT_DETAILS_URL_PATTERN % (year, api_event_short),
            FMSAPIEventListParser(year, short=event_short))
        if result:
            return result
        else:
            return [], []
    def post(self):
        if self.request.get("verdict") == "accept":
            webcast = dict()
            webcast["type"] = self.request.get("webcast_type")
            webcast["channel"] = self.request.get("webcast_channel")
            if self.request.get("webcast_file"):
                webcast["file"] = self.request.get("webcast_file")

            event = Event.get_by_id(self.request.get("event_key"))
            suggestion_key = self.request.get("suggestion_key")
            suggestion = Suggestion.get_by_id(int(suggestion_key) if suggestion_key.isdigit() else suggestion_key)

            EventWebcastAdder.add_webcast(event, webcast)
            MemcacheWebcastFlusher.flush()

            suggestion.review_state = Suggestion.REVIEW_ACCEPTED
            suggestion.reviewer = self.user_bundle.account.key
            suggestion.reviewed_at = datetime.datetime.now()
            suggestion.put()

            self.redirect("/suggest/event/webcast/review?success=accept&event_key=%s" % event.key.id())
            return

        elif self.request.get("verdict") == "reject":
            suggestion_key = self.request.get("suggestion_key")
            suggestion = Suggestion.get_by_id(int(suggestion_key) if suggestion_key.isdigit() else suggestion_key)

            suggestion.review_state = Suggestion.REVIEW_REJECTED
            suggestion.reviewer = self.user_bundle.account.key
            suggestion.reviewed_at = datetime.datetime.now()
            suggestion.put()

            self.redirect("/suggest/event/webcast/review?success=reject")
            return

        elif self.request.get("verdict") == "reject_all":
            suggestion_keys = self.request.get("suggestion_keys").split(",")

            suggestions = [Suggestion.get_by_id(int(suggestion_key) if suggestion_key.isdigit() else suggestion_key) for suggestion_key in suggestion_keys]

            for suggestion in suggestions:
                event_key = suggestion.target_key
                suggestion.review_state = Suggestion.REVIEW_REJECTED
                suggestion.reviewer = self.user_bundle.account.key
                suggestion.reviewed_at = datetime.datetime.now()
                suggestion.put()

            self.redirect("/suggest/event/webcast/review?success=reject_all&event_key=%s" % event_key)
            return

        self.redirect("/suggest/event/webcast/review")
    def get(self, event_key):
        self._require_login('/account/register')
        self._require_registration('/account/register')

        # Handle wildcard for all events in a year
        event = None
        is_wildcard = False
        if event_key.endswith('*'):
            try:
                year = int(event_key[:-1])
            except:
                year = None
            if year and year >= 1992 and year <= tba_config.MAX_YEAR:
                event = Event(  # fake event for rendering
                    name="ALL {} EVENTS".format(year),
                    year=year,
                )
                is_wildcard = True
        else:
            event = Event.get_by_id(event_key)

        if not event:
            self.abort(404)

        user = self.user_bundle.account.key
        favorite = Favorite.query(Favorite.model_key == event_key,
                                  Favorite.model_type == ModelType.EVENT,
                                  ancestor=user).get()
        subscription = Subscription.query(
            Favorite.model_key == event_key,
            Favorite.model_type == ModelType.EVENT,
            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_event_notifications
        ]

        self.template_values['event'] = event
        self.template_values['is_wildcard'] = is_wildcard
        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_event.html', self.template_values))
    def postUpdateHook(cls, event_details_list, updated_attr_list,
                       is_new_list):
        """
        To run after models have been updated
        """
        for (event_details, updated_attrs) in zip(event_details_list,
                                                  updated_attr_list):
            event = Event.get_by_id(event_details.key.id())
            if event.within_a_day and "alliance_selections" in updated_attrs:
                try:
                    NotificationHelper.send_alliance_update(event)
                except Exception:
                    logging.error(
                        "Error sending alliance update notification for {}".
                        format(event.key_name))
                    logging.error(traceback.format_exc())
                try:
                    TBANSHelper.alliance_selection(event)
                except Exception:
                    logging.error(
                        "Error sending alliance update notification for {}".
                        format(event.key_name))
                    logging.error(traceback.format_exc())

            # Enqueue task to calculate district points
            try:
                taskqueue.add(
                    url='/tasks/math/do/district_points_calc/{}'.format(
                        event.key.id()),
                    method='GET')
            except Exception:
                logging.error(
                    "Error enqueuing district_points_calc for {}".format(
                        event.key.id()))
                logging.error(traceback.format_exc())

            # Enqueue task to calculate event team status
            try:
                taskqueue.add(url='/tasks/math/do/event_team_status/{}'.format(
                    event.key.id()),
                              method='GET')
            except Exception:
                logging.error(
                    "Error enqueuing event_team_status for {}".format(
                        event.key.id()))
                logging.error(traceback.format_exc())

            try:
                FirebasePusher.update_event_details(event_details)
            except Exception:
                logging.warning("Firebase update_event_details failed!")
示例#42
0
    def create_target_model(self, suggestion):
        webcast = dict()
        webcast["type"] = self.request.get("webcast_type")
        webcast["channel"] = self.request.get("webcast_channel")
        if self.request.get("webcast_file"):
            webcast["file"] = self.request.get("webcast_file")
        if self.request.get('webcast_date'):
            webcast['date'] = self.request.get('webcast_date')

        event = Event.get_by_id(self.request.get("event_key"))
        # Defer because of transactions
        deferred.defer(EventWebcastAdder.add_webcast, event, webcast)
        deferred.defer(MemcacheWebcastFlusher.flush)
        return True
    def get(self):
        self._require_registration()

        if not self.request.get("event_key"):
            self.redirect("/", abort=True)

        event = Event.get_by_id(self.request.get("event_key"))

        self.template_values.update({
            "status": self.request.get("status"),
            "event": event,
        })

        self.response.out.write(jinja2_engine.render('suggestions/suggest_event_webcast.html', self.template_values))
示例#44
0
    def _update_rankings(self):
        """
        Generates and saves fake rankings
        """
        event = Event.get_by_id('2016nytr')

        team_wins = defaultdict(int)
        team_losses = defaultdict(int)
        team_ties = defaultdict(int)
        teams = set()
        for match in event.matches:
            if match.comp_level == 'qm':
                for alliance in ['red', 'blue']:
                    for team in match.alliances[alliance]['teams']:
                        teams.add(team)
                        if match.has_been_played:
                            if alliance == match.winning_alliance:
                                team_wins[team] += 1
                            elif match.winning_alliance == '':
                                team_ties[team] += 1
                            else:
                                team_losses[team] += 1

        rankings = []
        for team in sorted(teams):
            wins = team_wins[team]
            losses = team_losses[team]
            ties = team_ties[team]
            rankings.append({
                'team_key': team,
                'record': {
                    'wins': wins,
                    'losses': losses,
                    'ties': ties,
                },
                'matches_played': wins + losses + ties,
                'dq': 0,
                'sort_orders': [2 * wins + ties, 0, 0, 0, 0],
                'qual_average': None,
            })
        rankings = sorted(rankings, key=lambda r: -r['sort_orders'][0])

        for i, ranking in enumerate(rankings):
            ranking['rank'] = i + 1

        EventDetailsManipulator.createOrUpdate(
            EventDetails(
                id='2016nytr',
                rankings2=rankings,
            ))
示例#45
0
    def getMatches(self, event_key):
        year = int(event_key[:4])
        event_short = event_key[4:]

        event = Event.get_by_id(event_key)
        hs_parser = FMSAPIHybridScheduleParser(year, event_short)
        detail_parser = FMSAPIMatchDetailsParser(year, event_short)
        qual_matches_future = self._parse_async(
            self.FMS_API_HYBRID_SCHEDULE_QUAL_URL_PATTERN %
            (year, self._get_event_short(event_short, event)), hs_parser)
        playoff_matches_future = self._parse_async(
            self.FMS_API_HYBRID_SCHEDULE_PLAYOFF_URL_PATTERN %
            (year, self._get_event_short(event_short, event)), hs_parser)
        qual_details_future = self._parse_async(
            self.FMS_API_MATCH_DETAILS_QUAL_URL_PATTERN %
            (year, self._get_event_short(event_short, event)), detail_parser)
        playoff_details_future = self._parse_async(
            self.FMS_API_MATCH_DETAILS_PLAYOFF_URL_PATTERN %
            (year, self._get_event_short(event_short, event)), detail_parser)

        # Organize matches by key
        matches_by_key = {}
        qual_matches = qual_matches_future.get_result()
        if qual_matches is not None:
            for match in qual_matches[0]:
                matches_by_key[match.key.id()] = match
        playoff_matches = playoff_matches_future.get_result()
        remapped_playoff_matches = {}
        if playoff_matches is not None:
            for match in playoff_matches[0]:
                matches_by_key[match.key.id()] = match
            remapped_playoff_matches = playoff_matches[1]

        # Add details to matches based on key
        qual_details = qual_details_future.get_result()
        qual_details_items = qual_details.items(
        ) if qual_details is not None else []
        playoff_details = playoff_details_future.get_result()
        playoff_details_items = playoff_details.items(
        ) if playoff_details is not None else []
        for match_key, match_details in qual_details_items + playoff_details_items:
            # Deal with remapped playoff matches, defaulting to the original match key
            match_key = remapped_playoff_matches.get(match_key, match_key)
            if match_key in matches_by_key:
                matches_by_key[match_key].score_breakdown_json = json.dumps(
                    match_details)

        return filter(
            lambda m: not FMSAPIHybridScheduleParser.is_blank_match(m),
            matches_by_key.values())
示例#46
0
 def postUpdateHook(cls, event_details_list, updated_attr_list, is_new_list):
     """
     To run after models have been updated
     """
     for (event_details, updated_attrs) in zip(event_details_list, updated_attr_list):
         event = Event.get_by_id(event_details.key.id())
         try:
             if event.within_a_day and "alliance_selections" in updated_attrs:
                 # Send updated alliances notification
                 logging.info("Sending alliance notifications for {}".format(event.key_name))
                 NotificationHelper.send_alliance_update(event)
         except Exception:
             logging.error("Error sending alliance update notification for {}".format(event.key_name))
             logging.error(traceback.format_exc())
示例#47
0
    def get(self, event_key):
        import pytz

        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)

        matches = event.matches
        if not matches or not event.timezone_id:
            return

        timezone = pytz.timezone(event.timezone_id)
        played_matches = MatchHelper.recentMatches(matches, num=0)
        unplayed_matches = MatchHelper.upcomingMatches(matches,
                                                       num=len(matches))
        MatchTimePredictionHelper.predict_future_matches(
            event_key, played_matches, unplayed_matches, timezone,
            event.within_a_day)

        # Detect whether the event is down
        # An event NOT down if ANY unplayed match's predicted time is within its scheduled time by a threshold and
        # the last played match (if it exists) wasn't too long ago.
        event_down = len(unplayed_matches) > 0
        for unplayed_match in unplayed_matches:
            if ((unplayed_match.predicted_time and unplayed_match.time
                 and unplayed_match.predicted_time <
                 unplayed_match.time + datetime.timedelta(minutes=30)) or
                (played_matches == [] or played_matches[-1].actual_time is None
                 or played_matches[-1].actual_time >
                 datetime.datetime.now() - datetime.timedelta(minutes=30))):
                event_down = False
                break

        status_sitevar = Sitevar.get_by_id('apistatus.down_events')
        if status_sitevar is None:
            status_sitevar = Sitevar(id="apistatus.down_events",
                                     description="A list of down event keys",
                                     values_json="[]")
        old_status = set(status_sitevar.contents)
        new_status = old_status.copy()
        if event_down:
            new_status.add(event_key)
        elif event_key in new_status:
            new_status.remove(event_key)

        status_sitevar.contents = list(new_status)
        status_sitevar.put()

        # Clear API Response cache
        ApiStatusController.clear_cache_if_needed(old_status, new_status)
示例#48
0
    def get(self, event_key):
        self._require_admin()

        event = Event.get_by_id(event_key)

        self.template_values.update({
            "event": event,
            'alliance_selections': json.dumps(event.alliance_selections),
            'rankings': json.dumps(event.rankings),
            "playoff_types": PlayoffType.type_names,
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_edit.html')
        self.response.out.write(template.render(path, self.template_values))
    def get(self, event_key):
        df = DatafeedOffseason()

        event = Event.get_by_id(event_key)
        url = self.request.get('url')

        new_matches = MatchManipulator.createOrUpdate(df.getMatches(event, url))

        template_values = {
            'matches': new_matches,
        }

        path = os.path.join(os.path.dirname(__file__), '../templates/datafeeds/offseason_matches_get.html')
        self.response.out.write(template.render(path, template_values))
    def post(self):
        self._require_admin()

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

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

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

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

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

        self.redirect("/admin/event/" + event.key_name)
        return
示例#51
0
    def post(self, event_key_id):
        self._require_admin()
        event = Event.get_by_id(event_key_id)

        teams_csv = self.request.get('teams_csv')
        team_numbers = CSVTeamsParser.parse(teams_csv)

        event_teams = []
        for team_number in team_numbers:
            event_teams.append(ndb.Key(EventTeam, '{}_frc{}'.format(event.key.id(), team_number)))

        EventTeamManipulator.delete_keys(event_teams)

        self.redirect("/admin/event/" + event.key_name)
示例#52
0
    def get(self, event_key):
        self._require_admin()

        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)
        event.prepAwardsMatchesTeams()

        self.template_values.update({
            "event": event
        })

        path = os.path.join(os.path.dirname(__file__), '../../templates/admin/event_details.html')
        self.response.out.write(template.render(path, self.template_values))
    def get(self, event_key):
        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)

        matches = event.matches
        if not matches:
            return

        timezone = pytz.timezone(event.timezone_id)
        played_matches = MatchHelper.recentMatches(matches, num=0)
        unplayed_matches = MatchHelper.upcomingMatches(matches, num=10)
        MatchTimePredictionHelper.predict_future_matches(
            played_matches, unplayed_matches, timezone, event.within_a_day)
示例#54
0
 def get(self):
     try:
         q = self.request.get("q")
         logging.info("search query: %s" % q)
         if q.isdigit():
             team_id = "frc%s" % q
             team = Team.get_by_id(team_id)
             if team:
                 self.redirect(team.details_url)
                 return None
         elif q[:4].isdigit():  # Check for event key
             event = Event.get_by_id(q)
             if event:
                 self.redirect(event.details_url)
                 return None
         else:  # Check for event short
             year = datetime.datetime.now().year  # default to current year
             event = Event.get_by_id('{}{}'.format(year, q))
             if event:
                 self.redirect(event.details_url)
                 return None
     except Exception, e:
         logging.warning("warning: %s" % e)
示例#55
0
    def get(self, type):
        self._require_registration('/account/')
        user_id = self.user_bundle.account.key.id()

        logging.info("Sending for {}".format(type))
        try:
            type = int(type)
        except ValueError:
            # Not passed a valid int, just stop here
            logging.info("Invalid number passed")
            self.redirect('/apidocs/webhooks')
            return

        event = Event.get_by_id('2014necmp')
        match = Match.get_by_id('2014necmp_f1m1')

        if type == NotificationType.UPCOMING_MATCH:
            notification = UpcomingMatchNotification(match, event)
        elif type == NotificationType.MATCH_SCORE:
            notification = MatchScoreNotification(match)
        elif type == NotificationType.LEVEL_STARTING:
            notification = CompLevelStartingNotification(match, event)
        elif type == NotificationType.ALLIANCE_SELECTION:
            notification = AllianceSelectionNotification(event)
        elif type == NotificationType.AWARDS:
            notification = AwardsUpdatedNotification(event)
        elif type == NotificationType.MEDIA_POSTED:
            # Not implemented yet
            pass
        elif type == NotificationType.DISTRICT_POINTS_UPDATED:
            notification = DistrictPointsUpdatedNotification('2014ne')
        elif type == NotificationType.SCHEDULE_UPDATED:
            notification = ScheduleUpdatedNotification(event, match)
        elif type == NotificationType.FINAL_RESULTS:
            # Not implemented yet
            pass
        else:
            # Not passed a valid int, return
            self.redirect('/apidocs/webhooks')
            return

        keys = PushHelper.get_client_ids_for_users([user_id])
        logging.info("Keys: {}".format(keys))
        if notification:
            # This page should not push notifications to the firebase queue
            # Nor should its notifications be tracked in analytics
            notification.send(keys, push_firebase=False, track_call=False)

        self.redirect('/apidocs/webhooks')
    def getEventRankings(self, event_key):
        year = int(event_key[:4])
        event_short = event_key[4:]

        event = Event.get_by_id(event_key)
        result = self._parse(
            self.FMS_API_EVENT_RANKINGS_URL_PATTERN %
            (year, self._get_event_short(event_short, event)), [
                FMSAPIEventRankingsParser(year),
                FMSAPIEventRankings2Parser(year)
            ])
        if result:
            return result
        else:
            return None, None
    def post(self, event_key_id):
        self._require_admin()
        event = Event.get_by_id(event_key_id)

        alliance_selections_csv = self.request.get('alliance_selections_csv')
        alliance_selections = CSVAllianceSelectionsParser.parse(alliance_selections_csv)

        if alliance_selections and event.alliance_selections != alliance_selections:
            event.alliance_selections_json = json.dumps(alliance_selections)
            event._alliance_selections = None
            event.dirty = True

        EventManipulator.createOrUpdate(event)

        self.redirect("/admin/event/" + event.key_name)
    def post(self, event_key):
        self._require_admin()

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

        details = EventDetails.get_by_id(event.key_name)
        if details:
            details.playoff_advancement = {}
            EventDetailsManipulator.createOrUpdate(details)

        self.redirect("/admin/event/" + event.key_name)
        return
    def _render(self, event_key):
        event = Event.get_by_id(event_key)
        if not event:
            self.abort(404)

        matches = MatchHelper.organizeMatches(event.matches)

        self.template_values.update({
            "event": event,
            "matches": matches,
            "datetime": datetime.datetime.now()
        })

        self.response.headers['content-type'] = 'application/xml; charset=UTF-8'
        return jinja2_engine.render('event_rss.xml', self.template_values)
示例#60
0
    def get(self, event_key):
        event = Event.get_by_id(event_key)
        matchstats_dict = MatchstatsHelper.calculate_matchstats(
            event.matches, event.year)
        if any([v != {} for v in matchstats_dict.values()]):
            pass
        else:
            logging.warn(
                "Matchstat calculation for {} failed!".format(event_key))
            matchstats_dict = None

        predictions_dict = None
        if event.year in {
                2016, 2017, 2018, 2019, 2020
        } and event.event_type_enum in EventType.SEASON_EVENT_TYPES or event.enable_predictions:
            sorted_matches = MatchHelper.play_order_sort_matches(event.matches)
            match_predictions, match_prediction_stats, stat_mean_vars = PredictionHelper.get_match_predictions(
                sorted_matches)
            ranking_predictions, ranking_prediction_stats = PredictionHelper.get_ranking_predictions(
                sorted_matches, match_predictions)

            predictions_dict = {
                'match_predictions': match_predictions,
                'match_prediction_stats': match_prediction_stats,
                'stat_mean_vars': stat_mean_vars,
                'ranking_predictions': ranking_predictions,
                'ranking_prediction_stats': ranking_prediction_stats
            }

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

        event_details = EventDetails(
            id=event_key,
            matchstats=matchstats_dict,
            predictions=predictions_dict,
            insights=event_insights,
        )
        EventDetailsManipulator.createOrUpdate(event_details)

        template_values = {
            'matchstats_dict': matchstats_dict,
        }

        if 'X-Appengine-Taskname' not in self.request.headers:  # Only write out if not in taskqueue
            path = os.path.join(os.path.dirname(__file__),
                                '../templates/math/event_matchstats_do.html')
            self.response.out.write(template.render(path, template_values))