def authenticate():

    ## Strava API uses OAuth2, which requires users to manually allow permission, which generates
    ## a token only valid for a number of hours.

    ## get API client id and secret from config file

    config = configparser.ConfigParser()
    config.read("credentials.cfg")
    client_id = config.get('credentials', 'client_id')
    client_secret = config.get('credentials', 'client_secret')

    client = Client(rate_limiter=limiter.DefaultRateLimiter())
    authorize_url = client.authorization_url(
        client_id=client_id, redirect_uri='http://localhost:8282/authorized')

    ## getting token -- pretty manual process for now

    webbrowser.open_new_tab(authorize_url)

    code = input('Enter Temporary Code: ')
    code = str(code)

    ## authenticate using API credntials + token

    token_response = client.exchange_code_for_token(
        client_id=client_id, client_secret=client_secret, code=code)

    return client
    def get(request):
        """ Request -and store- a strava access token. """
        client = Client()

        # Extract the code from the response
        code = request.GET.get('code')
        access_token = client.exchange_code_for_token(
            client_id=settings.STRAVA_CLIENT_ID,
            client_secret=settings.STRAVA_CLIENT_SECRET,
            code=code
        )
        strava_athlete = client.get_athlete()

        try:
            athlete = Athlete.objects.get(strava_id=strava_athlete.id)
            athlete.strava_token = access_token
        except Athlete.DoesNotExist:
            athlete = Athlete(strava_id=strava_athlete.id, strava_token=access_token)
        athlete.save()

        cache_key = _get_cache_key(request)
        cache.delete(cache_key)
        redir_url = '{}?start_date={}&end_date={}'.format(
            reverse_lazy('strava-summary'),
            _get_start_date(request),
            _get_end_date(request)
        )
        return HttpResponseRedirect(redir_url)
Example #3
0
    def get(self):
        code = self.request.get('code')

        client = Client()
        access_token = client.exchange_code_for_token(client_id=conf.SV_CLIENT_ID, client_secret=conf.SV_CLIENT_SECRET, code=code)

        user_id = UserManager().AddUserToken(access_token)
        self.redirect('/user/{0}'.format(user_id))
Example #4
0
def auth_done(request):
    code = request.GET.get('code')
    client = Client()
    access_token = client.exchange_code_for_token(client_id=CLIENT_ID,
                                                  client_secret=CLIENT_SECRET,
                                                  code=code)
    request.session['access_token'] = access_token
    return redirect('home')
def get_token(client_id, client_secret, code):

    """Exchange a temporary code for a permanent token"""

    client = Client()
    response = client.exchange_code_for_token(client_id = client_id, client_secret = client_secret, code = code)

    print("[+] A new permanent token was generated, with the following details:\n\t- access token: {}\n\t- refresh access token: {}\n\t- expireS at: {}".format(response["access_token"], response["refresh_token"], response["expires_at"]))
Example #6
0
def authorization():
    code = request.args.get('code')
    client = Client()
    access_token = client.exchange_code_for_token(client_id=MY_STRAVA_CLIENT_ID,
                                                  client_secret=MY_STRAVA_CLIENT_SECRET,
                                                  code=code)
    response = redirect("/")
    response.set_cookie('access_token', access_token)
    return response
Example #7
0
def oauth_authorized():
    client = Client()
    code = request.args.get('code')
    access_token = client.exchange_code_for_token(
        client_id=CLIENT_ID,
        client_secret=CLIENT_SECRET,
        code=code)
    session['access_token'] = access_token
    return redirect(url_for('index'))
Example #8
0
def authorized():
    code = request.args.get('code')
    page = request.args.get('page')
    client = Client()
    token_struct = client.exchange_code_for_token(client_id=CLIENT_ID,
                                                  client_secret=CLIENT_SECRET,
                                                  code=code)
    session['token_struct'] = token_struct
    return redirect(page, code=302)
Example #9
0
def oauth_authorized():
    client = Client()
    code = request.args.get('code')
    access_token = client.exchange_code_for_token(
        client_id=CLIENT_ID,
        client_secret=CLIENT_SECRET,
        code=code)
    session['access_token'] = access_token
    return redirect(url_for('index'))
Example #10
0
 def __init__(self, token):
     if not token:
         client = Client()
         url = client.authorization_url(client_id=STRAVA_APP_ID, redirect_uri='http://localhost:8000/')
         code = input(f"Open {url}, copy code once redirected: ")
         token_response = client.exchange_code_for_token(client_id=STRAVA_APP_ID, client_secret=STRAVA_CLIENT_SECRET, code=code)
         self.STRAVA_ACCESS_TOKEN = token_response['access_token']
     else:
         self.STRAVA_ACCESS_TOKEN = token
