Example #1
0
def get_strava_token():
    """Return a valid strava token.

    This will initiate the OAUTH dance if needed (register or refresh), or just
    get the token from disk."""

    if get_tokens_from_disk() == {}:
        client = Client()
        url = client.authorization_url(client_id=CLIENT_ID,
                                       redirect_uri='http://127.0.0.1:5000/authorization')

        print("Please open this in your browser:" + url)

        server_address = ('', 5000)
        httpd = PainfulHTTPServer(server_address, StravaOauthRequestHandler)
        httpd.serve_until_stopped()

    # Now the file really shouldn't be empty anymore.
    tokens = get_tokens_from_disk()

    # Is our token expired?
    now = datetime.datetime.now()
    if now.timestamp() >= (tokens["expires_at"] - 10000): # 10 seconds leeway
        client = Client()
        refresh_response = client.refresh_access_token(
            client_id=CLIENT_ID, client_secret=CLIENT_SECRET,
            refresh_token=tokens["refresh_token"])

        with open(".hurtlocker", "w") as thefile:
            thefile.write(json.dumps(refresh_response))

        tokens = get_tokens_from_disk()

    return tokens["access_token"]
Example #2
0
    def pull_data(self, members, challenges):
        client = Client()

        for m in members:
            logger.debug("processing member: {}".format(m))

            # Check if the access token needs renewing.  Should last 6hrs, so only needs doing once regardless of how many calls we make.
            if time.time() > m.access_token_expiry:
                logger.info("Renewing token")
                refresh_response = client.refresh_access_token(
                    client_id=config.strava_client_id,
                    client_secret=config.strava_client_secret,
                    refresh_token=m.refresh_token)
                m.access_token = refresh_response['access_token']
                m.refresh_token = refresh_response['refresh_token']
                m.access_token_expiry = refresh_response['expires_at']
                m.save()

            client.access_token = m.access_token
            client.refresh_token = m.refresh_token
            client.token_expires_at = m.access_token_expiry

            for c in challenges:
                logger.debug("Processing challenge: {}".format(c))

                efforts = client.get_segment_efforts(
                    c.segment_id,
                    start_date_local=c.date_from,
                    end_date_local=c.date_to)
                for e in efforts:
                    logger.debug("Processing effort: {}".format(e))
                    Attempt.add(e, m, c)
Example #3
0
    def load_strava_tracks(self, strava_config: str) -> typing.List[Track]:
        tracks = []
        tracks_names = []
        if self.cache_dir:
            self.strava_cache_file = os.path.join(self.cache_dir, strava_config)
            if os.path.isfile(self.strava_cache_file):
                with open(self.strava_cache_file) as f:
                    strava_cache_data = json.load(f)
                    tracks = [self._strava_cache_to_track(i) for i in strava_cache_data]
                    tracks_names = [track.file_names[0] for track in tracks]

        with open(strava_config) as f:
            strava_data = json.load(f)
        filter_type = strava_data.pop("activity_type", None)
        client = Client()
        response = client.refresh_access_token(**strava_data)
        client.access_token = response["access_token"]
        filter_dict = {"before": datetime.datetime.utcnow()}
        if tracks:
            max_time = max(track.start_time() for track in tracks)
            filter_dict = {"after": max_time - datetime.timedelta(days=2)}
        for activity in client.get_activities(**filter_dict):
            # tricky to pass the timezone
            if str(activity.id) in tracks_names:
                continue
            if filter_type and activity.type not in (
                [filter_type] if isinstance(filter_type, str) else filter_type
            ):  # pylint: disable=superfluous-parens
                continue
            t = Track()
            t.load_strava(activity)
            tracks.append(t)
        self._store_strava_tracks_to_cache(tracks)
        return self._filter_and_merge_tracks(tracks)
