Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Adding initial user authentication. #2

Open
wants to merge 12 commits into from

2 participants

Andrew Olson Steven Chanin
Steven Chanin

can you remove the commented out stuff about rides?

Steven Chanin

This is starting to feel like it needs to be 3 separate lines
1 -- check for truly invalid responses (result.nil?) and maybe result["error"].blank? (raises InvalidResponseError)
2 -- AuthenticationErrors
3 -- more InvalidResponses if result[key] is nil?

I'm worried that if result comes back nil, then result["error"] will blow up

Steven Chanin
Owner

I'd like to get this merged in, but I've got a couple of questions / requests.

First, I wasn't aware that this API existed. As far as I can tell, Strava doesn't require authentication. From reading the code, it seems like the point is to get access to properties of your account rather than the token. Is that it?

Also, could you add a section to the README that explains these additions and how to use them?

Finally, I made a couple of comments on specific files / lines, I was hoping you could take a look at those.

Thanks.

Steven Chanin
Owner

Oops... I didn't mean to close it.

Steven Chanin stevenchanin reopened this
Andrew Olson

There are now several API methods that require user authentication by including a token with the request.

http://www.strava.com/api/v1/upload/create is one example.

I'm using the user authentication in a small app that I wrote, to avoid having the user having to create yet another account. Only option I could come up with, since they don't support OpenID.

I'll update the README.

Andrew Olson

Sorry about borking up the branch. I rebased to master.

The commit that you want for the README is 6de69e5

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Commits on May 9, 2011
  1. Andrew Olson
  2. Andrew Olson

    Merge branch 'add_ride_streams'

    anolson authored
    Conflicts:
    	lib/strava-api.rb
    	lib/strava-api/base.rb
Commits on May 10, 2011
  1. Andrew Olson

    Remove debug output.

    anolson authored
  2. Andrew Olson
Commits on Jul 5, 2011
  1. Andrew Olson

    Removing commented code.

    anolson authored
  2. Andrew Olson

    Refactoring error handling

    anolson authored
  3. Andrew Olson

    Version bump to 0.14.0

    authored anolson committed
  4. Andrew Olson

    merge Andrew Olson's implementation of Streams

    authored anolson committed
  5. Andrew Olson

    Removing commented code.

    anolson authored
  6. Andrew Olson

    Refactoring error handling

    anolson authored
  7. Andrew Olson
  8. Andrew Olson

    Updating README.

    anolson authored