Example #11
0
def create_authentication_token():
    logger = logging.getLogger("authenticator.create_authentication_token")

    client = Client()

    logger.info(
        "This is a one-time operation to generate the required authentication tokens for the app. Please follow the steps carefully"
    )
    logger.info("")
    logger.info(
        "Follow the instructions here: https://developers.strava.com/docs/getting-started/#account to create an 'API Application'"
    )
    logger.info(
        "The important bits: Set the 'authorization callback domain' to 'localhost'"
    )
    logger.info(
        "Make a note of the 'Client ID' and 'Client Secret' values (you may have to click 'show' to see the value of the secret"
    )
    logger.info("")
    logger.info(
        "Create a file called 'client.secret' and place it in the strava_data directory"
    )
    input("Once you have performed the above steps, hit enter")

    MY_STRAVA_CLIENT_ID, MY_STRAVA_CLIENT_SECRET = open(
        '/opt/strava_data/client.secret').read().strip().split(',')

    logger.info(
        'Client ID ({}) and secret read from file'.format(MY_STRAVA_CLIENT_ID))

    url = client.authorization_url(
        client_id=MY_STRAVA_CLIENT_ID,
        redirect_uri='http://127.0.0.1:5000/authorization',
        scope=[
            'read_all', 'profile:read_all', 'activity:read_all',
            'profile:write', 'activity:write'
        ])

    logger.info("Open the following URL in a browser and approve access:")
    logger.info(url)

    auth_url_eg = "http://127.0.0.1:5000/authorization?state=&code=1e6878eb4b0175123e87bd8d708c40717448ac33&scope=read,activity:read_all,profile:read_all,read_all"
    code_eg = "1e6878eb4b0175123e87bd8d708c40717448ac33"
    logger.info(
        "The re-directed URL will look something like this: {}, please enter just the 'code' value now e.g. {}"
        .format(auth_url_eg, code_eg))
    CODE = input()

    access_token = client.exchange_code_for_token(
        client_id=MY_STRAVA_CLIENT_ID,
        client_secret=MY_STRAVA_CLIENT_SECRET,
        code=CODE)
    logger.info(
        "Access_token: {}, outputting to local file".format(access_token))
    with open('/opt/strava_data/access_token.pickle', 'wb') as f:
        pickle.dump(access_token, f)
def set_access_token(request):
    """ Exchange the provided code for an access token and store it
    """

    # Our strava code
    json = request.json_body
    code = json['code']

    # If we don't have a strava secret, we can't make the key exchange
    if 'strava' not in request.registry.settings['secrets']:
        request.response.status_int = 500
        return

    # Exchange the code for an access token
    # The API will throw an unspecified error if code is invalid.
    # Catch that rather than taking down the server.
    access_token = ""

    try:
        client = StravaClient()
        access_token = client.exchange_code_for_token(
            client_id=request.registry.settings['secrets']['strava']
            ['strava_id'],
            client_secret=request.registry.settings['secrets']['strava']
            ['strava_secret'],
            code=code)
    except:
        # Return an error
        request.response.status_int = 502
        return

    # Our admin object
    admin = _get_admin(request)

    #Create the access token if it doesn't exist, or update the stored one
    if not admin.exists_document('strava_access_token'):
        # Store the access token
        admin.create_document({'strava_access_token': access_token},
                              doc_id='strava_access_token')
    else:
        # Update the stored access token
        stored_access_token = admin.get_document('strava_access_token')
        try:
            admin.update_document({
                'strava_access_token': access_token,
                '_id': 'strava_access_token',
                '_rev': stored_access_token['_rev']
            })
        except:
            # We likely hit a race condition where the _rev is no longer valid. Return accordingly.
            request.response.status_int = 409
            return

    # Return appropriately
    request.response.status_int = 200
    return {'access_token': access_token}
Example #13
0
def parse_args(args):
    access_token_file_name = args.output_file

    client = Client()
    access_token_does_exist = os.path.isfile(access_token_file_name)
    access_token_doesnt_exist = not (access_token_does_exist)
    access_token_expired = True

    if access_token_does_exist:
        with open(access_token_file_name, "r") as f:
            token_response = json.load(f)
            token_response = json.loads(token_response)
            token_expiry_time = token_response["expires_at"]
            current_time = time.time()
            access_token_expired = current_time > token_expiry_time

    if access_token_doesnt_exist or access_token_expired:
        client_id = args.client_id
        client_secret = args.client_secret
        scope = [
            "read",
            "read_all",
            "profile:read_all",
            "activity:read",
            "activity:read_all",
        ]
        authorize_url = client.authorization_url(
            client_id=client_id,
            redirect_uri="http://localhost:5000/authorized",
            scope=scope,
        )

        # Open the authorization url
        print("Opening: " + authorize_url)
        webbrowser.open(authorize_url)

        # Get code
        entered_code = str(input("Please enter code: "))
        # Exchange code for token:
        token_response = client.exchange_code_for_token(
            client_id=client_id, client_secret=client_secret, code=entered_code
        )
        # Save it to file so we can use it until it expires.
        access_token_string = json.dumps(token_response)
        with open(access_token_file_name, "w+") as f:
            json.dump(access_token_string, f)

    # Now we have a token_response dict either from file or from the
    # Strava API
    access_token = token_response["access_token"]
    refresh_token = token_response["refresh_token"]

    print("access_token:", access_token)
    print("refresh_token", refresh_token)
Example #14
0
def authorized_callback():
    client = Client()
    # Extract the code from your webapp response
    code = request.args.get('code')
    access_token = client.exchange_code_for_token(
        client_id=CONSTANTS.CLIENT_ID,
        client_secret=CONSTANTS.CLIENT_SECRET,
        code=code)
    # Now store that access token along with athlete details
    add_athlete(access_token)
    #return jsonify({"status": "success"})
    return redirect("http://34.211.61.161:3000/", code=302)
Example #15
0
def auth():
    try:
        code = request.args["code"]
        c = Client()
        token = c.exchange_code_for_token(app.config['STRAVA_ID'], app.config['STRAVA_SECRET'], code)
    except (KeyError, requests.exceptions.HTTPError):
        return redirect("/")

    session["token"] = c.access_token = token
    a = c.get_athlete()  # Technically shouldn't be needed as the athlete details are returned in the oauth call
    session["athlete"] = {"firstname": a.firstname, "picture": a.profile_medium}
    return redirect("/")
