spree_api 6.0.0.rc5 → 6.0.0.rc7
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/v3/admin/auth_cookies.rb +23 -0
- data/app/controllers/concerns/spree/api/v3/admin/refund_authorization.rb +26 -0
- data/app/controllers/concerns/spree/api/v3/admin_authentication.rb +1 -0
- data/app/controllers/concerns/spree/api/v3/api_key_authentication.rb +14 -2
- data/app/controllers/concerns/spree/api/v3/cart_resolvable.rb +15 -2
- data/app/controllers/concerns/spree/api/v3/digital_assets_resource.rb +68 -0
- data/app/controllers/concerns/spree/api/v3/error_handler.rb +3 -0
- data/app/controllers/concerns/spree/api/v3/jwt_authentication.rb +27 -1
- data/app/controllers/concerns/spree/api/v3/orders/fulfillment_actions.rb +6 -1
- data/app/controllers/spree/api/v3/admin/allowed_origins_controller.rb +4 -1
- data/app/controllers/spree/api/v3/admin/auth_controller.rb +32 -5
- data/app/controllers/spree/api/v3/admin/commission_lines_controller.rb +2 -2
- data/app/controllers/spree/api/v3/admin/custom_fields_controller.rb +4 -7
- data/app/controllers/spree/api/v3/admin/customer_groups_controller.rb +4 -0
- data/app/controllers/spree/api/v3/admin/customers/store_credits_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/customers_controller.rb +13 -8
- data/app/controllers/spree/api/v3/admin/delivery_profiles/origin_groups_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/delivery_profiles_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/digital_links_controller.rb +3 -1
- data/app/controllers/spree/api/v3/admin/invitation_acceptances_controller.rb +2 -0
- data/app/controllers/spree/api/v3/admin/me_controller.rb +2 -0
- data/app/controllers/spree/api/v3/admin/option_types_controller.rb +13 -0
- data/app/controllers/spree/api/v3/admin/orders/claims_controller.rb +2 -0
- data/app/controllers/spree/api/v3/admin/orders/exchanges_controller.rb +9 -0
- data/app/controllers/spree/api/v3/admin/orders/fulfillments_controller.rb +1 -1
- data/app/controllers/spree/api/v3/admin/orders/payments_controller.rb +7 -4
- data/app/controllers/spree/api/v3/admin/orders/returns_controller.rb +2 -0
- data/app/controllers/spree/api/v3/admin/orders_controller.rb +10 -2
- data/app/controllers/spree/api/v3/admin/password_resets_controller.rb +7 -1
- data/app/controllers/spree/api/v3/admin/price_lists_controller.rb +18 -0
- data/app/controllers/spree/api/v3/admin/product_types_controller.rb +12 -1
- data/app/controllers/spree/api/v3/admin/products/digital_assets_controller.rb +5 -109
- data/app/controllers/spree/api/v3/admin/products/variants_controller.rb +4 -1
- data/app/controllers/spree/api/v3/admin/products_controller.rb +28 -3
- data/app/controllers/spree/api/v3/admin/sellers/payouts_controller.rb +4 -3
- data/app/controllers/spree/api/v3/admin/stock_transfers_controller.rb +3 -2
- data/app/controllers/spree/api/v3/admin/store_controller.rb +7 -0
- data/app/controllers/spree/api/v3/admin/tags_controller.rb +11 -9
- data/app/controllers/spree/api/v3/admin/webhook_endpoints_controller.rb +5 -2
- data/app/controllers/spree/api/v3/resource_controller.rb +15 -2
- data/app/controllers/spree/api/v3/seller/auth_controller.rb +10 -0
- data/app/controllers/spree/api/v3/seller/invitation_acceptances_controller.rb +2 -0
- data/app/controllers/spree/api/v3/seller/me_controller.rb +4 -0
- data/app/controllers/spree/api/v3/seller/orders_controller.rb +11 -3
- data/app/controllers/spree/api/v3/seller/password_resets_controller.rb +5 -1
- data/app/controllers/spree/api/v3/seller/products/digital_assets_controller.rb +67 -0
- data/app/controllers/spree/api/v3/seller/products_controller.rb +4 -2
- data/app/controllers/spree/api/v3/seller/team_controller.rb +1 -1
- data/app/controllers/spree/api/v3/store/carts/store_credits_controller.rb +9 -1
- data/app/controllers/spree/api/v3/store/carts_controller.rb +14 -0
- data/app/controllers/spree/api/v3/store/customers_controller.rb +13 -1
- data/app/controllers/spree/api/v3/store/delivery_methods_controller.rb +6 -1
- data/app/controllers/spree/api/v3/store/products/filters_controller.rb +19 -4
- data/app/request_schemas/spree/api/v3/digital_asset_request_schema.rb +25 -0
- data/app/serializers/concerns/spree/api/v3/digital_asset_details.rb +70 -0
- data/app/serializers/spree/api/v3/admin/delivery_origin_group_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/delivery_profile_serializer.rb +3 -5
- data/app/serializers/spree/api/v3/admin/digital_asset_serializer.rb +3 -47
- data/app/serializers/spree/api/v3/admin/newsletter_subscriber_serializer.rb +1 -0
- data/app/serializers/spree/api/v3/admin/price_history_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/price_list_serializer.rb +8 -3
- data/app/serializers/spree/api/v3/admin/price_serializer.rb +1 -1
- data/app/serializers/spree/api/v3/admin/seller_payout_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/admin/seller_serializer.rb +1 -3
- data/app/serializers/spree/api/v3/admin/store_credit_serializer.rb +3 -5
- data/app/serializers/spree/api/v3/base_serializer.rb +6 -1
- data/app/serializers/spree/api/v3/newsletter_subscriber_serializer.rb +5 -1
- data/app/serializers/spree/api/v3/seller/digital_asset_serializer.rb +16 -0
- data/app/serializers/spree/api/v3/seller/payout_serializer.rb +2 -2
- data/app/serializers/spree/api/v3/seller/store_serializer.rb +18 -0
- data/app/services/spree/api/v3/filters_aggregator.rb +63 -18
- data/config/locales/en.yml +1 -0
- data/config/routes.rb +3 -0
- data/lib/spree/api/dependencies.rb +2 -2
- data/lib/spree/api/engine.rb +6 -0
- data/lib/spree/api/middleware/no_index.rb +33 -0
- data/lib/spree/api/openapi/schema_helper.rb +2 -1
- data/lib/spree/api/testing_support/v3/base.rb +18 -0
- metadata +14 -6
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Seller
|
|
5
|
+
module Products
|
|
6
|
+
# The downloadable files on one of this seller's own products.
|
|
7
|
+
#
|
|
8
|
+
# Uploaded files only: a provider is the operator's own code
|
|
9
|
+
# reaching into their internal systems, so a seller can neither pick
|
|
10
|
+
# one nor read its settings. An asset the operator set up with one
|
|
11
|
+
# is still listed, since it is part of what the seller's product
|
|
12
|
+
# delivers.
|
|
13
|
+
#
|
|
14
|
+
# The marketplace's rules for a seller's file — whether sellers may
|
|
15
|
+
# upload at all, which content types, and whether an approved
|
|
16
|
+
# listing goes back to review — apply because the workflow is told
|
|
17
|
+
# who is writing.
|
|
18
|
+
class DigitalAssetsController < Seller::ResourceController
|
|
19
|
+
include Spree::Api::V3::DigitalAssetsResource
|
|
20
|
+
|
|
21
|
+
scoped_resource :products
|
|
22
|
+
|
|
23
|
+
request_params :digital_asset do |body|
|
|
24
|
+
body.include_attributes Spree::Api::V3::DigitalAssetRequestSchema
|
|
25
|
+
body.require_attributes :signed_id, on: :create
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# DELETE /api/v3/seller/products/:product_id/digital_assets/:id
|
|
29
|
+
#
|
|
30
|
+
# Removing a file is covered by the same switch as adding one: a
|
|
31
|
+
# marketplace that keeps digital files to itself keeps the ones it
|
|
32
|
+
# attached to a seller's product.
|
|
33
|
+
def destroy
|
|
34
|
+
unless current_store.preferred_seller_digital_assets_enabled
|
|
35
|
+
return render_validation_error(I18n.t('spree.digital_assets_sellers_disabled'))
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
super
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
protected
|
|
42
|
+
|
|
43
|
+
def serializer_class
|
|
44
|
+
Spree.api.seller_digital_asset_serializer
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def create_workflow_arguments
|
|
48
|
+
super.merge(seller: current_seller, submitted_by: current_user)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def update_workflow_arguments
|
|
52
|
+
super.merge(seller: current_seller, submitted_by: current_user)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Rooted in the seller's own catalog, so another seller's product
|
|
56
|
+
# is a 404. Changing a product's files is a change to the product,
|
|
57
|
+
# so writes need `:update` on it, not just `:show`.
|
|
58
|
+
def set_parent
|
|
59
|
+
@parent = current_seller.products.find_by_prefix_id!(params[:product_id])
|
|
60
|
+
authorize_parent!(@parent)
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
@@ -142,8 +142,10 @@ module Spree
|
|
|
142
142
|
submitted_by: try_spree_current_user)
|
|
143
143
|
|
|
144
144
|
# A product Propose refused is untouched; one it accepted is in
|
|
145
|
-
# review or already through it.
|
|
146
|
-
|
|
145
|
+
# review or already through it. The saved value, not the
|
|
146
|
+
# attribute: a refused update leaves the new status unsaved on
|
|
147
|
+
# the record, and a rolled-back one restores what was stored.
|
|
148
|
+
product.status_in_database != was
|
|
147
149
|
}
|
|
148
150
|
end
|
|
149
151
|
|
|
@@ -8,7 +8,7 @@ module Spree
|
|
|
8
8
|
include Spree::Api::V3::OrderLock
|
|
9
9
|
|
|
10
10
|
before_action :require_authentication!
|
|
11
|
-
before_action :
|
|
11
|
+
before_action :find_owned_cart!
|
|
12
12
|
before_action :stringify_numeric_amount, only: :create
|
|
13
13
|
|
|
14
14
|
request_params 'ApplyStoreCreditParams', action: :create do |body|
|
|
@@ -50,6 +50,14 @@ module Spree
|
|
|
50
50
|
|
|
51
51
|
private
|
|
52
52
|
|
|
53
|
+
# The balance spent here is the cart owner's, so a guest token —
|
|
54
|
+
# which only proves the caller holds this cart — is not enough:
|
|
55
|
+
# the signed-in customer must be the owner.
|
|
56
|
+
def find_owned_cart!
|
|
57
|
+
@cart = resolve_cart(include_completed: false)
|
|
58
|
+
authorize_storefront_write!(@cart, token: nil)
|
|
59
|
+
end
|
|
60
|
+
|
|
53
61
|
# 5.6 storefronts sent a JSON number; read it through its text so no
|
|
54
62
|
# float reaches the money math.
|
|
55
63
|
def stringify_numeric_amount
|
|
@@ -112,6 +112,7 @@ module Spree
|
|
|
112
112
|
# Auto-advances to the next checkout step when possible.
|
|
113
113
|
def update
|
|
114
114
|
find_cart!
|
|
115
|
+
authorize_address_book_access!
|
|
115
116
|
|
|
116
117
|
with_order_lock do
|
|
117
118
|
result = Spree.carts_update_service.call(
|
|
@@ -238,6 +239,19 @@ module Spree
|
|
|
238
239
|
|
|
239
240
|
# Find incomplete cart for associate action.
|
|
240
241
|
# Only finds guest carts (no user) or carts already owned by current user (idempotent).
|
|
242
|
+
ADDRESS_BOOK_PARAMS = %i[shipping_address billing_address shipping_address_id billing_address_id].freeze
|
|
243
|
+
|
|
244
|
+
# A typed address on a customer's cart is saved into that customer's
|
|
245
|
+
# address book and may become their default, and an address id names
|
|
246
|
+
# an entry of that book. The guest token proves the caller holds the
|
|
247
|
+
# cart, not the account, so those writes need the owner.
|
|
248
|
+
def authorize_address_book_access!
|
|
249
|
+
return if @cart.customer.nil?
|
|
250
|
+
return unless ADDRESS_BOOK_PARAMS.any? { |key| params.key?(key) }
|
|
251
|
+
|
|
252
|
+
authorize_storefront_write!(@cart, token: nil)
|
|
253
|
+
end
|
|
254
|
+
|
|
241
255
|
def find_cart_for_association
|
|
242
256
|
current_store.carts.incomplete.where(customer: [nil, current_user]).find_by_prefix_id!(params[:id])
|
|
243
257
|
end
|
|
@@ -31,7 +31,8 @@ module Spree
|
|
|
31
31
|
|
|
32
32
|
request_params 'UpdateCustomerParams', action: :update do |body|
|
|
33
33
|
body.attribute :email, :string, format: :email, example: 'customer@example.com'
|
|
34
|
-
body.attribute :password, :string
|
|
34
|
+
body.attribute :password, :string,
|
|
35
|
+
description: 'Changing it signs the customer out everywhere: every refresh token is revoked, so sign in again once the access token expires.'
|
|
35
36
|
body.attribute :password_confirmation, :string
|
|
36
37
|
body.attribute :current_password, :string,
|
|
37
38
|
description: 'Required when changing the email or the password.'
|
|
@@ -75,6 +76,7 @@ module Spree
|
|
|
75
76
|
|
|
76
77
|
# GET /api/v3/store/customer
|
|
77
78
|
def show
|
|
79
|
+
preload_default_addresses
|
|
78
80
|
render json: serialize_resource(current_user)
|
|
79
81
|
end
|
|
80
82
|
|
|
@@ -86,6 +88,10 @@ module Spree
|
|
|
86
88
|
current_user.consent_source = Spree::ConsentRecord::ACCOUNT
|
|
87
89
|
|
|
88
90
|
if current_user.update(update_params)
|
|
91
|
+
# A password change is how a customer takes a stolen session
|
|
92
|
+
# back, so no refresh token issued before it may outlive it —
|
|
93
|
+
# the reset flow does the same.
|
|
94
|
+
Spree::RefreshToken.revoke_all_for(current_user) if update_params[:password].present?
|
|
89
95
|
render json: serialize_resource(current_user)
|
|
90
96
|
else
|
|
91
97
|
render_errors(current_user.errors)
|
|
@@ -115,6 +121,12 @@ module Spree
|
|
|
115
121
|
|
|
116
122
|
private
|
|
117
123
|
|
|
124
|
+
# Both default addresses live in one table, so they are fetched in one
|
|
125
|
+
# query rather than one each.
|
|
126
|
+
def preload_default_addresses
|
|
127
|
+
ActiveRecord::Associations::Preloader.new(records: [current_user], associations: %i[bill_address ship_address]).call
|
|
128
|
+
end
|
|
129
|
+
|
|
118
130
|
def sensitive_update?
|
|
119
131
|
(params[:email].present? && params[:email] != current_user.email) ||
|
|
120
132
|
params[:password].present?
|
|
@@ -93,7 +93,7 @@ module Spree
|
|
|
93
93
|
def covers_cart?(location, cart)
|
|
94
94
|
return true if location.pickup_stock_policy == 'any'
|
|
95
95
|
|
|
96
|
-
cart
|
|
96
|
+
pickup_line_items(cart).all? do |line_item|
|
|
97
97
|
next true if line_item.variant.digital?
|
|
98
98
|
next true unless line_item.variant.should_track_inventory?
|
|
99
99
|
|
|
@@ -101,6 +101,11 @@ module Spree
|
|
|
101
101
|
stock_level.present? && stock_level.available_count >= line_item.quantity
|
|
102
102
|
end
|
|
103
103
|
end
|
|
104
|
+
|
|
105
|
+
# Loaded once for every location the cart is checked against.
|
|
106
|
+
def pickup_line_items(cart)
|
|
107
|
+
@pickup_line_items ||= cart.line_items.includes(variant: [:delivery_profile, { product: %i[delivery_profile store] }]).to_a
|
|
108
|
+
end
|
|
104
109
|
end
|
|
105
110
|
end
|
|
106
111
|
end
|
|
@@ -5,6 +5,7 @@ module Spree
|
|
|
5
5
|
module Products
|
|
6
6
|
class FiltersController < Store::BaseController
|
|
7
7
|
include Spree::Api::V3::Store::SearchProviderSupport
|
|
8
|
+
include Spree::Api::V3::Store::StorefrontProducts
|
|
8
9
|
|
|
9
10
|
def index
|
|
10
11
|
json = Rails.cache.fetch(filters_cache_key, expires_in: 15.minutes) do
|
|
@@ -30,8 +31,8 @@ module Spree
|
|
|
30
31
|
|
|
31
32
|
def filters_cache_key
|
|
32
33
|
products_table = Spree::Product.table_name
|
|
33
|
-
stats =
|
|
34
|
-
|
|
34
|
+
stats = storefront_products.
|
|
35
|
+
pick(Arel.sql("MAX(#{products_table}.updated_at)"), Arel.sql("COUNT(DISTINCT #{products_table}.id)"))
|
|
35
36
|
max_updated = stats&.first&.to_i
|
|
36
37
|
product_count = stats&.last || 0
|
|
37
38
|
|
|
@@ -41,6 +42,7 @@ module Spree
|
|
|
41
42
|
current_currency,
|
|
42
43
|
current_locale,
|
|
43
44
|
(hide_prices? ? 'prices_hidden' : nil),
|
|
45
|
+
buyer_catalog_fragment,
|
|
44
46
|
category&.cache_key_with_version,
|
|
45
47
|
collection&.cache_key_with_version,
|
|
46
48
|
search_query,
|
|
@@ -53,11 +55,24 @@ module Spree
|
|
|
53
55
|
parts.compact.join('/')
|
|
54
56
|
end
|
|
55
57
|
|
|
58
|
+
# The buyer's catalogs partition the cache: a facet payload built
|
|
59
|
+
# for one assortment must not be served to a buyer who sees
|
|
60
|
+
# another, or it would describe products their listing never
|
|
61
|
+
# returns.
|
|
62
|
+
def buyer_catalog_fragment
|
|
63
|
+
catalogs = Spree::Catalog.for_buyer(store: current_store, customer: current_user, channel: current_channel)
|
|
64
|
+
return if catalogs.empty?
|
|
65
|
+
|
|
66
|
+
# Versioned, since adding or removing a product touches the
|
|
67
|
+
# catalog without touching the product count or timestamps.
|
|
68
|
+
catalogs.map(&:cache_key_with_version).sort.join('/')
|
|
69
|
+
end
|
|
70
|
+
|
|
56
71
|
def filters_scope
|
|
57
72
|
# Mirror ProductsController#scope so facet counts describe the
|
|
58
73
|
# same product set the listing returns (coming-soon pre-orders
|
|
59
|
-
# included).
|
|
60
|
-
scope =
|
|
74
|
+
# included) — narrowed to the buyer's catalogs like the listing.
|
|
75
|
+
scope = storefront_products
|
|
61
76
|
scope = scope.in_category(category) if category.present?
|
|
62
77
|
scope = scope.in_collection(collection) if collection.present?
|
|
63
78
|
scope
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
# What a downloadable file on a product carries, whichever panel writes
|
|
5
|
+
# it. The operator's endpoint adds the provider fields on top.
|
|
6
|
+
class DigitalAssetRequestSchema < Spree::Api::V3::RequestSchema
|
|
7
|
+
# Names a blob rather than a column, so it is attached separately.
|
|
8
|
+
attribute :signed_id, :string,
|
|
9
|
+
permit: false,
|
|
10
|
+
description: "A `signed_id` from `files.upload()` with `visibility: 'private'`. On update it replaces the file for everyone who already bought it. A seller's file must be of a content type the marketplace accepts, checked against the file's own signature where it has one."
|
|
11
|
+
# Resolved through the parent rather than assigned, so an asset can't
|
|
12
|
+
# be pointed at a variant of another product or store.
|
|
13
|
+
attribute :variant_id, :id,
|
|
14
|
+
permit: false,
|
|
15
|
+
description: "On create, defaults to the product's default variant when omitted. On update, omitting it keeps the current variant."
|
|
16
|
+
attribute :authorized_clicks, :integer,
|
|
17
|
+
nullable: true,
|
|
18
|
+
description: "Null means the store's download settings apply."
|
|
19
|
+
attribute :authorized_days, :integer,
|
|
20
|
+
nullable: true,
|
|
21
|
+
description: "Null means the store's download settings apply."
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
# What a panel shows about a downloadable file: its size, the limits
|
|
5
|
+
# that apply to it, and a short-lived link to check what was uploaded.
|
|
6
|
+
# Shared by the operator's and a seller's serializer, so both panels
|
|
7
|
+
# read the same fields.
|
|
8
|
+
module DigitalAssetDetails
|
|
9
|
+
extend ActiveSupport::Concern
|
|
10
|
+
|
|
11
|
+
# The store whose download settings apply: the request's, or the
|
|
12
|
+
# asset's own outside a request.
|
|
13
|
+
#
|
|
14
|
+
# @param digital_asset [Spree::DigitalAsset]
|
|
15
|
+
# @param params [Hash, nil] the serializer params
|
|
16
|
+
# @return [Spree::Store]
|
|
17
|
+
def self.store_for(digital_asset, params)
|
|
18
|
+
params&.dig(:store) || Spree::Current.store || digital_asset.store
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
included do
|
|
22
|
+
typelize byte_size: [:number, nullable: true],
|
|
23
|
+
authorized_clicks: [:number, nullable: true],
|
|
24
|
+
authorized_days: [:number, nullable: true],
|
|
25
|
+
effective_authorized_clicks: :number,
|
|
26
|
+
effective_authorized_days: :number,
|
|
27
|
+
provider_type: [:string, nullable: true, comment: 'Digital asset provider; null is an uploaded file. Built-in: file. Extensions may register more.'],
|
|
28
|
+
provider_name: [:string, comment: 'Digital asset provider name. Built-in: File. Extensions may register more.'],
|
|
29
|
+
download_url: [:string, nullable: true]
|
|
30
|
+
|
|
31
|
+
attributes :authorized_clicks, :authorized_days, :byte_size
|
|
32
|
+
attributes created_at: :iso8601, updated_at: :iso8601
|
|
33
|
+
|
|
34
|
+
api_type_attributes :provider_type
|
|
35
|
+
|
|
36
|
+
# Human-readable source for the listing. Blank provider_type is the
|
|
37
|
+
# uploaded-file default, so this reads "File" there.
|
|
38
|
+
attribute :provider_name do |digital_asset|
|
|
39
|
+
digital_asset.provider_class.provider_name
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Lets a merchant check what they actually uploaded. Short-lived and
|
|
43
|
+
# panel-only: this is the file itself, not a customer's download
|
|
44
|
+
# grant, so it carries no counter and spends nobody's allowance.
|
|
45
|
+
# Nil for a provider-backed asset (no file to preview) and outside a
|
|
46
|
+
# request (the Disk service needs a host only a controller supplies).
|
|
47
|
+
attribute :download_url do |digital_asset, params|
|
|
48
|
+
next nil unless digital_asset.downloadable?
|
|
49
|
+
|
|
50
|
+
store = DigitalAssetDetails.store_for(digital_asset, params)
|
|
51
|
+
begin
|
|
52
|
+
digital_asset.download_url(expires_in: store.preferred_digital_asset_link_expire_time.seconds)
|
|
53
|
+
rescue ArgumentError
|
|
54
|
+
nil
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
# The limits actually applied, after the store-settings fallback.
|
|
59
|
+
attribute :effective_authorized_clicks do |digital_asset, params|
|
|
60
|
+
digital_asset.effective_authorized_clicks(DigitalAssetDetails.store_for(digital_asset, params))
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
attribute :effective_authorized_days do |digital_asset, params|
|
|
64
|
+
digital_asset.effective_authorized_days(DigitalAssetDetails.store_for(digital_asset, params))
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
end
|
|
@@ -19,11 +19,11 @@ module Spree
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
attribute :delivery_zones_count do |record|
|
|
22
|
-
record.delivery_zones.
|
|
22
|
+
record.delivery_zones.size
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
attribute :delivery_methods_count do |record|
|
|
26
|
-
record.delivery_methods.
|
|
26
|
+
record.delivery_methods.size
|
|
27
27
|
end
|
|
28
28
|
end
|
|
29
29
|
end
|
|
@@ -47,16 +47,14 @@ module Spree
|
|
|
47
47
|
end
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
-
attribute :products_count
|
|
51
|
-
record.products.count
|
|
52
|
-
end
|
|
50
|
+
attribute :products_count, &:products_count
|
|
53
51
|
|
|
54
52
|
attribute :delivery_methods_count do |record|
|
|
55
|
-
record.delivery_methods.
|
|
53
|
+
record.delivery_methods.size
|
|
56
54
|
end
|
|
57
55
|
|
|
58
56
|
attribute :delivery_zones_count do |record|
|
|
59
|
-
record.delivery_zones.
|
|
57
|
+
record.delivery_zones.size
|
|
60
58
|
end
|
|
61
59
|
end
|
|
62
60
|
end
|
|
@@ -5,55 +5,11 @@ module Spree
|
|
|
5
5
|
module V3
|
|
6
6
|
module Admin
|
|
7
7
|
class DigitalAssetSerializer < V3::DigitalAssetSerializer
|
|
8
|
-
|
|
9
|
-
authorized_clicks: [:number, nullable: true],
|
|
10
|
-
authorized_days: [:number, nullable: true],
|
|
11
|
-
effective_authorized_clicks: :number,
|
|
12
|
-
effective_authorized_days: :number,
|
|
13
|
-
provider_type: [:string, nullable: true, comment: 'Digital asset provider; null is an uploaded file. Built-in: file. Extensions may register more.'],
|
|
14
|
-
provider_name: [:string, comment: 'Digital asset provider name. Built-in: File. Extensions may register more.'],
|
|
15
|
-
provider_settings: 'Record<string, unknown>',
|
|
16
|
-
download_url: [:string, nullable: true]
|
|
8
|
+
include Spree::Api::V3::DigitalAssetDetails
|
|
17
9
|
|
|
18
|
-
|
|
19
|
-
attributes created_at: :iso8601, updated_at: :iso8601
|
|
10
|
+
typelize provider_settings: 'Record<string, unknown>'
|
|
20
11
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
# Human-readable source for the admin listing. Blank provider_type is
|
|
24
|
-
# the uploaded-file default, so this reads "File" there.
|
|
25
|
-
attribute :provider_name do |digital_asset|
|
|
26
|
-
digital_asset.provider_class.provider_name
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
# Lets a merchant check what they actually uploaded. Short-lived and
|
|
30
|
-
# admin-only: this is the file itself, not a customer's download
|
|
31
|
-
# grant, so it carries no counter and spends nobody's allowance.
|
|
32
|
-
# Nil for a provider-backed asset (no file to preview) and outside a
|
|
33
|
-
# request (the Disk service needs a host only a controller supplies).
|
|
34
|
-
attribute :download_url do |digital_asset, params|
|
|
35
|
-
next nil unless digital_asset.downloadable?
|
|
36
|
-
|
|
37
|
-
store = params&.dig(:store) || Spree::Current.store || digital_asset.store
|
|
38
|
-
begin
|
|
39
|
-
digital_asset.download_url(expires_in: store.preferred_digital_asset_link_expire_time.seconds)
|
|
40
|
-
rescue ArgumentError
|
|
41
|
-
nil
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
|
|
45
|
-
# The limits actually applied, after the store-settings fallback. The
|
|
46
|
-
# request's store answers it — an admin request always carries one;
|
|
47
|
-
# the asset's own store covers serialization outside a request.
|
|
48
|
-
attribute :effective_authorized_clicks do |digital_asset, params|
|
|
49
|
-
store = params&.dig(:store) || Spree::Current.store || digital_asset.store
|
|
50
|
-
digital_asset.effective_authorized_clicks(store)
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
attribute :effective_authorized_days do |digital_asset, params|
|
|
54
|
-
store = params&.dig(:store) || Spree::Current.store || digital_asset.store
|
|
55
|
-
digital_asset.effective_authorized_days(store)
|
|
56
|
-
end
|
|
12
|
+
attributes :provider_settings
|
|
57
13
|
end
|
|
58
14
|
end
|
|
59
15
|
end
|
|
@@ -8,6 +8,7 @@ module Spree
|
|
|
8
8
|
# Back-office surface, nested under the admin customer serializer. Extends the
|
|
9
9
|
# customer-facing serializer so public fields stay in sync.
|
|
10
10
|
class NewsletterSubscriberSerializer < V3::NewsletterSubscriberSerializer
|
|
11
|
+
prefixed_id_attributes :customer
|
|
11
12
|
end
|
|
12
13
|
end
|
|
13
14
|
end
|
|
@@ -34,13 +34,18 @@ module Spree
|
|
|
34
34
|
attribute :currently_active, &:currently_active?
|
|
35
35
|
|
|
36
36
|
# Cheap counts so the index can render "12 products / 36 prices"
|
|
37
|
-
# without forcing each row to expand the children.
|
|
37
|
+
# without forcing each row to expand the children. The index counts
|
|
38
|
+
# the whole page at once; a single list asks for its own.
|
|
38
39
|
attribute :products_count do |pl|
|
|
39
|
-
|
|
40
|
+
counts = params[:products_counts]
|
|
41
|
+
|
|
42
|
+
(counts || Spree::PriceList.products_count_by_list(pl.id)).fetch(pl.id, 0)
|
|
40
43
|
end
|
|
41
44
|
|
|
42
45
|
attribute :prices_count do |pl|
|
|
43
|
-
|
|
46
|
+
counts = params[:prices_counts]
|
|
47
|
+
|
|
48
|
+
counts ? counts.fetch(pl.id, 0) : pl.prices.count
|
|
44
49
|
end
|
|
45
50
|
|
|
46
51
|
# Always expanded: a list's bands are the rest of the sentence its
|
|
@@ -32,8 +32,8 @@ module Spree
|
|
|
32
32
|
#
|
|
33
33
|
# Read from a count the controller made for the whole page when there
|
|
34
34
|
# is one; a single payout read falls back to asking for its own.
|
|
35
|
-
attribute(:transfers_count) do |payout
|
|
36
|
-
counts = params
|
|
35
|
+
attribute(:transfers_count) do |payout|
|
|
36
|
+
counts = params[:transfer_counts]
|
|
37
37
|
|
|
38
38
|
counts ? counts.fetch(payout.id, 0) : payout.transfers.count
|
|
39
39
|
end
|
|
@@ -54,9 +54,7 @@ module Spree
|
|
|
54
54
|
# so the minimum-products requirement asks the same question free.
|
|
55
55
|
attributes :products_count
|
|
56
56
|
|
|
57
|
-
|
|
58
|
-
seller.users.size
|
|
59
|
-
end
|
|
57
|
+
attributes :users_count
|
|
60
58
|
|
|
61
59
|
# How far through the marketplace's checklist this seller is — what
|
|
62
60
|
# the list's progress column and the profile's badge render. The
|
|
@@ -7,6 +7,7 @@ module Spree
|
|
|
7
7
|
|
|
8
8
|
typelize customer_id: [:string, nullable: true],
|
|
9
9
|
created_by_id: [:string, nullable: true],
|
|
10
|
+
created_by_type: [:string, nullable: true, enum: Spree::Actor::BUILT_IN_KINDS, enum_type_name: 'ActorKind'],
|
|
10
11
|
memo: [:string, nullable: true],
|
|
11
12
|
amount: [:string, nullable: false], amount_used: [:string, nullable: false],
|
|
12
13
|
amount_remaining: [:string, nullable: false],
|
|
@@ -27,7 +28,8 @@ module Spree
|
|
|
27
28
|
# money_attributes types its fields nullable for gated guests; the
|
|
28
29
|
# Admin API never gates prices.
|
|
29
30
|
typelize amount_authorized: [:string, nullable: false]
|
|
30
|
-
prefixed_id_attributes :customer
|
|
31
|
+
prefixed_id_attributes :customer
|
|
32
|
+
actor_attributes :created_by
|
|
31
33
|
|
|
32
34
|
# Why the credit exists: the return, exchange, claim or gift card
|
|
33
35
|
# that issued it, or null when an admin issued it by hand. The type
|
|
@@ -50,10 +52,6 @@ module Spree
|
|
|
50
52
|
one :customer,
|
|
51
53
|
resource: proc { Spree.api.admin_customer_serializer },
|
|
52
54
|
if: proc { expand?('customer') }
|
|
53
|
-
|
|
54
|
-
one :created_by,
|
|
55
|
-
resource: proc { Spree.api.admin_admin_user_serializer },
|
|
56
|
-
if: proc { expand?('created_by') }
|
|
57
55
|
end
|
|
58
56
|
end
|
|
59
57
|
end
|
|
@@ -154,9 +154,14 @@ module Spree
|
|
|
154
154
|
|
|
155
155
|
def self.preference_type_hint(schema, name)
|
|
156
156
|
types = Array(schema['type'])
|
|
157
|
-
hint = TYPELIZER_TYPES.fetch((types - ['null']).first, :unknown)
|
|
158
157
|
options = {}
|
|
159
158
|
options[:nullable] = true if types.include?('null')
|
|
159
|
+
if types.include?('array')
|
|
160
|
+
hint = TYPELIZER_TYPES.fetch(Array(schema.dig('items', 'type')).first, :unknown)
|
|
161
|
+
options[:multi] = true
|
|
162
|
+
else
|
|
163
|
+
hint = TYPELIZER_TYPES.fetch((types - ['null']).first, :unknown)
|
|
164
|
+
end
|
|
160
165
|
if schema['enum']
|
|
161
166
|
options[:enum] = schema['enum'].compact
|
|
162
167
|
options[:enum_type_name] = PREFERENCE_LIST_NAMES[name.to_sym] if PREFERENCE_LIST_NAMES.key?(name.to_sym)
|
|
@@ -16,7 +16,11 @@ module Spree
|
|
|
16
16
|
subscriber.verified_at&.iso8601
|
|
17
17
|
end
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
# Shown to the account's owner only: for anyone else, posting an email
|
|
20
|
+
# must not tell them whether an account exists for it.
|
|
21
|
+
attribute :customer_id do |subscriber|
|
|
22
|
+
subscriber.customer&.prefixed_id if current_user && subscriber.customer_id == current_user.id
|
|
23
|
+
end
|
|
20
24
|
end
|
|
21
25
|
end
|
|
22
26
|
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
module Api
|
|
5
|
+
module V3
|
|
6
|
+
module Seller
|
|
7
|
+
# A downloadable file on a seller's own product. Leaves out the
|
|
8
|
+
# provider's settings: they configure the operator's own systems, not
|
|
9
|
+
# the seller's listing.
|
|
10
|
+
class DigitalAssetSerializer < V3::DigitalAssetSerializer
|
|
11
|
+
include Spree::Api::V3::DigitalAssetDetails
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -22,8 +22,8 @@ module Spree
|
|
|
22
22
|
# How many earnings this settlement covers. Read from a count the
|
|
23
23
|
# controller made for the whole page when there is one; a single
|
|
24
24
|
# payout read falls back to asking for its own.
|
|
25
|
-
attribute(:transfers_count) do |payout
|
|
26
|
-
counts = params
|
|
25
|
+
attribute(:transfers_count) do |payout|
|
|
26
|
+
counts = params[:transfer_counts]
|
|
27
27
|
|
|
28
28
|
counts ? counts.fetch(payout.id, 0) : payout.transfers.count
|
|
29
29
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Spree
|
|
2
|
+
module Api
|
|
3
|
+
module V3
|
|
4
|
+
module Seller
|
|
5
|
+
# What a seller may know about the marketplace they sell on: its name,
|
|
6
|
+
# and the settings that shape what the panel lets them do.
|
|
7
|
+
class StoreSerializer < V3::BaseSerializer
|
|
8
|
+
typelize name: :string
|
|
9
|
+
|
|
10
|
+
attributes :name
|
|
11
|
+
|
|
12
|
+
preference_attributes Spree::Store, :seller_digital_assets_enabled, :seller_digital_asset_content_types,
|
|
13
|
+
:review_seller_digital_asset_changes
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|