strava-ruby-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +6 -0
  3. data/.rspec +2 -0
  4. data/.rubocop.yml +15 -0
  5. data/.rubocop_todo.yml +47 -0
  6. data/.travis.yml +9 -0
  7. data/CHANGELOG.md +3 -0
  8. data/CONTRIBUTING.md +125 -0
  9. data/Dangerfile +2 -0
  10. data/Gemfile +15 -0
  11. data/LICENSE.md +22 -0
  12. data/README.md +231 -0
  13. data/RELEASING.md +61 -0
  14. data/Rakefile +17 -0
  15. data/bin/oauth-token.rb +28 -0
  16. data/lib/strava-ruby-client.rb +30 -0
  17. data/lib/strava/api/client.rb +38 -0
  18. data/lib/strava/api/config.rb +31 -0
  19. data/lib/strava/errors/fault.rb +13 -0
  20. data/lib/strava/logger.rb +13 -0
  21. data/lib/strava/models/activity.rb +57 -0
  22. data/lib/strava/models/athlete.rb +25 -0
  23. data/lib/strava/models/map.rb +9 -0
  24. data/lib/strava/models/model.rb +5 -0
  25. data/lib/strava/models/token.rb +12 -0
  26. data/lib/strava/oauth/client.rb +70 -0
  27. data/lib/strava/oauth/config.rb +33 -0
  28. data/lib/strava/version.rb +3 -0
  29. data/lib/strava/web/client.rb +31 -0
  30. data/lib/strava/web/config.rb +41 -0
  31. data/lib/strava/web/connection.rb +35 -0
  32. data/lib/strava/web/raise_error.rb +29 -0
  33. data/lib/strava/web/request.rb +38 -0
  34. data/spec/fixtures/strava/client_athlete.yml +59 -0
  35. data/spec/fixtures/strava/client_athlete_activities.yml +121 -0
  36. data/spec/fixtures/strava/oauth_token_authorization_code.yml +53 -0
  37. data/spec/fixtures/strava/oauth_token_invalid_client.yml +50 -0
  38. data/spec/fixtures/strava/oauth_token_invalid_code.yml +50 -0
  39. data/spec/fixtures/strava/oauth_token_refresh_token.yml +52 -0
  40. data/spec/spec_helper.rb +10 -0
  41. data/spec/strava/api/client_spec.rb +36 -0
  42. data/spec/strava/api/config_spec.rb +22 -0
  43. data/spec/strava/oauth/client_spec.rb +120 -0
  44. data/spec/strava/oauth/config_spec.rb +24 -0
  45. data/spec/strava/version_spec.rb +7 -0
  46. data/spec/strava/web/client_spec.rb +9 -0
  47. data/spec/strava/web/config_spec.rb +4 -0
  48. data/spec/support/shared/it_behaves_like_web_client.rb +131 -0
  49. data/spec/support/vcr.rb +12 -0
  50. data/strava-ruby-client.gemspec +21 -0
  51. metadata +150 -0
@@ -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
+ ```
@@ -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]
@@ -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,13 @@
1
+ module Strava
2
+ module Errors
3
+ class Fault < ::Faraday::ClientError
4
+ def message
5
+ response[:body]['message'] || super
6
+ end
7
+
8
+ def errors
9
+ response[:body]['errors']
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ require 'logger'
2
+
3
+ module Strava
4
+ class Logger < ::Logger
5
+ def self.default
6
+ @logger ||= begin
7
+ logger = new STDOUT
8
+ logger.level = Logger::WARN
9
+ logger
10
+ end
11
+ end
12
+ end
13
+ end
@@ -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,9 @@
1
+ module Strava
2
+ module Models
3
+ class Map < Model
4
+ property 'id'
5
+ property 'summary_polyline'
6
+ property 'resource_state'
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,5 @@
1
+ module Strava
2
+ class Model < Hashie::Trash
3
+ include Hashie::Extensions::IgnoreUndeclared
4
+ end
5
+ 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