Example #4
0
    def load_strava_tracks(self, strava_config: str) -> typing.List[Track]:
        tracks = []
        tracks_names = []
        if self.cache_dir:
            self.strava_cache_file = os.path.join(self.cache_dir,
                                                  strava_config)
            if os.path.isfile(self.strava_cache_file):
                with open(self.strava_cache_file) as f:
                    strava_cache_data = json.load(f)
                    tracks = [
                        self._strava_cache_to_track(i)
                        for i in strava_cache_data
                    ]
                    tracks_names = [track.file_names[0] for track in tracks]

        with open(strava_config) as f:
            strava_data = json.load(f)
        client = Client()
        response = client.refresh_access_token(**strava_data)
        client.access_token = response["access_token"]
        fliter_dict = {"before": datetime.datetime.utcnow()}
        if tracks:
            max_time = max(track.start_time for track in tracks)
            if max_time:
                fliter_dict = {"after": max_time - datetime.timedelta(days=2)}
        for activate in client.get_activities(**fliter_dict):
            # tricky to pass the timezone
            if str(activate.id) in tracks_names:
                continue
            t = Track()
            t.load_strava(activate)
            tracks.append(t)
        self._store_strava_tracks_to_cache(tracks)
        return self._filter_and_merge_tracks(tracks)
Example #5
0
async def refresh_access_token(athlete):
    client = Client()
    response = client.refresh_access_token(client_id=STRAVA_CLIENT_ID,
                                           client_secret=STRAVA_CLIENT_SECRET,
                                           refresh_token=athlete.refresh_token)

    await athlete.update(access_token=response['access_token'],
                         refresh_token=response['refresh_token'],
                         token_expiration_datetime=datetime.utcfromtimestamp(
                             response['expires_at']).isoformat())

    return athlete
Example #6
0
def refresh_access_token():
    """
    Client posts a valid access token and refresh token and receives a dict
    containing 'access_token', 'refresh_token', and 'expires_at'.
    The function then saves this to Secret Manager
    """
    client = Client(sm.access_token)
    auth_dict = client.refresh_access_token(client_id=sm.client_id,
                                            client_secret=sm.client_secret,
                                            refresh_token=sm.refresh_token)
    logger.debug('Auth Dict: %s', auth_dict)

    # Save the dict back to Secret Manager
    sm.set_auth_dict(auth_dict)
Example #7
0
def main(action, filename):
    if action != "DOWNLOAD":
        return 0

    try:
        with open(STRAVA_CREDENTIALS_FILE, "rb") as f:
            token_data = pickle.load(f)
            access_token = token_data["access_token"]

            if token_data["expires_at"] <= time.time():
                client = Client()
                token_data = client.refresh_access_token(
                    client_id=CLIENT_ID,
                    client_secret=CLIENT_SECRET,
                    refresh_token=token_data["refresh_token"],
                )
                access_token = token_data["access_token"]

                with open(STRAVA_CREDENTIALS_FILE, "wb") as fw:
                    pickle.dump(token_data, fw, 0)
    except (FileNotFoundError, KeyError):
        print("No Strava credentials provided.")
        print("You first need to run the script to fetch the credentials")
        print("./40-upload_to_strava.py")
        return -1

    try:
        client = Client(access_token=access_token)
        print("Uploading {}: ".format(os.path.basename(filename)), end="")
        with open(filename, "rb") as f:
            upload = client.upload_activity(
                activity_file=f,
                data_type="fit",
                private=STRAVA_UPLOAD_PRIVATE,
            )
    except (ActivityUploadFailed, FileNotFoundError) as err:
        print("FAILED")
        print("Reason:", err)
        return -1

    print("SUCCESS")
    return 0
Example #8
0
def refresh_current_token():
    print("Refreshing current token")
    refresh_token = get_string_from_file('refresh_token')
    client_id = get_string_from_file('client_id')
    client_secret = get_string_from_file('client_secret')

    if not refresh_token:
        print("No refresh token present.")
        request_user_login()
    else:
        strava = Client()
        refresh_response = strava.refresh_access_token(client_id=client_id,
                                                       client_secret=client_secret,
                                                       refresh_token=refresh_token)

        write_string_to_file("access_token", refresh_response['access_token'])
        write_string_to_file("refresh_token", refresh_response['refresh_token'])
        print("Token expires at " + str(refresh_response['expires_at']))
        
        check_if_access_token_valid()
