Beispiel #1
0
    def create_client(self):
        self.s3_file_manager.download_file('strava_auth.json',
                                           '/tmp/strava_auth.json')
        with open('/tmp/strava_auth.json') as auth_json:
            data = json.load(auth_json)
            access_token = data['access_token']
            refresh_token = data['refresh_token']
            expires_at = data['expires_at']

        client = Client()
        client.access_token = access_token
        client.refresh_token = refresh_token
        client.token_expires_at = expires_at

        if time.time() > client.token_expires_at:
            print('Token has expired - refreshing...')
            refresh_response = client.refresh_access_token(
                client_id=int(os.getenv('STRAVA_CLIENT_ID', None)),
                client_secret=os.getenv('STRAVA_CLIENT_SECRET', None),
                refresh_token=client.refresh_token)

            with open('/tmp/strava_auth.json', 'w') as outfile:
                json.dump(refresh_response, outfile)

            self.s3_file_manager.upload_file('/tmp/strava_auth.json',
                                             'strava_auth.json')

        return client
Beispiel #2
0
class Strava:
    def __init__(self, token):
        self._token = token
        self._client = None
        self._verbose = True

    def connect(self):
        self._client = Client()
        token = self._token

        refresh_response = self._client.refresh_access_token(
            client_id=token['client_id'],
            client_secret=token['client_secret'],
            refresh_token=token['refresh_token'])

        token.update(refresh_response)
        self._token = token

        athlete = self._client.get_athlete()
        if self._verbose:
            logger.info("Connected to STRAVA as athelete \"{} {}\"".format(
                athlete.firstname, athlete.lastname))

        return self._token

    def set_weight(self, weight):
        self._client.update_athlete(weight=weight)

    @property
    def client(self):
        return self._client
def make_client(client_id, client_secret, refresh_token):
    client = Client()

    refresh_response = client.refresh_access_token(
        client_id=client_id, client_secret=client_secret, refresh_token=refresh_token
    )
    client.access_token = refresh_response["access_token"]
    return client
Beispiel #4
0
def api_profiles_activities_id(player_id, activity_id):
    if not request.stream:
        return '', 400
    activity_id = int(activity_id) & 0xffffffffffffffff
    activity = activity_pb2.Activity()
    activity.ParseFromString(request.stream.read())
    update_protobuf_in_db('activity', activity, activity_id)

    response = '{"id":%s}' % activity_id
    if request.args.get('upload-to-strava') != 'true':
        return response, 200
    try:
        from stravalib.client import Client
    except ImportError:
        logger.warn(
            "stravalib is not installed. Skipping Strava upload attempt.")
        return response, 200
    strava = Client()
    try:
        with open('%s/strava_token.txt' % STORAGE_DIR, 'r') as f:
            client_id = f.readline().rstrip('\n')
            client_secret = f.readline().rstrip('\n')
            strava.access_token = f.readline().rstrip('\n')
            refresh_token = f.readline().rstrip('\n')
            expires_at = f.readline().rstrip('\n')
    except:
        logger.warn(
            "Failed to read %s/strava_token.txt. Skipping Strava upload attempt."
            % STORAGE_DIR)
        return response, 200
    try:
        if time.time() > int(expires_at):
            refresh_response = strava.refresh_access_token(
                client_id=client_id,
                client_secret=client_secret,
                refresh_token=refresh_token)
            with open('%s/strava_token.txt' % STORAGE_DIR, 'w') as f:
                f.write(client_id + '\n')
                f.write(client_secret + '\n')
                f.write(refresh_response['access_token'] + '\n')
                f.write(refresh_response['refresh_token'] + '\n')
                f.write(str(refresh_response['expires_at']) + '\n')
    except:
        logger.warn("Failed to refresh token. Skipping Strava upload attempt.")
        return response, 200
    try:
        # See if there's internet to upload to Strava
        strava.upload_activity(BytesIO(activity.fit),
                               data_type='fit',
                               name=activity.name)
        # XXX: assume the upload succeeds on strava's end. not checking on it.
    except:
        logger.warn("Strava upload failed. No internet?")
    return response, 200
