Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add backend interface for roles management #362

Open
wants to merge 8 commits into
base: rainerd/incorporate-roles-management-code-into-the-core
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions backend/app/controllers/spree/admin/roles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

module Spree
module Admin
class RolesController < ResourceController
end
end
end
45 changes: 45 additions & 0 deletions backend/app/views/spree/admin/roles/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<div data-hook="admin_role_form_fields" class="row">
<div class="col-12">
<%= f.field_container :name do %>
<%= f.label :name %>
<%= f.text_field :name, class: 'fullwidth' %>
<%= error_message_on :role, :name %>
<% end %>
</div>

<div data-hook="admin_role_form_permissions" class="col-12 row">
<div class="col-4">
<strong><%= label_tag nil, t('spree.display_permissions') %></strong>
<ul class="fields">
<% Spree::PermissionSet.display_permissions.each do |permission| %>
<li>
<%= check_box_tag 'role[permission_set_ids][]', permission.id, f.object.try(:permission_sets).include?(permission) %>
<%= permission.name.titleize %>
</li>
<% end %>
</ul>
</div>
<div class="col-4">
<strong><%= label_tag nil, t('spree.management_permissions') %></strong>
<ul class="fields">
<% Spree::PermissionSet.management_permissions.each do |permission| %>
<li>
<%= check_box_tag 'role[permission_set_ids][]', permission.id, f.object.try(:permission_sets).include?(permission) %>
<%= permission.name.titleize %>
</li>
<% end %>
</ul>
</div>
<div class="col-4">
<strong><%= label_tag nil, t('spree.custom_permissions') %></strong>
<ul class="fields">
<% Spree::PermissionSet.custom_permissions.each do |permission| %>
<li>
<%= check_box_tag 'role[permission_set_ids][]', permission.id, f.object.try(:permission_sets).include?(permission) %>
<%= permission.name.titleize %>
</li>
<% end %>
</ul>
</div>
</div>
</div>
17 changes: 17 additions & 0 deletions backend/app/views/spree/admin/roles/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<% admin_breadcrumb(link_to plural_resource_name(Spree::LegacyUser), spree.admin_users_path) %>
<% admin_breadcrumb(link_to t('spree.roles'), spree.admin_roles_path) %>
<% admin_breadcrumb(@role.name) %>

<div data-hook="admin_role_edit_form_header">
<%= render partial: 'spree/shared/error_messages', locals: { target: @role } %>
</div>

<div data-hook="admin_role_edit_form">
<%= form_for [:admin, @role], url: admin_role_url(@role), method: :put do |f| %>
<%= render partial: 'form', locals: { f: f } %>

<div data-hook="admin_role_edit_form_buttons">
<%= render partial: 'spree/admin/shared/edit_resource_links' %>
</div>
<% end %>
</div>
40 changes: 40 additions & 0 deletions backend/app/views/spree/admin/roles/index.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<% admin_breadcrumb(plural_resource_name(Spree::LegacyUser)) %>
<% admin_breadcrumb(t('spree.roles')) %>

<% content_for :page_actions do %>
<% if can?(:admin, Spree::Role) && can?(:create, Spree::Role) %>
<li>
<%= link_to t('spree.new_role'), new_admin_role_url, class: 'btn btn-primary' %>
</li>
<% end %>
<% end %>

<table class="index">
<colgroup>
<col style="width: 30%">
<col style="width: 70%">
</colgroup>
<thead>
<tr data-hook="role_header">
<th><%= Spree.user_class.human_attribute_name(:name) %></th>
<th><%= Spree.user_class.human_attribute_name(:permissions) %></th>
<th class="actions"></th>
</tr>
</thead>
<tbody>
<% @roles.each do |role| %>
<tr id="<%= spree_dom_id role %>" data-hook="rate_row">
<td><%= role.try(:name) || t(:not_available) %></td>
<td><%= role.permission_sets.map(&:name).to_sentence %></td>
<td class="actions">
<% if can?(:edit, role) %>
<%= link_to_edit role, no_text: true %>
<% end %>
<% if can?(:destroy, role) && role.can_be_deleted? %>
<%= link_to_delete role, no_text: true, url: spree.admin_role_path(role) %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
17 changes: 17 additions & 0 deletions backend/app/views/spree/admin/roles/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<% admin_breadcrumb(link_to plural_resource_name(Spree::LegacyUser), spree.admin_users_path) %>
<% admin_breadcrumb(link_to t('spree.roles'), spree.admin_roles_path) %>
<% admin_breadcrumb(t('spree.new_role')) %>