def main(action, filename):
    if action != "DOWNLOAD":
        return 0

    try:
        with open(STRAVA_CREDENTIALS_FILE, 'rb') as f:
            token_data = pickle.load(f)
            access_token = token_data['access_token']

            if token_data['expires_at'] <= time.time():
                client = Client()
                token_data = client.refresh_access_token(
                    client_id=CLIENT_ID,
                    client_secret=CLIENT_SECRET,
                    refresh_token=token_data['refresh_token'])
                access_token = token_data['access_token']

                with open(STRAVA_CREDENTIALS_FILE, 'wb') as fw:
                    pickle.dump(token_data, fw, 0)
    except (FileNotFoundError, KeyError):
        print('No Strava credentials provided.')
        print('You first need to run the script to fetch the credentials')
        print('./40-upload_to_strava.py')
        return -1

    try:
        client = Client(access_token=access_token)
        print('Uploading {}: '.format(os.path.basename(filename)), end='')
        with open(filename, 'rb') as f:
            upload = client.upload_activity(
                activity_file=f,
                data_type='fit',
                private=STRAVA_UPLOAD_PRIVATE,
            )
    except (ActivityUploadFailed, FileNotFoundError) as err:
        print('FAILED')
        print('Reason:', err)
        return -1

    print('SUCCESS')
    return 0
Example #10
0
def strava_access_token(request):
    user_settings = request.user.settings
    if user_settings.strava_access_token:
        token = json.loads(user_settings.strava_access_token)
        if time.time() < token['expires_at']:
            return Response({'strava_access_token': token['access_token'], 'expires_at': token['expires_at']})
        client = StravaClient()
        try:
            access_token = client.refresh_access_token(
                client_id=settings.MY_STRAVA_CLIENT_ID,
                client_secret=settings.MY_STRAVA_CLIENT_SECRET,
                refresh_token=token['refresh_token']
            )
        except Exception:
            user_settings.strava_access_token = ''
            user_settings.save()
            return Response({})
        user_settings.strava_access_token = json.dumps(access_token)
        user_settings.save()
        return Response({'strava_access_token': access_token['access_token'], 'expires_at': access_token['expires_at']})
    return Response({})
Example #11
0
    def update_token(self):
        print("Update token")
        client = Client(access_token=self.bearer.get("access_token"))
        if time.time() > self.bearer["expires_at"]:
            print(self.bearer["refresh_token"])
            refresh_response = client.refresh_access_token(
                client_id=self.client_id,
                client_secret=self.client_secret,
                refresh_token=self.bearer["refresh_token"])

            self.bearer["refresh_token"] = refresh_response["refresh_token"]
            self.bearer["access_token"] = refresh_response["access_token"]
            self.bearer["expires_at"] = refresh_response["expires_at"]

            self.dbh.modify_user(user_hash=self.user_hash,
                                 key="strava_bearer",
                                 value=self.bearer,
                                 mode="update")

        else:
            dt = self.bearer["expires_at"] - time.time()
            print(f"Token valid for another {dt} seconds.")
Example #12
0
def get_segments(lowerlat, lowerlong, upperlat, upperlong):
    # Accepts lower and upper bounds for a given coordinate area
    # Returns an object with route data, as parsed in application.py

    # Sets our key
    # As per: https://github.com/hozn/stravalib/blob/master/docs/usage/auth.rst#id5
    client = Client()
    token_response = client.refresh_access_token(
        client_id=30378,
        client_secret="67b60f8a8c450a837a2337fe9eb57515915d8fba",
        refresh_token="ed64949d3614e9a0574ecba44d5514de593c2c0b")
    key = token_response['access_token']

    # Sets the client and registers the token
    client = Client()
    client = Client(access_token=key)

    # Calls user data for the given range for running routes
    data = client.explore_segments([lowerlat, lowerlong, upperlat, upperlong],
                                   activity_type='running')

    # Returns the object
    return data
