strava-ruby-client 0.2.0 → 0.3.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 (53) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/README.md +710 -88
  4. data/bin/strava-webhooks.rb +56 -0
  5. data/lib/strava-ruby-client.rb +37 -0
  6. data/lib/strava/api/client.rb +11 -141
  7. data/lib/strava/api/endpoints/activities.rb +120 -0
  8. data/lib/strava/api/endpoints/athletes.rb +42 -0
  9. data/lib/strava/api/endpoints/clubs.rb +75 -0
  10. data/lib/strava/api/endpoints/gears.rb +18 -0
  11. data/lib/strava/api/endpoints/routes.rb +55 -0
  12. data/lib/strava/api/endpoints/running_races.rb +30 -0
  13. data/lib/strava/api/endpoints/segment_efforts.rb +33 -0
  14. data/lib/strava/api/endpoints/segments.rb +111 -0
  15. data/lib/strava/api/endpoints/streams.rb +61 -0
  16. data/lib/strava/api/endpoints/uploads.rb +40 -0
  17. data/lib/strava/logger.rb +1 -1
  18. data/lib/strava/models/achievement.rb +9 -0
  19. data/lib/strava/models/activity.rb +11 -5
  20. data/lib/strava/models/activity_stats.rb +17 -0
  21. data/lib/strava/models/activity_total.rb +17 -0
  22. data/lib/strava/models/athlete.rb +10 -0
  23. data/lib/strava/models/club.rb +6 -0
  24. data/lib/strava/models/club_admin.rb +13 -0
  25. data/lib/strava/models/club_member.rb +16 -0
  26. data/lib/strava/models/explorer_segment.rb +19 -0
  27. data/lib/strava/models/gear.rb +5 -0
  28. data/lib/strava/models/heart_rate_zone_ranges.rb +8 -0
  29. data/lib/strava/models/kudoser.rb +10 -0
  30. data/lib/strava/models/lap.rb +3 -0
  31. data/lib/strava/models/mixins/distance.rb +18 -0
  32. data/lib/strava/models/power_zone_ranges.rb +7 -0
  33. data/lib/strava/models/route.rb +27 -0
  34. data/lib/strava/models/running_race.rb +33 -0
  35. data/lib/strava/models/segment.rb +15 -3
  36. data/lib/strava/models/segment_effort.rb +7 -2
  37. data/lib/strava/models/segment_leaderboard.rb +10 -0
  38. data/lib/strava/models/segment_leaderboard_entry.rb +12 -0
  39. data/lib/strava/models/segment_stats.rb +15 -0
  40. data/lib/strava/models/stream.rb +10 -0
  41. data/lib/strava/models/stream_set.rb +17 -0
  42. data/lib/strava/models/upload.rb +11 -0
  43. data/lib/strava/models/zone_range.rb +8 -0
  44. data/lib/strava/models/zones.rb +8 -0
  45. data/lib/strava/version.rb +1 -1
  46. data/lib/strava/web/client.rb +11 -1
  47. data/lib/strava/web/connection.rb +1 -1
  48. data/lib/strava/webhooks/client.rb +58 -0
  49. data/lib/strava/webhooks/config.rb +33 -0
  50. data/lib/strava/webhooks/models/challenge.rb +15 -0
  51. data/lib/strava/webhooks/models/event.rb +15 -0
  52. data/lib/strava/webhooks/models/subscription.rb +14 -0
  53. metadata +37 -2