def set_access_token(request):
    """ Exchange the provided code for an access token and store it
    """

    # Our strava code
    json = request.json_body
    code = json['code']

    # If we don't have a strava secret, we can't make the key exchange
    if 'strava' not in request.registry.settings['secrets']:
        request.response.status_int = 500
        return

    # Exchange the code for an access token
    # The API will throw an unspecified error if code is invalid.
    # Catch that rather than taking down the server.
    access_token = ""

    try:
        client = StravaClient()
        access_token = client.exchange_code_for_token(client_id=request.registry.settings['secrets']['strava']['strava_id'],
            client_secret=request.registry.settings['secrets']['strava']['strava_secret'],
            code=code)
    except:
        # Return an error
        request.response.status_int = 502
        return

    # Our admin object
    admin = _get_admin(request)

    #Create the access token if it doesn't exist, or update the stored one
    if not admin.exists_document('strava_access_token'):
        # Store the access token
        admin.create_document({'strava_access_token': access_token}, doc_id='strava_access_token')
    else:
        # Update the stored access token
        stored_access_token = admin.get_document('strava_access_token')
        try:
            admin.update_document({'strava_access_token': access_token, '_id':'strava_access_token', '_rev':stored_access_token['_rev']})
        except:
            # We likely hit a race condition where the _rev is no longer valid. Return accordingly.
            request.response.status_int = 409
            return
        

    # Return appropriately
    request.response.status_int = 200
    return {
        'access_token':
            access_token
    }
Example #17
0
def get_client():
    client = Client()
    authorize_url = client.authorization_url(
        client_id=26273,
        redirect_uri='https://localhost:8080',
        scope=['read', 'read_all', 'activity:read_all'])
    code = '299ad7943b6eb478247684620d87e341cfdcb6a2'
    access_token = client.exchange_code_for_token(
        client_id=26273,
        client_secret='80f4236b6e958701dbeebb8c09c99e9d2fb71d1a',
        code=code)
    client.access_token = access_token['access_token']
    return client
def strava_login():
    code = request.args.get('code')
    client = Client()
    cid = current_app.config['STRAVA_CLIENT_ID']
    csecret = current_app.config['STRAVA_CLIENT_SECRET']
    access_token = client.exchange_code_for_token(client_id=cid,
                                                  client_secret=csecret,
                                                  code=code)
    athlete = client.get_athlete()
    email = athlete.email
    send_user_to_dataservice(email, access_token)
    session['user'] = email
    session['token'] = access_token
    return redirect('/')
Example #19
0
def authorized():
	# get access token to make requests
	client = Client()
	code = request.args.get('code')
	client.access_token = client.exchange_code_for_token(client_id=creds.client_id, client_secret=creds.client_secret, code=code) # add id and secret

	# get data
	today = datetime.datetime.strptime(str(datetime.date.today()), "%Y-%m-%d")
	one_month_ago = today - dateutil.relativedelta.relativedelta(months=1)
	athlete = client.get_athlete()
	activities = client.get_activities(after=one_month_ago)
	rides = toolkit.get_activity_types(activities, 'ride')
	runs = toolkit.get_activity_types(activities, 'run')
	ride_set = ActivitySet("Rides", rides)
	run_set = ActivitySet("Runs", runs)
	return render_template('main.html', athlete=athlete, activity_sets=[ride_set, run_set])
Example #20
0
def index(request):

    user = None 

    if (request.user.is_authenticated):
        user = AuthUser.objects.get(user_id=request.user.id)

    client = Client()
    authorize_url = client.authorization_url(client_id=24429, redirect_uri="http://localhost:8000/main")

    #get code from get
    #Get Code from webapp response
    code = request.GET.get('code') if (request.GET.get('code') != None) else ''

    start_pos, end_pos, a_polyline = '', '', ''
    if (code != '' and request.user.is_authenticated):

        access_token = client.exchange_code_for_token(client_id=24429, client_secret=config_vars.STRAVA_CLIENT_SECRET, code=code)

        user_model = AuthUser.objects.get(user_id=request.user.id)
        
        # Store User Access Token in DB
        if (user_model is not None):
            user_model.auth_code = access_token
            user_model.save()

    # Set Access Token On Client
    if (request.user.is_authenticated and user.auth_code != ''):
        
        pprint("User Logged in and has an auth code")
        client.access_token = user.auth_code
        athlete = client.get_athlete()

        full_activity = client.get_activity(1486441471, True)
        
        a_polyline = full_activity.map.polyline
        start_pos = full_activity.start_latlng
        end_pos = full_activity.end_latlng


    return render(request, "index.html", {
        "auth_url": authorize_url, 
        "start_pos": start_pos,
        "end_pos": end_pos,
        "polyline": a_polyline,
        "user_is_authenticated": request.user.is_authenticated 
    })
Example #21
0
def strava_redirect(request):
    auth_code = request.GET.get("code")
    client = Client()
    access_token = client.exchange_code_for_token(CLIENT_ID, CLIENT_SECRET,
                                                  auth_code)
    client.access_token = access_token

    global accesToken
    accesToken = access_token

    athlete = client.get_athlete()

    currentUser = User.objects.get(pk=request.user.id)
    currentUser.profile.stravaAccessToken = access_token
    currentUser.profile.save()

    return render(request, 'strava_redirect.html',
                  {'athlete_name': athlete.username})