Example #13
0
    try:
        with open(CONFIG_FILE) as inf:
            new_dict = json.load(inf)
    except FileNotFoundError:
        new_dict = DEFAULT_DICT.copy()
        save_config(new_dict)
    return new_dict


settings = load_config()
client = Client()

if time.time() > int(settings['expires_at']):
    print("Renewing tokens")
    refresh_response = client.refresh_access_token(
        client_id=settings['client_id'],
        client_secret=settings['client_secret'],
        refresh_token=settings['refresh_token'])
    settings['refresh_token'] = refresh_response['refresh_token']
    settings['access_token'] = refresh_response['access_token']
    settings['expires_at'] = refresh_response['expires_at']
    save_config(settings)
else:
    client.access_token = settings['access_token']
    client.refresh_token = settings['refresh_token']
    client.expires_at = settings['expires_at']

activities = client.get_activities(limit=10)

for activity in activities:
    if activity.type == 'Run':
        ms = activity.average_speed
Example #14
0
def refresh_access_token(refresh_token):
    client = Client()
    return client.refresh_access_token(
        client_id=settings.STRAVA_CLIENT_ID,
        client_secret=settings.STRAVA_CLIENT_SECRET,
        refresh_token=refresh_token)
    Challenge.add(segment, year, month)


if __name__ == '__main__':
    m = Member.objects.filter(refresh_token__gte="").limit(1)

    print(list(m))
    m = list(m)[0]

    client.access_token = m.access_token
    client.refresh_token = m.refresh_token
    client.token_expires_at = m.access_token_expiry

    # Check if the access token needs renewing.  Should last 6hrs, so only needs doing once regardless of how many calls we make.
    if time.time() > m.access_token_expiry:
        logger.info("Renewing token")
        refresh_response = client.refresh_access_token(
            client_id=config.strava_client_id,
            client_secret=config.strava_client_secret,
            refresh_token=m.refresh_token)
        m.access_token = refresh_response['access_token']
        m.refresh_token = refresh_response['refresh_token']
        m.access_token_expiry = refresh_response['expires_at']
        m.save()

    add_challenge(4896037, 2019, 2)
    add_challenge(13028666, 2019, 3)
    add_challenge(5993929, 2019, 4)
    add_challenge(4837370, 2019, 8)
Example #16
0
class Tracker:

    def __init__(self):
        # Strava client to hold information for tracker.
        self.client = Client()

        # Time token expires at.
        self.token_expires_at_ = None

        # Client information.
        self.client_id = None
        self.client_secret = None

        # Time in seconds between refreshes.
        self.sleep_time_ = 300

        # Number of target activities per week.
        self.target_ = 4

        # Private display object.
        self.display_ = Display()

        # Activity tracking variables.
        self.start_date = datetime.datetime.utcnow().date()
        self.next_week  = self.start_date + datetime.timedelta(weeks=1)
        self.week_streak = 0
        self.num_activities = 0

        # Filename of save file.
        self.save_file_ = 'streak.yaml'


    def set_expiration(self, token_expires_at):
        self.token_expires_at_ = token_expires_at

    def set_client_info(self, client_id, client_secret):
        self.client_id = client_id
        self.client_secret = client_secret

    def save_status(self):
        save_obj = {'start_date' : self.start_date, 'next_week' : self.next_week, 
                'week_streak' : self.week_streak, 'num_activities' : self.num_activities}
        with open(self.save_file_, 'wb') as save_file:
            pickle.dump(save_obj, save_file)

    def load_status(self):
        save_obj = None
        try:
            with open(self.save_file_, 'rb') as save_file:
                save_obj = pickle.load(save_file)
            self.start_date = save_obj['start_date']
            self.next_week = save_obj['next_week']
            self.week_streak = save_obj['week_streak']
            self.num_activities = save_obj['num_activities']
        except (OSError, IOError, EOFError) as e:
            print('Nothing in this save file, going to save defaults.')
            self.save_status()

    def update(self):
        self.save_status()
        self.display_.show(self.week_streak, self.target_ - self.num_activities, self.target_)



    def run(self):
        # Save start date/time
        # Ask Strava for activities since 1 week ago
        # If len(activities) >= goal increment streak
        # Check that token won't expire in 12 hours
        # If token needs refreshing, refresh it
        # Sleep for sleep_time
        self.load_status()
        self.update()
        while(True):
            # Refresh token if necessary.
            if time.time() > self.token_expires_at_:
                refresh_response = self.client.refresh_access_token(client_id=self.client_id,
                                                      client_secret=self.client_secret,
                                                      refresh_token=self.client.refresh_token)
                self.token_expires_at_ = refresh_response['expires_at']
                print('Refreshing token, new one expires at {}'
                        .format(str(refresh_response['expires_at'])))

            new_activities = len(list(self.client.get_activities(after = self.start_date.isoformat())))

            # Handle null return from Strava servers.
            if not new_activities:
                new_activities = 0
            print(new_activities)

            if new_activities != self.num_activities:
                print("New activities detected!")
                self.num_activities = new_activities
                self.update()

            for activity in self.client.get_activities(after = self.start_date.isoformat()):
                print("{0.name} {0.moving_time}".format(activity))


            # Check if we've hit the target for this week.
            if self.num_activities >= self.target_:
                self.week_streak += 1
                self.update()

            cur_date = datetime.datetime.utcnow().date()

            # Check if it's next week.
            if cur_date == self.next_week:

                # Check if we haven't hit our target and reset.
                if self.num_activities < self.target_:
                    self.week_streak = 0

                # Advance the date to a week from now.
                self.start_date = cur_date
                self.next_week = cur_date + datetime.timedelta(weeks=1)
                self.update()

            time.sleep(self.sleep_time_)