Beispiel #5
0
def get_access_token():
    client = Client()
    refreshed_token_info = client.refresh_access_token(client_id,
                                                       client_secret,
                                                       refresh_token)
    new_access_token = refreshed_token_info['access_token']
    if refresh_token != refreshed_token_info['refresh_token']:
        print(
            'Refresh token does not match existing, this will most definitely cause issues in the future'
        )
    return new_access_token
def check_token_validity(client_id, client_secret, refresh_access_token, expires_at):

    """Check the validity of a permanent token and, if needed, request a new one"""

    client = Client()

    if time.time() <= expires_at:

        print("[+] The access token is still valid!")

    else:

        refresh_response = client.refresh_access_token(client_id = client_id, client_secret = client_secret, refresh_token = refresh_access_token)

        print("[!] The access token expired. A new access token was generated, with the following details:\n\t- access token: {}\n\t- refresh access token: {}\n\t- expireS at: {}".format(refresh_response["access_token"], refresh_response["refresh_token"], refresh_response["expires_at"]))
Beispiel #7
0
def strava_upload(player_id, activity):
    try:
        from stravalib.client import Client
    except ImportError:
        logger.warn(
            "stravalib is not installed. Skipping Strava upload attempt.")
        return
    profile_dir = '%s/%s' % (STORAGE_DIR, player_id)
    strava = Client()
    try:
        with open('%s/strava_token.txt' % profile_dir, 'r') as f:
            client_id = f.readline().rstrip('\r\n')
            client_secret = f.readline().rstrip('\r\n')
            strava.access_token = f.readline().rstrip('\r\n')
            refresh_token = f.readline().rstrip('\r\n')
            expires_at = f.readline().rstrip('\r\n')
    except:
        logger.warn(
            "Failed to read %s/strava_token.txt. Skipping Strava upload attempt."
            % profile_dir)
        return
    try:
        if time.time() > int(expires_at):
            refresh_response = strava.refresh_access_token(
                client_id=client_id,
                client_secret=client_secret,
                refresh_token=refresh_token)
            with open('%s/strava_token.txt' % profile_dir, 'w') as f:
                f.write(client_id + '\n')
                f.write(client_secret + '\n')
                f.write(refresh_response['access_token'] + '\n')
                f.write(refresh_response['refresh_token'] + '\n')
                f.write(str(refresh_response['expires_at']) + '\n')
    except:
        logger.warn("Failed to refresh token. Skipping Strava upload attempt.")
        return
    try:
        # See if there's internet to upload to Strava
        strava.upload_activity(BytesIO(activity.fit),
                               data_type='fit',
                               name=activity.name)
        # XXX: assume the upload succeeds on strava's end. not checking on it.
    except:
        logger.warn("Strava upload failed. No internet?")
Beispiel #8
0
def get_strava_client():
    token_dict = current_token_dict()
    if token_dict:
        client = Client()
        client.access_token = token_dict['access_token']
        client.refresh_token = token_dict['refresh_token']
        # If token is old, refresh it
        if time.time() > token_dict['expires_at']:
            app.server.logger.debug('Strava tokens expired, refreshing...')
            refresh_response = client.refresh_access_token(client_id=client_id, client_secret=client_secret,
                                                           refresh_token=client.refresh_token)
            # Save to db
            save_strava_token(refresh_response)
            # Update client
            client.access_token = refresh_response['access_token']
            client.refresh_token = refresh_response['refresh_token']
    else:
        client = Client()

    return client
Beispiel #9
0
def fetch_stats():
    client = Client()

    refresh_response = client.refresh_access_token(client_id=client_id,
                                                   client_secret=client_secret,
                                                   refresh_token=refresh_token)
    client.access_token = refresh_response['access_token']
    stats = client.get_athlete_stats()

    return textwrap.dedent(f"""\
    #### Recent rides

{get_stat_values(stats.recent_ride_totals)}

    #### YTD ride totals

{get_stat_values(stats.ytd_ride_totals)}

    #### All ride totals

{get_stat_values(stats.all_ride_totals)}
    """)