Example #22
0
def auth_success(request):
    temp_code = request.GET.get('code')  # temp auth code
    print(temp_code)
    client = Client()
    token = client.exchange_code_for_token(5928, 'a486a0b19c8d16aef41090371b7726dc510ee4a7', temp_code)
    if not athlete.objects.filter(pk=client.get_athlete().id):
        new_athlete = athlete(
            id = client.get_athlete().id,
            firstname = client.get_athlete().firstname,
            lastname = client.get_athlete().lastname,
            access_token = token
        )
        new_athlete.save()
        data_scraper(after_utc, before_utc, client.get_athlete().id)
        result = 'added'
    else:
        result = 'already exists'
    return render(request, 'auth_success.html', {'leaderboard':get_leaderboard(), 'result':result})
Example #23
0
def strava_client(client_id=None,
                  client_secret=None,
                  refresh_token=None,
                  access_token=None):
    client = Client()
    if access_token is None:
        authorize_url = client.authorization_url(
            client_id=client_id,
            redirect_uri='http://localhost:8282/authorized',
            scope='view_private,write')
        logging.info("Go to %s" % (authorize_url))
        code = raw_input("Code: ")
        client.access_token = client.exchange_code_for_token(
            client_id=client_id, client_secret=client_secret, code=code)
        logging.info("Access Token = %s" % (client.access_token))
    else:
        client.access_token = access_token

    return client
Example #24
0
def authenticate():
    """Authenticate user from Strava"""
    client = Client()
    code = request.args.get("code", None)

    try:
        token_response = client.exchange_code_for_token(
            client_id=STRAVA_CLIENT_ID, client_secret=STRAVA_SECRET, code=code)
        LOGGER.debug(token_response)
        session["strava_access_token"] = token_response["access_token"]
        session["strava_refresh_token"] = token_response["refresh_token"]
        session["strava_expires_at"] = token_response["expires_at"]

    except Exception as e:
        LOGGER.info(e)
        LOGGER.warning("Authentication failed")
        pass

    # return "Done"
    return redirect("/", code=302)
Example #25
0
def auth_success(request):
    temp_code = request.GET.get('code')  # temp auth code
    print(temp_code)
    client = Client()
    token = client.exchange_code_for_token(
        5928, 'a486a0b19c8d16aef41090371b7726dc510ee4a7', temp_code)
    if not athlete.objects.filter(pk=client.get_athlete().id):
        new_athlete = athlete(id=client.get_athlete().id,
                              firstname=client.get_athlete().firstname,
                              lastname=client.get_athlete().lastname,
                              access_token=token)
        new_athlete.save()
        data_scraper(after_utc, before_utc, client.get_athlete().id)
        result = 'added'
    else:
        result = 'already exists'
    return render(request, 'auth_success.html', {
        'leaderboard': get_leaderboard(),
        'result': result
    })
Example #26
0
def main():
    user_id = input("user id: ")
    access_token = input("access token: ")
    client = Client(access_token)

    #Build url or authorizing app
    url = client.authorization_url(
        client_id=user_id,
        redirect_uri='http://127.0.0.1:5000/authorization',
        approval_prompt='auto',
        scope='activity:read_all')
    print(url)

    #Extract access code from url response
    access_code = input("access code: ")
    client_secret = input("client secret: ")

    #Get permanent access token
    permanent_access_token = client.exchange_code_for_token(
        user_id, client_secret, access_code)
    print(permanent_access_token)
Example #27
0
class StrvaSignIn(StravaAuthSignIn):
    def __init__(self):
        super(StrvaSignIn, self).__init__('Strava')
        self.StravaClient = Client()

    def authorize(self):
        return redirect(
            self.StravaClient.authorization_url(
                client_id=self.consumer_id,
                redirect_uri=self.get_callback_url()))

    def callback(self):
        if 'code' not in request.args:
            return None
        access_token = self.StravaClient.exchange_code_for_token(
            client_id=self.consumer_id,
            client_secret=self.consumer_secret,
            code=request.args['code'])
        social_id = session['social_id']
        user = User.query.filter_by(social_id=social_id).first()
        user.stravatoken = access_token
        self.StravaClient.access_token = access_token
        user.athlete_id = self.StravaClient.get_athlete().id
        db.session.commit()
        a = Athlete.query.get(user.athlete_id)
        if a is None:
            dbathlete = Athlete(
                id=user.athlete_id,
                stravatoken=access_token,
                firstname=self.StravaClient.get_athlete().firstname,
                lastname=self.StravaClient.get_athlete().lastname)
            db.session.add(dbathlete)
        else:
            dbathlete = Athlete.query.filter_by(id=user.athlete_id).first()
            dbathlete.stravatoken = access_token
            dbathlete.firstname = self.StravaClient.get_athlete().firstname
            dbathlete.lastname = self.StravaClient.get_athlete().lastname
            db.session.add(dbathlete)
        db.session.commit()
        return (user, self.StravaClient.get_athlete())
Example #28
0
    def token_exchange(self, request):
        if 'code' in request.data:
            try:
                strava_client = Client()
                response = strava_client.exchange_code_for_token(SOCIAL_AUTH_STRAVA_KEY, SOCIAL_AUTH_STRAVA_SECRET, request.data['code'])
                leet = Athlete.objects.get(pk=request.user.pk)
                leet.strava_api_token = response
                leet.save()
            except HTTPError as e:
                code = e.args[0][:3]
                message = e.args[0][3:]
                return Response({
                    'status': code,
                    'message': message
                }, status=int(code))
        else:
            return Response({
                'status': 'Bad Request',
                'message': '"code" is required'
            }, status=status.HTTP_400_BAD_REQUEST)

        return Response({}, status.HTTP_201_CREATED)
