Пример #1
0
def register_athlete(strava_athlete, token_dict):
    """
    Ensure specified athlete is added to database, returns athlete orm.

    :return: The added athlete model object.
    :rtype: :class:`bafs.orm.Athlete`
    """
    athlete = meta.scoped_session().query(Athlete).get(strava_athlete.id)
    if athlete is None:
        athlete = Athlete()
    athlete.id = strava_athlete.id
    athlete.name = '{0} {1}'.format(strava_athlete.firstname,
                                    strava_athlete.lastname).strip()
    # Temporary; we will update this in disambiguation phase.  (This isn't optimal; needs to be
    # refactored....
    #
    #     Where does the disambiguation phase get called now? Nowhere...
    #     so let's fix it here for now.
    #     * Do not override already set display_names.
    #     * Use a first name and last initial (if available).
    #     See also:
    #       https://github.com/freezingsaddles/freezing-web/issues/80
    #       https://github.com/freezingsaddles/freezing-web/issues/75
    #       https://github.com/freezingsaddles/freezing-web/issues/73
    #     - @obscurerichard]
    if athlete.display_name is None:
        if strava_athlete.lastname is None:
            athlete.display_name = strava_athlete.firstname
        else:
            athlete.display_name = '{0} {1}'.format(
                strava_athlete.firstname.strip(),
                strava_athlete.lastname.strip(),
            )
    athlete.profile_photo = strava_athlete.profile

    athlete.access_token = token_dict['access_token']
    athlete.refresh_token = token_dict['refresh_token']
    athlete.expires_at = token_dict['expires_at']
    meta.scoped_session().add(athlete)
    # We really shouldn't be committing here, since we want to disambiguate names after registering
    meta.scoped_session().commit()

    return athlete
Пример #2
0
    def register_athlete(self, strava_athlete: sm.Athlete,
                         access_token: str) -> Athlete:
        """
        Ensure specified athlete is added to database, returns athlete model.

        :return: The added athlete model object.
        :rtype: :class:`bafs.model.Athlete`
        """
        session = meta.scoped_session()
        athlete = session.query(Athlete).get(strava_athlete.id)

        if athlete is None:
            athlete = Athlete()

        athlete.id = strava_athlete.id
        athlete_name = f"{strava_athlete.firstname} {strava_athlete.lastname}"
        athlete.profile_photo = strava_athlete.profile
        athlete.access_token = access_token

        def already_exists(display_name) -> bool:
            return (
                session.query(Athlete).filter(Athlete.id != athlete.id).filter(
                    Athlete.display_name == display_name).count() > 0)

        def unambiguous_display_name() -> str:
            display_name = f"{strava_athlete.firstname} {strava_athlete.lastname[0]}"
            if already_exists(display_name):
                self.logger.info(
                    f"display_name '{display_name}' conflicts, using '{athlete_name}'"
                )
                display_name = athlete_name
            return display_name

        # Only update the display name if it is either:
        # a new athlete, or the athlete name has changed
        try:
            if athlete_name != athlete.name:
                self.logger.info(
                    f"Athlete '{athlete_name}' was renamed '{athlete.name}'")
                athlete.display_name = unambiguous_display_name()
        except:
            self.logger.exception(
                f"Athlete name disambiguation error for {strava_athlete.id}",
                exc_info=True,
            )
            athlete.display_name = athlete_name
        finally:
            athlete.name = athlete_name
            session.add(athlete)
        return athlete
Пример #3
0
 def refresh_access_token(self, athlete: Athlete):
     assert athlete, "No athlete ID or Athlete object provided."
     if (athlete.refresh_token is not None):
         an_hour_from_now = time.time() + 60 * 60
         if (athlete.expires_at < an_hour_from_now):
             refresh_token = athlete.refresh_token
             self.logger.info(
                 "access token for athlete %s is stale, expires_at=%s",
                 athlete.id,
                 athlete.expires_at,
             )
         else:
             # Access token is still valid - no action needed
             refresh_token = None
             self.logger.info(
                 "access token for athlete %s is still valid ",
                 athlete.id,
             )
     elif (athlete.access_token is not None):
         # Athlete has an access token but no refresh token yet.
         # Upgrade the forever token to the new tokens as described in:
         # https://developers.strava.com/docs/oauth-updates/#migration-instructions
         refresh_token = athlete.access_token
     else:
         raise ValueError(
             "athlete %s had no access or refresh token".format(athlete.id))
     if (refresh_token):
         self.logger.info("saving refresh token for athlete %s", athlete.id)
         token_dict = super().refresh_access_token(
             Config.STRAVA_CLIENT_ID,
             Config.STRAVA_CLIENT_SECRET,
             refresh_token,
         )
         self.access_token = token_dict['access_token']
         athlete.access_token = token_dict['access_token']
         athlete.refresh_token = token_dict['refresh_token']
         athlete.expires_at = token_dict['expires_at']
         meta.scoped_session().add(athlete)
         meta.scoped_session().commit()
