spree_core 5.5.0.rc1 → 5.5.0.rc2
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/models/spree/api_key.rb +11 -4
- data/app/models/spree/current.rb +2 -2
- data/app/models/spree/export.rb +15 -0
- data/app/models/spree/exports/coupon_codes.rb +4 -0
- data/app/models/spree/exports/newsletter_subscribers.rb +4 -0
- data/app/models/spree/exports/product_translations.rb +4 -0
- data/app/models/spree/order_routing/strategy/rules.rb +3 -1
- data/config/locales/en.yml +1 -0
- data/db/migrate/20260612000001_change_spree_user_identities_info_to_jsonb.rb +13 -0
- data/lib/generators/spree/api_resource/templates/store_serializer.rb.tt +4 -1
- data/lib/generators/spree/subscriber/subscriber_generator.rb +116 -0
- data/lib/generators/spree/subscriber/templates/subscriber.rb.tt +17 -0
- data/lib/generators/spree/subscriber/templates/subscriber_spec.rb.tt +9 -0
- data/lib/spree/core/version.rb +1 -1
- data/lib/tasks/cli.rake +2 -1
- metadata +8 -4
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7d9453fadded9ac66f0b64ac5af7ca30a78516088edafa569cd18bcf0b541e1f
|
|
4
|
+
data.tar.gz: 72af3c8a53371f288c2084d2eed1e1f6635d0f2273bcb49f40adc626fe96d4c2
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 073262b0c991fdbae6c780957052d84ee297abfc6b438b6b1476bc301fc69af8c67ed9904a89e080a14309ac26b86352ad4627f934c0b972c649d520f105c936
|
|
7
|
+
data.tar.gz: 4c581530147dac6e5b3ea79c655a9c739f40f6ce10b55adcdd5abe46d02073a96268e27a64790cc93c607dfe60cc3aef2c62ded74ad4daa3635135ce21847293
|
data/app/models/spree/api_key.rb
CHANGED
|
@@ -12,6 +12,7 @@ module Spree
|
|
|
12
12
|
SCOPES = %w[
|
|
13
13
|
read_orders write_orders
|
|
14
14
|
read_products write_products
|
|
15
|
+
read_promotions write_promotions
|
|
15
16
|
read_customers write_customers
|
|
16
17
|
read_payments write_payments
|
|
17
18
|
read_fulfillments write_fulfillments
|
|
@@ -20,10 +21,9 @@ module Spree
|
|
|
20
21
|
read_store_credits write_store_credits
|
|
21
22
|
read_stock write_stock
|
|
22
23
|
read_categories write_categories
|
|
23
|
-
read_custom_field_definitions write_custom_field_definitions
|
|
24
|
-
read_exports write_exports
|
|
25
24
|
read_settings write_settings
|
|
26
25
|
read_webhooks write_webhooks
|
|
26
|
+
read_api_keys write_api_keys
|
|
27
27
|
read_dashboard
|
|
28
28
|
read_all write_all
|
|
29
29
|
].freeze
|
|
@@ -55,8 +55,8 @@ module Spree
|
|
|
55
55
|
validates :token_digest, presence: true, uniqueness: true, if: :secret?
|
|
56
56
|
validates :token_prefix, presence: true, if: :secret?
|
|
57
57
|
validates :store, presence: true
|
|
58
|
-
validates :scopes, presence: true, if:
|
|
59
|
-
validate :validate_known_scopes, if:
|
|
58
|
+
validates :scopes, presence: true, if: -> { secret? && scopes_enforceable? }
|
|
59
|
+
validate :validate_known_scopes, if: -> { secret? && scopes_enforceable? }
|
|
60
60
|
|
|
61
61
|
before_validation :generate_token, on: :create
|
|
62
62
|
|
|
@@ -133,6 +133,13 @@ module Spree
|
|
|
133
133
|
|
|
134
134
|
private
|
|
135
135
|
|
|
136
|
+
# Enforce the scope vocabulary on create and whenever scopes change, but
|
|
137
|
+
# not on unrelated updates — revoking a key minted under an older
|
|
138
|
+
# vocabulary (scopes since removed or renamed) must never fail validation.
|
|
139
|
+
def scopes_enforceable?
|
|
140
|
+
new_record? || scopes_changed?
|
|
141
|
+
end
|
|
142
|
+
|
|
136
143
|
def validate_known_scopes
|
|
137
144
|
invalid = scopes - SCOPES
|
|
138
145
|
errors.add(:scopes, "contains unknown scopes: #{invalid.join(', ')}") if invalid.any?
|
data/app/models/spree/current.rb
CHANGED
|
@@ -32,10 +32,10 @@ module Spree
|
|
|
32
32
|
end
|
|
33
33
|
|
|
34
34
|
# Returns the current locale.
|
|
35
|
-
# Fallback: market default locale -> store default locale.
|
|
35
|
+
# Fallback: market default locale -> store default locale -> I18n default.
|
|
36
36
|
# @return [String] locale code, e.g. +"en"+, +"de"+
|
|
37
37
|
def locale
|
|
38
|
-
super || market&.default_locale || store&.default_locale
|
|
38
|
+
super || market&.default_locale.presence || store&.default_locale.presence || I18n.default_locale.to_s
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
# Returns the current tax zone.
|
data/app/models/spree/export.rb
CHANGED
|
@@ -216,6 +216,21 @@ module Spree
|
|
|
216
216
|
Spree.export_types
|
|
217
217
|
end
|
|
218
218
|
|
|
219
|
+
# Admin API scope family gating this export type — an export is a bulk
|
|
220
|
+
# read, so an API key needs `read_<required_scope>` to create, view, and
|
|
221
|
+
# download it. Derived from the class name
|
|
222
|
+
# (Spree::Exports::Customers => :customers); override in subclasses whose
|
|
223
|
+
# records are gated by a different scope (e.g. coupon codes =>
|
|
224
|
+
# :promotions). Returns nil on the base class, so unmapped types are
|
|
225
|
+
# only accessible to `read_all`/`write_all` keys.
|
|
226
|
+
#
|
|
227
|
+
# @return [Symbol, nil]
|
|
228
|
+
def required_scope
|
|
229
|
+
return nil if self == Spree::Export
|
|
230
|
+
|
|
231
|
+
to_s.demodulize.underscore.to_sym
|
|
232
|
+
end
|
|
233
|
+
|
|
219
234
|
def available_models
|
|
220
235
|
available_types.map(&:model_class)
|
|
221
236
|
end
|
|
@@ -13,7 +13,9 @@ module Spree
|
|
|
13
13
|
locations = eligible_locations
|
|
14
14
|
return [] if locations.empty?
|
|
15
15
|
|
|
16
|
-
ordered = Reducer
|
|
16
|
+
ordered = Spree::OrderRouting::Strategy::Reducer
|
|
17
|
+
.new(applicable_rules.to_a, order: order)
|
|
18
|
+
.rank_all(locations)
|
|
17
19
|
return [] if ordered.empty?
|
|
18
20
|
|
|
19
21
|
packages = build_packages(ordered)
|
data/config/locales/en.yml
CHANGED
|
@@ -578,6 +578,7 @@ en:
|
|
|
578
578
|
invalid_token: Invalid authentication token.
|
|
579
579
|
locked: Your account is locked.
|
|
580
580
|
timeout: Your session expired, please sign in again to continue.
|
|
581
|
+
too_many_attempts: Too many attempts. Please wait a moment and try again.
|
|
581
582
|
unauthenticated: You need to sign in or sign up before continuing.
|
|
582
583
|
unconfirmed: You have to confirm your account before continuing.
|
|
583
584
|
mailer:
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
class ChangeSpreeUserIdentitiesInfoToJsonb < ActiveRecord::Migration[7.2]
|
|
2
|
+
def up
|
|
3
|
+
change_table :spree_user_identities do |t|
|
|
4
|
+
t.change :info, :jsonb, using: 'info::jsonb' if t.respond_to?(:jsonb)
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
def down
|
|
9
|
+
change_table :spree_user_identities do |t|
|
|
10
|
+
t.change :info, :json, using: 'info::json' if t.respond_to?(:jsonb)
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -1,10 +1,13 @@
|
|
|
1
|
+
<%# Decimal columns serialize as strings on the wire (Alba's oj_rails backend
|
|
2
|
+
casts BigDecimal via as_json), so they must be typed :string — only
|
|
3
|
+
integer/float are real JSON numbers. -%>
|
|
1
4
|
<% typelizable = attributes.reject(&:reference?).select { |a| %i[boolean integer decimal float].include?(a.type) } -%>
|
|
2
5
|
module Spree
|
|
3
6
|
module Api
|
|
4
7
|
module V3
|
|
5
8
|
class <%= bare_class_name %>Serializer < BaseSerializer
|
|
6
9
|
<% if typelizable.any? -%>
|
|
7
|
-
typelize <%= typelizable.map { |a|
|
|
10
|
+
typelize <%= typelizable.map { |a| type = a.type == :boolean ? 'boolean' : (a.type == :decimal ? 'string' : 'number'); "#{a.name}: :#{type}" }.join(', ') %>
|
|
8
11
|
|
|
9
12
|
<% end -%>
|
|
10
13
|
attributes <%= permitted_attribute_names.map { |a| ":#{a}" }.join(', ') %>
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Spree
|
|
4
|
+
# spree:subscriber — scaffold an event subscriber and register it.
|
|
5
|
+
#
|
|
6
|
+
# bin/rails g spree:subscriber OmsOrderSync order.completed order.canceled
|
|
7
|
+
# bin/rails g spree:subscriber MyApp::BrandSync brand.created brand.updated
|
|
8
|
+
# bin/rails g spree:subscriber CriticalSync order.completed --sync
|
|
9
|
+
#
|
|
10
|
+
# Subscribers are not auto-discovered — they must be appended to the
|
|
11
|
+
# Spree.subscribers array. Forgetting that step produces a silent no-op,
|
|
12
|
+
# so this generator also maintains the registration in
|
|
13
|
+
# config/initializers/spree.rb with an idempotent line per subscriber.
|
|
14
|
+
class SubscriberGenerator < Rails::Generators::NamedBase
|
|
15
|
+
desc 'Creates a Spree event subscriber and registers it in an initializer'
|
|
16
|
+
|
|
17
|
+
# Every Spree app ships config/initializers/spree.rb (created by
|
|
18
|
+
# spree:install) — registrations go there rather than into a second
|
|
19
|
+
# initializer file.
|
|
20
|
+
INITIALIZER_PATH = 'config/initializers/spree.rb'
|
|
21
|
+
REGISTRATION_ANCHOR = "Rails.application.config.after_initialize do\n"
|
|
22
|
+
|
|
23
|
+
argument :events, type: :array, default: [], banner: 'event.name event.name'
|
|
24
|
+
|
|
25
|
+
class_option :sync,
|
|
26
|
+
type: :boolean,
|
|
27
|
+
default: false,
|
|
28
|
+
desc: 'Run the subscriber synchronously (async: false) instead of via ActiveJob'
|
|
29
|
+
|
|
30
|
+
class_option :skip_spec,
|
|
31
|
+
type: :boolean,
|
|
32
|
+
default: false,
|
|
33
|
+
desc: "Don't generate a spec file"
|
|
34
|
+
|
|
35
|
+
def self.source_paths
|
|
36
|
+
[File.expand_path('templates', __dir__), *superclass.source_paths]
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def create_subscriber_file
|
|
40
|
+
template 'subscriber.rb.tt', File.join('app/subscribers', class_path, "#{subscriber_file_name}.rb")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def register_subscriber
|
|
44
|
+
if File.exist?(destination_path(INITIALIZER_PATH))
|
|
45
|
+
content = File.read(destination_path(INITIALIZER_PATH))
|
|
46
|
+
if content.include?(registration_line.strip)
|
|
47
|
+
say_status :identical, "#{INITIALIZER_PATH} (#{subscriber_class_name} already registered)", :blue
|
|
48
|
+
elsif content.include?(REGISTRATION_ANCHOR)
|
|
49
|
+
inject_into_file INITIALIZER_PATH, registration_line, after: REGISTRATION_ANCHOR
|
|
50
|
+
else
|
|
51
|
+
append_to_file INITIALIZER_PATH, registration_block
|
|
52
|
+
end
|
|
53
|
+
else
|
|
54
|
+
create_file INITIALIZER_PATH, registration_block.lstrip
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def create_spec_file
|
|
59
|
+
return if options[:skip_spec]
|
|
60
|
+
|
|
61
|
+
template 'subscriber_spec.rb.tt', File.join('spec/subscribers', class_path, "#{subscriber_file_name}_spec.rb")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def warn_about_missing_events
|
|
65
|
+
return if events.any?
|
|
66
|
+
|
|
67
|
+
say_status :note, "no events given — edit `subscribes_to` in the generated subscriber (e.g. 'order.completed')", :yellow
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# "OmsOrderSync" and "OmsOrderSyncSubscriber" both produce
|
|
73
|
+
# OmsOrderSyncSubscriber / oms_order_sync_subscriber.
|
|
74
|
+
def bare_subscriber_name
|
|
75
|
+
base = class_name.demodulize.sub(/Subscriber\z/, '')
|
|
76
|
+
"#{base}Subscriber"
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
def subscriber_file_name
|
|
80
|
+
bare_subscriber_name.underscore
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def subscriber_class_name
|
|
84
|
+
(class_path.map { |part| part.camelize } + [bare_subscriber_name]).join('::')
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def namespace_modules
|
|
88
|
+
class_path.map(&:camelize)
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def subscribes_to_arguments
|
|
92
|
+
listed = events.any? ? events.map { |e| "'#{e}'" } : ["'TODO.replace_with_event_name'"]
|
|
93
|
+
listed << 'async: false' if options[:sync]
|
|
94
|
+
listed.join(', ')
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def registration_line
|
|
98
|
+
" Spree.subscribers << #{subscriber_class_name}\n"
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def registration_block
|
|
102
|
+
<<~RUBY
|
|
103
|
+
|
|
104
|
+
# Event subscribers must be registered explicitly — Spree does not
|
|
105
|
+
# auto-discover classes in app/subscribers/.
|
|
106
|
+
Rails.application.config.after_initialize do
|
|
107
|
+
#{registration_line.chomp}
|
|
108
|
+
end
|
|
109
|
+
RUBY
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def destination_path(relative)
|
|
113
|
+
File.join(destination_root, relative)
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<% namespace_modules.each_with_index do |mod, i| -%>
|
|
2
|
+
<%= ' ' * i %>module <%= mod %>
|
|
3
|
+
<% end -%>
|
|
4
|
+
<% depth = namespace_modules.size -%>
|
|
5
|
+
<%= ' ' * depth %>class <%= bare_subscriber_name %> < Spree::Subscriber
|
|
6
|
+
<%= ' ' * (depth + 1) %>subscribes_to <%= subscribes_to_arguments %>
|
|
7
|
+
|
|
8
|
+
<%= ' ' * (depth + 1) %>def handle(event)
|
|
9
|
+
<%= ' ' * (depth + 2) %># Event payloads carry prefixed IDs — look records up with find_by_prefix_id:
|
|
10
|
+
<%= ' ' * (depth + 2) %>#
|
|
11
|
+
<%= ' ' * (depth + 2) %># record = Spree::Order.find_by_prefix_id(event.payload['id'])
|
|
12
|
+
<%= ' ' * (depth + 2) %># return unless record
|
|
13
|
+
<%= ' ' * (depth + 1) %>end
|
|
14
|
+
<%= ' ' * depth %>end
|
|
15
|
+
<% namespace_modules.each_with_index do |_, i| -%>
|
|
16
|
+
<%= ' ' * (namespace_modules.size - 1 - i) %>end
|
|
17
|
+
<% end -%>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
require 'rails_helper'
|
|
2
|
+
|
|
3
|
+
RSpec.describe <%= subscriber_class_name %> do
|
|
4
|
+
it 'handles <%= events.first || 'the subscribed event' %>' do
|
|
5
|
+
event = Spree::Event.new(name: <%= (events.first || 'some.event').inspect %>, payload: { 'id' => 'prefixed_id_here' })
|
|
6
|
+
|
|
7
|
+
expect { described_class.new.handle(event) }.not_to raise_error
|
|
8
|
+
end
|
|
9
|
+
end
|
data/lib/spree/core/version.rb
CHANGED
data/lib/tasks/cli.rake
CHANGED
|
@@ -12,8 +12,9 @@ namespace :spree do
|
|
|
12
12
|
task create_api_key: :environment do
|
|
13
13
|
name = ENV.fetch('NAME')
|
|
14
14
|
key_type = ENV.fetch('KEY_TYPE')
|
|
15
|
+
scopes = ENV.fetch('SCOPES', '').split(',').map(&:strip).reject(&:empty?)
|
|
15
16
|
store = Spree::Store.default
|
|
16
|
-
key = store.api_keys.create!(name: name, key_type: key_type)
|
|
17
|
+
key = store.api_keys.create!(name: name, key_type: key_type, scopes: scopes)
|
|
17
18
|
print key.plaintext_token
|
|
18
19
|
end
|
|
19
20
|
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: spree_core
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 5.5.0.
|
|
4
|
+
version: 5.5.0.rc2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Sean Schofield
|
|
@@ -10,7 +10,7 @@ authors:
|
|
|
10
10
|
autorequire:
|
|
11
11
|
bindir: bin
|
|
12
12
|
cert_chain: []
|
|
13
|
-
date: 2026-06-
|
|
13
|
+
date: 2026-06-15 00:00:00.000000000 Z
|
|
14
14
|
dependencies:
|
|
15
15
|
- !ruby/object:Gem::Dependency
|
|
16
16
|
name: i18n-tasks
|
|
@@ -1565,6 +1565,7 @@ files:
|
|
|
1565
1565
|
- db/migrate/20260601000001_create_spree_product_publications.rb
|
|
1566
1566
|
- db/migrate/20260601000002_add_store_id_to_spree_products.rb
|
|
1567
1567
|
- db/migrate/20260602000001_add_default_to_spree_channels.rb
|
|
1568
|
+
- db/migrate/20260612000001_change_spree_user_identities_info_to_jsonb.rb
|
|
1568
1569
|
- db/sample_data/channels.rb
|
|
1569
1570
|
- db/sample_data/customers.csv
|
|
1570
1571
|
- db/sample_data/markets.rb
|
|
@@ -1612,6 +1613,9 @@ files:
|
|
|
1612
1613
|
- lib/generators/spree/model/templates/model.rb.tt
|
|
1613
1614
|
- lib/generators/spree/model_decorator/model_decorator_generator.rb
|
|
1614
1615
|
- lib/generators/spree/model_decorator/templates/model_decorator.rb.tt
|
|
1616
|
+
- lib/generators/spree/subscriber/subscriber_generator.rb
|
|
1617
|
+
- lib/generators/spree/subscriber/templates/subscriber.rb.tt
|
|
1618
|
+
- lib/generators/spree/subscriber/templates/subscriber_spec.rb.tt
|
|
1615
1619
|
- lib/mobility/plugins/store_based_fallbacks.rb
|
|
1616
1620
|
- lib/spree/analytics.rb
|
|
1617
1621
|
- lib/spree/core.rb
|
|
@@ -1812,9 +1816,9 @@ licenses:
|
|
|
1812
1816
|
- BSD-3-Clause
|
|
1813
1817
|
metadata:
|
|
1814
1818
|
bug_tracker_uri: https://github.com/spree/spree/issues
|
|
1815
|
-
changelog_uri: https://github.com/spree/spree/releases/tag/v5.5.0.
|
|
1819
|
+
changelog_uri: https://github.com/spree/spree/releases/tag/v5.5.0.rc2
|
|
1816
1820
|
documentation_uri: https://docs.spreecommerce.org/
|
|
1817
|
-
source_code_uri: https://github.com/spree/spree/tree/v5.5.0.
|
|
1821
|
+
source_code_uri: https://github.com/spree/spree/tree/v5.5.0.rc2
|
|
1818
1822
|
post_install_message:
|
|
1819
1823
|
rdoc_options: []
|
|
1820
1824
|
require_paths:
|