Example #29
0
def auth():
    try:
        code = request.args["code"]
        c = Client()
        token = c.exchange_code_for_token(app.config['STRAVA_ID'], app.config['STRAVA_SECRET'], code)
    except (KeyError, requests.exceptions.HTTPError):
        return redirect("/")

    session["token"] = c.access_token = token
    a = c.get_athlete()  # Technically shouldn't be needed as the athlete details are returned in the oauth call
    session["athlete"] = {"name": a.firstname, "picture": a.profile_medium, "id": a.id}

    # lookup athlete in db
    cur = g.db.execute('select * from users where id = {}'.format(a.id))
    x = cur.fetchall()
    print x
    if not x:
        # Create the object in the db
        cur = g.db.cursor()
        cur.execute('insert into users (id, name, picture) values (?, ?, ?)', (a.id, a.firstname, a.profile))
        g.db.commit()
    cur.close()

    return redirect("/")
Example #30
0
def logged_in():
    """
    Method called by Strava (redirect) that includes parameters.
    - state
    - code
    - error
    """
    error = request.args.get('error')
    state = request.args.get('state')
    if error:
        return render_template('login_error.html', error=error)
    else:
        code = request.args.get('code')
        client = Client()
        access_token = client.exchange_code_for_token(
            client_id=app.config['STRAVA_CLIENT_ID'],
            client_secret=app.config['STRAVA_CLIENT_SECRET'],
            code=code)
        # Probably here you'd want to store this somewhere -- e.g. in a database.
        strava_athlete = client.get_athlete()

        return render_template('login_results.html',
                               athlete=strava_athlete,
                               access_token=access_token)
Example #31
0
def auth(request):
    client = Client()
    if request.method == "POST":
        form = forms.CreateUserForm(request.POST)
        if form.is_valid():
            userName = form.cleaned_data["username"]
            userPass = form.cleaned_data["password"]
            userMail = form.cleaned_data["mail"]
            userToken = form.cleaned_data["token"]
            user = User.objects.create_user(
                userName, userMail,
                userPass)  # Nous créons un nouvel utilisateur
            user.save()
            profil = Profile(user=user, user_token=userToken)
            profil.save()
    else:
        form = forms.CreateUserForm()
        code = request.GET['code']
        access_token = client.exchange_code_for_token(
            client_id=13966,
            client_secret='a67b6efd42d941633fd631b35df2d22ae9b566c1',
            code=code)

    return render(request, 'auth.html', locals())
Example #32
0
port = httpd.server_address[1]

authorize_url = client.authorization_url(
	client_id=APP["id"],
	redirect_uri="http://localhost:%d/authorized" % port,
	scope="write")

print "Now open the following URL and authorise this application."
print "Then Strava should send you to a localhost:%d URL handled by this script." % port
print "If that fails, rerun this script passing the code= value as an argument."
print
print authorize_url

# "code" gets updated once Strava calls us back.
while not code:
	httpd.handle_request()

access_token = client.exchange_code_for_token(
	client_id=APP["id"],
	client_secret=APP["client_secret"], code=code)

client.access_token = access_token
athlete = client.get_athlete()

print
print "Logged in as %s <%s>. Writing access token to file %s" % (athlete.firstname, athlete.email, FN)

f = file(FN, "w")
os.chmod(FN, 0600) # file won't do this as an extra argument, grrr
f.write(access_token)
Example #33
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)
Example #34
0
class Strava(object):
    def __init__(self):
        self.client_id = current_app.config['STRAVA_CLIENT_ID']
        self.client_secret = current_app.config['STRAVA_CLIENT_SECRET']
        self.redirect_uri = url_for('strava.confirm_auth', _external=True)

        self.client = StravaClient()

        self._activity_type = 'ride'  # rides or runs
        self._activities = None

    @property
    def activity_type(self):
        return self._activity_type

    @activity_type.setter
    def activity_type(self, value):
        self._activity_type = value
        self._activities = None

    @property
    def athlete(self):
        return self.client.get_athlete()

    @property
    def activities(self):
        if not self._activities:
            # current_year = datetime.datetime.now().year
            # after = datetime.datetime(current_year - 2, 12, 25)
            self._activities = Activities(self.client.get_activities(),
                                          self.activity_type)
        return self._activities

    @classmethod
    def authorization_url(cls):
        self = cls()
        return self.client.authorization_url(client_id=self.client_id,
                                             redirect_uri=self.redirect_uri)

    def get_access_token(self, code):
        return self.client.exchange_code_for_token(
            client_id=self.client_id,
            client_secret=self.client_secret,
            code=code)

    @classmethod
    def athlete_by_code(cls, code):
        self = cls()
        self.client.access_token = self.get_access_token(code)
        return self.athlete

    @classmethod
    def athlete_by_token(cls, token):
        self = cls()
        self.client.access_token = token
        return self.athlete

    @classmethod
    def activities_by_token(cls, token):
        self = cls()
        self.client.access_token = token
        return self.activities

    @classmethod
    def by_token(cls, token):
        self = cls()
        self.client.access_token = token
        return self
Example #35
0
        client_id = cfg.get("StravaClient", "ClientId")
        client_secret = cfg.get("StravaClient", "ClientSecret")
        port = int(cfg.get("Application", "Port"))
        
        # setup webserver for authentication redirect
        httpd = http.server.HTTPServer(('127.0.0.1', port), AuthHandler)

        # The url to authorize from
        authorize_url = client.authorization_url(client_id=client_id, redirect_uri='http://localhost:{port}/authorized'.format(port=port), scope='view_private,write')
        # Open the url in your browser
        webbrowser.open(authorize_url, new=0, autoraise=True)

        # wait until you click the authorize link in the browser
        httpd.handle_request()
        code = httpd.code

        # Get the token
        token = client.exchange_code_for_token(client_id=client_id, client_secret=client_secret, code=code)

        # Now store that access token in the config
        cfg.set("UserAcct", "Token", token)
        with open("stravamng.cfg", "w") as cfg_file:
            cfg.write(cfg_file)

    client.access_token = token

    # do stuff
    athlete = client.get_athlete()
    print("For {id}, I now have an access token {token}".format(id=athlete.id, token=token))