@@ -0,0 +1,18 @@
1
+ module Strava
2
+ module Api
3
+ module Endpoints
4
+ module Gears
5
+ #
6
+ # Returns an equipment using its identifier.
7
+ #
8
+ # @option options [String] :id
9
+ # Gear id.
10
+ #
11
+ def gear(id_or_options, options = {})
12
+ id, options = parse_args(id_or_options, options)
13
+ Strava::Models::Gear.new(get("gear/#{id}", options))
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,55 @@
1
+ module Strava
2
+ module Api
3
+ module Endpoints
4
+ module Routes
5
+ #
6
+ # Returns a GPX file of the route.
7
+ #
8
+ # @option options [String] :id
9
+ # Route id.
10
+ #
11
+ def export_route_gpx(id_or_options, options = {})
12
+ id, options = parse_args(id_or_options, options)
13
+ get "routes/#{id}/export_gpx", options
14
+ end
15
+
16
+ #
17
+ # Returns a TCS file of the route.
18
+ #
19
+ # @option options [String] :id
20
+ # Route id.
21
+ #
22
+ def export_route_tcx(id_or_options, options = {})
23
+ id, options = parse_args(id_or_options, options)
24
+ get "routes/#{id}/export_tcx", options
25
+ end
26
+
27
+ #
28
+ # Returns a route using its identifier.
29
+ #
30
+ # @option options [String] :id
31
+ # Route id.
32
+ #
33
+ def route(id_or_options, options = {})
34
+ id, options = parse_args(id_or_options, options)
35
+ Strava::Models::Route.new(get("routes/#{id}", options))
36
+ end
37
+
38
+ #
39
+ # Returns a list of the routes created by the authenticated athlete using their athlete ID.
40
+ #
41
+ # @option options [Integer] :id
42
+ # The identifier of the athlete.
43
+ # @option options [Integer] :page
44
+ # Page number.
45
+ # @option options [Integer] :per_page
46
+ # Number of items per page. Defaults to 30.
47
+ #
48
+ def athlete_routes(id_or_options, options = {}, &block)
49
+ id, options = parse_args(id_or_options, options)
50
+ paginate "athletes/#{id}/routes", options, Strava::Models::Route, &block
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,30 @@
1
+ module Strava
2
+ module Api
3
+ module Endpoints
4
+ module RunningRaces
5
+ #
6
+ # Returns a running race for a given identifier.
7
+ #
8
+ # @option options [String] :id
9
+ # The identifier of the running race.
10
+ #
11
+ def running_race(id_or_options, options = {})
12
+ id, options = parse_args(id_or_options, options)
13
+ Strava::Models::RunningRace.new(get("running_races/#{id}", options))
14
+ end
15
+
16
+ #
17
+ # Returns a list running races based on a set of search criteria.
18
+ #
19
+ # @option options [Integer] :year
20
+ # Filters the list by a given year.
21
+ #
22
+ def running_races(options = {})
23
+ get('running_races', options).map do |row|
24
+ Strava::Models::RunningRace.new(row)
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,33 @@
1
+ module Strava
2
+ module Api
3
+ module Endpoints
4
+ module SegmentEfforts
5
+ #
6
+ # Returns a segment effort from an activity that is owned by the authenticated athlete.
7
+ #
8
+ # @option options [String] :id
9
+ # The identifier of the segment effort.
10
+ #
11
+ def segment_effort(id_or_options, options = {})
12
+ id, options = parse_args(id_or_options, options)
13
+ Strava::Models::SegmentEffort.new(get("segment_efforts/#{id}", options))
14
+ end
15
+
16
+ #
17
+ # Returns a set of the authenticated athlete's segment efforts for a given segment.
18
+ #
19
+ # @option options [Integer] :id
20
+ # The identifier of the segment.
21
+ # @option options [Integer] :page
22
+ # Page number.
23
+ # @option options [Integer] :per_page
24
+ # Number of items per page. Defaults to 30.
25
+ #
26
+ def segment_efforts(id_or_options, options = {}, &block)
27
+ id, options = parse_args(id_or_options, options)
28
+ paginate "segments/#{id}/all_efforts", options, Strava::Models::SegmentEffort, &block
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,111 @@
1
+ module Strava
2
+ module Api
3
+ module Endpoints
4
+ module Segments
5
+ #
6
+ # Returns the top 10 segments matching a specified query.
7
+ #
8
+ # @option options [Array[Float]] :bounds
9
+ # The latitude and longitude for two points describing a rectangular boundary for the search: [southwest corner latitude, southwest corner longitude, northeast corner latitude, northeast corner longitude].
10
+ # @option options [String] :activity_type
11
+ # Desired activity type. May take one of the following values: running, riding.
12
+ # @option options [Integer] :min_cat
13
+ # The minimum climbing category.
14
+ # @option options [Integer] :max_cat
15
+ # The maximum climbing category.
16
+ #
17
+ def explore_segments(options = {})
18
+ throw ArgumentError.new('Required argument :bounds missing') if options[:bounds].nil?
19
+ bounds = options[:bounds]
20
+ bounds = bounds.map(&:to_s).join(',') if bounds.is_a?(Array)
21
+ get('segments/explore', options.merge(bounds: bounds))['segments'].map do |row|
22
+ Strava::Models::ExplorerSegment.new(row)
23
+ end
24
+ end
25
+
26
+ #
27
+ # Returns the specified segment leaderboard.
28
+ #
29
+ # @option options [Integer] :id
30
+ # The identifier of the segment leaderboard.
31
+ # @option options [String] :gender
32
+ # Filter by gender.
33
+ # @option options [String] :age_group
34
+ # Filter by age group.
35
+ # @option options [String] :weight_class
36
+ # Filter by weight class.
37
+ # @option options [Boolean] :following
38
+ # Filter by friends of the authenticated athlete.
39
+ # @option options [Integer] :club_id
40
+ # Filter by club.
41
+ # @option options [String] :date_range
42
+ # Filter by date range.
43
+ # @option options [Integer] :context_entries
44
+ # ?
45
+ # @option options [Integer] :page
46
+ # Page number.
47
+ # @option options [Integer] :per_page
48
+ # Number of items per page. Defaults to 30.
49
+ #
50
+ def segment_leaderboard(id_or_options, options = {})
51
+ id, options = parse_args(id_or_options, options)
52
+
53
+ if block_given?
54
+ next_page = 1
55
+ total_count = 0
56
+ loop do
57
+ query = options.merge(page: next_page)
58
+ response = Strava::Models::SegmentLeaderboard.new(get("segments/#{id}/leaderboard", query))
59
+ total_count += response.entries.count
60
+ break unless response.entries.any?
61
+
62
+ yield response
63
+ break if total_count >= response.entry_count
64
+
65
+ next_page += 1
66
+ end
67
+ else
68
+ Strava::Models::SegmentLeaderboard.new(get("segments/#{id}/leaderboard", options))
69
+ end
70
+ end
71
+
72
+ #
73
+ # List of the authenticated athlete's starred segments.
74
+ #
75
+ # @option options [Integer] :page
76
+ # Page number.
77
+ # @option options [Integer] :per_page
78
+ # Number of items per page. Defaults to 30.
79
+ #
80
+ def starred_segments(options = {}, &block)
81
+ paginate 'segments/starred', options, Strava::Models::Segment, &block
82
+ end
83
+
84
+ #
85
+ # Returns the specified segment.
86
+ #
87
+ # @option options [String] :id
88
+ # The identifier of the segment.
89
+ #
90
+ def segment(id_or_options, options = {})
91
+ id, options = parse_args(id_or_options, options)
92
+ Strava::Models::Segment.new(get("segments/#{id}", options))
93
+ end
94
+
95
+ #
96
+ # Stars/Unstars the given segment for the authenticated athlete.
97
+ #
98
+ # @option options [String] :id
99
+ # The identifier of the segment to star.
100
+ # @option options [Boolean] :starred
101
+ # If true, star the segment; if false, unstar the segment.
102
+ #
103
+ def star_segment(id_or_options, options = {})
104
+ id, options = parse_args(id_or_options, options)
105
+ throw ArgumentError.new('Required argument :starred missing') if options[:starred].nil?
106
+ Strava::Models::Segment.new(put("segments/#{id}/starred", options))
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,61 @@
1
+ module Strava
2
+ module Api
3
+ module Endpoints
4
+ module Streams
5
+ #
6
+ # Returns the given activity's streams.
7
+ #
8
+ # @option options [String] :id
9
+ # The identifier of the activity.
10
+ # @option options [Array[String]] :keys
11
+ # Desired stream types.
12
+ # @option options [Boolean] :key_by_type
13
+ # Must be true.
14
+ #
15
+ def activity_streams(id_or_options, options = {})
16
+ id, options = parse_args(id_or_options, options)
17
+ query = options.dup
18
+ query[:key_by_type] = true unless options.key?(:key_by_type)
19
+ query[:keys] = options[:keys].join(',') if options[:keys] && options[:keys].is_a?(Array)
20
+ Strava::Models::StreamSet.new(get("activities/#{id}/streams", query))
21
+ end
22
+
23
+ #
24
+ # Returns a set of streams for a segment effort completed by the authenticated athlete.
25
+ #
26
+ # @option options [String] :id
27
+ # The identifier of the segment effort.
28
+ # @option options [Array[String]] :keys
29
+ # The types of streams to return.
30
+ # @option options [Boolean] :key_by_type
31
+ # Must be true.
32
+ #
33
+ def segment_effort_streams(id_or_options, options = {})
34
+ id, options = parse_args(id_or_options, options)
35
+ query = options.dup
36
+ query[:key_by_type] = true unless options.key?(:key_by_type)
37
+ query[:keys] = options[:keys].join(',') if options[:keys] && options[:keys].is_a?(Array)
38
+ Strava::Models::StreamSet.new(get("segment_efforts/#{id}/streams", query))
39
+ end
40
+
41
+ #
42
+ # Returns the given segment's streams.
43
+ #
44
+ # @option options [String] :id
45
+ # The identifier of the segment.
46
+ # @option options [Array[String]] :keys
47
+ # The types of streams to return.
48
+ # @option options [Boolean] :key_by_type
49
+ # Must be true.
50
+ #
51
+ def segment_streams(id_or_options, options = {})
52
+ id, options = parse_args(id_or_options, options)
53
+ query = options.dup
54
+ query[:key_by_type] = true unless options.key?(:key_by_type)
55
+ query[:keys] = options[:keys].join(',') if options[:keys] && options[:keys].is_a?(Array)
56
+ Strava::Models::StreamSet.new(get("segments/#{id}/streams", query))
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,40 @@
1
+ module Strava
2
+ module Api
3
+ module Endpoints
4
+ module Uploads
5
+ #
6
+ # Uploads a new data file to create an activity from.
7
+ #
8
+ # @option options [File] :file
9
+ # The uploaded file.
10
+ # @option options [String] :name
11
+ # The desired name of the resulting activity.
12
+ # @option options [String] :description
13
+ # The desired description of the resulting activity.
14
+ # @option options [Boolean] :trainer
15
+ # Whether the resulting activity should be marked as having been performed on a trainer.
16
+ # @option options [Boolean] :commute
17
+ # Whether the resulting activity should be tagged as a commute.
18
+ # @option options [String] :data_type
19
+ # The format of the uploaded file.
20
+ # @option options [String] :external_id
21
+ # The desired external identifier of the resulting activity.
22
+ #
23
+ def create_upload(options = {})
24
+ Strava::Models::Upload.new(post('uploads', options))
25
+ end
26
+
27
+ #
28
+ # Returns an upload for a given identifier.
29
+ #
30
+ # @option options [String] :id
31
+ # The identifier of the upload.
32
+ #
33
+ def upload(id_or_options, options = {})
34
+ id, options = parse_args(id_or_options, options)
35
+ Strava::Models::Upload.new(get("uploads/#{id}", options))
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -2,7 +2,7 @@ require 'logger'
2
2
 
