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
data/lib/strava/models/xoms.rb
CHANGED
|
@@ -2,11 +2,45 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents segment leaderboard achievements (KOM/QOM).
|
|
7
|
+
#
|
|
8
|
+
# Contains information about King of the Mountain (KOM), Queen of the Mountain (QOM),
|
|
9
|
+
# and overall segment records. This model is not documented in the official Strava
|
|
10
|
+
# API reference.
|
|
11
|
+
#
|
|
12
|
+
# @note This model is not documented by Strava API documentation. Properties
|
|
13
|
+
# are inferred from API responses.
|
|
14
|
+
#
|
|
15
|
+
# @see Strava::Models::DetailedActivity
|
|
16
|
+
# @see Strava::Models::Destination
|
|
17
|
+
#
|
|
18
|
+
# @example Accessing XOM (KOM/QOM) information
|
|
19
|
+
# activity = client.activity(1234567890)
|
|
20
|
+
# if activity.xoms
|
|
21
|
+
# puts "KOM: #{activity.xoms.kom}"
|
|
22
|
+
# puts "QOM: #{activity.xoms.qom}"
|
|
23
|
+
# puts "Overall: #{activity.xoms.overall}"
|
|
24
|
+
# if activity.xoms.destination
|
|
25
|
+
# puts "Segment: #{activity.xoms.destination.name}"
|
|
26
|
+
# end
|
|
27
|
+
# end
|
|
28
|
+
#
|
|
6
29
|
class Xoms < Strava::Models::Response
|
|
30
|
+
# @return [String, Integer, nil] King of the Mountain achievement data
|
|
31
|
+
# @note Not documented by Strava API
|
|
7
32
|
property 'kom'
|
|
33
|
+
|
|
34
|
+
# @return [String, Integer, nil] Queen of the Mountain achievement data
|
|
35
|
+
# @note Not documented by Strava API
|
|
8
36
|
property 'qom'
|
|
37
|
+
|
|
38
|
+
# @return [String, Integer, nil] Overall segment record data
|
|
39
|
+
# @note Not documented by Strava API
|
|
9
40
|
property 'overall'
|
|
41
|
+
|
|
42
|
+
# @return [Destination, nil] Link to the segment where this achievement was earned
|
|
43
|
+
# @note Not documented by Strava API
|
|
10
44
|
property 'destination', transform_with: ->(v) { Strava::Models::Destination.new(v) }
|
|
11
45
|
end
|
|
12
46
|
end
|
|
@@ -2,9 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents a single training zone range.
|
|
7
|
+
#
|
|
8
|
+
# Training zones define intensity levels for heart rate or power. Each zone
|
|
9
|
+
# has a minimum and maximum value that defines the range for that intensity level.
|
|
10
|
+
#
|
|
11
|
+
# @see https://developers.strava.com/docs/reference/#api-models-ZoneRange Strava API ZoneRange reference
|
|
12
|
+
# @see Strava::Models::HeartRateZoneRanges
|
|
13
|
+
# @see Strava::Models::PowerZoneRanges
|
|
14
|
+
# @see Strava::Models::TimedZoneRange
|
|
15
|
+
#
|
|
16
|
+
# @example Accessing zone ranges
|
|
17
|
+
# zones = client.athlete_zones
|
|
18
|
+
# zones.heart_rate.zones.each_with_index do |zone, i|
|
|
19
|
+
# puts "Zone #{i + 1}: #{zone.min}-#{zone.max} bpm"
|
|
20
|
+
# end
|
|
21
|
+
#
|
|
6
22
|
class ZoneRange < Strava::Models::Response
|
|
23
|
+
# @return [Integer] Maximum value for this zone (e.g., maximum heart rate or power)
|
|
7
24
|
property 'max'
|
|
25
|
+
|
|
26
|
+
# @return [Integer] Minimum value for this zone (e.g., minimum heart rate or power)
|
|
8
27
|
property 'min'
|
|
9
28
|
end
|
|
10
29
|
end
|
data/lib/strava/models/zones.rb
CHANGED
|
@@ -2,9 +2,40 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Models
|
|
5
|
-
#
|
|
5
|
+
#
|
|
6
|
+
# Represents an athlete's training zones configuration.
|
|
7
|
+
#
|
|
8
|
+
# Training zones are used to define intensity levels for heart rate and power.
|
|
9
|
+
# These zones help athletes train at specific intensities and track time spent
|
|
10
|
+
# in each zone during activities.
|
|
11
|
+
#
|
|
12
|
+
# @see https://developers.strava.com/docs/reference/#api-models-Zones Strava API Zones reference
|
|
13
|
+
# @see Strava::Models::HeartRateZoneRanges
|
|
14
|
+
# @see Strava::Models::PowerZoneRanges
|
|
15
|
+
# @see Strava::Api::Client#athlete_zones
|
|
16
|
+
#
|
|
17
|
+
# @example Accessing athlete's training zones
|
|
18
|
+
# zones = client.athlete_zones
|
|
19
|
+
#
|
|
20
|
+
# # Heart rate zones
|
|
21
|
+
# if zones.heart_rate
|
|
22
|
+
# zones.heart_rate.zones.each_with_index do |zone, i|
|
|
23
|
+
# puts "HR Zone #{i + 1}: #{zone.min}-#{zone.max} bpm"
|
|
24
|
+
# end
|
|
25
|
+
# end
|
|
26
|
+
#
|
|
27
|
+
# # Power zones
|
|
28
|
+
# if zones.power
|
|
29
|
+
# zones.power.zones.each_with_index do |zone, i|
|
|
30
|
+
# puts "Power Zone #{i + 1}: #{zone.min}-#{zone.max}W"
|
|
31
|
+
# end
|
|
32
|
+
# end
|
|
33
|
+
#
|
|
6
34
|
class Zones < Strava::Models::Response
|
|
35
|
+
# @return [HeartRateZoneRanges, nil] Heart rate zone configuration with zone ranges
|
|
7
36
|
property 'heart_rate', transform_with: ->(v) { Strava::Models::HeartRateZoneRanges.new(v) }
|
|
37
|
+
|
|
38
|
+
# @return [PowerZoneRanges, nil] Power zone configuration with zone ranges (for cyclists)
|
|
8
39
|
property 'power', transform_with: ->(v) { Strava::Models::PowerZoneRanges.new(v) }
|
|
9
40
|
end
|
|
10
41
|
end
|
data/lib/strava/oauth/client.rb
CHANGED
|
@@ -2,9 +2,50 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module OAuth
|
|
5
|
+
#
|
|
6
|
+
# OAuth client for Strava authentication.
|
|
7
|
+
#
|
|
8
|
+
# This client handles the OAuth 2.0 authentication flow with Strava, including:
|
|
9
|
+
# * Generating authorization URLs
|
|
10
|
+
# * Exchanging authorization codes for access tokens
|
|
11
|
+
# * Refreshing expired access tokens
|
|
12
|
+
#
|
|
13
|
+
# @example Basic OAuth flow
|
|
14
|
+
# client = Strava::OAuth::Client.new(
|
|
15
|
+
# client_id: "your_client_id",
|
|
16
|
+
# client_secret: "your_client_secret"
|
|
17
|
+
# )
|
|
18
|
+
#
|
|
19
|
+
# # Step 1: Get authorization URL
|
|
20
|
+
# url = client.authorize_url(
|
|
21
|
+
# redirect_uri: 'http://localhost:3000/callback',
|
|
22
|
+
# scope: 'read,activity:read_all'
|
|
23
|
+
# )
|
|
24
|
+
# # Redirect user to this URL
|
|
25
|
+
#
|
|
26
|
+
# # Step 2: Exchange code for token
|
|
27
|
+
# token = client.oauth_token(code: params[:code])
|
|
28
|
+
# # Store token.access_token and token.refresh_token
|
|
29
|
+
#
|
|
30
|
+
# # Step 3: Refresh token when expired
|
|
31
|
+
# new_token = client.oauth_token(
|
|
32
|
+
# refresh_token: saved_refresh_token,
|
|
33
|
+
# grant_type: 'refresh_token'
|
|
34
|
+
# )
|
|
35
|
+
#
|
|
36
|
+
# @see https://developers.strava.com/docs/authentication/
|
|
37
|
+
#
|
|
5
38
|
class Client < Strava::Web::Client
|
|
6
39
|
attr_accessor(*Config::ATTRIBUTES)
|
|
7
40
|
|
|
41
|
+
#
|
|
42
|
+
# Initialize a new OAuth client.
|
|
43
|
+
#
|
|
44
|
+
# @param [Hash] options Configuration options
|
|
45
|
+
# @option options [String] :client_id Strava application client ID (required)
|
|
46
|
+
# @option options [String] :client_secret Strava application client secret (required)
|
|
47
|
+
# @option options [String] :endpoint OAuth endpoint URL (defaults to https://www.strava.com/oauth)
|
|
48
|
+
#
|
|
8
49
|
def initialize(options = {})
|
|
9
50
|
Strava::OAuth::Config::ATTRIBUTES.each do |key|
|
|
10
51
|
send("#{key}=", options[key] || Strava::OAuth.config.send(key))
|
|
@@ -13,20 +54,31 @@ module Strava
|
|
|
13
54
|
end
|
|
14
55
|
|
|
15
56
|
#
|
|
16
|
-
#
|
|
17
|
-
#
|
|
18
|
-
#
|
|
19
|
-
#
|
|
20
|
-
#
|
|
21
|
-
#
|
|
22
|
-
# @
|
|
23
|
-
#
|
|
24
|
-
# @option options [
|
|
25
|
-
#
|
|
26
|
-
# @option options [
|
|
27
|
-
#
|
|
57
|
+
# Generate the authorization URL for OAuth flow.
|
|
58
|
+
#
|
|
59
|
+
# Creates a URL to redirect users to for Strava authorization. After the user
|
|
60
|
+
# authorizes your application, they will be redirected back to your redirect_uri
|
|
61
|
+
# with an authorization code.
|
|
62
|
+
#
|
|
63
|
+
# @param [Hash] options Authorization parameters
|
|
64
|
+
# @option options [String] :redirect_uri URL where user is redirected after authorization (default: http://localhost)
|
|
65
|
+
# @option options [String] :response_type Must be 'code' (default: 'code')
|
|
66
|
+
# @option options [String] :approval_prompt 'force' to always show approval page, 'auto' to auto-approve (default: 'auto')
|
|
67
|
+
# @option options [String] :scope Comma-delimited string of permissions (default: 'read')
|
|
68
|
+
# Available scopes: read, read_all, profile:read_all, profile:write, activity:read, activity:read_all, activity:write
|
|
69
|
+
# @option options [String] :state Optional value returned in redirect URI for CSRF protection
|
|
70
|
+
#
|
|
71
|
+
# @return [String] Full authorization URL
|
|
72
|
+
#
|
|
73
|
+
# @example Generate authorization URL
|
|
74
|
+
# url = client.authorize_url(
|
|
75
|
+
# redirect_uri: 'https://myapp.com/callback',
|
|
76
|
+
# scope: 'read,activity:read_all,activity:write',
|
|
77
|
+
# state: 'random_state_value'
|
|
78
|
+
# )
|
|
79
|
+
#
|
|
28
80
|
# @see https://developers.strava.com/docs/authentication/
|
|
29
|
-
#
|
|
81
|
+
#
|
|
30
82
|
def authorize_url(options = {})
|
|
31
83
|
query = options.merge(
|
|
32
84
|
client_id: client_id || raise(ArgumentError, 'Missing Strava client id.'),
|
|
@@ -40,14 +92,33 @@ module Strava
|
|
|
40
92
|
end
|
|
41
93
|
|
|
42
94
|
#
|
|
43
|
-
#
|
|
95
|
+
# Exchange authorization code for access token or refresh an expired token.
|
|
96
|
+
#
|
|
97
|
+
# This method handles two OAuth flows:
|
|
98
|
+
# 1. Initial token exchange: Exchange authorization code for access/refresh tokens
|
|
99
|
+
# 2. Token refresh: Use refresh_token to get new access/refresh tokens
|
|
100
|
+
#
|
|
101
|
+
# @param [Hash] options Token request parameters
|
|
102
|
+
# @option options [String] :code Authorization code from redirect (for initial exchange)
|
|
103
|
+
# @option options [String] :refresh_token Refresh token (for token refresh)
|
|
104
|
+
# @option options [String] :grant_type Grant type: 'authorization_code' (default) or 'refresh_token'
|
|
105
|
+
#
|
|
106
|
+
# @return [Strava::Models::Token] Token object with access_token, refresh_token, expires_at, and athlete
|
|
107
|
+
#
|
|
108
|
+
# @example Exchange authorization code for token
|
|
109
|
+
# token = client.oauth_token(code: 'authorization_code_from_redirect')
|
|
110
|
+
# access_token = token.access_token
|
|
111
|
+
# refresh_token = token.refresh_token
|
|
112
|
+
# expires_at = token.expires_at
|
|
113
|
+
#
|
|
114
|
+
# @example Refresh an expired token
|
|
115
|
+
# new_token = client.oauth_token(
|
|
116
|
+
# refresh_token: 'saved_refresh_token',
|
|
117
|
+
# grant_type: 'refresh_token'
|
|
118
|
+
# )
|
|
44
119
|
#
|
|
45
|
-
# @option options [Object] :code
|
|
46
|
-
# The code parameter obtained in the redirect.
|
|
47
|
-
# @option options [Object] :grant_type
|
|
48
|
-
# The grant type for the request.
|
|
49
120
|
# @see https://developers.strava.com/docs/authentication/
|
|
50
|
-
#
|
|
121
|
+
#
|
|
51
122
|
def oauth_token(options = {})
|
|
52
123
|
query = options.merge(
|
|
53
124
|
client_id: client_id || raise(ArgumentError, 'Missing Strava client id.'),
|
|
@@ -59,10 +130,27 @@ module Strava
|
|
|
59
130
|
end
|
|
60
131
|
|
|
61
132
|
class << self
|
|
133
|
+
#
|
|
134
|
+
# Configure the OAuth client with a block.
|
|
135
|
+
#
|
|
136
|
+
# @yield [Config] Yields the configuration module for setup
|
|
137
|
+
# @return [Module] The Config module
|
|
138
|
+
#
|
|
139
|
+
# @example
|
|
140
|
+
# Strava::OAuth::Client.configure do |config|
|
|
141
|
+
# config.client_id = ENV['STRAVA_CLIENT_ID']
|
|
142
|
+
# config.client_secret = ENV['STRAVA_CLIENT_SECRET']
|
|
143
|
+
# end
|
|
144
|
+
#
|
|
62
145
|
def configure
|
|
63
146
|
block_given? ? yield(Config) : Config
|
|
64
147
|
end
|
|
65
148
|
|
|
149
|
+
#
|
|
150
|
+
# Returns the current OAuth client configuration.
|
|
151
|
+
#
|
|
152
|
+
# @return [Module] The Config module
|
|
153
|
+
#
|
|
66
154
|
def config
|
|
67
155
|
Config
|
|
68
156
|
end
|
data/lib/strava/oauth/config.rb
CHANGED
|
@@ -2,9 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module OAuth
|
|
5
|
+
#
|
|
6
|
+
# Configuration module for the OAuth client.
|
|
7
|
+
#
|
|
8
|
+
# This module manages OAuth-specific configuration settings including the
|
|
9
|
+
# OAuth endpoint URL and application credentials (client ID and secret)
|
|
10
|
+
# required for token exchange and refresh operations.
|
|
11
|
+
#
|
|
12
|
+
# @example Configure OAuth client
|
|
13
|
+
# Strava::OAuth.configure do |config|
|
|
14
|
+
# config.client_id = ENV['STRAVA_CLIENT_ID']
|
|
15
|
+
# config.client_secret = ENV['STRAVA_CLIENT_SECRET']
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
# @see https://developers.strava.com/docs/authentication/
|
|
19
|
+
#
|
|
5
20
|
module Config
|
|
6
21
|
extend self
|
|
7
22
|
|
|
23
|
+
# @return [Array<Symbol>] List of configurable OAuth attributes
|
|
8
24
|
ATTRIBUTES = %i[
|
|
9
25
|
endpoint
|
|
10
26
|
client_id
|
|
@@ -13,6 +29,14 @@ module Strava
|
|
|
13
29
|
|
|
14
30
|
attr_accessor(*Config::ATTRIBUTES)
|
|
15
31
|
|
|
32
|
+
#
|
|
33
|
+
# Reset configuration to default values.
|
|
34
|
+
#
|
|
35
|
+
# Sets the endpoint to the default Strava OAuth URL and clears
|
|
36
|
+
# the client credentials.
|
|
37
|
+
#
|
|
38
|
+
# @return [void]
|
|
39
|
+
#
|
|
16
40
|
def reset
|
|
17
41
|
self.endpoint = 'https://www.strava.com/oauth'
|
|
18
42
|
self.client_id = nil
|
|
@@ -21,10 +45,27 @@ module Strava
|
|
|
21
45
|
end
|
|
22
46
|
|
|
23
47
|
class << self
|
|
48
|
+
#
|
|
49
|
+
# Configure the OAuth client with a block.
|
|
50
|
+
#
|
|
51
|
+
# @yield [Config] Yields the configuration module for setup
|
|
52
|
+
# @return [Module] The Config module
|
|
53
|
+
#
|
|
54
|
+
# @example
|
|
55
|
+
# Strava::OAuth.configure do |config|
|
|
56
|
+
# config.client_id = '12345'
|
|
57
|
+
# config.client_secret = 'your_client_secret'
|
|
58
|
+
# end
|
|
59
|
+
#
|
|
24
60
|
def configure
|
|
25
61
|
block_given? ? yield(Config) : Config
|
|
26
62
|
end
|
|
27
63
|
|
|
64
|
+
#
|
|
65
|
+
# Returns the current OAuth configuration.
|
|
66
|
+
#
|
|
67
|
+
# @return [Module] The Config module
|
|
68
|
+
#
|
|
28
69
|
def config
|
|
29
70
|
Config
|
|
30
71
|
end
|
data/lib/strava/version.rb
CHANGED
|
@@ -2,11 +2,37 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Web
|
|
5
|
+
#
|
|
6
|
+
# Wraps an HTTP response with rate limit information.
|
|
7
|
+
#
|
|
8
|
+
# This class provides access to both the raw HTTP response and
|
|
9
|
+
# parsed rate limit data from the response headers.
|
|
10
|
+
#
|
|
11
|
+
# @see Strava::Api::Ratelimit
|
|
12
|
+
# @see Strava::Models::Mixins::HttpResponse
|
|
13
|
+
#
|
|
14
|
+
# @example Accessing response data
|
|
15
|
+
# activity = client.activity(1234567890)
|
|
16
|
+
# api_response = activity.http_response
|
|
17
|
+
#
|
|
18
|
+
# # Access raw HTTP response
|
|
19
|
+
# status = api_response.response.status
|
|
20
|
+
# headers = api_response.response.headers
|
|
21
|
+
#
|
|
22
|
+
# # Access rate limit information
|
|
23
|
+
# puts "Requests remaining: #{api_response.ratelimit.fifteen_minutes_remaining}"
|
|
24
|
+
#
|
|
5
25
|
class ApiResponse
|
|
6
|
-
|
|
26
|
+
# @return [Faraday::Response] The raw HTTP response
|
|
27
|
+
attr_accessor :response
|
|
7
28
|
|
|
29
|
+
# @return [Strava::Api::Ratelimit] Rate limit information extracted from response headers
|
|
30
|
+
attr_accessor :ratelimit
|
|
31
|
+
|
|
32
|
+
#
|
|
33
|
+
# Initialize a new ApiResponse with an HTTP response.
|
|
8
34
|
#
|
|
9
|
-
# @param [Faraday::Response]
|
|
35
|
+
# @param http_response [Faraday::Response] HTTP response from the Strava API
|
|
10
36
|
#
|
|
11
37
|
def initialize(http_response)
|
|
12
38
|
@response = http_response
|
data/lib/strava/web/client.rb
CHANGED
|
@@ -2,12 +2,35 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Web
|
|
5
|
+
#
|
|
6
|
+
# Base web client class for making HTTP requests to Strava APIs.
|
|
7
|
+
#
|
|
8
|
+
# This class provides the foundation for all Strava client implementations
|
|
9
|
+
# (API, OAuth, and Webhooks clients). It handles HTTP connection management,
|
|
10
|
+
# request execution, and configuration management.
|
|
11
|
+
#
|
|
12
|
+
# The client includes mixins for connection handling and HTTP request methods,
|
|
13
|
+
# and manages configuration attributes like endpoint URLs, user agents, and
|
|
14
|
+
# authentication tokens.
|
|
15
|
+
#
|
|
16
|
+
# @see Strava::Web::Connection
|
|
17
|
+
# @see Strava::Web::Request
|
|
18
|
+
#
|
|
5
19
|
class Client
|
|
6
20
|
include Strava::Web::Connection
|
|
7
21
|
include Strava::Web::Request
|
|
8
22
|
|
|
9
23
|
attr_accessor(*Config::ATTRIBUTES)
|
|
10
24
|
|
|
25
|
+
#
|
|
26
|
+
# Initialize a new client instance.
|
|
27
|
+
#
|
|
28
|
+
# @param options [Hash] Configuration options for the client
|
|
29
|
+
# @option options [String] :endpoint The API endpoint URL
|
|
30
|
+
# @option options [String] :user_agent The user agent string
|
|
31
|
+
# @option options [String] :token The access token for authentication
|
|
32
|
+
# @option options [Logger] :logger Custom logger instance
|
|
33
|
+
#
|
|
11
34
|
def initialize(options = {})
|
|
12
35
|
Strava::Web::Config::ATTRIBUTES.each do |key|
|
|
13
36
|
send("#{key}=", options[key] || Strava::Web.config.send(key))
|
|
@@ -15,26 +38,73 @@ module Strava
|
|
|
15
38
|
@logger ||= Strava::Logger.logger
|
|
16
39
|
end
|
|
17
40
|
|
|
41
|
+
#
|
|
42
|
+
# Returns the API endpoint URL for this client.
|
|
43
|
+
#
|
|
44
|
+
# @note This method must be implemented by subclasses
|
|
45
|
+
# @raise [NotImplementedError] if not implemented by subclass
|
|
46
|
+
# @return [String] The API endpoint URL
|
|
47
|
+
#
|
|
18
48
|
def endpoint
|
|
19
49
|
raise NotImplementedError
|
|
20
50
|
end
|
|
21
51
|
|
|
22
52
|
class << self
|
|
53
|
+
#
|
|
54
|
+
# Configure the client with a block or return the configuration.
|
|
55
|
+
#
|
|
56
|
+
# @yield [Config] Yields the configuration module for setup
|
|
57
|
+
# @return [Module] The Config module
|
|
58
|
+
#
|
|
59
|
+
# @example Configure the client
|
|
60
|
+
# Strava::Web::Client.configure do |config|
|
|
61
|
+
# config.endpoint = 'https://www.strava.com/api/v3'
|
|
62
|
+
# end
|
|
63
|
+
#
|
|
23
64
|
def configure
|
|
24
65
|
block_given? ? yield(Config) : Config
|
|
25
66
|
end
|
|
26
67
|
|
|
68
|
+
#
|
|
69
|
+
# Returns the current configuration.
|
|
70
|
+
#
|
|
71
|
+
# @return [Module] The Config module
|
|
72
|
+
#
|
|
27
73
|
def config
|
|
28
74
|
Config
|
|
29
75
|
end
|
|
30
76
|
end
|
|
31
77
|
|
|
78
|
+
#
|
|
79
|
+
# Parse method arguments that can be either (id, options) or (options).
|
|
80
|
+
#
|
|
81
|
+
# This helper method standardizes the common pattern where Strava API methods
|
|
82
|
+
# accept either a resource ID as the first parameter followed by an options hash,
|
|
83
|
+
# or just an options hash containing an :id key.
|
|
84
|
+
#
|
|
85
|
+
# @param id_or_options [String, Integer, Hash] Either a resource ID or options hash
|
|
86
|
+
# @param options [Hash] Options hash (when first param is an ID)
|
|
87
|
+
#
|
|
88
|
+
# @raise [ArgumentError] if the :id is missing from the options hash
|
|
89
|
+
#
|
|
90
|
+
# @return [Array<(String, Hash)>] Tuple of [id, options]
|
|
91
|
+
#
|
|
92
|
+
# @example With separate ID and options
|
|
93
|
+
# parse_args('12345', {per_page: 10})
|
|
94
|
+
# # => ['12345', {per_page: 10}]
|
|
95
|
+
#
|
|
96
|
+
# @example With ID in options hash
|
|
97
|
+
# parse_args({id: '12345', per_page: 10})
|
|
98
|
+
# # => ['12345', {per_page: 10}]
|
|
99
|
+
#
|
|
32
100
|
def parse_args(id_or_options, options = {})
|
|
33
101
|
if id_or_options.is_a?(Hash)
|
|
34
|
-
|
|
102
|
+
raise ArgumentError, 'Required argument :id missing' if id_or_options[:id].nil?
|
|
103
|
+
|
|
35
104
|
[id_or_options[:id], id_or_options.except(:id)]
|
|
36
105
|
else
|
|
37
|
-
|
|
106
|
+
raise ArgumentError, 'Required argument :id missing' if id_or_options.nil?
|
|
107
|
+
|
|
38
108
|
[id_or_options, options]
|
|
39
109
|
end
|
|
40
110
|
end
|
data/lib/strava/web/config.rb
CHANGED
|
@@ -2,9 +2,24 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Web
|
|
5
|
+
#
|
|
6
|
+
# Configuration module for web client HTTP settings.
|
|
7
|
+
#
|
|
8
|
+
# This module manages HTTP-related configuration settings shared across
|
|
9
|
+
# all Strava web clients (API, OAuth, Webhooks), including proxy settings,
|
|
10
|
+
# SSL certificate validation, timeouts, and logging.
|
|
11
|
+
#
|
|
12
|
+
# @example Configure web client settings
|
|
13
|
+
# Strava::Web.configure do |config|
|
|
14
|
+
# config.user_agent = 'MyApp/1.0'
|
|
15
|
+
# config.timeout = 30
|
|
16
|
+
# config.logger = Logger.new(STDOUT)
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
5
19
|
module Config
|
|
6
20
|
extend self
|
|
7
21
|
|
|
22
|
+
# @return [Array<Symbol>] List of configurable HTTP attributes
|
|
8
23
|
ATTRIBUTES = %i[
|
|
9
24
|
proxy
|
|
10
25
|
user_agent
|
|
@@ -17,6 +32,14 @@ module Strava
|
|
|
17
32
|
|
|
18
33
|
attr_accessor(*Config::ATTRIBUTES)
|
|
19
34
|
|
|
35
|
+
#
|
|
36
|
+
# Reset configuration to default values.
|
|
37
|
+
#
|
|
38
|
+
# Sets the user agent to the default client identifier and clears
|
|
39
|
+
# all optional settings (proxy, SSL certificates, timeouts, logger).
|
|
40
|
+
#
|
|
41
|
+
# @return [void]
|
|
42
|
+
#
|
|
20
43
|
def reset
|
|
21
44
|
self.user_agent = "Strava Ruby Client/#{Strava::VERSION}"
|
|
22
45
|
self.ca_path = nil
|
|
@@ -29,10 +52,27 @@ module Strava
|
|
|
29
52
|
end
|
|
30
53
|
|
|
31
54
|
class << self
|
|
55
|
+
#
|
|
56
|
+
# Configure the web client with a block.
|
|
57
|
+
#
|
|
58
|
+
# @yield [Config] Yields the configuration module for setup
|
|
59
|
+
# @return [Module] The Config module
|
|
60
|
+
#
|
|
61
|
+
# @example
|
|
62
|
+
# Strava::Web.configure do |config|
|
|
63
|
+
# config.proxy = 'http://proxy.example.com:8080'
|
|
64
|
+
# config.ca_file = '/path/to/ca-bundle.crt'
|
|
65
|
+
# end
|
|
66
|
+
#
|
|
32
67
|
def configure
|
|
33
68
|
block_given? ? yield(Config) : Config
|
|
34
69
|
end
|
|
35
70
|
|
|
71
|
+
#
|
|
72
|
+
# Returns the current web client configuration.
|
|
73
|
+
#
|
|
74
|
+
# @return [Module] The Config module
|
|
75
|
+
#
|
|
36
76
|
def config
|
|
37
77
|
Config
|
|
38
78
|
end
|
|
@@ -2,13 +2,52 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Web
|
|
5
|
+
#
|
|
6
|
+
# HTTP connection management for Strava web clients.
|
|
7
|
+
#
|
|
8
|
+
# This module provides connection handling and configuration for making HTTP
|
|
9
|
+
# requests to Strava APIs. It sets up a Faraday connection with proper headers,
|
|
10
|
+
# middleware, SSL configuration, and timeout settings.
|
|
11
|
+
#
|
|
12
|
+
# The connection is configured with:
|
|
13
|
+
# - JSON request and response handling
|
|
14
|
+
# - Automatic error raising for failed responses
|
|
15
|
+
# - Optional logging
|
|
16
|
+
# - SSL certificate validation
|
|
17
|
+
# - Request timeouts
|
|
18
|
+
#
|
|
19
|
+
# @api private
|
|
20
|
+
#
|
|
5
21
|
module Connection
|
|
6
22
|
private
|
|
7
23
|
|
|
24
|
+
#
|
|
25
|
+
# Returns HTTP headers to be included in requests.
|
|
26
|
+
#
|
|
27
|
+
# This method can be overridden in including classes to provide
|
|
28
|
+
# custom headers (e.g., authentication headers).
|
|
29
|
+
#
|
|
30
|
+
# @api private
|
|
31
|
+
# @return [Hash] HTTP headers hash
|
|
32
|
+
#
|
|
8
33
|
def headers
|
|
9
34
|
{}
|
|
10
35
|
end
|
|
11
36
|
|
|
37
|
+
#
|
|
38
|
+
# Establishes and returns a Faraday HTTP connection.
|
|
39
|
+
#
|
|
40
|
+
# Creates a memoized Faraday connection configured with:
|
|
41
|
+
# - Base endpoint URL
|
|
42
|
+
# - Custom headers including Accept and User-Agent
|
|
43
|
+
# - Proxy settings if configured
|
|
44
|
+
# - SSL certificate paths
|
|
45
|
+
# - Request timeouts
|
|
46
|
+
# - Middleware stack for multipart, URL encoding, error handling, and JSON parsing
|
|
47
|
+
#
|
|
48
|
+
# @api private
|
|
49
|
+
# @return [Faraday::Connection] Configured Faraday connection instance
|
|
50
|
+
#
|
|
12
51
|
def connection
|
|
13
52
|
@connection ||= begin
|
|
14
53
|
options = {
|