Example #36
0
class Strava:
    """Class to interact with Strava API"""
    # pylint: disable=too-many-instance-attributes
    # pylint: disable=invalid-name

    # CH1.5: Global variables in a class
    # CH1.5: Easy way to create a list
    cols = 'id name type start_date_local average_heartrate' \
           ' distance average_speed elapsed_time'.split()
    funcs = []

    def __init__(self, api_file, local_db_fp, verbose=False, update=True):
        # Read API parameters from CSV file
        if os.path.isfile(api_file):
            api = pd.read_csv(api_file)
        else:
            raise FileNotFoundError('API key file not found')

        # Initialise local variables and objects
        self._client_id = api['client_id']
        self._client_secret = api['client_secret']
        self._code = api['code']
        self._local_db_fp = local_db_fp
        self._client = Client()
        self._access_token = self._client.exchange_code_for_token(
            client_id=self._client_id,
            client_secret=self._client_secret,
            code=self._code)
        self._last_remote_id = None
        self._verbose = verbose

        # Handle exceptions in requesting the access token
        if not self._access_token:
            raise ConnectionError(
                'Client did not receive a valid access token')

        # Verify if local database exists
        if os.path.isfile(self._local_db_fp):
            # Read from file and sort by id
            if self._verbose:
                print('Reading local database from: %s' % self._local_db_fp)
            self._db = pd.read_csv(self._local_db_fp, index_col='id')
            self._db.sort_values(by=['id'], inplace=True)
        else:
            # Create new DataFrame
            self._db = pd.DataFrame(columns=self.cols)
            self._db.set_index('id', drop=True, inplace=True)

        if self._verbose:
            print('Local database contains %d entries' % len(self))

        if update:
            # Verify if local database up to date
            if not self._local_db_in_sync():
                if self._verbose:
                    print('Local database not in sync, downloading...')
                self._update_local_db()
                self._save_local_db()
                if self._verbose:
                    print('Local database now contains %d entries' % len(self))
            else:
                if self._verbose:
                    print('Local database in sync')

    def __repr__(self):
        return 'Strava(%d)' % len(self)

    def __len__(self):
        # CH1.5: Custom special method
        return len(self._db.index)

    def __getitem__(self, row):
        # CH1.5: Custom special method
        return self._db.iloc[[row]]

    def __call__(self):
        # CH5.152: Custom __call__ method
        self.update()
        if self._verbose:
            print('Update completed')

    def decorator_factory(scope):
        # CH 7.194: Decorators
        def decorator(func):
            def wrapper(self, *args, **kwargs):
                self.funcs.append(Functions(func.__name__, scope))
                return func(self, *args, **kwargs)

            return wrapper

        return decorator

    @decorator_factory('private')
    def _last_local_id(self):
        if self:
            last_local_id = self._db.iloc[[-1]].index.item()
        else:
            last_local_id = None
        return last_local_id

    @decorator_factory('private')
    def _local_db_in_sync(self):
        activity = self._client.get_activities(limit=1)
        activity = activity.next()
        self._last_remote_id = int(activity.id)
        return self._last_remote_id == self._last_local_id()

    @decorator_factory('private')
    def _update_local_db(self):
        last_start_date = None
        if self:
            last_start_date = str(
                self._db['start_date_local'].tail(1).values[0])
        activities = self._client.get_activities(after=last_start_date)
        data = []
        for activity in activities:
            if int(activity.id) != self._last_local_id():
                my_dict = activity.to_dict()
                data.append([activity.id] +
                            [my_dict.get(x) for x in self.cols[1:]])
            else:
                # All new activities processed
                break

        df = pd.DataFrame(data, columns=self.cols)
        df['average_speed'] *= 3.6
        df['distance'] /= 1000
        df.set_index('id', drop=True, inplace=True)
        self._db = pd.concat([self._db, df])
        self._db.sort_values(by=['id'], inplace=True)

    @decorator_factory('private')
    def _save_local_db(self):
        self._db.to_csv(self._local_db_fp)

    @decorator_factory('public')
    def update(self, in_memory=False):
        """Update local database and store to disk if requested"""
        self._update_local_db()
        if not in_memory:
            self._save_local_db()

    @decorator_factory('public')
    def filter(self, activity_type='', name=''):
        """Filter database based on activity type and name"""
        df = self._db
        if activity_type:
            df = df[df['type'].str.contains(activity_type)]
        if name:
            df = df[df['name'].str.contains(name)]

        return df
Example #37
0
from stravalib.client import Client
from config import *
import functions

#connection stuff
client = Client()
authorize_url = client.authorization_url(
    client_id=C_ID, redirect_uri='http://localhost:8282/authorized')
access_token = client.exchange_code_for_token(client_id=C_ID,
                                              client_secret=C_SECRET,
                                              code=CODE)
client.access_token = access_token

#getting activites
activities = client.get_club_activities(club_id=CLUB, limit=200)

#getting activities already recorded
done = functions.get_array('done')