Beispiel #10
0
def main():
    ChallengeSqlDB.init(MYSQL_HOST, MYSQL_USERNAME, MYSQL_PASSWORD,
                        MYSQL_DB_NAME)
    print("Challenge start date:", CHALLENGE_START_DATE)
    print("Challenge end date:", CHALLENGE_END_DATE)
    # Read all runners that have intania from DB
    print("Get all runners from db")

    if SERVICE_TYPE.lower() == 'ranger':
        print("Service type: %s" % ('RANGER'))
        users = ChallengeSqlDB.get_all_ranger_users()
    else:
        print("Service type: %s" % ('INTANIA'))
        users = ChallengeSqlDB.get_all_intania_users()
    n_user = len(users)
    print("Total runners: %d" % (n_user))
    # For each runners get their activities
    runs = []
    for idx, user in enumerate(users):
        # if user.clubs is None or not user.clubs:
        #     print("Skip runner with None intania: id=%s displayname='%s %s'" %
        #           (user.strava_id, user.first_name, user.last_name))
        #     continue
        if not user.credentials:
            print(
                "Skip runner with empty credentials: id=%s displayname='%s %s'"
                % (user.strava_id, user.first_name, user.last_name))
            continue

        refresh_token = None
        for cred in user.credentials:
            if cred.strava_client == CLIENT_ID:
                refresh_token = cred.strava_refresh
        if refresh_token is None:
            print(
                "Skip runner with empty credentials for client_id=%s : id=%s displayname='%s %s'"
                % (CLIENT_ID, user.strava_id, user.first_name, user.last_name))
            continue

        print('Found refresh_token for the user ...')

        try:
            client = Client()
            # Get new access token
            refresh_response = client.refresh_access_token(
                client_id=CLIENT_ID,
                client_secret=CLIENT_SECRET,
                refresh_token=refresh_token)
            # Set up user's access token and ready to fetch Strava data
            client.access_token = refresh_response['access_token']
        except Exception as e:
            continue

        if user.clubs:
            intania = user.clubs[0].intania
        else:
            intania = 0

        if user.registration and user.registration.foundation:
            ranger_team = user.registration.foundation.name
        else:
            ranger_team = None

        time.sleep(0.25)
        activities = client.get_activities(after=CHALLENGE_START_DATE,
                                           before=CHALLENGE_END_DATE)
        print(
            "Get activities: idx=%d/%d id=%s displayname='%s %s' intania='%s' ranger='%s'"
            % (idx + 1, n_user, user.strava_id, user.first_name,
               user.last_name, intania, ranger_team))
        n_run = 0

        try:
            for act in activities:
                if act.type not in [Activity.RUN, Activity.WALK]:
                    continue
                n_run += 1
                run = Run.from_activity(act, user.id)
                # Adjust promo multiplier
                adjust_run_promo(run)
                # Try to save activity to DB
                try:
                    if ChallengeSqlDB.get_run_by_strava_id(
                            run.strava_id) is None:
                        # New run activity
                        ChallengeSqlDB.insert_run(run)
                except Exception as e:
                    ChallengeSqlDB.insert_run(run)

            runs.append(run)
        except Exception as e:
            print(e)
        print('Got run acitivities: %d' % (n_run))
    print("Total run activities: %d" % (len(runs)))
Beispiel #11
0
def refresh_token(refresh_token):
    client = Client()
    token = client.refresh_access_token(client_id=config.client_id, client_secret=config.client_secret, refresh_token=refresh_token)
    return token
Beispiel #12
0
try:
  MY_STRAVA_CLIENT_ID, MY_STRAVA_CLIENT_SECRET = open(STRAVA_DATA_DIR + '/client.secret').read().strip().split(',')
except FileNotFoundError as e:
  logger.error("client.secret file not found. Please run with the --generate-auth-token to generate it")
  sys.exit(1)

#Open & refresh the access token if necessary
access_token = None
with open(STRAVA_DATA_DIR + '/access_token.pickle', 'rb') as f:
  access_token = pickle.load(f)

logger.debug('Latest access token read from file: {0}'.format(access_token))

if time.time() > access_token['expires_at']:
    logger.info('Token has expired, will refresh')
    refresh_response = client.refresh_access_token(client_id=MY_STRAVA_CLIENT_ID, client_secret=MY_STRAVA_CLIENT_SECRET, refresh_token=access_token['refresh_token'])
    access_token = refresh_response
    with open(STRAVA_DATA_DIR + '/access_token.pickle', 'wb') as f:
        pickle.dump(refresh_response, f)
    logger.debug('Refreshed token saved to file')
    client.access_token = refresh_response['access_token']
    client.refresh_token = refresh_response['refresh_token']
    client.token_expires_at = refresh_response['expires_at']