3
3
  module Strava
4
4
  class Logger < ::Logger
5
- def self.default
5
+ def self.logger
6
6
  @logger ||= begin
7
7
  logger = new STDOUT
8
8
  logger.level = Logger::WARN
@@ -0,0 +1,9 @@
1
+ module Strava
2
+ module Models
3
+ class Achievement < Model
4
+ property 'rank'
5
+ property 'type'
6
+ property 'type_id'
7
+ end
8
+ end
9
+ end
@@ -1,7 +1,7 @@
1
1
  module Strava
2
2
  module Models
3
3
  class Activity < Model
4
- include Mixins::Distance
4
+ include Mixins::MetricDistance
5
5
  include Mixins::Time
6
6
  include Mixins::Elevation
7
7
 
@@ -65,10 +65,16 @@ module Strava
65
65
  property 'laps', transform_with: ->(v) { v.map { |r| Strava::Models::Lap.new(r) } }
66
66
  property 'gear', transform_with: ->(v) { Strava::Models::Gear.new(v) }
67
67
  property 'device_name'
68
-
69
- def units
70
- :metric
71
- end
68
+ property 'average_cadence'
69
+ property 'average_temp'
70
+ property 'average_watts'
71
+ property 'weighted_average_watts'
72
+ property 'kilojoules'
73
+ property 'device_watts'
74
+ property 'max_watts'
75
+ property 'highlighted_kudosers', transform_with: ->(v) { v.map { |r| Strava::Models::Kudoser.new(r) } }
76
+ property 'segment_leaderboard_opt_out'
77
+ property 'leaderboard_opt_out'
72
78
 