#going through activities
data = []
for run in activities:
    #using local activity start date as a metric since using IDs feels shady
    if (str(run.start_date) not in done):
        #taking only runs
        if (run.type == 'Run'):
            data.append(run.start_date_local)
            data.append(run.elapsed_time)
            data.append(run.distance)
            data.append(run.total_elevation_gain)
            data.append(run.pr_count)
Example #38
0
        # The url to authorize from
        authorize_url = client.authorization_url(
            client_id=client_id,
            redirect_uri='http://localhost:{port}/authorized'.format(
                port=port),
            scope='view_private,write')
        # Open the url in your browser
        webbrowser.open(authorize_url, new=0, autoraise=True)

        # wait until you click the authorize link in the browser
        httpd.handle_request()
        code = httpd.code

        # Get the token
        token = client.exchange_code_for_token(client_id=client_id,
                                               client_secret=client_secret,
                                               code=code)

        # Now store that access token in the config
        cfg.set("UserAcct", "Token", token)
        with open("stravamng.cfg", "w") as cfg_file:
            cfg.write(cfg_file)

    client.access_token = token

    # do stuff
    athlete = client.get_athlete()
    print("For {id}, I now have an access token {token}".format(id=athlete.id,
                                                                token=token))
Example #39
0
class Strava(object):
    def __init__(self):
        self.client_id = current_app.config['STRAVA_CLIENT_ID']
        self.client_secret = current_app.config['STRAVA_CLIENT_SECRET']
        self.redirect_uri = url_for('strava.confirm_auth', _external=True)

        self.client = StravaClient()

        self._activity_type = 'ride'  # rides or runs
        self._activities = None

    @property
    def activity_type(self):
        return self._activity_type

    @activity_type.setter
    def activity_type(self, value):
        self._activity_type = value
        self._activities = None

    @property
    def athlete(self):
        return self.client.get_athlete()

    @property
    def activities(self):
        if not self._activities:
            # current_year = datetime.datetime.now().year
            # after = datetime.datetime(current_year - 2, 12, 25)
            self._activities = Activities(self.client.get_activities(), self.activity_type)
        return self._activities

    @classmethod
    def authorization_url(cls):
        self = cls()
        return self.client.authorization_url(client_id=self.client_id,
                                             redirect_uri=self.redirect_uri)

    def get_access_token(self, code):
        return self.client.exchange_code_for_token(client_id=self.client_id,
                                                   client_secret=self.client_secret,
                                                   code=code)

    @classmethod
    def athlete_by_code(cls, code):
        self = cls()
        self.client.access_token = self.get_access_token(code)
        return self.athlete

    @classmethod
    def athlete_by_token(cls, token):
        self = cls()
        self.client.access_token = token
        return self.athlete

    @classmethod
    def activities_by_token(cls, token):
        self = cls()
        self.client.access_token = token
        return self.activities

    @classmethod
    def by_token(cls, token):
        self = cls()
        self.client.access_token = token
        return self