Пример #4
0
def register_athlete(strava_athlete, token_dict):
    """
    Ensure specified athlete is added to database, returns athlete orm.

    :return: The added athlete model object.
    :rtype: :class:`bafs.orm.Athlete`
    """
    athlete = meta.scoped_session().query(Athlete).get(strava_athlete.id)
    if athlete is None:
        athlete = Athlete()
    athlete.id = strava_athlete.id
    athlete.name = '{0} {1}'.format(strava_athlete.firstname, strava_athlete.lastname).strip()
    # Temporary; we will update this in disambiguation phase.  (This isn't optimal; needs to be
    # refactored....
    #
    #     Where does the disambiguation phase get called now? Nowhere...
    #     so let's fix it here for now.
    #     * Do not override already set display_names.
    #     * Use a first name and last initial (if available).
    #     See also:
    #       https://github.com/freezingsaddles/freezing-web/issues/80
    #       https://github.com/freezingsaddles/freezing-web/issues/75
    #       https://github.com/freezingsaddles/freezing-web/issues/73
    #     - @obscurerichard]
    if athlete.display_name is None:
        if strava_athlete.lastname is None:
            athlete.display_name = strava_athlete.firstname
        else:
            athlete.display_name = '{0} {1}'.format(
                    strava_athlete.firstname.strip(),
                    strava_athlete.lastname.strip(),
                    )
    athlete.profile_photo = strava_athlete.profile

    athlete.access_token = token_dict['access_token']
    athlete.refresh_token = token_dict['refresh_token']
    athlete.expires_at = token_dict['expires_at']
    meta.scoped_session().add(athlete)
    # We really shouldn't be committing here, since we want to disambiguate names after registering
    meta.scoped_session().commit()

    return athlete
Пример #5
0
    def register_athlete(self, strava_athlete: sm.Athlete, access_token: str):
        """
        Ensure specified athlete is added to database, returns athlete model.

        :return: The added athlete model object.
        :rtype: :class:`bafs.model.Athlete`
        """
        session = meta.scoped_session()
        athlete = session.query(Athlete).get(strava_athlete.id)
        if athlete is None:
            athlete = Athlete()
        athlete.id = strava_athlete.id
        athlete.name = '{0} {1}'.format(strava_athlete.firstname,
                                        strava_athlete.lastname).strip()

        display_name = strava_athlete.firstname + ' ' + strava_athlete.lastname[
            0]

        def already_exists(display_name):
            return session.query(Athlete).filter(Athlete.id != athlete.id)\
                       .filter(Athlete.display_name == display_name)\
                       .count() > 0

        charidx = 1
        while already_exists(display_name):
            try:
                display_name += str(strava_athlete.lastname[charidx])
                charidx += 1
            except IndexError:
                self.logger.warning(
                    "Ran out of last-name letters to disambiguate {}".format(
                        athlete))
                break

        athlete.display_name = display_name
        athlete.profile_photo = strava_athlete.profile

        athlete.access_token = access_token
        session.add(athlete)

        return athlete
Пример #6
0
    def register_athlete_team(self, strava_athlete: sm.Athlete,
                              athlete_model: Athlete) -> Team:
        """
        Updates db with configured team that matches the athlete's teams.

        Updates the passed-in Athlete model object with created/updated team.

        :param strava_athlete: The Strava model object for the athlete.
        :param athlete_model: The athlete model object.
        :return: The :class:`bafs.model.Team` object will be returned which matches
                 configured teams.
        :raise MultipleTeamsError: If this athlete is registered for multiple of
                                   the configured teams.  That won't work.
        :raise NoTeamsError: If no teams match.
        """

        all_teams = config.COMPETITION_TEAMS
        self.logger.info("Checking {0!r} against {1!r}".format(
            strava_athlete.clubs, all_teams))
        try:
            if strava_athlete.clubs is None:
                raise NoTeamsError(
                    "Athlete {0} ({1} {2}): No clubs returned- {3}. {4}.".
                    format(
                        strava_athlete.id,
                        strava_athlete.firstname,
                        strava_athlete.lastname,
                        "Full Profile Access required",
                        "Please re-authorize",
                    ))
            matches = [c for c in strava_athlete.clubs if c.id in all_teams]
            self.logger.debug("Matched: {0!r}".format(matches))
            athlete_model.team = None
            if len(matches) > 1:
                # you can be on multiple teams
                # as long as only one is an official team
                matches = [
                    c for c in matches if c.id not in config.OBSERVER_TEAMS
                ]
            if len(matches) > 1:
                self.logger.info("Multiple teams matched for {}: {}".format(
                    strava_athlete,
                    matches,
                ))
                raise MultipleTeamsError(matches)
            if len(matches) == 0:
                # Fall back to main team if it is the only team they are in
                matches = [
                    c for c in strava_athlete.clubs if c.id == config.MAIN_TEAM
                ]
            if len(matches) == 0:
                raise NoTeamsError("Athlete {0} ({1} {2}): {3} {4}".format(
                    strava_athlete.id,
                    strava_athlete.firstname,
                    strava_athlete.lastname,
                    "No teams matched ours. Teams defined:",
                    strava_athlete.clubs,
                ))
            else:
                club = matches[0]
                # create the team row if it does not exist
                team = meta.scoped_session().query(Team).get(club.id)
                if team is None:
                    team = Team()
                team.id = club.id
                team.name = club.name
                team.leaderboard_exclude = club.id in config.OBSERVER_TEAMS
                athlete_model.team = team
                meta.scoped_session().add(team)
                return team
        finally:
            meta.scoped_session().commit()