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,10 +2,41 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Web
|
|
5
|
+
#
|
|
6
|
+
# Faraday middleware that raises exceptions for HTTP error responses.
|
|
7
|
+
#
|
|
8
|
+
# This middleware intercepts HTTP responses and raises appropriate exceptions
|
|
9
|
+
# based on the status code. It handles common HTTP error statuses and maps them
|
|
10
|
+
# to specific Strava error classes, including special handling for rate limiting
|
|
11
|
+
# (429) and resource not found (404) responses.
|
|
12
|
+
#
|
|
13
|
+
# @see Faraday::Middleware
|
|
14
|
+
# @see Strava::Errors::Fault
|
|
15
|
+
# @see Strava::Errors::RatelimitError
|
|
16
|
+
#
|
|
5
17
|
class RaiseResponseError < ::Faraday::Middleware
|
|
18
|
+
# @return [Hash] Default options inherited from Faraday's RaiseError middleware
|
|
6
19
|
DEFAULT_OPTIONS = Faraday::Response::RaiseError::DEFAULT_OPTIONS
|
|
20
|
+
|
|
21
|
+
# @return [Range] HTTP status codes that are considered client errors (400-599)
|
|
7
22
|
CLIENT_ERROR_STATUSES = (400...600)
|
|
8
23
|
|
|
24
|
+
#
|
|
25
|
+
# Callback invoked when an HTTP response is complete.
|
|
26
|
+
#
|
|
27
|
+
# Examines the HTTP status code and raises appropriate exceptions:
|
|
28
|
+
# - 404: Faraday::ResourceNotFound
|
|
29
|
+
# - 407: Faraday::ConnectionFailed (proxy authentication required)
|
|
30
|
+
# - 429: Strava::Errors::RatelimitError (rate limit exceeded)
|
|
31
|
+
# - 400-599: Strava::Errors::Fault (general client/server errors)
|
|
32
|
+
#
|
|
33
|
+
# @param env [Faraday::Env] The Faraday request/response environment
|
|
34
|
+
# @raise [Faraday::ResourceNotFound] When resource is not found (404)
|
|
35
|
+
# @raise [Faraday::ConnectionFailed] When proxy authentication fails (407)
|
|
36
|
+
# @raise [Strava::Errors::RatelimitError] When rate limit is exceeded (429)
|
|
37
|
+
# @raise [Strava::Errors::Fault] For other client/server errors (400-599)
|
|
38
|
+
# @return [void]
|
|
39
|
+
#
|
|
9
40
|
def on_complete(env)
|
|
10
41
|
case env[:status]
|
|
11
42
|
when 404
|
|
@@ -20,6 +51,16 @@ module Strava
|
|
|
20
51
|
end
|
|
21
52
|
end
|
|
22
53
|
|
|
54
|
+
#
|
|
55
|
+
# Extracts response values from the Faraday environment.
|
|
56
|
+
#
|
|
57
|
+
# Builds a hash containing response information (status, headers, body)
|
|
58
|
+
# and optionally includes request details if the middleware is configured
|
|
59
|
+
# with `include_request: true`.
|
|
60
|
+
#
|
|
61
|
+
# @param env [Faraday::Env] The Faraday request/response environment
|
|
62
|
+
# @return [Hash] Response values including status, headers, body, and optionally request details
|
|
63
|
+
#
|
|
23
64
|
def response_values(env)
|
|
24
65
|
response = {
|
|
25
66
|
status: env.status,
|
|
@@ -43,6 +84,12 @@ module Strava
|
|
|
43
84
|
)
|
|
44
85
|
end
|
|
45
86
|
|
|
87
|
+
#
|
|
88
|
+
# Extracts and decodes query parameters from the request URL.
|
|
89
|
+
#
|
|
90
|
+
# @param env [Faraday::Env] The Faraday request/response environment
|
|
91
|
+
# @return [Hash] Decoded query parameters
|
|
92
|
+
#
|
|
46
93
|
def query_params(env)
|
|
47
94
|
env.request.params_encoder ||= Faraday::Utils.default_params_encoder
|
|
48
95
|
env.params_encoder.decode(env.url.query)
|
data/lib/strava/web/request.rb
CHANGED
|
@@ -2,25 +2,81 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Web
|
|
5
|
+
#
|
|
6
|
+
# HTTP request methods for Strava web clients.
|
|
7
|
+
#
|
|
8
|
+
# This module provides GET, POST, PUT, and DELETE HTTP methods for making
|
|
9
|
+
# requests to Strava APIs. All methods return a wrapped response object
|
|
10
|
+
# that provides easy access to response data and metadata.
|
|
11
|
+
#
|
|
12
|
+
# @api private
|
|
13
|
+
#
|
|
5
14
|
module Request
|
|
15
|
+
#
|
|
16
|
+
# Perform an HTTP GET request.
|
|
17
|
+
#
|
|
18
|
+
# @param path [String] The API path (relative to endpoint)
|
|
19
|
+
# @param options [Hash] Query parameters and options
|
|
20
|
+
#
|
|
21
|
+
# @return [Strava::Web::Response] Wrapped HTTP response
|
|
22
|
+
#
|
|
6
23
|
def get(path, options = {})
|
|
7
24
|
request(:get, path, options)
|
|
8
25
|
end
|
|
9
26
|
|
|
27
|
+
#
|
|
28
|
+
# Perform an HTTP POST request.
|
|
29
|
+
#
|
|
30
|
+
# @param path [String] The API path (relative to endpoint)
|
|
31
|
+
# @param options [Hash] Request body parameters and options
|
|
32
|
+
#
|
|
33
|
+
# @return [Strava::Web::Response] Wrapped HTTP response
|
|
34
|
+
#
|
|
10
35
|
def post(path, options = {})
|
|
11
36
|
request(:post, path, options)
|
|
12
37
|
end
|
|
13
38
|
|
|
39
|
+
#
|
|
40
|
+
# Perform an HTTP PUT request.
|
|
41
|
+
#
|
|
42
|
+
# @param path [String] The API path (relative to endpoint)
|
|
43
|
+
# @param options [Hash] Request body parameters and options
|
|
44
|
+
#
|
|
45
|
+
# @return [Strava::Web::Response] Wrapped HTTP response
|
|
46
|
+
#
|
|
14
47
|
def put(path, options = {})
|
|
15
48
|
request(:put, path, options)
|
|
16
49
|
end
|
|
17
50
|
|
|
51
|
+
#
|
|
52
|
+
# Perform an HTTP DELETE request.
|
|
53
|
+
#
|
|
54
|
+
# @param path [String] The API path (relative to endpoint)
|
|
55
|
+
# @param options [Hash] Query parameters and options
|
|
56
|
+
#
|
|
57
|
+
# @return [Strava::Web::Response] Wrapped HTTP response
|
|
58
|
+
#
|
|
18
59
|
def delete(path, options = {})
|
|
19
60
|
request(:delete, path, options)
|
|
20
61
|
end
|
|
21
62
|
|
|
22
63
|
private
|
|
23
64
|
|
|
65
|
+
#
|
|
66
|
+
# Executes an HTTP request with the specified method.
|
|
67
|
+
#
|
|
68
|
+
# Constructs the full URL from the endpoint and path, sends the request
|
|
69
|
+
# using Faraday, and wraps the response in a Strava::Web::Response object.
|
|
70
|
+
#
|
|
71
|
+
# @api private
|
|
72
|
+
# @param method [Symbol] HTTP method (:get, :post, :put, :delete)
|
|
73
|
+
# @param path [String] The API path (relative to endpoint)
|
|
74
|
+
# @param options [Hash] Request parameters and options
|
|
75
|
+
# @option options [String] :endpoint Override the default endpoint URL
|
|
76
|
+
# @option options [Hash] :request Faraday request options (timeouts, etc.)
|
|
77
|
+
#
|
|
78
|
+
# @return [Strava::Web::Response] Wrapped HTTP response
|
|
79
|
+
#
|
|
24
80
|
def request(method, path, options)
|
|
25
81
|
options = options.dup if options.key?(:request) || options.key?(:endpoint)
|
|
26
82
|
root = options.delete(:endpoint) || endpoint
|
data/lib/strava/web/response.rb
CHANGED
|
@@ -75,6 +75,17 @@ module Strava
|
|
|
75
75
|
end
|
|
76
76
|
end
|
|
77
77
|
|
|
78
|
+
#
|
|
79
|
+
# Delegates missing methods to the response body or array.
|
|
80
|
+
#
|
|
81
|
+
# If the response is an array, delegates methods to the array.
|
|
82
|
+
# Otherwise, delegates to the response body hash, allowing access
|
|
83
|
+
# to response fields as if they were methods.
|
|
84
|
+
#
|
|
85
|
+
# @param method_symbol [Symbol] The method name to forward
|
|
86
|
+
# @param args [Array] Arguments to pass to the method
|
|
87
|
+
# @return [Object] Result from the delegated method
|
|
88
|
+
#
|
|
78
89
|
def method_missing(method_symbol, ...)
|
|
79
90
|
case @response
|
|
80
91
|
when Array
|
|
@@ -84,6 +95,13 @@ module Strava
|
|
|
84
95
|
end
|
|
85
96
|
end
|
|
86
97
|
|
|
98
|
+
#
|
|
99
|
+
# Checks if the response body or array responds to a method.
|
|
100
|
+
#
|
|
101
|
+
# @param method_name [Symbol] The method name to check
|
|
102
|
+
# @param include_private [Boolean] Whether to include private methods
|
|
103
|
+
# @return [Boolean] true if the response responds to the method
|
|
104
|
+
#
|
|
87
105
|
def respond_to_missing?(method_name, include_private = false)
|
|
88
106
|
super
|
|
89
107
|
end
|
|
@@ -2,9 +2,49 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Webhooks
|
|
5
|
+
#
|
|
6
|
+
# Webhooks client for Strava push subscriptions.
|
|
7
|
+
#
|
|
8
|
+
# Strava provides webhooks for receiving real-time updates about athlete activities
|
|
9
|
+
# and other events. This client manages webhook subscriptions (create, list, delete).
|
|
10
|
+
#
|
|
11
|
+
# Before creating a subscription, you must implement an HTTP endpoint that:
|
|
12
|
+
# 1. Handles GET requests for subscription validation (Challenge)
|
|
13
|
+
# 2. Handles POST requests for webhook events (Event)
|
|
14
|
+
#
|
|
15
|
+
# @example Create and manage a webhook subscription
|
|
16
|
+
# client = Strava::Webhooks::Client.new(
|
|
17
|
+
# client_id: "your_client_id",
|
|
18
|
+
# client_secret: "your_client_secret"
|
|
19
|
+
# )
|
|
20
|
+
#
|
|
21
|
+
# # Create subscription
|
|
22
|
+
# subscription = client.create_push_subscription(
|
|
23
|
+
# callback_url: 'https://myapp.com/strava/webhook',
|
|
24
|
+
# verify_token: 'my_verify_token'
|
|
25
|
+
# )
|
|
26
|
+
#
|
|
27
|
+
# # List subscriptions
|
|
28
|
+
# subscriptions = client.push_subscriptions
|
|
29
|
+
#
|
|
30
|
+
# # Delete subscription
|
|
31
|
+
# client.delete_push_subscription(subscription.id)
|
|
32
|
+
#
|
|
33
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
34
|
+
# @see Strava::Webhooks::Models::Challenge
|
|
35
|
+
# @see Strava::Webhooks::Models::Event
|
|
36
|
+
#
|
|
5
37
|
class Client < Strava::Web::Client
|
|
6
38
|
attr_accessor(*Config::ATTRIBUTES)
|
|
7
39
|
|
|
40
|
+
#
|
|
41
|
+
# Initialize a new Webhooks client.
|
|
42
|
+
#
|
|
43
|
+
# @param [Hash] options Configuration options
|
|
44
|
+
# @option options [String] :client_id Strava application client ID (required)
|
|
45
|
+
# @option options [String] :client_secret Strava application client secret (required)
|
|
46
|
+
# @option options [String] :endpoint API endpoint URL (defaults to https://www.strava.com/api/v3)
|
|
47
|
+
#
|
|
8
48
|
def initialize(options = {})
|
|
9
49
|
Strava::Webhooks::Config::ATTRIBUTES.each do |key|
|
|
10
50
|
send("#{key}=", options[key] || Strava::Webhooks.config.send(key))
|
|
@@ -17,7 +57,20 @@ module Strava
|
|
|
17
57
|
end
|
|
18
58
|
|
|
19
59
|
#
|
|
20
|
-
#
|
|
60
|
+
# List existing push subscriptions.
|
|
61
|
+
#
|
|
62
|
+
# Returns all active webhook subscriptions for your application.
|
|
63
|
+
# Typically, Strava only allows one subscription per application.
|
|
64
|
+
#
|
|
65
|
+
# @param [Hash] options Additional options
|
|
66
|
+
#
|
|
67
|
+
# @return [Array<Strava::Webhooks::Models::Subscription>] Array of subscriptions
|
|
68
|
+
#
|
|
69
|
+
# @example List subscriptions
|
|
70
|
+
# subscriptions = client.push_subscriptions
|
|
71
|
+
# subscriptions.each { |sub| puts "ID: #{sub.id}, URL: #{sub.callback_url}" }
|
|
72
|
+
#
|
|
73
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
21
74
|
#
|
|
22
75
|
def push_subscriptions(options = {})
|
|
23
76
|
get('push_subscriptions', options).map do |row|
|
|
@@ -26,7 +79,20 @@ module Strava
|
|
|
26
79
|
end
|
|
27
80
|
|
|
28
81
|
#
|
|
29
|
-
# Delete
|
|
82
|
+
# Delete a push subscription.
|
|
83
|
+
#
|
|
84
|
+
# Removes an existing webhook subscription by ID. After deletion,
|
|
85
|
+
# your application will no longer receive webhook events.
|
|
86
|
+
#
|
|
87
|
+
# @param [Integer, Hash] id_or_options Subscription ID or options hash with :id key
|
|
88
|
+
# @param [Hash] options Additional options
|
|
89
|
+
#
|
|
90
|
+
# @return [nil]
|
|
91
|
+
#
|
|
92
|
+
# @example Delete subscription
|
|
93
|
+
# client.delete_push_subscription(12345)
|
|
94
|
+
#
|
|
95
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
30
96
|
#
|
|
31
97
|
def delete_push_subscription(id_or_options, options = {})
|
|
32
98
|
id, options = parse_args(id_or_options, options)
|
|
@@ -35,22 +101,57 @@ module Strava
|
|
|
35
101
|
end
|
|
36
102
|
|
|
37
103
|
#
|
|
38
|
-
# Create a subscription.
|
|
104
|
+
# Create a new push subscription.
|
|
105
|
+
#
|
|
106
|
+
# Creates a webhook subscription for receiving real-time activity updates.
|
|
107
|
+
# Your callback URL must be publicly accessible and handle both GET (for validation)
|
|
108
|
+
# and POST (for events) requests.
|
|
109
|
+
#
|
|
110
|
+
# Strava will send a GET request to validate your callback URL before creating
|
|
111
|
+
# the subscription. Your endpoint must respond with the challenge token.
|
|
112
|
+
#
|
|
113
|
+
# @param [Hash] options Subscription parameters
|
|
114
|
+
# @option options [String] :callback_url Public HTTPS URL where webhook events will be sent (required)
|
|
115
|
+
# @option options [String] :verify_token Token for validating webhook challenges (required)
|
|
116
|
+
#
|
|
117
|
+
# @return [Strava::Webhooks::Models::Subscription] The created subscription
|
|
118
|
+
#
|
|
119
|
+
# @example Create subscription
|
|
120
|
+
# subscription = client.create_push_subscription(
|
|
121
|
+
# callback_url: 'https://myapp.com/strava/webhook',
|
|
122
|
+
# verify_token: 'my_secret_token_123'
|
|
123
|
+
# )
|
|
124
|
+
# puts "Subscription ID: #{subscription.id}"
|
|
39
125
|
#
|
|
40
|
-
# @
|
|
41
|
-
#
|
|
42
|
-
# @option options [String] :verify_token
|
|
43
|
-
# String chosen by the application owner for client security. An identical string should be returned by Strava's subscription service.
|
|
126
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
127
|
+
# @see Strava::Webhooks::Models::Challenge
|
|
44
128
|
#
|
|
45
129
|
def create_push_subscription(options = {})
|
|
46
130
|
Strava::Webhooks::Models::Subscription.new(post('push_subscriptions', options))
|
|
47
131
|
end
|
|
48
132
|
|
|
49
133
|
class << self
|
|
134
|
+
#
|
|
135
|
+
# Configure the Webhooks client with a block.
|
|
136
|
+
#
|
|
137
|
+
# @yield [Config] Yields the configuration module for setup
|
|
138
|
+
# @return [Module] The Config module
|
|
139
|
+
#
|
|
140
|
+
# @example
|
|
141
|
+
# Strava::Webhooks::Client.configure do |config|
|
|
142
|
+
# config.client_id = ENV['STRAVA_CLIENT_ID']
|
|
143
|
+
# config.client_secret = ENV['STRAVA_CLIENT_SECRET']
|
|
144
|
+
# end
|
|
145
|
+
#
|
|
50
146
|
def configure
|
|
51
147
|
block_given? ? yield(Config) : Config
|
|
52
148
|
end
|
|
53
149
|
|
|
150
|
+
#
|
|
151
|
+
# Returns the current Webhooks client configuration.
|
|
152
|
+
#
|
|
153
|
+
# @return [Module] The Config module
|
|
154
|
+
#
|
|
54
155
|
def config
|
|
55
156
|
Config
|
|
56
157
|
end
|
|
@@ -2,9 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Webhooks
|
|
5
|
+
#
|
|
6
|
+
# Configuration module for the Webhooks client.
|
|
7
|
+
#
|
|
8
|
+
# This module manages webhook-specific configuration settings including the
|
|
9
|
+
# API endpoint URL and application credentials (client ID and secret) required
|
|
10
|
+
# for managing webhook subscriptions.
|
|
11
|
+
#
|
|
12
|
+
# Webhooks allow your application to receive real-time notifications when
|
|
13
|
+
# athletes create new activities or update their profile information.
|
|
14
|
+
#
|
|
15
|
+
# @example Configure Webhooks client
|
|
16
|
+
# Strava::Webhooks.configure do |config|
|
|
17
|
+
# config.client_id = ENV['STRAVA_CLIENT_ID']
|
|
18
|
+
# config.client_secret = ENV['STRAVA_CLIENT_SECRET']
|
|
19
|
+
# end
|
|
20
|
+
#
|
|
21
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
22
|
+
#
|
|
5
23
|
module Config
|
|
6
24
|
extend self
|
|
7
25
|
|
|
26
|
+
# @return [Array<Symbol>] List of configurable webhook attributes
|
|
8
27
|
ATTRIBUTES = %i[
|
|
9
28
|
endpoint
|
|
10
29
|
client_id
|
|
@@ -13,6 +32,14 @@ module Strava
|
|
|
13
32
|
|
|
14
33
|
attr_accessor(*Config::ATTRIBUTES)
|
|
15
34
|
|
|
35
|
+
#
|
|
36
|
+
# Reset configuration to default values.
|
|
37
|
+
#
|
|
38
|
+
# Sets the endpoint to the default Strava API v3 URL and clears
|
|
39
|
+
# the client credentials.
|
|
40
|
+
#
|
|
41
|
+
# @return [void]
|
|
42
|
+
#
|
|
16
43
|
def reset
|
|
17
44
|
self.endpoint = 'https://www.strava.com/api/v3'
|
|
18
45
|
self.client_id = nil
|
|
@@ -21,10 +48,27 @@ module Strava
|
|
|
21
48
|
end
|
|
22
49
|
|
|
23
50
|
class << self
|
|
51
|
+
#
|
|
52
|
+
# Configure the Webhooks client with a block.
|
|
53
|
+
#
|
|
54
|
+
# @yield [Config] Yields the configuration module for setup
|
|
55
|
+
# @return [Module] The Config module
|
|
56
|
+
#
|
|
57
|
+
# @example
|
|
58
|
+
# Strava::Webhooks.configure do |config|
|
|
59
|
+
# config.client_id = '12345'
|
|
60
|
+
# config.client_secret = 'your_client_secret'
|
|
61
|
+
# end
|
|
62
|
+
#
|
|
24
63
|
def configure
|
|
25
64
|
block_given? ? yield(Config) : Config
|
|
26
65
|
end
|
|
27
66
|
|
|
67
|
+
#
|
|
68
|
+
# Returns the current Webhooks configuration.
|
|
69
|
+
#
|
|
70
|
+
# @return [Module] The Config module
|
|
71
|
+
#
|
|
28
72
|
def config
|
|
29
73
|
Config
|
|
30
74
|
end
|
|
@@ -3,11 +3,51 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Webhooks
|
|
5
5
|
module Models
|
|
6
|
+
#
|
|
7
|
+
# Represents a webhook subscription validation challenge.
|
|
8
|
+
#
|
|
9
|
+
# When creating a webhook subscription, Strava sends a GET request to your
|
|
10
|
+
# callback URL with challenge parameters. Your application must validate the
|
|
11
|
+
# verify_token and respond with the challenge value.
|
|
12
|
+
#
|
|
13
|
+
# @example Handle webhook challenge in Rails
|
|
14
|
+
# def webhook
|
|
15
|
+
# if request.get?
|
|
16
|
+
# challenge = Strava::Webhooks::Models::Challenge.new(request.query_parameters)
|
|
17
|
+
# if challenge.verify_token == ENV['STRAVA_VERIFY_TOKEN']
|
|
18
|
+
# render json: challenge.response
|
|
19
|
+
# else
|
|
20
|
+
# head :forbidden
|
|
21
|
+
# end
|
|
22
|
+
# end
|
|
23
|
+
# end
|
|
24
|
+
#
|
|
25
|
+
# @example Handle challenge in Sinatra
|
|
26
|
+
# get '/webhook' do
|
|
27
|
+
# challenge = Strava::Webhooks::Models::Challenge.new(params)
|
|
28
|
+
# halt 403 unless challenge.verify_token == ENV['STRAVA_VERIFY_TOKEN']
|
|
29
|
+
# content_type :json
|
|
30
|
+
# challenge.response.to_json
|
|
31
|
+
# end
|
|
32
|
+
#
|
|
33
|
+
# @see Strava::Webhooks::Client#create_push_subscription
|
|
34
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
35
|
+
#
|
|
6
36
|
class Challenge < Hashie::Trash
|
|
37
|
+
# @return [String] Subscription mode, typically "subscribe"
|
|
7
38
|
property 'mode', from: 'hub.mode'
|
|
39
|
+
|
|
40
|
+
# @return [String] Verification token to validate the request
|
|
8
41
|
property 'verify_token', from: 'hub.verify_token'
|
|
42
|
+
|
|
43
|
+
# @return [String] Challenge value that must be echoed back
|
|
9
44
|
property 'challenge', from: 'hub.challenge'
|
|
10
45
|
|
|
46
|
+
#
|
|
47
|
+
# Returns the response hash that should be sent back to Strava.
|
|
48
|
+
#
|
|
49
|
+
# @return [Hash] Response containing the challenge value
|
|
50
|
+
#
|
|
11
51
|
def response
|
|
12
52
|
{ 'hub.challenge' => challenge }
|
|
13
53
|
end
|
|
@@ -3,13 +3,63 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Webhooks
|
|
5
5
|
module Models
|
|
6
|
+
#
|
|
7
|
+
# Represents a webhook event from Strava.
|
|
8
|
+
#
|
|
9
|
+
# After successfully creating a webhook subscription, Strava will send POST
|
|
10
|
+
# requests to your callback URL when activity events occur. Events include
|
|
11
|
+
# activity creation, updates, and deletions.
|
|
12
|
+
#
|
|
13
|
+
# @example Handle webhook event in Rails
|
|
14
|
+
# def webhook
|
|
15
|
+
# if request.post?
|
|
16
|
+
# event = Strava::Webhooks::Models::Event.new(JSON.parse(request.body.read))
|
|
17
|
+
#
|
|
18
|
+
# case event.object_type
|
|
19
|
+
# when 'activity'
|
|
20
|
+
# case event.aspect_type
|
|
21
|
+
# when 'create'
|
|
22
|
+
# # Fetch and process the new activity
|
|
23
|
+
# activity = client.activity(event.id)
|
|
24
|
+
# process_new_activity(activity)
|
|
25
|
+
# when 'update'
|
|
26
|
+
# # Handle activity update
|
|
27
|
+
# puts "Activity #{event.id} updated: #{event.updates.inspect}"
|
|
28
|
+
# when 'delete'
|
|
29
|
+
# # Handle activity deletion
|
|
30
|
+
# delete_activity(event.id)
|
|
31
|
+
# end
|
|
32
|
+
# when 'athlete'
|
|
33
|
+
# # Handle athlete updates (authorization revoked, etc.)
|
|
34
|
+
# end
|
|
35
|
+
#
|
|
36
|
+
# head :ok
|
|
37
|
+
# end
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
# @see Strava::Webhooks::Client#create_push_subscription
|
|
41
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
42
|
+
#
|
|
6
43
|
class Event < Hashie::Trash
|
|
44
|
+
# @return [String] Type of object (e.g., "activity", "athlete")
|
|
7
45
|
property 'object_type'
|
|
46
|
+
|
|
47
|
+
# @return [Integer] ID of the object (activity ID, athlete ID, etc.)
|
|
8
48
|
property 'id', from: 'object_id'
|
|
49
|
+
|
|
50
|
+
# @return [String] Type of event: "create", "update", or "delete"
|
|
9
51
|
property 'aspect_type'
|
|
52
|
+
|
|
53
|
+
# @return [Hash] Map of updated properties (only for update events)
|
|
10
54
|
property 'updates'
|
|
55
|
+
|
|
56
|
+
# @return [Integer] Athlete ID who owns the object
|
|
11
57
|
property 'owner_id'
|
|
58
|
+
|
|
59
|
+
# @return [Integer] ID of the webhook subscription
|
|
12
60
|
property 'subscription_id'
|
|
61
|
+
|
|
62
|
+
# @return [Time] Timestamp when the event occurred
|
|
13
63
|
property 'event_time', transform_with: ->(v) { Time.at(v) }
|
|
14
64
|
end
|
|
15
65
|
end
|
|
@@ -3,12 +3,39 @@
|
|
|
3
3
|
module Strava
|
|
4
4
|
module Webhooks
|
|
5
5
|
module Models
|
|
6
|
+
#
|
|
7
|
+
# Represents a webhook subscription.
|
|
8
|
+
#
|
|
9
|
+
# Webhook subscriptions allow your application to receive real-time notifications
|
|
10
|
+
# when athletes create or update activities, or update their profile information.
|
|
11
|
+
# Each subscription is associated with a callback URL where events will be posted.
|
|
12
|
+
#
|
|
13
|
+
# @example List subscriptions
|
|
14
|
+
# subscriptions = client.subscriptions
|
|
15
|
+
# subscriptions.each do |sub|
|
|
16
|
+
# puts "Subscription #{sub.id}: #{sub.callback_url}"
|
|
17
|
+
# end
|
|
18
|
+
#
|
|
19
|
+
# @see Strava::Webhooks::Client
|
|
20
|
+
# @see https://developers.strava.com/docs/webhooks/
|
|
21
|
+
#
|
|
6
22
|
class Subscription < Strava::Models::Response
|
|
23
|
+
# @return [Integer] The subscription ID
|
|
7
24
|
property 'id'
|
|
25
|
+
|
|
26
|
+
# @return [Integer] The ID of the application that created the subscription
|
|
8
27
|
property 'application_id'
|
|
28
|
+
|
|
29
|
+
# @return [String] The callback URL where webhook events will be posted
|
|
9
30
|
property 'callback_url'
|
|
31
|
+
|
|
32
|
+
# @return [Integer] Resource state indicator
|
|
10
33
|
property 'resource_state'
|
|
34
|
+
|
|
35
|
+
# @return [Time] When the subscription was created
|
|
11
36
|
property 'created_at', transform_with: ->(v) { Time.parse(v) }
|
|
37
|
+
|
|
38
|
+
# @return [Time] When the subscription was last updated
|
|
12
39
|
property 'updated_at', transform_with: ->(v) { Time.parse(v) }
|
|
13
40
|
end
|
|
14
41
|
end
|
data/lib/strava-ruby-client.rb
CHANGED
|
@@ -44,8 +44,6 @@ require_relative 'strava/models/activity_stats'
|
|
|
44
44
|
require_relative 'strava/models/activity_total'
|
|
45
45
|
require_relative 'strava/models/activity_zone'
|
|
46
46
|
require_relative 'strava/models/base_stream'
|
|
47
|
-
require_relative 'strava/models/club_activity'
|
|
48
|
-
require_relative 'strava/models/club_athlete'
|
|
49
47
|
require_relative 'strava/models/club_event'
|
|
50
48
|
require_relative 'strava/models/comment'
|
|
51
49
|
require_relative 'strava/models/destination'
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: strava-ruby-client
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 3.
|
|
4
|
+
version: 3.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Daniel Doubrovkine
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-08-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -108,8 +108,6 @@ files:
|
|
|
108
108
|
- lib/strava/models/activity_zone.rb
|
|
109
109
|
- lib/strava/models/authorization.rb
|
|
110
110
|
- lib/strava/models/base_stream.rb
|
|
111
|
-
- lib/strava/models/club_activity.rb
|
|
112
|
-
- lib/strava/models/club_athlete.rb
|
|
113
111
|
- lib/strava/models/club_event.rb
|
|
114
112
|
- lib/strava/models/comment.rb
|
|
115
113
|
- lib/strava/models/destination.rb
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Strava
|
|
4
|
-
module Models
|
|
5
|
-
# https://developers.strava.com/docs/reference/#api-models-ClubActivity
|
|
6
|
-
class ClubActivity < Strava::Models::Response
|
|
7
|
-
include Mixins::ElevationGain
|
|
8
|
-
include Mixins::SportType
|
|
9
|
-
|
|
10
|
-
property 'athlete', transform_with: ->(v) { Strava::Models::MetaAthlete.new(v) }
|
|
11
|
-
property 'name'
|
|
12
|
-
include Mixins::Distance
|
|
13
|
-
include Mixins::MovingTime
|
|
14
|
-
include Mixins::ElapsedTime
|
|
15
|
-
include Mixins::TotalElevationGain
|
|
16
|
-
include Mixins::SportType
|
|
17
|
-
property 'workout_type'
|
|
18
|
-
# undocumented
|
|
19
|
-
property 'resource_state'
|
|
20
|
-
end
|
|
21
|
-
end
|
|
22
|
-
end
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module Strava
|
|
4
|
-
module Models
|
|
5
|
-
# https://developers.strava.com/docs/reference/#api-models-ClubAthlete
|
|
6
|
-
class ClubAthlete < Strava::Models::Response
|
|
7
|
-
property 'resource_state'
|
|
8
|
-
property 'firstname'
|
|
9
|
-
property 'lastname'
|
|
10
|
-
property 'member'
|
|
11
|
-
property 'admin'
|
|
12
|
-
property 'owner'
|
|
13
|
-
# undocumented
|
|
14
|
-
property 'membership'
|
|
15
|
-
|
|
16
|
-
def name
|
|
17
|
-
[firstname, lastname].compact.join(' ') if firstname || lastname
|
|
18
|
-
end
|
|
19
|
-
end
|
|
20
|
-
end
|
|
21
|
-
end
|