else:
    logger.debug('Token still valid, expires at {}'
          .format(time.strftime("%a, %d %b %Y %H:%M:%S %Z", time.localtime(access_token['expires_at']))))
    client.access_token = access_token['access_token']
    client.refresh_token = access_token['refresh_token']
    client.token_expires_at = access_token['expires_at']

#Start getting some data
Beispiel #13
0
def main():
    ChallengeSqlDB.init(MYSQL_HOST, MYSQL_USERNAME, MYSQL_PASSWORD,
                        MYSQL_DB_NAME)

    print("Get all runners from db")
    users = ChallengeSqlDB.get_all_users()

    intania_clubs = ChallengeSqlDB.get_all_intania_clubs()
    # Map strava_id -> club.id
    intania_clubs_dict = {}
    for intania_club in intania_clubs:
        intania_clubs_dict[intania_club.strava_id] = intania_club

    # Find intania for
    for user in users:
        # User already has basic data in the database
        print("User: strava_id=%s displayname='%s %s'" %
              (user.strava_id, user.first_name, user.last_name))

        if not user.credentials:
            print(
                "Skip runner with empty credentials: id=%s displayname='%s %s'"
                % (user.strava_id, user.first_name, user.last_name))
            continue

        refresh_token = None
        for cred in user.credentials:
            if cred.strava_client == CLIENT_ID:
                refresh_token = cred.strava_refresh
        if refresh_token is None:
            print(
                "Skip runner with empty credentials for client_id=%s : id=%s displayname='%s %s'"
                % (CLIENT_ID, user.strava_id, user.first_name, user.last_name))
            continue

        print('Found refresh_token for the user ...')

        client = Client()
        # Get new access token
        refresh_response = client.refresh_access_token(
            client_id=CLIENT_ID,
            client_secret=CLIENT_SECRET,
            refresh_token=refresh_token)
        # Set up user's access token and ready to fetch Strava data
        client.access_token = refresh_response['access_token']

        # stravalib.exc.RateLimitExceeded
        try:
            athlete = client.get_athlete()
        except Exception as e:
            print('Error: failed to fetch Strava profile')
            print(e)
            continue
        joined_clubs = athlete.clubs

        if not (user.clubs is None or not user.clubs):
            print("%s %s is in '%s' club, skip club update..." %
                  (user.first_name, user.last_name, user.clubs[0].name))
        elif joined_clubs is None:
            print(
                "Error: failed to fetch clubs for %s %s, skip club update..." %
                (user.first_name, user.last_name))
        else:
            for club in joined_clubs:
                #         print("id:", club.id, "Club name:", club.name)
                club_strava_id = str(club.id)
                if club_strava_id in intania_clubs_dict:
                    # update in database
                    intania_club = intania_clubs_dict[club_strava_id]
                    print('Update intania club (%s) for %s %s' %
                          (intania_club.name, user.first_name, user.last_name))
                    ChallengeSqlDB.update_user_intania(user.id,
                                                       intania_club.id)

        # Update first & last name
        try:
            ChallengeSqlDB.update_user_name(user.id, athlete.firstname,
                                            athlete.lastname)
        except Exception as e:
            print(
                'Error: failed to update user entity: id=%d displayname=%s %s'
                % (user.id, athlete.firstname, athlete.lastname))
            print(e)

        time.sleep(0.2)
