@spree/docs 0.1.177 → 0.1.178
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.
- package/dist/developer/cli/quickstart.md +1 -1
- package/dist/developer/contributing/creating-an-extension.md +2 -2
- package/dist/developer/core-concepts/addresses.md +3 -3
- package/dist/developer/core-concepts/architecture.md +4 -4
- package/dist/developer/core-concepts/calculators.md +2 -2
- package/dist/developer/core-concepts/carts.md +207 -0
- package/dist/developer/core-concepts/channels.md +3 -3
- package/dist/developer/core-concepts/customers.md +1 -1
- package/dist/developer/core-concepts/events.md +1 -1
- package/dist/developer/core-concepts/fulfillments.md +278 -0
- package/dist/developer/core-concepts/imports-exports.md +6 -18
- package/dist/developer/core-concepts/inventory.md +3 -3
- package/dist/developer/core-concepts/media.md +1 -1
- package/dist/developer/core-concepts/metafields.md +1 -1
- package/dist/developer/core-concepts/orders.md +92 -339
- package/dist/developer/core-concepts/payments.md +1 -1
- package/dist/developer/core-concepts/promotions.md +68 -195
- package/dist/developer/core-concepts/returns-exchanges-claims.md +173 -0
- package/dist/developer/core-concepts/store-credits-gift-cards.md +16 -18
- package/dist/developer/core-concepts/stores.md +1 -1
- package/dist/developer/core-concepts/taxes-discounts-fees.md +199 -0
- package/dist/developer/core-concepts/taxes.md +3 -3
- package/dist/developer/create-spree-app/quickstart.md +1 -1
- package/dist/developer/customization/api.md +36 -11
- package/dist/developer/customization/configuration.md +207 -37
- package/dist/developer/customization/decorators.md +8 -8
- package/dist/developer/customization/permissions.md +34 -229
- package/dist/developer/customization/quickstart.md +159 -108
- package/dist/developer/customization/validations.md +1 -1
- package/dist/developer/dashboard/overview.md +1 -1
- package/dist/developer/how-to/build-a-b2b-store.md +21 -0
- package/dist/developer/how-to/build-a-marketplace.md +25 -0
- package/dist/developer/how-to/custom-api-authentication.md +1 -1
- package/dist/developer/how-to/custom-delivery-rate-provider.md +242 -0
- package/dist/developer/how-to/custom-document-numbers.md +154 -0
- package/dist/developer/how-to/custom-order-routing.md +1 -1
- package/dist/developer/how-to/custom-payment-method.md +1 -1
- package/dist/developer/how-to/custom-promotion.md +76 -115
- package/dist/developer/how-to/custom-report.md +2 -2
- package/dist/developer/how-to/custom-stock-splitter.md +5 -5
- package/dist/developer/how-to/sell-digital-products.md +20 -0
- package/dist/developer/multi-tenant/quickstart.md +1 -1
- package/dist/developer/providers/dam.md +14 -0
- package/dist/developer/providers/erp.md +31 -0
- package/dist/developer/providers/fulfillment.md +25 -0
- package/dist/developer/{deployment/telemetry.md → providers/observability.md} +1 -1
- package/dist/developer/providers/overview.md +44 -0
- package/dist/developer/providers/pim.md +25 -0
- package/dist/developer/providers/sso.md +20 -0
- package/dist/developer/sdk/admin/extending.md +1 -1
- package/dist/developer/sdk/admin/quickstart.md +1 -1
- package/dist/developer/sdk/admin/resources.md +1 -1
- package/dist/developer/sdk/extending.md +1 -1
- package/dist/developer/tutorial/admin-api.md +13 -0
- package/dist/developer/tutorial/dashboard-plugin.md +14 -0
- package/dist/developer/tutorial/events.md +7 -161
- package/dist/developer/tutorial/introduction.md +15 -35
- package/dist/developer/tutorial/model.md +7 -98
- package/dist/developer/tutorial/store-api.md +13 -0
- package/dist/developer/tutorial/storefront.md +12 -0
- package/dist/developer/tutorial/testing.md +7 -711
- package/dist/developer/upgrades/5.6-to-6.0.md +2 -2
- package/package.json +1 -1
- package/dist/developer/admin/admin.md +0 -214
- package/dist/developer/admin/authentication.md +0 -59
- package/dist/developer/admin/components.md +0 -711
- package/dist/developer/admin/custom-css.md +0 -256
- package/dist/developer/admin/custom-javascript.md +0 -116
- package/dist/developer/admin/extending-ui.md +0 -1839
- package/dist/developer/admin/form-builder.md +0 -444
- package/dist/developer/admin/helper-methods.md +0 -531
- package/dist/developer/admin/navigation.md +0 -805
- package/dist/developer/admin/tables.md +0 -490
- package/dist/developer/advanced/adding_spree_to_rails_app.md +0 -92
- package/dist/developer/core-concepts/adjustments.md +0 -113
- package/dist/developer/core-concepts/reports.md +0 -208
- package/dist/developer/core-concepts/shipments.md +0 -307
- package/dist/developer/core-concepts/users.md +0 -303
- package/dist/developer/customization/authentication.md +0 -100
- package/dist/developer/customization/checkout.md +0 -202
- package/dist/developer/customization/emails.md +0 -18
- package/dist/developer/customization/routes.md +0 -24
- package/dist/developer/multi-vendor/installation.md +0 -61
- package/dist/developer/multi-vendor/quickstart.md +0 -17
- package/dist/developer/tutorial/admin.md +0 -206
- package/dist/developer/tutorial/api.md +0 -606
- package/dist/developer/tutorial/extending-models.md +0 -393
- package/dist/developer/tutorial/sdk.md +0 -170
- package/dist/developer/upgrades/2.0-to-2.1.md +0 -46
- package/dist/developer/upgrades/2.1-to-2.2.md +0 -59
- package/dist/developer/upgrades/2.2-to-2.3.md +0 -44
- package/dist/developer/upgrades/2.3-to-2.4.md +0 -42
- package/dist/developer/upgrades/3.0-to-3.1.md +0 -47
- package/dist/developer/upgrades/3.1-to-3.2.md +0 -34
- package/dist/developer/upgrades/3.2-to-3.3.md +0 -70
- package/dist/developer/upgrades/3.3-to-3.4.md +0 -36
- package/dist/developer/upgrades/3.4-to-3.5.md +0 -44
- package/dist/developer/upgrades/3.5-to-3.6.md +0 -40
- package/dist/developer/upgrades/3.6-to-3.7.md +0 -62
- package/dist/developer/upgrades/3.7-to-4.0.md +0 -152
- package/dist/developer/upgrades/4.0-to-4.1.md +0 -92
- package/dist/developer/upgrades/4.1-to-4.2.md +0 -109
- package/dist/developer/upgrades/4.10-to-5.0.md +0 -131
- package/dist/developer/upgrades/4.2-to-4.3.md +0 -100
- package/dist/developer/upgrades/4.3-to-4.4.md +0 -125
- package/dist/developer/upgrades/4.4-to-4.5.md +0 -94
- package/dist/developer/upgrades/4.5-to-4.6.md +0 -119
- package/dist/developer/upgrades/4.6-to-4.7.md +0 -39
- package/dist/developer/upgrades/4.8-to-4.9.md +0 -24
- package/dist/developer/upgrades/4.9-to-4.10.md +0 -24
- package/dist/developer/upgrades/4.x-to-4.8.md +0 -52
- package/dist/developer/upgrades/5.0-to-5.1.md +0 -28
- package/dist/developer/upgrades/5.1-to-5.2.md +0 -131
- package/dist/developer/upgrades/5.2-to-5.3.md +0 -338
- package/dist/developer/upgrades/5.3-to-5.4.md +0 -277
- package/dist/developer/upgrades/5.4-to-5.5.md +0 -301
- package/dist/developer/upgrades/5.5-to-5.6.md +0 -207
|
@@ -1,265 +1,70 @@
|
|
|
1
1
|
---
|
|
2
2
|
title: Permissions
|
|
3
|
+
description: The permission catalog, staff roles, and how extensions register their own permissions.
|
|
3
4
|
---
|
|
4
5
|
|
|
5
|
-
|
|
6
|
+
Staff roles and their permissions are managed as data — in the dashboard under **Settings → Roles**, through the Admin API (`/api/v3/admin/roles`), or in seeds. There is nothing to configure in Ruby for day-to-day permission management. This page covers what extension and host-application developers can plug into.
|
|
6
7
|
|
|
7
|
-
##
|
|
8
|
+
## The permission catalog
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
Every grantable capability is a flat key of the form `read_<resource>` or `write_<resource>` — the same vocabulary secret API keys use as scopes. `write_*` implies the matching `read_*`. Discover the catalog at runtime with `GET /api/v3/admin/permissions`; the role editor and the API-key scope picker are both rendered from it.
|
|
10
11
|
|
|
11
|
-
|
|
12
|
+
Keys are per resource, not per action. The money-adjacent areas (`payments`, `refunds`, `gift_cards`, `store_credits`) are separate resources from `orders`, so "view orders but don't refund" needs no special casing.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
2. **Permission Sets** - Contain the logic defining what actions users can perform on resources
|
|
15
|
-
3. **Role Configuration** - Associates roles with their corresponding permission sets
|
|
16
|
-
|
|
17
|
-
### Configuring Roles
|
|
18
|
-
|
|
19
|
-
In your `config/initializers/spree.rb`, configure which permission sets are assigned to each role:
|
|
20
|
-
|
|
21
|
-
```ruby
|
|
22
|
-
Rails.application.config.after_initialize do
|
|
23
|
-
# Default permissions for all users (guests and logged-in customers)
|
|
24
|
-
Spree.permissions.assign(:default, [Spree::PermissionSets::DefaultCustomer])
|
|
25
|
-
|
|
26
|
-
# Full admin access
|
|
27
|
-
Spree.permissions.assign(:admin, [Spree::PermissionSets::SuperUser])
|
|
28
|
-
|
|
29
|
-
# Custom role with specific permissions
|
|
30
|
-
Spree.permissions.assign(:customer_service, [
|
|
31
|
-
Spree::PermissionSets::DashboardDisplay,
|
|
32
|
-
Spree::PermissionSets::OrderManagement,
|
|
33
|
-
Spree::PermissionSets::UserDisplay
|
|
34
|
-
])
|
|
35
|
-
|
|
36
|
-
# Merchandiser role for product management
|
|
37
|
-
Spree.permissions.assign(:merchandiser, [
|
|
38
|
-
Spree::PermissionSets::DashboardDisplay,
|
|
39
|
-
Spree::PermissionSets::ProductManagement,
|
|
40
|
-
Spree::PermissionSets::StockManagement
|
|
41
|
-
])
|
|
42
|
-
end
|
|
43
|
-
```
|
|
44
|
-
|
|
45
|
-
### Built-in Permission Sets
|
|
46
|
-
|
|
47
|
-
| Permission Set | Description |
|
|
48
|
-
|---------------|-------------|
|
|
49
|
-
| `SuperUser` | Full admin access with safety restrictions |
|
|
50
|
-
| `DefaultCustomer` | Basic storefront permissions (browse, checkout, manage own account) |
|
|
51
|
-
| `DashboardDisplay` | View admin dashboard |
|
|
52
|
-
| `OrderDisplay` | Read-only access to orders |
|
|
53
|
-
| `OrderManagement` | Full order management (view, edit, refund, etc.) |
|
|
54
|
-
| `ProductDisplay` | Read-only access to products and catalog |
|
|
55
|
-
| `ProductManagement` | Full catalog management (products, variants, taxonomies) |
|
|
56
|
-
| `UserDisplay` | Read-only access to users |
|
|
57
|
-
| `UserManagement` | Full user management |
|
|
58
|
-
| `StockDisplay` | Read-only access to inventory |
|
|
59
|
-
| `StockManagement` | Full inventory management |
|
|
60
|
-
| `PromotionManagement` | Manage promotions and coupon codes |
|
|
61
|
-
| `ConfigurationManagement` | Manage store settings, shipping, taxes, etc. |
|
|
62
|
-
| `RoleManagement` | Manage roles (except the protected admin role) |
|
|
63
|
-
|
|
64
|
-
### Creating Custom Permission Sets
|
|
65
|
-
|
|
66
|
-
Create a new permission set in `app/models/spree/permission_sets/`:
|
|
67
|
-
|
|
68
|
-
```ruby
|
|
69
|
-
# app/models/spree/permission_sets/warehouse_management.rb
|
|
70
|
-
module Spree
|
|
71
|
-
module PermissionSets
|
|
72
|
-
class WarehouseManagement < Base
|
|
73
|
-
def activate!
|
|
74
|
-
can :manage, Spree::StockItem
|
|
75
|
-
can :manage, Spree::StockLocation
|
|
76
|
-
can :manage, Spree::StockMovement
|
|
77
|
-
can :manage, Spree::Shipment
|
|
78
|
-
can [:read, :admin], Spree::Order
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
end
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
Then assign it to a role:
|
|
86
|
-
|
|
87
|
-
```ruby
|
|
88
|
-
Spree.permissions.assign(:warehouse_staff, [
|
|
89
|
-
Spree::PermissionSets::DashboardDisplay,
|
|
90
|
-
Spree::PermissionSets::WarehouseManagement
|
|
91
|
-
])
|
|
92
|
-
```
|
|
93
|
-
|
|
94
|
-
### Permission Set API
|
|
95
|
-
|
|
96
|
-
Within a permission set, you have access to:
|
|
97
|
-
|
|
98
|
-
- `can(action, subject, conditions = {})` - Grant permission
|
|
99
|
-
- `cannot(action, subject, conditions = {})` - Deny permission
|
|
100
|
-
- `can?(action, subject)` - Check if permission exists
|
|
101
|
-
- `user` - The current user
|
|
102
|
-
- `store` - The current store (for multi-store setups)
|
|
103
|
-
|
|
104
|
-
```ruby
|
|
105
|
-
module Spree
|
|
106
|
-
module PermissionSets
|
|
107
|
-
class OrderManagementForOwnOrders < Base
|
|
108
|
-
def activate!
|
|
109
|
-
# Users can only manage orders they created
|
|
110
|
-
can :manage, Spree::Order, created_by_id: user.id
|
|
111
|
-
|
|
112
|
-
# But cannot cancel any order
|
|
113
|
-
cannot :cancel, Spree::Order
|
|
114
|
-
|
|
115
|
-
# Unless it's cancellable
|
|
116
|
-
can :cancel, Spree::Order, &:allow_cancel?
|
|
117
|
-
end
|
|
118
|
-
end
|
|
119
|
-
end
|
|
120
|
-
end
|
|
121
|
-
```
|
|
122
|
-
|
|
123
|
-
### Managing Permission Configuration
|
|
14
|
+
Roles as code is plain ActiveRecord:
|
|
124
15
|
|
|
125
16
|
```ruby
|
|
126
|
-
#
|
|
127
|
-
Spree.
|
|
128
|
-
|
|
129
|
-
Spree::PermissionSets::UserManagement
|
|
130
|
-
])
|
|
131
|
-
|
|
132
|
-
# Add more permission sets to an existing role
|
|
133
|
-
Spree.permissions.assign(:customer_service, [
|
|
134
|
-
Spree::PermissionSets::StockDisplay
|
|
135
|
-
])
|
|
136
|
-
|
|
137
|
-
# Clear all permission sets from a role
|
|
138
|
-
Spree.permissions.clear(:customer_service)
|
|
139
|
-
|
|
140
|
-
# Check what permission sets a role has
|
|
141
|
-
Spree.permissions.permission_sets_for(:customer_service)
|
|
142
|
-
# => [Spree::PermissionSets::OrderDisplay, ...]
|
|
143
|
-
|
|
144
|
-
# Check if a role is configured
|
|
145
|
-
Spree.permissions.role_configured?(:customer_service)
|
|
146
|
-
# => true
|
|
17
|
+
# db/seeds.rb
|
|
18
|
+
Spree::Role.find_or_create_by!(name: 'support')
|
|
19
|
+
.update!(permissions: %w[read_orders read_customers], description: 'Read-only support')
|
|
147
20
|
```
|
|
148
21
|
|
|
149
|
-
|
|
22
|
+
A role with `mutable: false` (set from seeds or the console) renders read-only in the dashboard — for roles the application does not want store staff to edit. The `admin` role is always protected.
|
|
150
23
|
|
|
151
|
-
|
|
24
|
+
## Registering extension permissions
|
|
152
25
|
|
|
153
|
-
|
|
154
|
-
Spree::Role.find_or_create_by(name: 'customer_service')
|
|
155
|
-
Spree::Role.find_or_create_by(name: 'merchandiser')
|
|
156
|
-
Spree::Role.find_or_create_by(name: 'warehouse_staff')
|
|
157
|
-
```
|
|
158
|
-
|
|
159
|
-
Assign a role to a user:
|
|
26
|
+
Register your models as a catalog resource once; the keys appear in the role editor and become mintable API-key scopes with no further wiring:
|
|
160
27
|
|
|
161
28
|
```ruby
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
29
|
+
# in your engine's initializer
|
|
30
|
+
Spree.permissions.register_resource(:reviews, group: :catalog, subjects: -> {
|
|
31
|
+
[SpreeReviews::Review]
|
|
32
|
+
})
|
|
165
33
|
```
|
|
166
34
|
|
|
167
|
-
|
|
35
|
+
- `group` places the row in the permission pickers (`:orders`, `:catalog`, `:marketing`, `:customers`, `:settings`, `:access`, `:analytics` — or your own).
|
|
36
|
+
- `subjects` is a lambda returning the CanCanCan subjects the keys grant; it resolves lazily, so load order does not matter.
|
|
37
|
+
- Pass `write: false` for read-only resources.
|
|
168
38
|
|
|
169
|
-
|
|
170
|
-
- No `RoleUser` records are created for regular customers
|
|
171
|
-
- Only users with special permissions need explicit role assignments
|
|
39
|
+
Localize the labels in your engine's locale file under `spree.permissions_catalog.resources.<name>` (`label` and `description`), and declare the same resource on your admin controllers with `scoped_resource :reviews`.
|
|
172
40
|
|
|
173
|
-
##
|
|
41
|
+
## Beyond the catalog
|
|
174
42
|
|
|
175
|
-
|
|
43
|
+
The catalog is deliberately flat: it answers "may this role touch this kind of record", and that is the whole grant vocabulary. Two rules that do *not* belong in it:
|
|
176
44
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
Create a new ability class in `app/models/customer_service_ability.rb`:
|
|
180
|
-
|
|
181
|
-
```ruby
|
|
182
|
-
class CustomerServiceAbility
|
|
183
|
-
include CanCan::Ability
|
|
184
|
-
|
|
185
|
-
def initialize(user)
|
|
186
|
-
if user.respond_to?(:has_spree_role?) && user.has_spree_role?('customer_service')
|
|
187
|
-
can :manage, Spree::Order
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
end
|
|
191
|
-
```
|
|
192
|
-
|
|
193
|
-
Register it via a decorator in `app/models/spree/ability_decorator.rb`:
|
|
194
|
-
|
|
195
|
-
```ruby
|
|
196
|
-
module Spree
|
|
197
|
-
module AbilityDecorator
|
|
198
|
-
def abilities_to_register
|
|
199
|
-
[CustomerServiceAbility]
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
Ability.prepend(AbilityDecorator)
|
|
204
|
-
end
|
|
205
|
-
```
|
|
206
|
-
|
|
207
|
-
### Replacing the Ability Class
|
|
208
|
-
|
|
209
|
-
You can replace the entire ability class via [Dependencies](dependencies.md):
|
|
45
|
+
- **Record-state rules** ("a completed order cannot be deleted") live on models and workflows, so they bind every caller — including secret API keys, which never consult CanCanCan.
|
|
46
|
+
- **Row-level restrictions** (a support agent limited to one market) are not expressible as keys. Replace the ability class outright:
|
|
210
47
|
|
|
211
48
|
```ruby
|
|
212
49
|
# config/initializers/spree.rb
|
|
213
|
-
Spree::Dependencies.ability_class = '
|
|
50
|
+
Spree::Dependencies.ability_class = 'MyApp::Ability'
|
|
214
51
|
```
|
|
215
52
|
|
|
216
53
|
```ruby
|
|
217
|
-
# app/models/
|
|
218
|
-
class
|
|
54
|
+
# app/models/my_app/ability.rb
|
|
55
|
+
class MyApp::Ability < Spree::Ability
|
|
219
56
|
def initialize(user, options = {})
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
@user = user || Spree.user_class.new
|
|
223
|
-
@store = options[:store] || Spree::Current.store
|
|
224
|
-
|
|
225
|
-
if @user.respond_to?(:has_spree_role?) && @user.has_spree_role?('admin')
|
|
226
|
-
apply_admin_permissions(@user, options)
|
|
227
|
-
elsif @user.respond_to?(:has_spree_role?) && @user.has_spree_role?(:customer_service)
|
|
228
|
-
apply_customer_service_permissions(@user)
|
|
229
|
-
else
|
|
230
|
-
apply_user_permissions(@user, options)
|
|
231
|
-
end
|
|
57
|
+
super
|
|
58
|
+
return unless user.respond_to?(:market_id) && user.market_id
|
|
232
59
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
protected
|
|
237
|
-
|
|
238
|
-
def apply_customer_service_permissions(user)
|
|
239
|
-
can :manage, Spree::Order
|
|
240
|
-
can [:read, :admin], Spree.user_class
|
|
60
|
+
cannot :manage, Spree::Order
|
|
61
|
+
can [:read, :admin], Spree::Order, market_id: user.market_id
|
|
241
62
|
end
|
|
242
63
|
end
|
|
243
64
|
```
|
|
244
65
|
|
|
245
|
-
##
|
|
246
|
-
|
|
247
|
-
Spree's permission system is built on CanCanCan. Key concepts:
|
|
66
|
+
## How enforcement works
|
|
248
67
|
|
|
249
|
-
|
|
250
|
-
- `can :manage, Subject` - Grant all actions (create, read, update, destroy)
|
|
251
|
-
- `cannot :action, Subject` - Explicitly deny permission
|
|
252
|
-
- `can :action, Subject, conditions` - Conditional permission
|
|
253
|
-
|
|
254
|
-
```ruby
|
|
255
|
-
# Examples
|
|
256
|
-
can :read, Spree::Product # Can read any product
|
|
257
|
-
can :manage, Spree::Order, user_id: user.id # Can manage own orders
|
|
258
|
-
can :update, Spree::Order do |order| # Block conditions
|
|
259
|
-
order.user == user && !order.completed?
|
|
260
|
-
end
|
|
261
|
-
cannot :destroy, Spree::Order # Cannot destroy any order
|
|
262
|
-
can :destroy, Spree::Order, &:can_be_deleted? # Unless it's deletable
|
|
263
|
-
```
|
|
68
|
+
Every Admin API controller declares its resource (`scoped_resource :orders`). Each request checks the principal's keys — a staff member's role permissions on the current store, or a secret key's scopes — against `read_<resource>` or `write_<resource>` for the action. A missing key produces a 403 naming it in `details.required_permission`. Behind that gate, keys compile to CanCanCan rules for record-level concerns, and `GET /api/v3/admin/me` returns both the rule dump the dashboard mirrors and `permission_keys`, the flat key list.
|
|
264
69
|
|
|
265
|
-
|
|
70
|
+
Storefront customers are not part of this system — customer authorization is ownership, enforced by the Store API's scoped lookups, with nothing to configure. The one swappable piece is `Spree::Storefront::AccessPolicy` (via `Spree::Dependencies.storefront_access_policy_class`): a generic `readable?` / `writable?` / `scope` protocol that defaults to "the caller owns the record", with carts and orders adding guest-token access. Replace it only when access must widen beyond the owner, such as company accounts sharing purchases or wishlists.
|