strava-ruby-client 3.0.0 → 3.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/README.md +41 -57
- data/lib/strava/api/client.rb +69 -0
- data/lib/strava/api/config.rb +40 -0
- data/lib/strava/api/cursor.rb +32 -1
- data/lib/strava/api/endpoints/activities.rb +197 -57
- data/lib/strava/api/endpoints/athletes.rb +64 -8
- data/lib/strava/api/endpoints/clubs.rb +24 -59
- data/lib/strava/api/endpoints/gears.rb +11 -2
- data/lib/strava/api/endpoints/oauth.rb +45 -0
- data/lib/strava/api/endpoints/routes.rb +20 -13
- data/lib/strava/api/endpoints/segment_efforts.rb +15 -8
- data/lib/strava/api/endpoints/segments.rb +74 -21
- data/lib/strava/api/endpoints/streams.rb +22 -18
- data/lib/strava/api/endpoints/uploads.rb +12 -2
- data/lib/strava/api/pagination.rb +25 -0
- data/lib/strava/api/ratelimit.rb +34 -0
- data/lib/strava/deep_copyable.rb +20 -1
- data/lib/strava/errors/fault.rb +32 -0
- data/lib/strava/errors/ratelimit_error.rb +35 -0
- data/lib/strava/errors/upload_error.rb +55 -0
- data/lib/strava/logger.rb +27 -0
- data/lib/strava/models/achievement.rb +28 -1
- data/lib/strava/models/activity_stats.rb +47 -1
- data/lib/strava/models/activity_total.rb +25 -1
- data/lib/strava/models/activity_zone.rb +39 -2
- data/lib/strava/models/authorization.rb +13 -0
- data/lib/strava/models/base_stream.rb +22 -1
- data/lib/strava/models/club_event.rb +64 -1
- data/lib/strava/models/comment.rb +39 -1
- data/lib/strava/models/destination.rb +28 -1
- data/lib/strava/models/detailed_activity.rb +203 -2
- data/lib/strava/models/detailed_athlete.rb +104 -2
- data/lib/strava/models/detailed_club.rb +76 -2
- data/lib/strava/models/detailed_gear.rb +45 -2
- data/lib/strava/models/detailed_photo.rb +61 -1
- data/lib/strava/models/detailed_photos.rb +29 -1
- data/lib/strava/models/detailed_segment.rb +89 -2
- data/lib/strava/models/detailed_segment_effort.rb +92 -3
- data/lib/strava/models/explorer_segment.rb +55 -2
- data/lib/strava/models/heart_rate_zone_ranges.rb +29 -1
- data/lib/strava/models/kudoser.rb +29 -1
- data/lib/strava/models/lap.rb +62 -2
- data/lib/strava/models/lat_lng.rb +42 -4
- data/lib/strava/models/local_legend.rb +41 -1
- data/lib/strava/models/map.rb +31 -0
- data/lib/strava/models/meta_activity.rb +15 -2
- data/lib/strava/models/meta_athlete.rb +17 -2
- data/lib/strava/models/meta_club.rb +15 -1
- data/lib/strava/models/mixins/average_speed.rb +81 -3
- data/lib/strava/models/mixins/distance.rb +25 -0
- data/lib/strava/models/mixins/elapsed_time.rb +18 -0
- data/lib/strava/models/mixins/elevation_difference.rb +42 -0
- data/lib/strava/models/mixins/elevation_gain.rb +39 -0
- data/lib/strava/models/mixins/estimated_moving_time.rb +18 -0
- data/lib/strava/models/mixins/http_response.rb +36 -0
- data/lib/strava/models/mixins/moving_time.rb +18 -0
- data/lib/strava/models/mixins/sport_type.rb +39 -1
- data/lib/strava/models/mixins/start_date_local.rb +40 -24
- data/lib/strava/models/mixins/time_in_hours.rb +23 -0
- data/lib/strava/models/mixins/total_elevation_gain.rb +42 -0
- data/lib/strava/models/model.rb +14 -0
- data/lib/strava/models/photos_summary.rb +26 -2
- data/lib/strava/models/photos_summary_primary.rb +28 -2
- data/lib/strava/models/power_zone_ranges.rb +23 -1
- data/lib/strava/models/response.rb +18 -0
- data/lib/strava/models/route.rb +63 -2
- data/lib/strava/models/similar_activities.rb +57 -1
- data/lib/strava/models/split.rb +27 -2
- data/lib/strava/models/stats_visibility.rb +24 -1
- data/lib/strava/models/stream.rb +107 -0
- data/lib/strava/models/stream_set.rb +52 -1
- data/lib/strava/models/summary_activity.rb +145 -2
- data/lib/strava/models/summary_athlete.rb +54 -1
- data/lib/strava/models/summary_club.rb +61 -2
- data/lib/strava/models/summary_gear.rb +31 -2
- data/lib/strava/models/summary_pr_segment_effort.rb +32 -2
- data/lib/strava/models/summary_segment.rb +80 -2
- data/lib/strava/models/summary_segment_effort.rb +32 -1
- data/lib/strava/models/timed_zone_range.rb +24 -1
- data/lib/strava/models/token.rb +31 -0
- data/lib/strava/models/trend.rb +38 -1
- data/lib/strava/models/updatable_activity.rb +36 -1
- data/lib/strava/models/upload.rb +50 -1
- data/lib/strava/models/waypoint.rb +31 -1
- data/lib/strava/models/xoms.rb +35 -1
- data/lib/strava/models/zone_range.rb +20 -1
- data/lib/strava/models/zones.rb +32 -1
- data/lib/strava/oauth/client.rb +107 -19
- data/lib/strava/oauth/config.rb +41 -0
- data/lib/strava/version.rb +1 -1
- data/lib/strava/web/api_response.rb +28 -2
- data/lib/strava/web/client.rb +72 -2
- data/lib/strava/web/config.rb +40 -0
- data/lib/strava/web/connection.rb +39 -0
- data/lib/strava/web/raise_response_error.rb +47 -0
- data/lib/strava/web/request.rb +56 -0
- data/lib/strava/web/response.rb +18 -0
- data/lib/strava/webhooks/client.rb +108 -7
- data/lib/strava/webhooks/config.rb +44 -0
- data/lib/strava/webhooks/models/challenge.rb +40 -0
- data/lib/strava/webhooks/models/event.rb +50 -0
- data/lib/strava/webhooks/models/subscription.rb +27 -0
- data/lib/strava-ruby-client.rb +0 -2
- metadata +2 -4
- data/lib/strava/models/club_activity.rb +0 -22
- data/lib/strava/models/club_athlete.rb +0 -21
|
@@ -2,87 +2,288 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents a detailed Strava activity.
|
|
7
|
+
#
|
|
8
|
+
# A detailed activity contains all information about a single workout, ride, run,
|
|
9
|
+
# or other athletic pursuit recorded on Strava. This includes basic information
|
|
10
|
+
# (name, type, date), metrics (distance, time, elevation), maps, segments, photos,
|
|
11
|
+
# and social interactions (kudos, comments).
|
|
12
|
+
#
|
|
13
|
+
# This model includes several mixins that provide helper methods for formatting data:
|
|
14
|
+
# * {Mixins::Distance} - distance_s, distance_in_miles, etc.
|
|
15
|
+
# * {Mixins::MovingTime} - moving_time_in_hours_s, etc.
|
|
16
|
+
# * {Mixins::ElapsedTime} - elapsed_time_in_hours_s, etc.
|
|
17
|
+
# * {Mixins::AverageSpeed} - average_speed_s, pace_s, etc.
|
|
18
|
+
# * {Mixins::TotalElevationGain} - total_elevation_gain_s, etc.
|
|
19
|
+
# * {Mixins::SportType} - sport_type_emoji
|
|
20
|
+
#
|
|
21
|
+
# @example Get and display activity details
|
|
22
|
+
# activity = client.activity(1234567890)
|
|
23
|
+
# puts activity.name
|
|
24
|
+
# puts "Distance: #{activity.distance_s}"
|
|
25
|
+
# puts "Time: #{activity.moving_time_in_hours_s}"
|
|
26
|
+
# puts "Pace: #{activity.pace_s}"
|
|
27
|
+
# puts "Elevation: #{activity.total_elevation_gain_s}"
|
|
28
|
+
# puts "URL: #{activity.strava_url}"
|
|
29
|
+
#
|
|
30
|
+
# @see https://developers.strava.com/docs/reference/#api-models-DetailedActivity
|
|
31
|
+
#
|
|
6
32
|
class DetailedActivity < Strava::Models::Response
|
|
33
|
+
# @return [Integer] Activity ID
|
|
7
34
|
property 'id'
|
|
35
|
+
|
|
36
|
+
# @return [String, nil] External ID from the original upload source
|
|
8
37
|
property 'external_id'
|
|
38
|
+
|
|
39
|
+
# @return [Integer, nil] Upload ID
|
|
9
40
|
property 'upload_id'
|
|
41
|
+
|
|
42
|
+
# @return [MetaAthlete] The athlete who performed the activity
|
|
10
43
|
property 'athlete', transform_with: ->(v) { Strava::Models::MetaAthlete.new(v) }
|
|
44
|
+
|
|
45
|
+
# @return [String] Activity name
|
|
11
46
|
property 'name'
|
|
47
|
+
|
|
12
48
|
include Mixins::Distance
|
|
13
49
|
include Mixins::MovingTime
|
|
14
50
|
include Mixins::ElapsedTime
|
|
15
51
|
include Mixins::AverageSpeed
|
|
16
52
|
include Mixins::TotalElevationGain
|
|
53
|
+
|
|
54
|
+
# @return [Float, nil] Highest elevation in meters
|
|
17
55
|
property 'elev_high'
|
|
56
|
+
|
|
57
|
+
# @return [Float, nil] Lowest elevation in meters
|
|
18
58
|
property 'elev_low'
|
|
59
|
+
|
|
19
60
|
include Mixins::SportType
|
|
61
|
+
|
|
62
|
+
# @return [Time] Start date and time (UTC)
|
|
20
63
|
property 'start_date', transform_with: ->(v) { Time.parse(v) }
|
|
64
|
+
|
|
21
65
|
include Mixins::StartDateLocal
|
|
66
|
+
|
|
67
|
+
# @return [String] Timezone in which the activity was recorded (e.g., '(GMT-08:00) America/Los_Angeles')
|
|
22
68
|
property 'timezone'
|
|
69
|
+
|
|
70
|
+
# @return [LatLng, nil] Starting coordinates [latitude, longitude]
|
|
23
71
|
property 'start_latlng', transform_with: ->(v) { Strava::Models::LatLng.new(v) }
|
|
72
|
+
|
|
73
|
+
# @return [LatLng, nil] Ending coordinates [latitude, longitude]
|
|
24
74
|
property 'end_latlng', transform_with: ->(v) { Strava::Models::LatLng.new(v) }
|
|
75
|
+
|
|
76
|
+
# @return [Integer] Number of achievements (segment PRs, CRs, etc.)
|
|
25
77
|
property 'achievement_count'
|
|
78
|
+
|
|
79
|
+
# @return [Integer] Number of kudos received
|
|
26
80
|
property 'kudos_count'
|
|
81
|
+
|
|
82
|
+
# @return [Integer] Number of comments
|
|
27
83
|
property 'comment_count'
|
|
84
|
+
|
|
85
|
+
# @return [Integer] Number of athletes who participated (group activities)
|
|
28
86
|
property 'athlete_count'
|
|
87
|
+
|
|
88
|
+
# @return [Integer] Number of photos attached
|
|
29
89
|
property 'photo_count'
|
|
90
|
+
|
|
91
|
+
# @return [Integer] Total number of photos including Instagram
|
|
30
92
|
property 'total_photo_count'
|
|
93
|
+
|
|
94
|
+
# @return [Map] Activity map with polyline data
|
|
31
95
|
property 'map', transform_with: ->(v) { Strava::Models::Map.new(v) }
|
|
96
|
+
|
|
97
|
+
# @return [Boolean] Whether this activity was on a stationary trainer
|
|
32
98
|
property 'trainer'
|
|
99
|
+
|
|
100
|
+
# @return [Boolean] Whether this activity was a commute
|
|
33
101
|
property 'commute'
|
|
102
|
+
|
|
103
|
+
# @return [Boolean] Whether this activity was manually entered
|
|
34
104
|
property 'manual'
|
|
105
|
+
|
|
106
|
+
# @return [Boolean] Whether this activity is set to private
|
|
35
107
|
property 'private'
|
|
108
|
+
|
|
109
|
+
# @return [Boolean] Whether this activity has been flagged
|
|
36
110
|
property 'flagged'
|
|
111
|
+
|
|
112
|
+
# @return [Integer, nil] Workout type (e.g., 10 = Race, 11 = Workout)
|
|
37
113
|
property 'workout_type'
|
|
114
|
+
|
|
115
|
+
# @return [String, nil] Upload ID as a string
|
|
38
116
|
property 'upload_id_str'
|
|
117
|
+
|
|
118
|
+
# @return [Float] Average speed in meters per second
|
|
39
119
|
property 'average_speed'
|
|
120
|
+
|
|
121
|
+
# @return [Float] Maximum speed in meters per second
|
|
40
122
|
property 'max_speed'
|
|
123
|
+
|
|
124
|
+
# @return [Boolean] Whether the authenticated athlete has kudoed this activity
|
|
41
125
|
property 'has_kudoed'
|
|
126
|
+
|
|
127
|
+
# @return [Boolean] Whether to hide this activity from the home feed
|
|
42
128
|
property 'hide_from_home'
|
|
129
|
+
|
|
130
|
+
# @return [String, nil] Gear (bike/shoes) ID used for this activity
|
|
43
131
|
property 'gear_id'
|
|
132
|
+
|
|
133
|
+
# @return [Float, nil] Kilojoules of energy expended
|
|
44
134
|
property 'kilojoules'
|
|
135
|
+
|
|
136
|
+
# @return [Float, nil] Average power in watts
|
|
45
137
|
property 'average_watts'
|
|
138
|
+
|
|
139
|
+
# @return [Boolean, nil] Whether the watts are from a power meter (true) or estimated (false)
|
|
46
140
|
property 'device_watts'
|
|
141
|
+
|
|
142
|
+
# @return [Integer, nil] Maximum power in watts
|
|
47
143
|
property 'max_watts'
|
|
144
|
+
|
|
145
|
+
# @return [Integer, nil] Weighted average power in watts
|
|
48
146
|
property 'weighted_average_watts'
|
|
147
|
+
|
|
148
|
+
# @return [String, nil] Activity description
|
|
49
149
|
property 'description'
|
|
150
|
+
|
|
151
|
+
# @return [PhotosSummary, nil] Summary of activity photos
|
|
50
152
|
property 'photos', transform_with: ->(v) { Strava::Models::PhotosSummary.new(v) }
|
|
153
|
+
|
|
154
|
+
# @return [SummaryGear, nil] The gear (bike/shoes) used for this activity
|
|
51
155
|
property 'gear', transform_with: ->(v) { Strava::Models::SummaryGear.new(v) }
|
|
156
|
+
|
|
157
|
+
# @return [Float, nil] Estimated calories burned
|
|
52
158
|
property 'calories'
|
|
159
|
+
|
|
160
|
+
# @return [Array<DetailedSegmentEffort>] All segment efforts for this activity
|
|
53
161
|
property 'segment_efforts', transform_with: ->(v) { v.map { |r| Strava::Models::DetailedSegmentEffort.new(r) } }
|
|
162
|
+
|
|
163
|
+
# @return [String, nil] Name of the device used to record the activity
|
|
54
164
|
property 'device_name'
|
|
165
|
+
|
|
166
|
+
# @return [String, nil] Embed token for the activity
|
|
55
167
|
property 'embed_token'
|
|
168
|
+
|
|
169
|
+
# @return [Array<Split>] Metric splits (per kilometer)
|
|
56
170
|
property 'splits_metric', transform_with: ->(v) { v.map { |r| Strava::Models::Split.new(r) } }
|
|
171
|
+
|
|
172
|
+
# @return [Array<Split>] Standard/imperial splits (per mile)
|
|
57
173
|
property 'splits_standard', transform_with: ->(v) { v.map { |r| Strava::Models::Split.new(r) } }
|
|
174
|
+
|
|
175
|
+
# @return [Array<Lap>] Laps for the activity
|
|
58
176
|
property 'laps', transform_with: ->(v) { v.map { |r| Strava::Models::Lap.new(r) } }
|
|
177
|
+
|
|
178
|
+
# @return [Array<DetailedSegmentEffort>] Best efforts (e.g., 400m, 1/2 mile, 1k, etc.)
|
|
59
179
|
property 'best_efforts', transform_with: ->(v) { v.map { |r| Strava::Models::DetailedSegmentEffort.new(r) } }
|
|
60
|
-
|
|
180
|
+
|
|
181
|
+
# @note Undocumented in official API
|
|
182
|
+
# @return [Integer, nil] Resource state indicator
|
|
61
183
|
property 'resource_state'
|
|
184
|
+
|
|
185
|
+
# @note Undocumented in official API
|
|
186
|
+
# @return [Float, nil] UTC offset in seconds
|
|
62
187
|
property 'utc_offset'
|
|
188
|
+
|
|
189
|
+
# @note Undocumented in official API
|
|
190
|
+
# @return [String, nil] City where the activity took place
|
|
63
191
|
property 'location_city'
|
|
192
|
+
|
|
193
|
+
# @note Undocumented in official API
|
|
194
|
+
# @return [String, nil] State/province where the activity took place
|
|
64
195
|
property 'location_state'
|
|
196
|
+
|
|
197
|
+
# @note Undocumented in official API
|
|
198
|
+
# @return [String, nil] Country where the activity took place
|
|
65
199
|
property 'location_country'
|
|
200
|
+
|
|
201
|
+
# @note Undocumented in official API
|
|
202
|
+
# @return [String, nil] Activity visibility setting (e.g., 'everyone', 'followers_only')
|
|
66
203
|
property 'visibility'
|
|
204
|
+
|
|
205
|
+
# @note Undocumented in official API
|
|
206
|
+
# @return [Float, nil] Average temperature during the activity in Celsius
|
|
67
207
|
property 'average_temp'
|
|
208
|
+
|
|
209
|
+
# @note Undocumented in official API
|
|
210
|
+
# @return [Boolean, nil] Whether the activity has heart rate data
|
|
68
211
|
property 'has_heartrate'
|
|
212
|
+
|
|
213
|
+
# @note Undocumented in official API
|
|
214
|
+
# @return [Float, nil] Average heart rate in beats per minute
|
|
69
215
|
property 'average_heartrate'
|
|
216
|
+
|
|
217
|
+
# @note Undocumented in official API
|
|
218
|
+
# @return [Float, nil] Maximum heart rate in beats per minute
|
|
70
219
|
property 'max_heartrate'
|
|
220
|
+
|
|
221
|
+
# @note Undocumented in official API
|
|
222
|
+
# @return [Boolean, nil] Whether the athlete has opted out of heart rate display
|
|
71
223
|
property 'heartrate_opt_out'
|
|
224
|
+
|
|
225
|
+
# @note Undocumented in official API
|
|
226
|
+
# @return [Boolean, nil] Whether to display the hide heart rate option
|
|
72
227
|
property 'display_hide_heartrate_option'
|
|
228
|
+
|
|
229
|
+
# @note Undocumented in official API
|
|
230
|
+
# @return [Boolean, nil] Whether the activity was created from an accepted tag
|
|
73
231
|
property 'from_accepted_tag'
|
|
232
|
+
|
|
233
|
+
# @note Undocumented in official API
|
|
234
|
+
# @return [Integer, nil] Number of personal records achieved in this activity
|
|
74
235
|
property 'pr_count'
|
|
236
|
+
|
|
237
|
+
# @note Undocumented in official API
|
|
238
|
+
# @return [Integer, nil] Relative effort score (suffer score)
|
|
75
239
|
property 'suffer_score'
|
|
240
|
+
|
|
241
|
+
# @note Undocumented in official API
|
|
242
|
+
# @return [Integer, nil] Athlete's perceived exertion rating
|
|
76
243
|
property 'perceived_exertion'
|
|
244
|
+
|
|
245
|
+
# @note Undocumented in official API
|
|
246
|
+
# @return [Boolean, nil] Whether to prefer perceived exertion over calculated metrics
|
|
77
247
|
property 'prefer_perceived_exertion'
|
|
248
|
+
|
|
249
|
+
# @note Undocumented in official API
|
|
250
|
+
# @return [Array<StatsVisibility>, nil] Stats visibility settings
|
|
78
251
|
property 'stats_visibility', transform_with: ->(v) { v.map { |r| Strava::Models::StatsVisibility.new(r) } }
|
|
252
|
+
|
|
253
|
+
# @note Undocumented in official API
|
|
254
|
+
# @return [Array<String>, nil] List of available zone types for this activity
|
|
79
255
|
property 'available_zones'
|
|
256
|
+
|
|
257
|
+
# @note Undocumented in official API
|
|
258
|
+
# @return [SimilarActivities, nil] Information about similar activities
|
|
80
259
|
property 'similar_activities', transform_with: ->(v) { Strava::Models::SimilarActivities.new(v) }
|
|
260
|
+
|
|
261
|
+
# @note Undocumented in official API
|
|
262
|
+
# @return [Float, nil] Average cadence (RPM for cycling, steps/minute for running)
|
|
81
263
|
property 'average_cadence'
|
|
264
|
+
|
|
265
|
+
# @note Undocumented in official API
|
|
266
|
+
# @return [Array, nil] List of highlighted athletes who gave kudos
|
|
82
267
|
property 'highlighted_kudosers'
|
|
268
|
+
|
|
269
|
+
# @note Undocumented in official API
|
|
270
|
+
# @return [Boolean, nil] Whether the athlete has opted out of segment leaderboards
|
|
83
271
|
property 'segment_leaderboard_opt_out'
|
|
272
|
+
|
|
273
|
+
# @note Undocumented in official API
|
|
274
|
+
# @return [Boolean, nil] Whether the athlete has opted out of all leaderboards
|
|
84
275
|
property 'leaderboard_opt_out'
|
|
85
276
|
|
|
277
|
+
#
|
|
278
|
+
# Returns the Strava web URL for this activity.
|
|
279
|
+
#
|
|
280
|
+
# @return [String] Full URL to view the activity on Strava.com
|
|
281
|
+
#
|
|
282
|
+
# @example
|
|
283
|
+
# activity = client.activity(1234567890)
|
|
284
|
+
# puts activity.strava_url
|
|
285
|
+
# # => "https://www.strava.com/activities/1234567890"
|
|
286
|
+
#
|
|
86
287
|
def strava_url
|
|
87
288
|
"https://www.strava.com/activities/#{id}"
|
|
88
289
|
end
|
|
@@ -2,47 +2,149 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents detailed information about a Strava athlete.
|
|
7
|
+
#
|
|
8
|
+
# Contains comprehensive profile information including personal details,
|
|
9
|
+
# preferences, gear, clubs, and social connections. This model is typically
|
|
10
|
+
# returned when accessing the authenticated athlete's own profile.
|
|
11
|
+
#
|
|
12
|
+
# @example Get athlete profile
|
|
13
|
+
# athlete = client.athlete
|
|
14
|
+
# puts athlete.name
|
|
15
|
+
# puts "Location: #{athlete.city}, #{athlete.state}, #{athlete.country}"
|
|
16
|
+
# puts "Premium: #{athlete.premium}"
|
|
17
|
+
# puts "Weight: #{athlete.weight}kg"
|
|
18
|
+
# puts athlete.strava_url
|
|
19
|
+
#
|
|
20
|
+
# @see SummaryAthlete
|
|
21
|
+
# @see https://developers.strava.com/docs/reference/#api-models-DetailedAthlete
|
|
22
|
+
#
|
|
6
23
|
class DetailedAthlete < Strava::Models::Response
|
|
24
|
+
# @return [Integer] Athlete ID
|
|
7
25
|
property 'id'
|
|
26
|
+
|
|
27
|
+
# @return [Integer] Resource state indicator
|
|
8
28
|
property 'resource_state'
|
|
29
|
+
|
|
30
|
+
# @return [String] First name
|
|
9
31
|
property 'firstname'
|
|
32
|
+
|
|
33
|
+
# @return [String] Last name
|
|
10
34
|
property 'lastname'
|
|
35
|
+
|
|
36
|
+
# @return [String, nil] URL to medium-sized profile picture
|
|
11
37
|
property 'profile_medium'
|
|
38
|
+
|
|
39
|
+
# @return [String, nil] URL to full-sized profile picture
|
|
12
40
|
property 'profile'
|
|
41
|
+
|
|
42
|
+
# @return [String, nil] City
|
|
13
43
|
property 'city'
|
|
44
|
+
|
|
45
|
+
# @return [String, nil] State or province
|
|
14
46
|
property 'state'
|
|
47
|
+
|
|
48
|
+
# @return [String, nil] Country
|
|
15
49
|
property 'country'
|
|
50
|
+
|
|
51
|
+
# @return [String] Sex ('M' for male, 'F' for female)
|
|
16
52
|
property 'sex'
|
|
53
|
+
|
|
54
|
+
# @return [Boolean] Whether the athlete has a premium subscription
|
|
17
55
|
property 'premium'
|
|
56
|
+
|
|
57
|
+
# @return [Boolean] Whether the athlete has a Summit subscription
|
|
18
58
|
property 'summit'
|
|
59
|
+
|
|
60
|
+
# @return [Time] When the athlete account was created
|
|
19
61
|
property 'created_at', transform_with: ->(v) { Time.parse(v) }
|
|
62
|
+
|
|
63
|
+
# @return [Time] When the athlete account was last updated
|
|
20
64
|
property 'updated_at', transform_with: ->(v) { Time.parse(v) }
|
|
65
|
+
|
|
66
|
+
# @return [Integer] Number of followers
|
|
21
67
|
property 'follower_count'
|
|
68
|
+
|
|
69
|
+
# @return [Integer] Number of friends (mutual follows)
|
|
22
70
|
property 'friend_count'
|
|
71
|
+
|
|
72
|
+
# @return [String] Preferred measurement system ('feet' or 'meters')
|
|
23
73
|
property 'measurement_preference'
|
|
74
|
+
|
|
75
|
+
# @return [Integer, nil] Functional Threshold Power in watts
|
|
24
76
|
property 'ftp'
|
|
77
|
+
|
|
78
|
+
# @return [Float, nil] Weight in kilograms
|
|
25
79
|
property 'weight'
|
|
80
|
+
|
|
81
|
+
# @return [Array<SummaryClub>] Clubs the athlete belongs to
|
|
26
82
|
property 'clubs', transform_with: ->(v) { v.map { |r| Strava::Models::SummaryClub.new(r) } }
|
|
83
|
+
|
|
84
|
+
# @return [Array<SummaryGear>] Bikes registered to this athlete
|
|
27
85
|
property 'bikes', transform_with: ->(v) { v.map { |r| Strava::Models::SummaryGear.new(r) } }
|
|
86
|
+
|
|
87
|
+
# @return [Array<SummaryGear>] Shoes registered to this athlete
|
|
28
88
|
property 'shoes', transform_with: ->(v) { v.map { |r| Strava::Models::SummaryGear.new(r) } }
|
|
29
|
-
|
|
89
|
+
|
|
90
|
+
# @note Undocumented in official API
|
|
91
|
+
# @return [String, nil] Username/vanity URL
|
|
30
92
|
property 'username'
|
|
93
|
+
|
|
94
|
+
# @note Undocumented in official API
|
|
95
|
+
# @return [String, nil] Athlete bio/description
|
|
31
96
|
property 'bio'
|
|
97
|
+
|
|
98
|
+
# @note Undocumented in official API
|
|
99
|
+
# @return [Integer, nil] Badge type identifier
|
|
32
100
|
property 'badge_type_id'
|
|
101
|
+
|
|
102
|
+
# @note Undocumented in official API
|
|
103
|
+
# @return [String, nil] Relationship status with authenticated athlete ('pending', 'accepted', 'blocked', or nil)
|
|
33
104
|
property 'friend'
|
|
105
|
+
|
|
106
|
+
# @note Undocumented in official API
|
|
107
|
+
# @return [String, nil] Follower relationship status
|
|
34
108
|
property 'follower'
|
|
109
|
+
|
|
110
|
+
# @note Undocumented in official API
|
|
111
|
+
# @return [Boolean, nil] Whether this athlete is blocked by the authenticated athlete
|
|
35
112
|
property 'blocked'
|
|
113
|
+
|
|
114
|
+
# @note Undocumented in official API
|
|
115
|
+
# @return [Boolean, nil] Whether the authenticated athlete can follow this athlete
|
|
36
116
|
property 'can_follow'
|
|
117
|
+
|
|
118
|
+
# @note Undocumented in official API
|
|
119
|
+
# @return [Integer, nil] Number of mutual friends with the authenticated athlete
|
|
37
120
|
property 'mutual_friend_count'
|
|
121
|
+
|
|
122
|
+
# @note Undocumented in official API
|
|
123
|
+
# @return [Integer, nil] Athlete type identifier (0 = Cyclist, 1 = Runner)
|
|
38
124
|
property 'athlete_type'
|
|
125
|
+
|
|
126
|
+
# @note Undocumented in official API
|
|
127
|
+
# @return [String, nil] Preferred date format
|
|
39
128
|
property 'date_preference'
|
|
129
|
+
|
|
130
|
+
# @note Undocumented in official API
|
|
131
|
+
# @return [Integer, nil] Number of clubs where athlete can post
|
|
40
132
|
property 'postable_clubs_count'
|
|
41
133
|
|
|
134
|
+
#
|
|
135
|
+
# Returns the athlete's full name.
|
|
136
|
+
#
|
|
137
|
+
# @return [String, nil] Full name combining firstname and lastname, or nil if neither exists
|
|
138
|
+
#
|
|
42
139
|
def name
|
|
43
140
|
[firstname, lastname].compact.join(' ') if firstname || lastname
|
|
44
141
|
end
|
|
45
142
|
|
|
143
|
+
#
|
|
144
|
+
# Returns the Strava web URL for this athlete's profile.
|
|
145
|
+
#
|
|
146
|
+
# @return [String] Full URL to view the athlete on Strava.com
|
|
147
|
+
#
|
|
46
148
|
def strava_url
|
|
47
149
|
"https://www.strava.com/athletes/#{username || id}"
|
|
48
150
|
end
|
|
@@ -2,37 +2,111 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents detailed information about a Strava club.
|
|
7
|
+
#
|
|
8
|
+
# Clubs are groups of athletes on Strava. This model contains comprehensive
|
|
9
|
+
# club information including member counts, location, sport type, and membership
|
|
10
|
+
# status for the authenticated athlete.
|
|
11
|
+
#
|
|
12
|
+
# @example Get club details
|
|
13
|
+
# club = client.club(12345)
|
|
14
|
+
# puts club.name
|
|
15
|
+
# puts "#{club.member_count} members in #{club.city}, #{club.country}"
|
|
16
|
+
# puts "Sport type: #{club.sport_type}"
|
|
17
|
+
# puts "Private: #{club.private}"
|
|
18
|
+
# puts club.strava_url
|
|
19
|
+
#
|
|
20
|
+
# @see SummaryClub
|
|
21
|
+
# @see https://developers.strava.com/docs/reference/#api-models-DetailedClub
|
|
22
|
+
#
|
|
6
23
|
class DetailedClub < Strava::Models::Response
|
|
24
|
+
# @return [Integer] Club identifier
|
|
7
25
|
property 'id'
|
|
26
|
+
|
|
27
|
+
# @return [Integer] Resource state indicator (1=meta, 2=summary, 3=detailed)
|
|
8
28
|
property 'resource_state'
|
|
29
|
+
|
|
30
|
+
# @return [String] Club name
|
|
9
31
|
property 'name'
|
|
32
|
+
|
|
33
|
+
# @return [String] URL to medium-sized profile picture
|
|
10
34
|
property 'profile_medium'
|
|
35
|
+
|
|
36
|
+
# @return [String] URL to club cover photo
|
|
11
37
|
property 'cover_photo'
|
|
38
|
+
|
|
39
|
+
# @return [String] URL to smaller club cover photo
|
|
12
40
|
property 'cover_photo_small'
|
|
41
|
+
|
|
42
|
+
# @return [String] Primary sport type (e.g., "cycling", "running", "other")
|
|
13
43
|
property 'sport_type'
|
|
44
|
+
|
|
45
|
+
# @return [Array<String>] List of activity types the club supports
|
|
14
46
|
property 'activity_types'
|
|
47
|
+
|
|
48
|
+
# @return [String] City where club is located
|
|
15
49
|
property 'city'
|
|
50
|
+
|
|
51
|
+
# @return [String] State/province where club is located
|
|
16
52
|
property 'state'
|
|
53
|
+
|
|
54
|
+
# @return [String] Country where club is located
|
|
17
55
|
property 'country'
|
|
56
|
+
|
|
57
|
+
# @return [Boolean] Whether club is private
|
|
18
58
|
property 'private'
|
|
59
|
+
|
|
60
|
+
# @return [Integer] Number of club members
|
|
19
61
|
property 'member_count'
|
|
62
|
+
|
|
63
|
+
# @return [Boolean] Whether club is featured by Strava
|
|
20
64
|
property 'featured'
|
|
65
|
+
|
|
66
|
+
# @return [Boolean] Whether club is verified by Strava
|
|
21
67
|
property 'verified'
|
|
68
|
+
|
|
69
|
+
# @return [String] Club URL slug
|
|
22
70
|
property 'url'
|
|
71
|
+
|
|
72
|
+
# @return [String] Authenticated athlete's membership status (e.g., "member", "pending")
|
|
23
73
|
property 'membership'
|
|
74
|
+
|
|
75
|
+
# @return [Boolean] Whether authenticated athlete is a club administrator
|
|
24
76
|
property 'admin'
|
|
77
|
+
|
|
78
|
+
# @return [Boolean] Whether authenticated athlete is the club owner
|
|
25
79
|
property 'owner'
|
|
80
|
+
|
|
81
|
+
# @return [String] Type of club (e.g., "casual_club", "racing_team", "shop", "company", "other")
|
|
26
82
|
property 'club_type'
|
|
83
|
+
|
|
84
|
+
# @return [Integer] Number of athletes following this club
|
|
27
85
|
property 'following_count'
|
|
28
|
-
|
|
86
|
+
|
|
87
|
+
# @return [String] URL to full-sized profile picture
|
|
29
88
|
property 'profile'
|
|
89
|
+
|
|
90
|
+
# @return [String] Icon representing the activity types
|
|
30
91
|
property 'activity_types_icon'
|
|
92
|
+
|
|
93
|
+
# @return [Array<Integer>] Dimensions of cover photo [width, height]
|
|
31
94
|
property 'dimensions'
|
|
95
|
+
|
|
96
|
+
# @return [String] Localized sport type string
|
|
32
97
|
property 'localized_sport_type'
|
|
98
|
+
|
|
99
|
+
# @return [String] Club description text
|
|
33
100
|
property 'description'
|
|
101
|
+
|
|
102
|
+
# @return [String] Club website URL
|
|
34
103
|
property 'website'
|
|
35
104
|
|
|
105
|
+
#
|
|
106
|
+
# Returns the Strava web URL for this club.
|
|
107
|
+
#
|
|
108
|
+
# @return [String] Full URL to view the club on Strava.com
|
|
109
|
+
#
|
|
36
110
|
def strava_url
|
|
37
111
|
"https://www.strava.com/clubs/#{url || id}"
|
|
38
112
|
end
|
|
@@ -2,22 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents detailed information about an athlete's equipment/gear.
|
|
7
|
+
#
|
|
8
|
+
# Gear includes bikes, shoes, and other equipment that athletes track mileage on.
|
|
9
|
+
# Each piece of gear has a name, brand, model, and accumulated distance.
|
|
10
|
+
#
|
|
11
|
+
# Includes the Distance mixin for formatting accumulated distance.
|
|
12
|
+
#
|
|
13
|
+
# @example Get gear details
|
|
14
|
+
# gear = client.gear('b12345')
|
|
15
|
+
# puts gear.name
|
|
16
|
+
# puts "#{gear.brand_name} #{gear.model_name}"
|
|
17
|
+
# puts "Total distance: #{gear.distance_s}"
|
|
18
|
+
# puts "Weight: #{gear.weight}g" if gear.weight
|
|
19
|
+
# puts "Retired" if gear.retired
|
|
20
|
+
#
|
|
21
|
+
# @see SummaryGear
|
|
22
|
+
# @see https://developers.strava.com/docs/reference/#api-models-DetailedGear
|
|
23
|
+
#
|
|
6
24
|
class DetailedGear < Strava::Models::Response
|
|
25
|
+
# @return [String] Gear identifier (e.g., "b12345" for bike, "g12345" for shoes)
|
|
7
26
|
property 'id'
|
|
27
|
+
|
|
28
|
+
# @return [Integer] Resource state indicator
|
|
8
29
|
property 'resource_state'
|
|
30
|
+
|
|
31
|
+
# @return [Boolean] Whether this is the athlete's primary gear for this type
|
|
9
32
|
property 'primary'
|
|
33
|
+
|
|
34
|
+
# @return [String] Gear name/title
|
|
10
35
|
property 'name'
|
|
36
|
+
|
|
11
37
|
include Mixins::Distance
|
|
38
|
+
|
|
39
|
+
# @return [String] Brand/manufacturer name
|
|
12
40
|
property 'brand_name'
|
|
41
|
+
|
|
42
|
+
# @return [String] Model name
|
|
13
43
|
property 'model_name'
|
|
44
|
+
|
|
45
|
+
# @return [Integer] Frame type identifier (for bikes)
|
|
14
46
|
property 'frame_type'
|
|
47
|
+
|
|
48
|
+
# @return [String] Gear description/notes
|
|
15
49
|
property 'description'
|
|
16
|
-
|
|
50
|
+
|
|
51
|
+
# @return [String] Nickname for the gear
|
|
17
52
|
property 'nickname'
|
|
53
|
+
|
|
54
|
+
# @return [Boolean] Whether gear has been retired/is no longer in use
|
|
18
55
|
property 'retired'
|
|
56
|
+
|
|
57
|
+
# @return [Float] Distance in meters after conversion (likely for imperial users)
|
|
19
58
|
property 'converted_distance'
|
|
59
|
+
|
|
60
|
+
# @return [Float] Distance threshold for maintenance notifications (in meters)
|
|
20
61
|
property 'notification_distance'
|
|
62
|
+
|
|
63
|
+
# @return [Float] Weight of the gear in grams
|
|
21
64
|
property 'weight'
|
|
22
65
|
end
|
|
23
66
|
end
|