strava-ruby-client 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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