<div data-hook="admin_role_new_form_header">
<%= render partial: 'spree/shared/error_messages', locals: { target: @role } %>
</div>

<div data-hook="admin_role_new_form">
<%= form_for [:admin, @role], url: admin_roles_url, method: :post do |f| %>
<%= render partial: 'form', locals: { f: f } %>

<div data-hook="admin_role_new_form_buttons">
<%= render partial: 'spree/admin/shared/new_resource_links' %>
</div>
<% end %>
</div>
9 changes: 9 additions & 0 deletions backend/app/views/spree/admin/shared/_user_sub_menu.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<ul class="admin-subnav" data-hook="admin_user_sub_tabs">
<% if can?(:admin, Spree.user_class) %>
<%= tab :user, label: :users, url: spree.admin_users_path %>
<% end %>

<% if can?(:admin, Spree::Role) %>
<%= tab :roles, label: :roles, url: spree.admin_roles_path %>
<% end %>
</ul>
2 changes: 2 additions & 0 deletions backend/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,8 @@
end
end

resources :roles

resources :style_guide, only: [:index]
end

Expand Down
3 changes: 2 additions & 1 deletion backend/lib/spree/backend_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ def theme_path(user_theme = nil)
:store_credit_reasons]
PROMOTION_TABS ||= [:promotions, :promotion_categories]
STOCK_TABS ||= [:stock_items]
USER_TABS ||= [:users, :store_credits]
USER_TABS ||= [:users, :roles, :store_credits]