Example #17
0
class Strava:
    def __init__(self, client_id, client_secret):
        self.client = Client()
        self.client_id = client_id
        self.client_secret = client_secret

    def _check_and_refresh_token(self, member=None):

        if not member:
            member = Member.objects.filter(
                refresh_token__gte="").order_by('refresh_token').limit(1)
            member = list(member)[0]

        logger.info("Using access token for: {}".format(member))

        self.client.access_token = member.access_token
        self.client.refresh_token = member.refresh_token
        self.client.token_expires_at = member.access_token_expiry

        # Check if the access token needs renewing.  Should last 6hrs, so only needs doing once regardless of how many calls we make.
        if time.time() > member.access_token_expiry:
            logger.info("Renewing token")
            refresh_response = self.client.refresh_access_token(
                client_id=self.client_id,
                client_secret=self.client_secret,
                refresh_token=member.refresh_token)
            member.access_token = refresh_response['access_token']
            member.refresh_token = refresh_response['refresh_token']
            member.access_token_expiry = refresh_response['expires_at']
            member.save()

    def register_new_member(self, code):
        token_response = self.client.exchange_code_for_token(
            client_id=self.client_id,
            client_secret=self.client_secret,
            code=code)
        access_token = token_response['access_token']
        refresh_token = token_response['refresh_token']
        expires_at = token_response['expires_at']

        self.client.access_token = access_token
        self.client.refresh_token = refresh_token
        self.client.token_expires_at = expires_at

        athlete = self.client.get_athlete()
        logger.debug("Retrieved the authenticated athlete: {}".format(athlete))
        return athlete, access_token, refresh_token, expires_at

    def get_member_avatar(self, athlete_id, medium=False):
        logger.debug("Getting an avatar for member {} that is sized {}".format(
            athlete_id, medium))
        member = Member.objects.get(id=str(athlete_id))
        self._check_and_refresh_token(member)
        athlete = self.client.get_athlete()

        if medium:
            return athlete.profile_medium
        else:
            return athlete.profile

    def get_redirect_url(self, client_id, redirect_url, state):
        return self.client.authorization_url(client_id,
                                             redirect_url,
                                             state=state)