73
79
  def distance_s
74
80
  if type == 'Swim'
@@ -0,0 +1,17 @@
1
+ module Strava
2
+ module Models
3
+ class ActivityStats < Model
4
+ property 'biggest_ride_distance'
5
+ property 'biggest_climb_elevation_gain'
6
+ property 'recent_ride_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
7
+ property 'recent_run_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
8
+ property 'recent_swim_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
9
+ property 'ytd_ride_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
10
+ property 'ytd_run_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
11
+ property 'ytd_swim_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
12
+ property 'all_ride_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
13
+ property 'all_run_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
14
+ property 'all_swim_totals', transform_with: ->(v) { Strava::Models::ActivityTotal.new(v) }
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,17 @@
1
+ module Strava
2
+ module Models
3
+ class ActivityTotal < Model
4
+ include Mixins::MetricDistance
5
+ include Mixins::Time
6
+ include Mixins::Elevation
7
+
8
+ property 'count'
9
+ property 'achievement_count'
10
+ property 'elevation_gain'
11
+
12
+ def total_elevation_gain
13
+ elevation_gain
14
+ end
15
+ end
16
+ end
17
+ end
@@ -20,6 +20,16 @@ module Strava
20
20
  property 'follower'
21
21
  property 'friend'
22
22
  property 'summit'
23
+ property 'follower_count'
24
+ property 'friend_count'
25
+ property 'mutual_friend_count'
26
+ property 'athlete_type'
27
+ property 'date_preference'
28
+ property 'measurement_preference'
29
+ property 'clubs', transform_with: ->(v) { v.map { |r| Strava::Models::Club.new(r) } }
30
+ property 'weight'
31
+ property 'bikes', transform_with: ->(v) { v.map { |r| Strava::Models::Gear.new(r) } }
32
+ property 'shoes', transform_with: ->(v) { v.map { |r| Strava::Models::Gear.new(r) } }
23
33
 
24
34
  def name
25
35
  [firstname, lastname].compact.join(' ') if firstname || lastname