This page is out of date. Refresh to see the latest.
43 README.rdoc
View
@@ -164,6 +164,46 @@ If you have an efforts object (StravaApi::Effort) that has been returned by anot
my_ride.efforts.first.show
+== Streams
+The Strava API also has a Streams API call as well. This isn't documented on the Strava API wiki, so use it at your own risk.
+
+The Steam for a ride provides the raw data from your ride
+
+* altitude
+* cadence
+* distance
+* heartrate
+* latlng
+* time
+* watts
+* watts_calc
+
+To get a the underlying stream for a ride, you can call
+
+ ##returns a StravaApi::Streams
+ s.ride_streams(ride_id)
+
+Or you can start from a ride (StravaApi::Ride) and call
+
+ my_ride.streams
+
+Thanks to Andrew Olson (https://github.com/anolson) for this feature.
+
+== User Authentication
+To authenticate a user with Strava, you can call
+
+ user = s.login("email@gmail.com", "secret")
+
+A successful authentication returns a User object containing:
+
+* token
+* athlete_id
+* agreed_to_terms
+* super_user
+* default_settings
+
+An AuthenticationError is raised for a failed authentication attempt.
+
== Error Handling
The StravaApi gem raises errors under various conditions.
@@ -178,6 +218,9 @@ This is raised when the attempt to connect to Strava via httparty raises any of
* HTTParty::ResponseError
* HTTParty::RedirectionTooDeep
+=== StravaApi::AuthenticationError
+This is raised when a user authentication attempt failed.
+
=== StravaApi::InvalidResponseError
This is raised is the call to Strava returns a result describing an error rather than the data you requested.
2  VERSION
View
@@ -1 +1 @@
-0.13.0
+0.14.0
3  lib/strava-api.rb
View
@@ -9,6 +9,8 @@
require 'strava-api/ride'
require 'strava-api/segment'
require 'strava-api/effort'
+require 'strava-api/settings'
+require 'strava-api/user'
require 'strava-api/streams'
module StravaApi
@@ -16,6 +18,7 @@ module StravaApi
end
#classes to perform network access to Strava
+require 'strava-api/authentication'
require 'strava-api/clubs'
require 'strava-api/rides'
require 'strava-api/segments'
9 lib/strava-api/authentication.rb
View
@@ -0,0 +1,9 @@
+module StravaApi
+ module Authentication
+ # authenticate a user with their Strava credentials.
+ def login(email, password)
+ result = call("authentication/login", nil, {:email => email, :password => password}, :post)
+ User.new(self, result)
+ end
+ end
+end
39 lib/strava-api/base.rb
View
@@ -1,36 +1,49 @@
module StravaApi
class Base
include HTTParty
-
+
+ include StravaApi::Authentication
include StravaApi::Clubs
include StravaApi::Rides
include StravaApi::Segments
include StravaApi::Efforts
-
+
format :json
base_uri 'www.strava.com/api/v1'
-
+
attr_reader :errors
-
+
def initialize
@errors = []
end
-
- def call(command, key, options)
+
+ def call(command, key, options, *args)
+ method = args[0] || :get
+
begin
- result = self.class.get("/#{command}", :query => options)
+ if(method == :get)
+ result = self.class.get("/#{command}", :query => options)
+ else
+ result = self.class.post("/#{command}", :body => options)
+ end
+
rescue HTTParty::UnsupportedFormat, HTTParty::UnsupportedURIScheme, HTTParty::ResponseError, HTTParty::RedirectionTooDeep
raise NetworkError.new
end
-
+
if result && result.parsed_response == "<html><body><h1>500 Internal Server Error</h1></body></html>"
@errors << "Strava returned a 500 error"
- raise CommandError.new
+ raise CommandError.new
end
-
- @errors << result["error"] if result && result["error"]
- raise InvalidResponseError.new if result.nil? || !result["error"].blank? || (!key.nil? && result[key].nil?)
-
+
+ if result && result["error"]
+ @errors << result["error"]
+ raise AuthenticationError.new if result["error"] == "Invalid email or password."
+ raise InvalidResponseError.new
+ end
+
+ raise InvalidResponseError.new if result.nil? || (!key.nil? && result[key].nil?)
+
result
end
end
2  lib/strava-api/exceptions.rb
View
@@ -6,4 +6,6 @@ class CommandError < StandardError; end
class NetworkError < StandardError; end
class InternalError < StandardError; end
+
+ class AuthenticationError < StandardError; end
end
15 lib/strava-api/settings.rb
View
@@ -0,0 +1,15 @@
+module StravaApi
+ class Settings < HashBasedStore
+ ATTRIBUTE_MAP = {"sampleRate" => :sample_rate,
+ "continuousGps" => :continuous_gps,
+ "accuracy" => :accuracy,
+ "distanceFilter" => :distance_filter,
+ "maxSearchTime" => :max_search_time,
+ "minStaleTime" => :min_stale_time,
+ "minAccuracy" => :min_accuracy}
+
+ def initialize(connection, options = {})
+ super(connection, ATTRIBUTE_MAP, {}, options)
+ end
+ end
+end
18 lib/strava-api/user.rb
View
@@ -0,0 +1,18 @@
+module StravaApi
+ class User < HashBasedStore
+ ATTRIBUTE_MAP = {
+ "token" => :token,
+ "athlete_id" => :athlete_id,
+ "agreedToTerms" => :agreed_to_terms,
+ "superUser" => :super_user,
+ "defaultSettings" => :default_settings
+ }
+
+ NESTED_CLASS_MAP = { :default_settings => Settings }
+
+ def initialize(connection, options = {})
+ super(connection, ATTRIBUTE_MAP, NESTED_CLASS_MAP, options)
+ end
+
+ end
+end
81 strava-api.gemspec
View
@@ -1,72 +1,59 @@
# Generated by jeweler
# DO NOT EDIT THIS FILE DIRECTLY
-# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
+# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
# -*- encoding: utf-8 -*-
Gem::Specification.new do |s|
s.name = %q{strava-api}
- s.version = "0.13.0"
+ s.version = "0.14.0"
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Steven Chanin"]
- s.date = %q{2010-10-04}
+ s.date = %q{2011-07-01}
s.description = %q{Strava (http://www.strava.com/) allows access to it's data via a JSON api. This gem wraps that API an allows you to interact with Ruby classes instead.}
s.email = %q{schanin@devleverage.com}
s.extra_rdoc_files = [
"LICENSE",
- "README.rdoc"
+ "README.rdoc"
]
s.files = [
"LICENSE",
- "README.rdoc",
- "Rakefile",
- "lib/strava-api.rb",
- "lib/strava-api/base.rb",
- "lib/strava-api/bike.rb",
- "lib/strava-api/club.rb",
- "lib/strava-api/clubs.rb",
- "lib/strava-api/effort.rb",
- "lib/strava-api/efforts.rb",
- "lib/strava-api/exceptions.rb",
- "lib/strava-api/hash_based_store.rb",
- "lib/strava-api/member.rb",
- "lib/strava-api/ride.rb",
- "lib/strava-api/rides.rb",
- "lib/strava-api/segment.rb",
- "lib/strava-api/segments.rb",
- "test/helper.rb",
- "test/test_base.rb",
- "test/test_club.rb",
- "test/test_clubs.rb",
- "test/test_effort.rb",
- "test/test_hash_based_store.rb",
- "test/test_ride.rb",
- "test/test_rides.rb",
- "test/test_segment.rb",
- "test/test_segments.rb",
- "test/test_strava.rb"
+ "README.rdoc",
+ "Rakefile",
+ "lib/strava-api.rb",
+ "lib/strava-api/base.rb",
+ "lib/strava-api/bike.rb",
+ "lib/strava-api/club.rb",
+ "lib/strava-api/clubs.rb",
+ "lib/strava-api/effort.rb",
+ "lib/strava-api/efforts.rb",
+ "lib/strava-api/exceptions.rb",
+ "lib/strava-api/hash_based_store.rb",
+ "lib/strava-api/member.rb",
+ "lib/strava-api/ride.rb",
+ "lib/strava-api/rides.rb",
+ "lib/strava-api/segment.rb",
+ "lib/strava-api/segments.rb",
+ "lib/strava-api/streams.rb",
+ "test/helper.rb",
+ "test/streams.json",
+ "test/test_base.rb",
+ "test/test_club.rb",
+ "test/test_clubs.rb",
+ "test/test_effort.rb",
+ "test/test_hash_based_store.rb",
+ "test/test_ride.rb",
+ "test/test_rides.rb",
+ "test/test_segment.rb",
+ "test/test_segments.rb",
+ "test/test_strava.rb"
]
s.homepage = %q{http://github.com/stevenchanin/strava-api}
- s.rdoc_options = ["--charset=UTF-8"]
s.require_paths = ["lib"]
- s.rubygems_version = %q{1.3.7}
+ s.rubygems_version = %q{1.5.2}
s.summary = %q{Provides a Ruby interface to the Strava api}
- s.test_files = [
- "test/helper.rb",
- "test/test_base.rb",
- "test/test_club.rb",
- "test/test_clubs.rb",
- "test/test_effort.rb",
- "test/test_hash_based_store.rb",
- "test/test_ride.rb",
- "test/test_rides.rb",
- "test/test_segment.rb",
- "test/test_segments.rb",
- "test/test_strava.rb"
- ]
if s.respond_to? :specification_version then
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
s.specification_version = 3
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
10 test/helper.rb
View
@@ -78,7 +78,7 @@ def ride_efforts_json
def ride_streams_json
#curl "http://www.strava.com/api/v1/streams/77563"
- File.new('streams.json').gets
+ File.new('test/streams.json').gets
end
def segments_index_json
@@ -135,4 +135,12 @@ def ride_effort_method_json
def effort_show_method
'{"effort":{"ride":{"name":"02/28/10 San Francisco, CA","id":77563},"averageSpeed":20149.3205741627,"startDate":"2010-02-28T08:38:39-08:00","averageWatts":151.84,"startDateLocal":"2010-02-28T00:38:39-08:00","maximumSpeed":26861.148,"timeZoneOffset":-8.0,"athlete":{"username":"julianbill","name":"Julian Bill","id":1139},"elevationGain":15.8616,"distance":1181.38,"elapsedTime":209,"segment":{"name":"Panhandle to GGP","id":623323},"id":2231990,"movingTime":209}}'
end
+
+ def login_failure_json
+ '{"success":"false","error":"Invalid email or password."}'
+ end
+
+ def login_success_json
+ '{"success":true,"token":"d41d8cd98f00b204e980","athlete_id":1234,"agreedToTerms":true,"superUser":false,"defaultSettings":{"sampleRate":3,"continuousGps":true,"accuracy":0,"distanceFilter":3,"maxSearchTime":30,"minStaleTime":300,"minAccuracy":150}}'
+ end
end
33 test/test_user_authentication.rb
View
@@ -0,0 +1,33 @@
+require 'helper'
+require 'mocha'
+require 'json'
+
+class TestUserAuthentication < Test::Unit::TestCase
+ def setup
+ @s = StravaApi::Base.new
+ end
+
+ def test_login_failure
+ api_result = JSON.parse login_failure_json
+ api_result.stubs(:parsed_response).returns("")
+ StravaApi::Base.stubs(:post).with('/authentication/login', {:body => {:email => "fail@gmail.com", :password => "secret"}}).returns(api_result)
+
+ expect_error(StravaApi::AuthenticationError) { @s.login("fail@gmail.com", "secret") }
+ end
+
+
+ def test_login_success
+ api_result = JSON.parse login_success_json
+ api_result.stubs(:parsed_response).returns("")
+ StravaApi::Base.stubs(:post).with('/authentication/login', { :body => {:email => "success@gmail.com", :password => "secret"} }).returns(api_result)
+
+ user = @s.login("success@gmail.com", "secret")
+
+ assert_instance_of StravaApi::User, user
+ assert_equal "d41d8cd98f00b204e980", user.token
+ assert_equal 1234, user.athlete_id
+ assert_instance_of StravaApi::Settings, user.default_settings
+ end
+
+
+end
Something went wrong with that request. Please try again.