# Items can be added to the menu by using code like the following:
#
Expand Down Expand Up @@ -107,6 +107,7 @@ def menu_items
MenuItem.new(
USER_TABS,
'user',
partial: 'spree/admin/shared/user_sub_menu',
condition: -> { Spree.user_class && can?(:admin, Spree.user_class) },
url: :admin_users_path,
position: 4
Expand Down
8 changes: 4 additions & 4 deletions backend/spec/features/admin/store_credits_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
describe "visiting the store credits page" do
before do
visit spree.admin_path
click_link "Users"
click_nav "Users"
end

it "should be on the store credits page" do
Expand All @@ -37,7 +37,7 @@
describe "creating store credit" do
before do
visit spree.admin_path
click_link "Users"
click_nav "Users"
click_link store_credit.user.email
click_link "Store Credit"
allow_any_instance_of(Spree::Admin::StoreCreditsController).to receive_messages(spree_current_user: admin_user)
Expand All @@ -59,7 +59,7 @@
describe "displaying a store credit details page" do
before do
visit spree.admin_path
click_link "Users"
click_nav "Users"
click_link store_credit.user.email
click_link "Store Credit"
page.find(".sc-table td.actions a.fa-edit").click
Expand Down Expand Up @@ -111,7 +111,7 @@

before do
visit spree.admin_path
click_link "Users"
click_nav "Users"
click_link store_credit.user.email
click_link "Store Credit"
allow_any_instance_of(Spree::Admin::StoreCreditsController).to receive_messages(spree_current_user: admin_user)
Expand Down
4 changes: 2 additions & 2 deletions backend/spec/features/admin/users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@

before do
visit spree.admin_path
click_link 'Users'
click_nav 'Users'
end

context 'users index' do
Expand Down Expand Up @@ -357,7 +357,7 @@ def always_invalid_email
context 'if an user has placed orders' do
before do
visit spree.admin_path
click_link 'Users'
click_nav 'Users'
end

it "can't be deleted" do
Expand Down
19 changes: 19 additions & 0 deletions core/app/models/spree/permission_set.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# frozen_string_literal: true

module Spree
class PermissionSet < Spree::Base
has_many :role_permissions
has_many :roles, through: :role_permissions

validates :name, :set, presence: true

scope :display_permissions, -> { where('name LIKE ?', '%Display') }
scope :management_permissions, -> { where('name LIKE ?', '%Management') }

scope :custom_permissions, -> {
where.not(id: display_permissions)
.where.not(id: management_permissions)
.where.not(set: ['Spree::PermissionSets::SuperUser', 'Spree::PermissionSets::DefaultCustomer'])
}
end
end
18 changes: 18 additions & 0 deletions core/app/models/spree/role.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,30 @@
module Spree
class Role < Spree::Base
has_many :role_users, class_name: "Spree::RoleUser", dependent: :destroy
has_many :role_permissions, dependent: :destroy
has_many :permission_sets, through: :role_permissions
has_many :users, through: :role_users

scope :non_base_roles, -> { where.not(name: ['admin', 'default']) }

validates_uniqueness_of :name, case_sensitive: true
validates :name, uniqueness: true
after_save :assign_permissions

def admin?
name == "admin"
end

def permission_sets_constantized
permission_sets.map(&:set).map(&:constantize)
end

def assign_permissions
::Spree::Config.roles.assign_permissions name, permission_sets_constantized
end

def can_be_deleted?
permission_sets.find_by(set: ["Spree::PermissionSets::SuperUser", "Spree::PermissionSets::DefaultCustomer"]).nil?
end
end
end
8 changes: 8 additions & 0 deletions core/app/models/spree/role_permission.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

module Spree
class RolePermission < Spree::Base
belongs_to :role
belongs_to :permission_set
end
end
5 changes: 5 additions & 0 deletions core/config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -961,6 +961,7 @@ en:
promotions: Promotions
properties: Property Types
rma: RMA
roles: Roles
settings: Settings
shipping: Shipping
stock: Stock
Expand Down Expand Up @@ -1450,6 +1451,7 @@ en:
currency_settings: Currency Settings
current: Current
current_promotion_usage: 'Current Usage: %{count}'
custom_permissions: Custom Permissions
customer: Customer
customer_details: Customer Details
customer_details_updated: Customer Details Updated
Expand Down Expand Up @@ -1491,6 +1493,7 @@ en:
discount_rules: Discount Rules
dismiss_banner: No. Thanks! I'm not interested, do not display this message again
display: Display
display_permissions: Display Permissions
download_promotion_codes_list: Download codes list
edit: Edit
edit_refund_reason: Edit Refund Reason
Expand Down Expand Up @@ -1763,6 +1766,7 @@ en:
manage_promotion_categories: Manage Promotion Categories
manage_stock: Store Stock
manage_variants: Manage Variants
management_permissions: Management Permissions
manual_intervention_required: Manual intervention required
master_price: Master Price
master_sku: Master SKU
Expand Down Expand Up @@ -1811,6 +1815,7 @@ en:
new_refund_reason: New Refund Reason
new_return_authorization: New RMA
new_rma_reason: New RMA Reason
new_role: New Role
new_shipment_at_location: New shipment at location
new_shipping_category: New Shipping Category
new_shipping_method: New Shipping Method
Expand Down
11 changes: 11 additions & 0 deletions core/db/migrate/20230607100048_create_spree_permission_sets.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class CreateSpreePermissionSets < ActiveRecord::Migration[7.0]
def change
create_table :spree_permission_sets do |t|
t.string :name
t.string :set
t.timestamps
end
end
end
11 changes: 11 additions & 0 deletions core/db/migrate/20230607100109_create_spree_roles_permissions.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# frozen_string_literal: true

class CreateSpreeRolesPermissions < ActiveRecord::Migration[7.0]
def change
create_table :spree_role_permissions do |t|
t.references :role
t.references :permission_set
t.timestamps
end
end
end
4 changes: 4 additions & 0 deletions core/lib/spree/app_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -605,6 +605,10 @@ def roles
@roles ||= Spree::RoleConfiguration.new.tap do |roles|
roles.assign_permissions :default, ['Spree::PermissionSets::DefaultCustomer']
roles.assign_permissions :admin, ['Spree::PermissionSets::SuperUser']

Spree::Role.non_base_roles.each do |role|
roles.assign_permissions role.name, role.permission_sets_constantized
end
end
end

Expand Down
1 change: 1 addition & 0 deletions core/lib/spree/permission_sets.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
require 'spree/permission_sets/promotion_management'
require 'spree/permission_sets/restricted_stock_display'
require 'spree/permission_sets/restricted_stock_management'
require 'spree/permission_sets/role_management'
require 'spree/permission_sets/stock_display'
require 'spree/permission_sets/stock_management'
require 'spree/permission_sets/super_user'
Expand Down
15 changes: 15 additions & 0 deletions core/lib/spree/permission_sets/role_management.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# frozen_string_literal: true

module Spree
module PermissionSets
# Permissions for viewing and editing the user roles.
#
# This permission set allows full control over roles, but only allows reading users.
class RoleManagement < PermissionSets::Base
def activate!
can [:read, :admin, :edit, :addresses, :orders, :items], Spree.user_class
can :manage, Spree::Role
end
end
end
end
2 changes: 1 addition & 1 deletion core/lib/spree/permission_sets/user_display.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ class UserDisplay < PermissionSets::Base
def activate!
can [:read, :admin, :edit, :addresses, :orders, :items], Spree.user_class
can [:read, :admin], Spree::StoreCredit
can :read, Spree::Role
can [:read, :admin], Spree::Role
end
end
end
Expand Down