Example #40
0
class stravaImporter(object):
    def __init__(self):
        self.client = Client()
        self.API_CALL_PAUSE_SECONDS = 1.5  # 40 requests per minute

        # the self-authorization is NOT working right now -- using hard-coded URL / ACCESS_CODE right now
        #url = self.client.authorization_url(client_id=CLIENT_ID,
        #                       redirect_uri='http://localhost:5000/authorization')
        #code = request.args.get('code') # or whatever flask does

        #url = 'http://www.strava.com/oauth/authorize?client_id=16424&response_type=code&redirect_uri=http://localhost/5001&approval_prompt=force&scope=write'
        #print(url)

        access_token = self.client.exchange_code_for_token(
            client_id=CLIENT_ID, client_secret=CLIENT_SECRET, code=ACCESS_CODE)
        # Now store that access token somewhere (a database?)
        self.client.access_token = access_token

        # retrieve the athlete
        self.athlete = self.client.get_athlete()
        print("For {}, I now have an access token".format(self.athlete.id))

        # name of tables in model
        self.user_TBL = 'users'
        self.activity_TBL = 'activities'
        self.streams_TBL = 'streams'
        self.gear_TBL = 'gear'

        # streams to extract from strava
        self.streams = [
            'time', 'latlng', 'distance', 'altitude', 'velocity_smooth',
            'heartrate', 'cadence', 'temp', 'moving', 'grade_smooth'
        ]

    def get_activities(self, before=None, after=None, limit=None):
        """ Get activities and the related metadata from strava """
        return list(
            self.client.get_activities(before=before, after=after,
                                       limit=limit))

    def get_streams(self, activity_id):
        # download the entire stream: `resolution` = `all` (default)
        # download all stream_types except `power`
        try:
            s = self.client.get_activity_streams(activity_id,
                                                 types=self.streams)
            return s
        except:
            print('Could not get streams for activity {0}. Manual upload?'.
                  format(activity_id))
            return

    def stream_to_DF(self, s):
        """ Convert a Strava Stream to a pandas DF """
        return pd.DataFrame.from_dict({k: s[k].data for k in s.keys()})

    def add_user(self,
                 username,
                 email=None,
                 fname=None,
                 lname=None,
                 password=None):
        """ Add a user to the DB"""

        s = Session()
        try:
            u = User(username=username,
                     email=email,
                     fname=fname,
                     lname=lname,
                     password=password,
                     strava_id=self.athlete.id)
            s.add(u)
            s.commit()
            return int(u.id)
        except SQLAlchemyError as err:
            s.rollback()
            print('Error: \n', err)
            raise

        s.close()
        return

    def add_streams(self, user_id, s_id):
        """ Add Strava data streams for a given user_id and activity_id """

        # get the strava streams for that activity
        stream = self.get_streams(s_id)
        # convert the streams to a DF
        if stream is not None:
            s = Session()

            df = self.stream_to_DF(stream)

            # add `user_id` to the DF
            df['user_id'] = user_id
            # add `activity_id` to the DF
            df['activity_id'] = s.query(
                Activity.id).filter_by(strava_id=s_id.astype(str)).one()[0]

            try:
                df.to_sql(self.streams_TBL,
                          engine,
                          if_exists='append',
                          index=False)
                s.commit()
            except:
                s.rollback()
                print('Error: `add_streams` cannot write event to DB. \n')
                raise

            s.close()
        else:
            print('Error: Stream is empty for User {0}, Activity {1}'.format(
                user_id, s_id))
        return

    def add_activity(self,
                     user_id,
                     before=None,
                     after=None,
                     limit=None,
                     add_streams=True):
        """ Get & add a list of activities from strava """

        # get the list of activities from strava
        activities = self.get_activities(before=before,
                                         after=after,
                                         limit=limit)
        activities = activities
        # transform activities to a DF ready for Postgres
        df = self.munge_activity(activities)
        df['user_id'] = user_id

        s = Session()
        try:
            df.to_sql(self.activity_TBL,
                      engine,
                      if_exists='append',
                      index=False)
            s.commit()
            print('Added {0} activities from Strava.\n'.format(
                len(df.strava_id)))
        except:
            s.rollback()
            print('Error: `add_activity` cannot write event to DB. \n')
            raise
        s.close()

        # if needed, add the streams as well
        if add_streams is True:
            size = len(df.strava_id)
            for (i, strava_id) in enumerate(df.strava_id):
                print('Fetching data streams for {0}: {1} of {2}'.format(
                    strava_id, i, size),
                      end='\r')
                time.sleep(
                    self.API_CALL_PAUSE_SECONDS)  # limit API call to 40 / min

                self.add_streams(user_id, strava_id)
            print('Added `Streams` for {0} activities from Strava.'.format(
                len(df.strava_id)))

        return

    def strip_units(self, df, cols):
        """ strip units from columns -- changes dtype from `object` to `float`"""

        d = {
            'average_speed': ' m / s',
            'max_speed': ' m / s',
            'distance': ' m',
            'total_elevation_gain': ' m'
        }

        for col in cols:
            if col in df.columns:
                df[col] = pd.to_numeric(df[col].astype('str').str.strip(
                    d[col]),
                                        errors='coerce')

        return df

    def munge_activity(self, activities):
        """ Get `activities` ready for Postgres DB """

        # `stravalib`.`activity` attributes to import
        fields = [
            'athlete_count', 'average_cadence', 'average_heartrate',
            'average_speed', 'distance', 'elapsed_time', 'elev_high',
            'elev_low', 'end_latlng', 'external_id', 'gear_id',
            'has_heartrate', 'id', 'location_city', 'location_country',
            'location_state', 'manual', 'max_heartrate', 'max_speed',
            'moving_time', 'name', 'pr_count', 'start_date',
            'start_date_local', 'start_latitude', 'start_latlng',
            'start_longitude', 'suffer_score', 'timezone',
            'total_elevation_gain', 'type', 'upload_id', 'workout_type'
        ]

        # convert `activities` into a df with `fields` as columns
        df = pd.DataFrame([[getattr(i, j) for j in fields]
                           for i in activities],
                          columns=fields)

        # rename since `id` will be an internal DB `id`
        df.rename(columns={'id': 'strava_id'}, inplace=True)

        # pandas or SQL does not support units, so strip the units from the fields
        # could be worth adding units when the tables are imported
        # I want GIS support, so can't really move to JSONB or BSON
        cols_to_strip = ('average_speed', 'max_speed', 'distance',
                         'total_elevation_gain')
        df = self.strip_units(df, cols_to_strip)

        # pd.to_sql does not yet support TZ, so strip it. for now.
        # also does not suport timedelta ... maybe I have to ditch `pd.to_sql`
        # https://github.com/pandas-dev/pandas/issues/9086
        df.start_date = pd.DatetimeIndex(df.start_date).tz_convert(None)
        df.timezone = df.timezone.astype(str)
        return df
Example #41
0
gear = None

#
# Date range to retrieve. Defaults to 2 weeks, but can be overridden
# by providing a different # of days in the command line.
#
numdays = 14
if (len(sys.argv) > 1):
	numdays=int(sys.argv[1])
now=datetime.datetime.now()
then=now - datetime.timedelta(numdays)

#
# Authenticate with Strava.
#
token_response = client.exchange_code_for_token(client_id=client_id,
	client_secret=client_secret, code=client_code)

client.access_token = token_response['access_token']
client.refresh_token = token_response['refresh_token']
client.expires_at = token_response['expires_at']

athlete = client.get_athlete()
print("Retrieving records of the past {days} days for {id}: {firstname} {lastname}".format(
	days=numdays, id=athlete.id,
	firstname=athlete.firstname, lastname=athlete.lastname))

activities = list(client.get_activities(after=then, before=now))
activities.reverse()
for activity in activities:
	if (activity.gear_id is None):
		gear_name = "N/A"
Example #42
0
 def get_token(self, code):
     client = Client(requests_session=self.session)
     return client.exchange_code_for_token(self.CLIENT_ID,
                                           self.client_secret, code)
Example #43
0
def token_exchange(code):
    client = Client()
    token = client.exchange_code_for_token(client_id=config.client_id, client_secret=config.client_secret, code=code)
    return token