Example #18
0
def main(event, context):
    """Triggered from a message on a Cloud Pub/Sub topic.
    Args:
         event (dict): Event payload.
         context (google.cloud.functions.Context): Metadata for the event.
    """
    STRAVA_CLIENT_ID = os.environ.get('strava_client_id')
    STRAVA_CLIENT_SECRET = os.environ.get('strava_client_secret')

    pubsub_message = base64.b64decode(event['data']).decode('utf-8')
    pubsub_dict = json.loads(pubsub_message.replace("'", '"'))
    print(pubsub_dict)
    datastore_client = datastore.Client(project='strava-int')
    bq_client = bigquery.Client(project='strava-int')
    strava_client = Client()

    # event notification from strava
    aspect_type = pubsub_dict['aspect_type']
    object_id = pubsub_dict['object_id']
    owner_id = pubsub_dict['owner_id']
    object_type = pubsub_dict['object_type']
    event_time = pubsub_dict['event_time']
    event_datetime = time.strftime('%Y-%m-%d %H:%M:%S',
                                   time.localtime(event_time))

    if object_type == 'activity':
        now = time.time()

        if aspect_type == 'delete':
            athlete_activity_dict = [{
                'activity_hub_seq':
                hashlib.md5(str(object_id).encode()).hexdigest(),
                'sat_load_date':
                event_datetime,
                'delete_ind':
                True
            }]
            # athlete_activity_obj = AthleteActivity(athlete_activity_dict)
            # sat_athlete_activity = athlete_activity_obj.satellite()
            sat_table_ref = bq_client.dataset('strava_datavault').table(
                'activity_sat')
            bq_client.load_table_from_json(athlete_activity_dict,
                                           sat_table_ref)

        if aspect_type != 'delete':
            # stored athlete from datastore
            athlete_key = datastore_client.key('Athlete', owner_id)
            athlete = datastore_client.get(athlete_key)
            if now > athlete['expires_at']:
                access_token = strava_client.refresh_access_token(
                    client_id=STRAVA_CLIENT_ID,
                    client_secret=STRAVA_CLIENT_SECRET,
                    refresh_token=athlete['refresh_token'])

                athlete.update(access_token)
                datastore_client.put(athlete)

            # create new client for authenticated athlete
            athlete_client = Client(access_token=athlete['access_token'])
            activity = athlete_client.get_activity(object_id)
            activity_dict = activity.to_dict()
            supplement = {
                'athlete_id': owner_id,
                'activity_id': object_id,
                'load_date': event_datetime
            }
            activity_dict.update(supplement)

            # GCS Storage
            upload_blob(activity_dict, owner_id, object_id, event_time,
                        aspect_type)

            converted_units = {
                'distance_mi':
                unithelper.mile(getattr(activity, 'distance', None)).get_num(),
                'average_speed_mi':
                unithelper.mph(getattr(activity, 'average_speed',
                                       None)).get_num(),
                'max_speed_mi':
                unithelper.mph(getattr(activity, 'max_speed', None)).get_num(),
                'elapsed_time_s':
                int(
                    unithelper.timedelta_to_seconds(
                        getattr(activity, 'elapsed_time', None))),
                'moving_time_s':
                int(
                    unithelper.timedelta_to_seconds(
                        getattr(activity, 'moving_time', None)))
            }

            activity_dict.update(converted_units)

            athlete_activity_obj = AthleteActivity(activity_dict)
            sat_athlete_activity = athlete_activity_obj.satellite()
            print(sat_athlete_activity)
            # BQ insert
            sat_table_ref = bq_client.dataset('strava_datavault').table(
                'activity_sat')
            bq_client.load_table_from_json(sat_athlete_activity, sat_table_ref)
            if aspect_type == 'create':
                link_athlete_activity = athlete_activity_obj.link()
                link_table_ref = bq_client.dataset('strava_datavault').table(
                    'athlete_activity_link')
                bq_client.load_table_from_json(link_athlete_activity,
                                               link_table_ref)

                hub_activity = athlete_activity_obj.hub()
                hub_table_ref = bq_client.dataset('strava_datavault').table(
                    'activity_hub')
                bq_client.load_table_from_json(hub_activity, hub_table_ref)