Beispiel #14
0
class Strava(object):
    def __init__(self, client_id, client_secret, refresh_token, club_id):
        # First store the client id, secret and refresh token
        self.client_id = client_id
        self.client_secret = client_secret
        self.refresh_token = refresh_token

        # And store some other fields
        self.club_id = club_id
        self.club = None
        self.club_expires_at = 0

        # Then we get a new access token using the client id, secret and refresh token
        self.token = self.get_access_token()

        # Now we have the access token we can create an instance of the stravalib Client
        self.client = Client(access_token=self.token['access_token'])

    def get_access_token(self):
        # Get a new access token to fetch data from the Strava API
        auth_url = "https://www.strava.com/oauth/token"
        payload = {
            'client_id': self.client_id,
            'client_secret': self.client_secret,
            'refresh_token': self.refresh_token,
            'grant_type': "refresh_token",
            'f': 'json'
        }
        res = requests.post(auth_url, data=payload, verify=False)
        return res.json()

    def update_access_token(self):
        # Update the existing access token

        refresh_response = self.client.refresh_access_token(
            client_id=self.client_id,
            client_secret=self.client_secret,
            refresh_token=self.refresh_token)

        # refresh_response contains the following fields:
        # - refresh_token
        # - expires_at

        # We save the new token
        self.token = refresh_response
        # And save the new refresh token which should be used next time
        self.refresh_token = refresh_response['refresh_token']

    def update_club(self):
        # Get new data of the strava club

        if self.token_expired:
            # If the access token has been expired, we need to update it beofre we can fetch data from strava
            print('access_token has expired, updating access_token')
            self.update_access_token()

        # Get the strava club data
        self.club = self.client.get_club(self.club_id)
        # And set the data to expire in 5 minutes
        self.club_expires_at = time.time() + 300

    def get_member_count(self):
        # Get the member count of the strava club

        if self.club_expired:
            # Only fetch data from strava if the club data has been expired
            print('club has expired, updating club')
            self.update_club()

        return self.club.member_count

    @property
    def token_expired(self):
        # Check if the straca access token has been expired
        return time.time() > self.token['expires_at']

    @property
    def club_expired(self):
        # Check if the cached club data has been expired
        return time.time() > self.club_expires_at
Beispiel #15
0
def main(args):
    client = Client()
    client_id = 40291
    client_secret = '174e515190aa81a04416b147a32937ea5a86c672'
    with open("stravtoken.json", "r") as stravtoken:
        tokendict = json.load(stravtoken)
    access_token = tokendict["access_token"]
    refresh_token1 = tokendict["refresh_token"]
    expires_at = tokendict['expires_at']
    if time.time() > tokendict['expires_at']:
        refresh_response = client.refresh_access_token(client_id,
                                                       client_secret,
                                                       refresh_token1)
        access_token = refresh_response['access_token']
        refresh_token1 = refresh_response['refresh_token']
        expires_at = refresh_response['expires_at']
        with open("stravtoken.json", "w+") as json_file:
            json.dump(refresh_response, json_file)

    client.access_token = access_token
    client.refresh_access_token = refresh_token1
    client.token_expires_at = expires_at

    api_instance = swagger_client.ActivitiesApi()
    api_instance.api_client.configuration.access_token = access_token
    list_acts2 = []
    for x in range(1, 20):
        try:
            api_response = api_instance.get_logged_in_athlete_activities(
                page=x, per_page=100)
            acts = str(api_response)
            acts = acts.replace("\'", "\"")
            acts = acts.replace("None", "0")
            acts = acts.replace("False", "0")
            acts = acts.replace("True", "1")
            acts = json.loads(acts)
            for each in acts:
                if isinstance(each['start_latlng'], list):
                    list_acts2.append([
                        each['id'], each['distance'] / 1609.344,
                        each['moving_time'],
                        each['elapsed_time'] - each['moving_time'],
                        each['total_elevation_gain'],
                        each['total_elevation_gain'] / each['moving_time'],
                        each['start_latlng'][0], each['start_latlng'][1],
                        each['map']['summary_polyline']
                    ])
        except ApiException as e:
            print(x)

    acts_df = pd.DataFrame(list_acts2)
    acts_df.columns = [
        'Run ID', 'Distance', 'Time', 'Resting Time', 'Elevation Gain',
        'Elevation Grade', 'Start Latitude', 'Start Longitude', 'Polyline'
    ]

    acts_df_clean = acts_df.drop(acts_df[acts_df['Start Latitude'] > 34].index)
    acts_df_clean = acts_df_clean.drop(
        acts_df[acts_df['Start Latitude'] < 33].index).reset_index()

    #DIST LABEL --------------------------------------------------------------------------------
    conditions = [
        (acts_df_clean['Distance'] <= 5),
        (acts_df_clean['Distance'] > 5) & (acts_df_clean['Distance'] <= 9),
        (acts_df_clean['Distance'] > 9)
    ]
    values = ['Short', 'Medium', 'Long']
    acts_df_clean['Difficulty'] = np.select(conditions, values)

    #DIFF LABEL ---------------------------------------------------------------------------------
    #clust_df = acts_df_clean.filter(['Distance','Elevation Grade'], axis=1)
    #clust_df['Distance'] = clust_df['Distance'].apply(lambda x: pow(x*150,.35))
    #clust_df['Elevation Grade'] = clust_df['Elevation Grade'].apply(lambda x: pow(x*150,.8))
    #kmeans = KMeans(n_clusters=6,random_state=3425)
    #kmeans.fit(clust_df)
    #labels = pd.Series(kmeans.predict(clust_df),name='Difficulty').to_frame().reset_index()
    #clust_df = pd.concat([clust_df, labels], axis=1, sort=False)
    #acts_df_clean = pd.concat([acts_df_clean, labels], axis=1, sort=False)
    #maps = {0:2,1:1,2:0,3:2,4:0,5:1}
    #acts_df_clean['Difficulty'] = acts_df_clean['Difficulty'].apply(lambda x: maps[x])

    acts_df_clean.to_csv('activities.csv', index=False)
