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
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
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
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"]))
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?")
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
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)} """)
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)))
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
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
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)
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
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)
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)