spree_api 4.5.5 → 4.6.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/app/controllers/concerns/spree/api/v2/product_list_includes.rb +2 -1
- data/app/controllers/spree/api/v2/base_controller.rb +2 -0
- data/app/controllers/spree/api/v2/data_feeds/google_controller.rb +24 -0
- data/app/controllers/spree/api/v2/platform/data_feeds_controller.rb +15 -0
- data/app/controllers/spree/api/v2/resource_controller.rb +1 -1
- data/app/controllers/spree/api/v2/storefront/products_controller.rb +1 -1
- data/app/controllers/spree/api/v2/storefront/taxons_controller.rb +4 -3
- data/app/helpers/spree/api/v2/collection_options_helpers.rb +1 -1
- data/app/models/spree/webhooks/event.rb +8 -0
- data/app/models/spree/webhooks/event_signature.rb +33 -0
- data/app/models/spree/webhooks/subscriber.rb +2 -1
- data/app/serializers/spree/api/v2/platform/data_feed_serializer.rb +13 -0
- data/app/serializers/spree/api/v2/platform/user_serializer.rb +1 -1
- data/app/serializers/spree/v2/storefront/product_serializer.rb +4 -0
- data/app/serializers/spree/v2/storefront/taxon_serializer.rb +4 -0
- data/app/serializers/spree/v2/storefront/user_serializer.rb +1 -1
- data/app/services/spree/webhooks/subscribers/handle_request.rb +5 -1
- data/app/services/spree/webhooks/subscribers/make_request.rb +3 -2
- data/brakeman.ignore +7 -0
- data/config/routes.rb +8 -0
- data/db/migrate/20221221122100_add_secret_key_to_spree_webhooks_subscribers.rb +5 -0
- data/db/migrate/20230116204600_backfill_secret_key_for_spree_webhooks_subscribers.rb +5 -0
- data/db/migrate/20230116205000_change_secret_key_to_non_null_column.rb +5 -0
- data/docs/oauth/index.yml +5 -5
- data/docs/v2/platform/index.yaml +329 -1
- data/docs/v2/storefront/index.yaml +129 -105
- data/lib/spree/api/dependencies.rb +86 -129
- metadata +15 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6324feb2fed1bf0f72361c80626006ad1de52f6516c0799993ab83ae61251166
|
4
|
+
data.tar.gz: c0006992c93b9bdafcc04cd0ac4934f92b08d0c5056b5981e54cbe847cb0a969
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b4e71a7c23dc66e6a93df0fea81e8882bf2934de213ecc0d4eee6a260622dbdd82a71c46d8bddcb71147b8b8c3395786ea06dbd3b2f8f23353adf5c8a2139238
|
7
|
+
data.tar.gz: cc8b2ecef98e57554dce21a75608562389d65c4a9a8b049ea26cdf8e38d1729ddf30fde834b1cf4c928b1ae970597a2039a303ef2fd7a5cd665eadafc9f4fc75
|
@@ -82,6 +82,8 @@ module Spree
|
|
82
82
|
@spree_current_user ||= doorkeeper_token.resource_owner
|
83
83
|
end
|
84
84
|
|
85
|
+
alias try_spree_current_user spree_current_user # for compatibility with spree_legacy_frontend
|
86
|
+
|
85
87
|
def spree_authorize!(action, subject, *args)
|
86
88
|
authorize!(action, subject, *args)
|
87
89
|
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Spree
|
2
|
+
module Api
|
3
|
+
module V2
|
4
|
+
module DataFeeds
|
5
|
+
class GoogleController < ::Spree::Api::V2::BaseController
|
6
|
+
def rss_feed
|
7
|
+
send_data data_feeds_google_rss_service.value[:file], filename: 'products.rss', type: 'text/xml'
|
8
|
+
end
|
9
|
+
|
10
|
+
private
|
11
|
+
|
12
|
+
def settings
|
13
|
+
@settings ||= Spree::DataFeed::Google.find_by!(store: current_store, slug: params[:slug], active: true)
|
14
|
+
end
|
15
|
+
|
16
|
+
def data_feeds_google_rss_service
|
17
|
+
Spree::Dependencies.data_feeds_google_rss_service.constantize.new.call(settings)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
@@ -35,7 +35,7 @@ module Spree
|
|
35
35
|
base_scope = model_class.for_store(current_store)
|
36
36
|
base_scope = base_scope.accessible_by(current_ability, :show) unless skip_cancancan
|
37
37
|
base_scope = base_scope.includes(scope_includes) if scope_includes.any? && action_name == 'index'
|
38
|
-
base_scope
|
38
|
+
model_class.include?(TranslatableResource) ? base_scope.i18n : base_scope
|
39
39
|
end
|
40
40
|
|
41
41
|
def scope_includes
|
@@ -16,7 +16,7 @@ module Spree
|
|
16
16
|
end
|
17
17
|
|
18
18
|
def resource
|
19
|
-
@resource ||= scope.find_by(slug: params[:id]) || scope.find(params[:id])
|
19
|
+
@resource ||= find_with_fallback_default_locale { scope.find_by(slug: params[:id]) } || scope.find(params[:id])
|
20
20
|
end
|
21
21
|
|
22
22
|
def collection_sorter
|
@@ -22,7 +22,7 @@ module Spree
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def resource
|
25
|
-
@resource ||= scope.find_by(permalink: params[:id]) || scope.find(params[:id])
|
25
|
+
@resource ||= find_with_fallback_default_locale { scope.find_by(permalink: params[:id]) } || scope.find(params[:id])
|
26
26
|
end
|
27
27
|
|
28
28
|
def model_class
|
@@ -30,13 +30,14 @@ module Spree
|
|
30
30
|
end
|
31
31
|
|
32
32
|
def scope_includes
|
33
|
-
node_includes = %i[icon parent taxonomy]
|
33
|
+
node_includes = %i[icon parent taxonomy translations]
|
34
34
|
|
35
35
|
{
|
36
36
|
parent: node_includes,
|
37
37
|
children: node_includes,
|
38
38
|
taxonomy: [root: node_includes],
|
39
|
-
icon: [attachment_attachment: :blob]
|
39
|
+
icon: [attachment_attachment: :blob],
|
40
|
+
translations: []
|
40
41
|
}
|
41
42
|
end
|
42
43
|
|
@@ -23,7 +23,7 @@ module Spree
|
|
23
23
|
# leaving this method in public scope so it's still possible to modify
|
24
24
|
# those params to support non-standard non-JSON API parameters
|
25
25
|
def collection_permitted_params
|
26
|
-
params.permit(:format, :page, :per_page, :sort, :include, fields: {}, filter: {})
|
26
|
+
params.permit(:format, :page, :per_page, :sort, :include, :locale, fields: {}, filter: {})
|
27
27
|
end
|
28
28
|
|
29
29
|
private
|
@@ -7,6 +7,14 @@ module Spree
|
|
7
7
|
|
8
8
|
self.whitelisted_ransackable_associations = %w[subscriber]
|
9
9
|
self.whitelisted_ransackable_attributes = %w[name request_errors response_code success url]
|
10
|
+
|
11
|
+
# Computes the base64-encoded HMAC SHA256 signature of the event for the given payload.
|
12
|
+
#
|
13
|
+
# @param payload [Hash, String] The payload for to the webhook subscriber.
|
14
|
+
# @return [String]
|
15
|
+
def signature_for(payload)
|
16
|
+
EventSignature.new(self, payload).computed_signature
|
17
|
+
end
|
10
18
|
end
|
11
19
|
end
|
12
20
|
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'openssl'
|
3
|
+
|
4
|
+
module Spree
|
5
|
+
module Webhooks
|
6
|
+
class EventSignature
|
7
|
+
def initialize(event, payload)
|
8
|
+
@event = event
|
9
|
+
@payload = payload
|
10
|
+
end
|
11
|
+
|
12
|
+
# Generates a base64-encoded HMAC SHA256 signature for the payload of the event.
|
13
|
+
#
|
14
|
+
# By using the stringified payload, the signature is made tamper-proof as any
|
15
|
+
# alterations of the data during transit will lead to an incorrect signature
|
16
|
+
# comparison by the client.
|
17
|
+
#
|
18
|
+
# @return [String] The computed signature
|
19
|
+
def computed_signature
|
20
|
+
@computed_signature ||=
|
21
|
+
Base64.strict_encode64(
|
22
|
+
OpenSSL::HMAC.digest('sha256', @event.subscriber.secret_key, payload)
|
23
|
+
)
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def payload
|
29
|
+
@payload.is_a?(String) ? @payload : @payload.to_json
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -5,10 +5,11 @@ module Spree
|
|
5
5
|
include Spree::VendorConcern
|
6
6
|
end
|
7
7
|
|
8
|
+
has_secure_token :secret_key
|
9
|
+
|
8
10
|
has_many :events, inverse_of: :subscriber
|
9
11
|
|
10
12
|
validates :url, 'spree/url': true, presence: true
|
11
|
-
|
12
13
|
validate :check_uri_path
|
13
14
|
|
14
15
|
self.whitelisted_ransackable_attributes = %w[active subscriptions url]
|
@@ -5,7 +5,7 @@ module Spree
|
|
5
5
|
class UserSerializer < BaseSerializer
|
6
6
|
set_type :user
|
7
7
|
|
8
|
-
attributes :email, :first_name, :last_name, :created_at, :updated_at, :public_metadata, :private_metadata
|
8
|
+
attributes :email, :first_name, :last_name, :created_at, :updated_at, :public_metadata, :private_metadata, :selected_locale
|
9
9
|
|
10
10
|
attribute :average_order_value do |user, params|
|
11
11
|
price_stats(user.report_values_for(:average_order_value, params[:store]))
|
@@ -44,6 +44,10 @@ module Spree
|
|
44
44
|
display_compare_at_price(product, params[:currency])
|
45
45
|
end
|
46
46
|
|
47
|
+
attribute :localized_slugs do |product, params|
|
48
|
+
product.localized_slugs_for_store(params[:store])
|
49
|
+
end
|
50
|
+
|
47
51
|
has_many :variants
|
48
52
|
has_many :option_types
|
49
53
|
has_many :product_properties
|
@@ -19,6 +19,10 @@ module Spree
|
|
19
19
|
taxon.leaf?
|
20
20
|
end
|
21
21
|
|
22
|
+
attribute :localized_slugs do |taxon, params|
|
23
|
+
taxon.localized_slugs_for_store(params[:store])
|
24
|
+
end
|
25
|
+
|
22
26
|
belongs_to :parent, record_type: :taxon, serializer: :taxon
|
23
27
|
belongs_to :taxonomy, record_type: :taxonomy
|
24
28
|
|
@@ -4,7 +4,7 @@ module Spree
|
|
4
4
|
class UserSerializer < BaseSerializer
|
5
5
|
set_type :user
|
6
6
|
|
7
|
-
attributes :email, :first_name, :last_name, :public_metadata
|
7
|
+
attributes :email, :first_name, :selected_locale, :last_name, :public_metadata
|
8
8
|
|
9
9
|
attribute :store_credits do |user|
|
10
10
|
user.total_available_store_credit
|
@@ -39,7 +39,11 @@ module Spree
|
|
39
39
|
|
40
40
|
def request
|
41
41
|
@request ||=
|
42
|
-
Spree::Webhooks::Subscribers::MakeRequest.new(
|
42
|
+
Spree::Webhooks::Subscribers::MakeRequest.new(
|
43
|
+
signature: event.signature_for(body_with_event_metadata),
|
44
|
+
url: url,
|
45
|
+
webhook_payload_body: body_with_event_metadata
|
46
|
+
)
|
43
47
|
end
|
44
48
|
alias make_request request
|
45
49
|
|
@@ -4,8 +4,9 @@ module Spree
|
|
4
4
|
module Webhooks
|
5
5
|
module Subscribers
|
6
6
|
class MakeRequest
|
7
|
-
def initialize(url:, webhook_payload_body:)
|
7
|
+
def initialize(signature:, url:, webhook_payload_body:)
|
8
8
|
@execution_time_in_milliseconds = 0
|
9
|
+
@signature = signature
|
9
10
|
@url = url
|
10
11
|
@webhook_payload_body = webhook_payload_body
|
11
12
|
@webhooks_timeout = ENV['SPREE_WEBHOOKS_TIMEOUT']
|
@@ -49,7 +50,7 @@ module Spree
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def request
|
52
|
-
req = Net::HTTP::Post.new(uri_path, HEADERS)
|
53
|
+
req = Net::HTTP::Post.new(uri_path, HEADERS.merge('X-Spree-Hmac-SHA256' => @signature))
|
53
54
|
req.body = webhook_payload_body
|
54
55
|
@request ||= begin
|
55
56
|
start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
data/brakeman.ignore
ADDED
data/config/routes.rb
CHANGED
@@ -196,6 +196,9 @@ Spree::Core::Engine.add_routes do
|
|
196
196
|
# Store API
|
197
197
|
resources :stores
|
198
198
|
|
199
|
+
# Data Feeds API
|
200
|
+
resources :data_feeds
|
201
|
+
|
199
202
|
# Configurations API
|
200
203
|
resources :payment_methods
|
201
204
|
resources :shipping_categories
|
@@ -207,6 +210,11 @@ Spree::Core::Engine.add_routes do
|
|
207
210
|
resources :subscribers
|
208
211
|
end
|
209
212
|
end
|
213
|
+
|
214
|
+
namespace :data_feeds do
|
215
|
+
# google data feed API
|
216
|
+
get '/google/:slug', to: 'google#rss_feed'
|
217
|
+
end
|
210
218
|
end
|
211
219
|
end
|
212
220
|
end
|
data/docs/oauth/index.yml
CHANGED
@@ -2,7 +2,7 @@ openapi: 3.0.3
|
|
2
2
|
servers:
|
3
3
|
- url: 'https://demo.spreecommerce.org'
|
4
4
|
description: demo
|
5
|
-
- url: 'http://localhost:
|
5
|
+
- url: 'http://localhost:4000'
|
6
6
|
description: localhost
|
7
7
|
info:
|
8
8
|
version: 1.0.0
|
@@ -139,7 +139,7 @@ components:
|
|
139
139
|
- expires_in
|
140
140
|
- refresh_token
|
141
141
|
- created_at
|
142
|
-
x-internal:
|
142
|
+
x-internal: false
|
143
143
|
CreateTokenBody:
|
144
144
|
type: object
|
145
145
|
x-examples:
|
@@ -152,7 +152,7 @@ components:
|
|
152
152
|
username: spree@example.com
|
153
153
|
password: spree123
|
154
154
|
scope: admin
|
155
|
-
x-internal:
|
155
|
+
x-internal: false
|
156
156
|
title: 'Create a new token (grant_type: password)'
|
157
157
|
description: ''
|
158
158
|
properties:
|
@@ -186,7 +186,7 @@ components:
|
|
186
186
|
example-1:
|
187
187
|
grant_type: refresh_token
|
188
188
|
refresh_token: SqJDIwX00fehqHxS6xmb-kzqAlrYe_0EHgekMexVT8k
|
189
|
-
x-internal:
|
189
|
+
x-internal: false
|
190
190
|
title: 'Create a new token (grant_type: client_credentials)'
|
191
191
|
description: ''
|
192
192
|
properties:
|
@@ -213,7 +213,7 @@ components:
|
|
213
213
|
example-1:
|
214
214
|
grant_type: refresh_token
|
215
215
|
refresh_token: SqJDIwX00fehqHxS6xmb-kzqAlrYe_0EHgekMexVT8k
|
216
|
-
x-internal:
|
216
|
+
x-internal: false
|
217
217
|
title: 'Refresh an existing token (grant_type: refresh_token)'
|
218
218
|
description: ''
|
219
219
|
properties:
|