strava-ruby-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +6 -0
- data/.rspec +2 -0
- data/.rubocop.yml +15 -0
- data/.rubocop_todo.yml +47 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +3 -0
- data/CONTRIBUTING.md +125 -0
- data/Dangerfile +2 -0
- data/Gemfile +15 -0
- data/LICENSE.md +22 -0
- data/README.md +231 -0
- data/RELEASING.md +61 -0
- data/Rakefile +17 -0
- data/bin/oauth-token.rb +28 -0
- data/lib/strava-ruby-client.rb +30 -0
- data/lib/strava/api/client.rb +38 -0
- data/lib/strava/api/config.rb +31 -0
- data/lib/strava/errors/fault.rb +13 -0
- data/lib/strava/logger.rb +13 -0
- data/lib/strava/models/activity.rb +57 -0
- data/lib/strava/models/athlete.rb +25 -0
- data/lib/strava/models/map.rb +9 -0
- data/lib/strava/models/model.rb +5 -0
- data/lib/strava/models/token.rb +12 -0
- data/lib/strava/oauth/client.rb +70 -0
- data/lib/strava/oauth/config.rb +33 -0
- data/lib/strava/version.rb +3 -0
- data/lib/strava/web/client.rb +31 -0
- data/lib/strava/web/config.rb +41 -0
- data/lib/strava/web/connection.rb +35 -0
- data/lib/strava/web/raise_error.rb +29 -0
- data/lib/strava/web/request.rb +38 -0
- data/spec/fixtures/strava/client_athlete.yml +59 -0
- data/spec/fixtures/strava/client_athlete_activities.yml +121 -0
- data/spec/fixtures/strava/oauth_token_authorization_code.yml +53 -0
- data/spec/fixtures/strava/oauth_token_invalid_client.yml +50 -0
- data/spec/fixtures/strava/oauth_token_invalid_code.yml +50 -0
- data/spec/fixtures/strava/oauth_token_refresh_token.yml +52 -0
- data/spec/spec_helper.rb +10 -0
- data/spec/strava/api/client_spec.rb +36 -0
- data/spec/strava/api/config_spec.rb +22 -0
- data/spec/strava/oauth/client_spec.rb +120 -0
- data/spec/strava/oauth/config_spec.rb +24 -0
- data/spec/strava/version_spec.rb +7 -0
- data/spec/strava/web/client_spec.rb +9 -0
- data/spec/strava/web/config_spec.rb +4 -0
- data/spec/support/shared/it_behaves_like_web_client.rb +131 -0
- data/spec/support/vcr.rb +12 -0
- data/strava-ruby-client.gemspec +21 -0
- metadata +150 -0
data/RELEASING.md
ADDED
@@ -0,0 +1,61 @@
|
|
1
|
+
# Releasing Strava-Ruby-Client
|
2
|
+
|
3
|
+
There're no hard rules about when to release strava-ruby-client. Release bug fixes frequently, features not so frequently and breaking API changes rarely.
|
4
|
+
|
5
|
+
### Release
|
6
|
+
|
7
|
+
Run tests, check that all tests succeed locally.
|
8
|
+
|
9
|
+
```
|
10
|
+
bundle install
|
11
|
+
rake
|
12
|
+
```
|
13
|
+
|
14
|
+
Check that the last build succeeded in [Travis CI](https://travis-ci.org/dblock/strava-ruby-client) for all supported platforms.
|
15
|
+
|
16
|
+
Change "Next" in [CHANGELOG.md](CHANGELOG.md) to the current date.
|
17
|
+
|
18
|
+
```
|
19
|
+
### 0.2.2 (7/10/2015)
|
20
|
+
```
|
21
|
+
|
22
|
+
Remove the line with "Your contribution here.", since there will be no more contributions to this release.
|
23
|
+
|
24
|
+
Commit your changes.
|
25
|
+
|
26
|
+
```
|
27
|
+
git add CHANGELOG.md
|
28
|
+
git commit -m "Preparing for release, 0.2.2."
|
29
|
+
git push origin master
|
30
|
+
```
|
31
|
+
|
32
|
+
Release.
|
33
|
+
|
34
|
+
```
|
35
|
+
$ rake release
|
36
|
+
|
37
|
+
strava-ruby-client 0.2.2 built to pkg/strava-ruby-client-0.2.2.gem.
|
38
|
+
Tagged v0.2.2.
|
39
|
+
Pushed git commits and tags.
|
40
|
+
Pushed strava-ruby-client 0.2.2 to rubygems.org.
|
41
|
+
```
|
42
|
+
|
43
|
+
### Prepare for the Next Version
|
44
|
+
|
45
|
+
Add the next release to [CHANGELOG.md](CHANGELOG.md).
|
46
|
+
|
47
|
+
```
|
48
|
+
### 0.2.3 (Next)
|
49
|
+
|
50
|
+
* Your contribution here.
|
51
|
+
```
|
52
|
+
|
53
|
+
Increment the third version number in [lib/strava/version.rb](lib/strava/version.rb).
|
54
|
+
|
55
|
+
Commit your changes.
|
56
|
+
|
57
|
+
```
|
58
|
+
git add CHANGELOG.md lib/strava/version.rb
|
59
|
+
git commit -m "Preparing for next development iteration, 0.2.3."
|
60
|
+
git push origin master
|
61
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
require 'bundler/gem_tasks'
|
4
|
+
|
5
|
+
Bundler.setup :default, :development
|
6
|
+
|
7
|
+
require 'rspec/core'
|
8
|
+
require 'rspec/core/rake_task'
|
9
|
+
|
10
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
11
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
12
|
+
end
|
13
|
+
|
14
|
+
require 'rubocop/rake_task'
|
15
|
+
RuboCop::RakeTask.new
|
16
|
+
|
17
|
+
task default: %i[rubocop spec]
|
data/bin/oauth-token.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'dotenv/load'
|
4
|
+
require 'strava-ruby-client'
|
5
|
+
|
6
|
+
client = Strava::OAuth::Client.new(
|
7
|
+
client_id: ENV['STRAVA_CLIENT_ID'],
|
8
|
+
client_secret: ENV['STRAVA_CLIENT_SECRET']
|
9
|
+
)
|
10
|
+
|
11
|
+
redirect_url = client.authorize_url(
|
12
|
+
redirect_uri: 'http://localhost',
|
13
|
+
response_type: 'code',
|
14
|
+
scope: 'activity:read'
|
15
|
+
)
|
16
|
+
|
17
|
+
STDOUT.write "Opening browser at #{redirect_url}\n"
|
18
|
+
system 'open', redirect_url
|
19
|
+
|
20
|
+
STDOUT.write 'Copy paste the code from the redirect URL: '
|
21
|
+
code = gets.strip
|
22
|
+
|
23
|
+
response = client.oauth_token(code: code)
|
24
|
+
|
25
|
+
puts "token_type: #{response.token_type}"
|
26
|
+
puts "refresh_token: #{response.refresh_token}"
|
27
|
+
puts "access_token: #{response.access_token}"
|
28
|
+
puts "expires_at: #{response.expires_at}"
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'faraday_middleware'
|
3
|
+
require 'json'
|
4
|
+
require 'logger'
|
5
|
+
require 'hashie'
|
6
|
+
require 'active_support/core_ext/object/to_query'
|
7
|
+
require 'time'
|
8
|
+
|
9
|
+
require_relative 'strava/version'
|
10
|
+
require_relative 'strava/logger'
|
11
|
+
|
12
|
+
require_relative 'strava/errors/fault'
|
13
|
+
|
14
|
+
require_relative 'strava/models/model'
|
15
|
+
require_relative 'strava/models/token'
|
16
|
+
require_relative 'strava/models/athlete'
|
17
|
+
require_relative 'strava/models/map'
|
18
|
+
require_relative 'strava/models/activity'
|
19
|
+
|
20
|
+
require_relative 'strava/web/raise_error'
|
21
|
+
require_relative 'strava/web/connection'
|
22
|
+
require_relative 'strava/web/request'
|
23
|
+
require_relative 'strava/web/config'
|
24
|
+
require_relative 'strava/web/client'
|
25
|
+
|
26
|
+
require_relative 'strava/oauth/config'
|
27
|
+
require_relative 'strava/oauth/client'
|
28
|
+
|
29
|
+
require_relative 'strava/api/config'
|
30
|
+
require_relative 'strava/api/client'
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Strava
|
2
|
+
module Api
|
3
|
+
class Client < Strava::Web::Client
|
4
|
+
attr_accessor(*Config::ATTRIBUTES)
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
Config::ATTRIBUTES.each do |key|
|
8
|
+
send("#{key}=", options[key] || Strava::Api.config.send(key))
|
9
|
+
end
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
def headers
|
14
|
+
{ 'Authorization' => "Bearer #{access_token}" }
|
15
|
+
end
|
16
|
+
|
17
|
+
def athlete
|
18
|
+
Strava::Models::Athlete.new(get('athlete'))
|
19
|
+
end
|
20
|
+
|
21
|
+
def athlete_activities(options = {})
|
22
|
+
get('athlete/activities', options).map do |activity|
|
23
|
+
Strava::Models::Activity.new(activity)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class << self
|
28
|
+
def configure
|
29
|
+
block_given? ? yield(Config) : Config
|
30
|
+
end
|
31
|
+
|
32
|
+
def config
|
33
|
+
Config
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Strava
|
2
|
+
module Api
|
3
|
+
module Config
|
4
|
+
extend self
|
5
|
+
|
6
|
+
ATTRIBUTES = %i[
|
7
|
+
endpoint
|
8
|
+
access_token
|
9
|
+
].freeze
|
10
|
+
|
11
|
+
attr_accessor(*Config::ATTRIBUTES)
|
12
|
+
|
13
|
+
def reset
|
14
|
+
self.endpoint = 'https://www.strava.com/api/v3'
|
15
|
+
self.access_token = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
class << self
|
20
|
+
def configure
|
21
|
+
block_given? ? yield(Config) : Config
|
22
|
+
end
|
23
|
+
|
24
|
+
def config
|
25
|
+
Config
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Strava::Api::Config.reset
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Strava
|
2
|
+
module Models
|
3
|
+
class Activity < Model
|
4
|
+
property 'id'
|
5
|
+
property 'resource_state'
|
6
|
+
property 'athlete', transform_with: ->(v) { Strava::Models::Athlete.new(v) }
|
7
|
+
property 'name'
|
8
|
+
property 'distance'
|
9
|
+
property 'moving_time'
|
10
|
+
property 'elapsed_time'
|
11
|
+
property 'total_elevation_gain'
|
12
|
+
property 'type'
|
13
|
+
property 'workout_type'
|
14
|
+
property 'id'
|
15
|
+
property 'external_id'
|
16
|
+
property 'upload_id'
|
17
|
+
property 'start_date', transform_with: ->(v) { Time.parse(v) }
|
18
|
+
property 'start_date_local', transform_with: ->(v) { Time.parse(v) }
|
19
|
+
property 'timezone'
|
20
|
+
property 'utc_offset'
|
21
|
+
property 'start_latlng'
|
22
|
+
property 'end_latlng'
|
23
|
+
property 'location_city'
|
24
|
+
property 'location_state'
|
25
|
+
property 'location_country'
|
26
|
+
property 'start_latitude'
|
27
|
+
property 'start_longitude'
|
28
|
+
property 'achievement_count'
|
29
|
+
property 'kudos_count'
|
30
|
+
property 'comment_count'
|
31
|
+
property 'athlete_count'
|
32
|
+
property 'photo_count'
|
33
|
+
property 'map', transform_with: ->(v) { Strava::Models::Map.new(v) }
|
34
|
+
property 'trainer'
|
35
|
+
property 'commute'
|
36
|
+
property 'manual'
|
37
|
+
property 'private'
|
38
|
+
property 'visibility'
|
39
|
+
property 'flagged'
|
40
|
+
property 'gear_id'
|
41
|
+
property 'from_accepted_tag'
|
42
|
+
property 'average_speed'
|
43
|
+
property 'max_speed'
|
44
|
+
property 'has_heartrate'
|
45
|
+
property 'average_heartrate'
|
46
|
+
property 'max_heartrate'
|
47
|
+
property 'heartrate_opt_out'
|
48
|
+
property 'display_hide_heartrate_option'
|
49
|
+
property 'elev_high'
|
50
|
+
property 'elev_low'
|
51
|
+
property 'pr_count'
|
52
|
+
property 'total_photo_count'
|
53
|
+
property 'has_kudoed'
|
54
|
+
property 'suffer_score'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Strava
|
2
|
+
module Models
|
3
|
+
class Athlete < Model
|
4
|
+
property 'id'
|
5
|
+
property 'username'
|
6
|
+
property 'resource_state'
|
7
|
+
property 'firstname'
|
8
|
+
property 'lastname'
|
9
|
+
property 'city'
|
10
|
+
property 'state'
|
11
|
+
property 'country'
|
12
|
+
property 'sex'
|
13
|
+
property 'premium'
|
14
|
+
property 'created_at', transform_with: ->(v) { Time.parse(v) }
|
15
|
+
property 'updated_at', transform_with: ->(v) { Time.parse(v) }
|
16
|
+
property 'badge_type_id'
|
17
|
+
property 'profile'
|
18
|
+
property 'profile_medium'
|
19
|
+
property 'email'
|
20
|
+
property 'follower'
|
21
|
+
property 'friend'
|
22
|
+
property 'summit'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module Strava
|
2
|
+
module Models
|
3
|
+
class Token < Model
|
4
|
+
property 'token_type'
|
5
|
+
property 'access_token'
|
6
|
+
property 'refresh_token'
|
7
|
+
property 'expires_in'
|
8
|
+
property 'expires_at', transform_with: ->(v) { Time.at(v) }
|
9
|
+
property 'athlete', transform_with: ->(v) { Strava::Models::Athlete.new(v) }
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Strava
|
2
|
+
module OAuth
|
3
|
+
class Client < Strava::Web::Client
|
4
|
+
attr_accessor(*Config::ATTRIBUTES)
|
5
|
+
|
6
|
+
def initialize(options = {})
|
7
|
+
Strava::OAuth::Config::ATTRIBUTES.each do |key|
|
8
|
+
send("#{key}=", options[key] || Strava::OAuth.config.send(key))
|
9
|
+
end
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
#
|
14
|
+
# Obtain the request access URL.
|
15
|
+
#
|
16
|
+
# @option options [Object] :redirect_uri
|
17
|
+
# URL to which the user will be redirected after authentication.
|
18
|
+
# @option options [Object] :response_type
|
19
|
+
# Must be code.
|
20
|
+
# @option options [Object] :approval_prompt
|
21
|
+
# Prompt behavior, force or auto.
|
22
|
+
# @option options [Object] :scope
|
23
|
+
# Requested scopes, as a comma delimited string.
|
24
|
+
# @option options [Object] :state
|
25
|
+
# Returned in the redirect URI.
|
26
|
+
# @see https://developers.strava.com/docs/authentication/
|
27
|
+
# @return [String] URL to redirect the user to.
|
28
|
+
def authorize_url(options = {})
|
29
|
+
query = options.merge(
|
30
|
+
client_id: client_id || raise(ArgumentError, 'Missing Strava client id.'),
|
31
|
+
response_type: options[:response_type] || 'code',
|
32
|
+
redirect_uri: options[:redirect_uri] || 'http://localhost',
|
33
|
+
approval_prompt: options[:approval_prompt] || 'auto',
|
34
|
+
scope: options[:scope] || 'read'
|
35
|
+
)
|
36
|
+
|
37
|
+
[endpoint, "authorize?#{query.to_query}"].join('/')
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
# Complete the authentication process.
|
42
|
+
#
|
43
|
+
# @option options [Object] :code
|
44
|
+
# The code parameter obtained in the redirect.
|
45
|
+
# @option options [Object] :grant_type
|
46
|
+
# The grant type for the request.
|
47
|
+
# @see https://developers.strava.com/docs/authentication/
|
48
|
+
# @return [Hash] Token information.
|
49
|
+
def oauth_token(options = {})
|
50
|
+
query = options.merge(
|
51
|
+
client_id: client_id || raise(ArgumentError, 'Missing Strava client id.'),
|
52
|
+
client_secret: client_secret || raise(ArgumentError, 'Missing Strava client secret.'),
|
53
|
+
grant_type: options[:grant_type] || 'authorization_code'
|
54
|
+
)
|
55
|
+
|
56
|
+
Strava::Models::Token.new(post('token', query))
|
57
|
+
end
|
58
|
+
|
59
|
+
class << self
|
60
|
+
def configure
|
61
|
+
block_given? ? yield(Config) : Config
|
62
|
+
end
|
63
|
+
|
64
|
+
def config
|
65
|
+
Config
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Strava
|
2
|
+
module OAuth
|
3
|
+
module Config
|
4
|
+
extend self
|
5
|
+
|
6
|
+
ATTRIBUTES = %i[
|
7
|
+
endpoint
|
8
|
+
client_id
|
9
|
+
client_secret
|
10
|
+
].freeze
|
11
|
+
|
12
|
+
attr_accessor(*Config::ATTRIBUTES)
|
13
|
+
|
14
|
+
def reset
|
15
|
+
self.endpoint = 'https://www.strava.com/oauth'
|
16
|
+
self.client_id = nil
|
17
|
+
self.client_secret = nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class << self
|
22
|
+
def configure
|
23
|
+
block_given? ? yield(Config) : Config
|
24
|
+
end
|
25
|
+
|
26
|
+
def config
|
27
|
+
Config
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Strava::OAuth::Config.reset
|