Beispiel #16
0
class StravaAccess:
    '''
    Retrieves data from Strava API, using slightly interactive OAuth2 protocol, requiring user to log in, click approve, paste returned URL
    '''
    CACHE_FILE = os.path.join(os.path.dirname(__file__), r'strava_token.json')

    def __init__(self):
        self.client = Client()
        self.token_cache = {}
        self.load_token_cache()

        if time.time() > self.token_cache['expire']:
            print('Access token {old_token} expired, refreshing...'.format(
                old_token=self.token_cache['atoken']))

            refresh_response = self.client.refresh_access_token(
                client_id=keychain.app['client_id'],
                client_secret=keychain.app['client_secret'],
                refresh_token=self.token_cache['rtoken'])

            self.token_cache['atoken'] = refresh_response['access_token']
            self.token_cache['rtoken'] = refresh_response['refresh_token']
            self.token_cache['expire'] = refresh_response['expires_at']

            self.save_token_cache()

        self.client.access_token = self.token_cache['atoken']
        self.client.refresh_token = self.token_cache['rtoken']
        self.client.token_expires_at = self.token_cache['expire']

    def authorize_app(self):
        '''
        Opens new tab in default browser to Strava OAuth2 site for our app
        User is asked to authorize in browser
        User is asked to paste redirect URL (not a real URL but I don't want to set up a web server to capture this)
        Parses the redirect URL for code in query and uses it to generate token for user
        '''
        # Generate code from url copy from url on redirect
        redirect_domain = 'https://localhost/urlforauth/'
        authorize_url = self.client.authorization_url(
            client_id=keychain.app['client_id'], redirect_uri=redirect_domain)
        webbrowser.open_new_tab(authorize_url)

        print('Please Authorize application access in browser.')
        redirect_url_with_code = input(
            'URL redirect after authorization (e.g. %s...) :' %
            redirect_domain)
        parsed_url = urllib.parse.urlparse(redirect_url_with_code)

        try:
            code = urllib.parse.parse_qs(parsed_url.query)['code'][0]
        except KeyError:
            raise KeyError(
                'Invalid URL, expected copied URL from browser after clicking authorize containing auth code.'
            )

        token_response = self.client.exchange_code_for_token(
            client_id=keychain.app['client_id'],
            client_secret=keychain.app['client_secret'],
            code=code)

        self.token_cache = {
            'atoken': token_response['access_token'],
            'rtoken': token_response['refresh_token'],
            'expire': token_response['expires_at']
        }
        self.save_token_cache()

    def load_token_cache(self):
        '''
        load or initialize self.token_cache dictionary
        keys: atoken, rtoken, expire
        '''
        print('Loading token cache ({cache_file})...'.format(
            cache_file=self.CACHE_FILE))
        try:
            with open(self.CACHE_FILE, 'r') as json_file:
                self.token_cache = json.load(json_file)

        except FileNotFoundError:
            print(
                'Could not load token cache, proceeding with full authorization...'
            )
            self.authorize_app()

    def save_token_cache(self):
        print('Saving token cache ({cache_file})...'.format(
            cache_file=self.CACHE_FILE))
        with open(self.CACHE_FILE, 'w') as json_file:
            json.dump(self.token_cache, json_file)