Skip to content
581 changes: 260 additions & 321 deletions .rubocop_todo.yml

Large diffs are not rendered by default.

13 changes: 13 additions & 0 deletions api/app/controllers/spree/api/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ def create
@user = user_class.new(permitted_user_params)

if @user.save
set_user_group if current_store&.enforce_group_upon_signup

respond_with(@user, status: 201, default_template: :show)
else
invalid_resource!(@user)
Expand Down Expand Up @@ -86,4 +88,15 @@ def permitted_user_attributes
super
end
end

# Sets the user group for a user if they don't have one assigned
# This method checks if there's a user (@user) and if they don't have a user group on sign up
# If these conditions are met, it assigns the default cart user group from the current store
# If enforce_group_upon_signup is enabled on the store settings
def set_user_group
if @user && @user.user_group.nil?
user_group = current_store.default_cart_user_group
@user.update(user_group: user_group) if user_group
end
end
end
2 changes: 1 addition & 1 deletion api/lib/spree/api_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ class ApiConfiguration < Preferences::Configuration
:id, :month, :year, :cc_type, :last_digits, :name
]

preference :user_attributes, :array, default: [:id, :email, :created_at, :updated_at, :customer_metadata]
preference :user_attributes, :array, default: [:id, :email, :user_group_id, :created_at, :updated_at, :customer_metadata]

preference :property_attributes, :array, default: [:id, :name, :presentation]

Expand Down
27 changes: 26 additions & 1 deletion api/spec/requests/spree/api/users_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@ module Spree::Api
describe 'Users', type: :request do
let(:user) { create(:user, spree_api_key: SecureRandom.hex) }
let(:stranger) { create(:user, email: 'stranger@example.com') }
let(:attributes) { [:id, :email, :created_at, :updated_at, :customer_metadata] }
let(:attributes) { [:id, :email, :user_group_id, :created_at, :updated_at, :customer_metadata] }
let(:default_user_group) { create(:user_group) }
let(:store) { create(:store) }

context "as a normal user" do
it "can get own details" do
Expand Down Expand Up @@ -155,6 +157,29 @@ module Spree::Api
expect(json_response['count']).to eq 1
expect(json_response['users'].size).to eq 1
end

it "assigns default user group upon creation if store enforces it" do
store.update(enforce_group_upon_signup: true, default_cart_user_group: default_user_group)
user_params = {
email: 'new@example.com', password: 'spree123', password_confirmation: 'spree123'
}

post spree.api_users_path, params: { user: user_params, token: user.spree_api_key }
expect(json_response['email']).to eq 'new@example.com'
expect(json_response['user_group_id']).to eq default_user_group.id
end

it "does not assign user group if store does not enforce it" do
store.update(enforce_group_upon_signup: false)

user_params = {
email: 'new@example.com', password: 'spree123', password_confirmation: 'spree123'
}

post spree.api_users_path, params: { user: user_params, token: user.spree_api_key }
expect(json_response['email']).to eq 'new@example.com'
expect(json_response['user_group_id']).to be_nil
end
end

context "as an admin" do
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

module Spree
module Admin
class UserGroupsController < ResourceController
end
end
end
17 changes: 17 additions & 0 deletions backend/app/controllers/spree/admin/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ def create
if @user.save
set_roles
set_stock_locations
set_user_group if current_store&.enforce_group_upon_signup

flash[:success] = t('spree.created_successfully')
redirect_to edit_admin_user_url(@user)
Expand Down Expand Up @@ -111,6 +112,10 @@ def user_params
attributes -= [:password, :password_confirmation]
end

if can? :manage, Spree::UserGroup
attributes += [:user_group_id]
end

params.require(:user).permit(attributes)
end

Expand Down Expand Up @@ -153,6 +158,18 @@ def set_stock_locations
Spree::StockLocation.accessible_by(current_ability).where(id: user_params[:stock_location_ids])
end
end

# Sets the user group for a user if they don't have one assigned
# This method checks if there's a user (@user) and if they don't have a user group on sign up
# If these conditions are met, it assigns the default cart user group from the current store
# If enforce_group_upon_signup is enabled on the store settings
# @return [void]
def set_user_group
if @user && @user.user_group.nil?
user_group = current_store.default_cart_user_group
@user.update(user_group: user_group) if user_group
end
end
end
end
end
11 changes: 11 additions & 0 deletions backend/app/views/spree/admin/shared/users_sub_menu.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<% Spree.deprecator.warn "Using the #{@virtual_path.inspect} partial is deprecated, please use MenuItem#children instead." %>

<ul class="admin-subnav" data-hook="admin_users_sub_tabs">
<% if can?(:admin, Spree.user_class) %>
<%= tab label: :users, url: spree.admin_users_path %>
<% end %>

<% if can?(:admin, Spree::UserGroup) %>
<%= tab label: :user_groups, url: spree.admin_user_groups_path %>
<% end %>
</ul>
14 changes: 14 additions & 0 deletions backend/app/views/spree/admin/stores/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,20 @@
<%= f.error_message_on :reverse_charge_status %>
<% end %>
<% end %>

<%= f.field_container :default_cart_user_group_id do %>
<%= f.label :default_cart_user_group_id %>
<%= f.collection_select :default_cart_user_group_id, Spree::UserGroup.all, :id, :group_name, { include_blank: true }, { class: 'custom-select' } %>
<%= f.error_message_on :default_cart_user_group_id %>
<% end %>

<%= f.field_container :enforce_group_upon_signup, class: %w(checkbox) do %>
<label>
<%= f.check_box(:enforce_group_upon_signup) %>
<%= t('spree.enforce_group_upon_signup') %>
</label>
<%= f.error_message_on :enforce_group_upon_signup %>
<% end %>
</div>
<div class="col-12 col-md-6">
<%= f.field_container :url do %>
Expand Down
9 changes: 9 additions & 0 deletions backend/app/views/spree/admin/user_groups/_form.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<div data-hook="admin_user_group_form_fields" class="row">
<div data-hook="admin_user_group_form_group_name_field" class="col-5">
<%= f.field_container :group_name do %>
<%= f.label :group_name, class: 'required' %>
<%= f.text_field :group_name, class: 'fullwidth' %>
<%= error_message_on :user_group, :group_name %>
<% end %>
</div>
</div>
24 changes: 24 additions & 0 deletions backend/app/views/spree/admin/user_groups/edit.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<% admin_breadcrumb(link_to plural_resource_name(Spree::LegacyUser), spree.admin_users_path) %>
<% admin_breadcrumb(link_to plural_resource_name(Spree::UserGroup), spree.admin_user_groups_path) %>
<% admin_breadcrumb(@user_group.group_name) %>

<% content_for :page_actions do %>
<% end %>

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

<div data-hook="admin_user_group_edit_form">
<%= form_for [:admin, @user_group] do |f| %>
<fieldset class="no-border-top">
<%= render partial: 'form', locals: { f: f } %>

<div class="clear"></div>

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

<% content_for :page_actions do %>
<% if can?(:create, Spree::UserGroup) %>
<li>
<%= link_to t('spree.new_user_group'), new_object_url, id: 'admin_new_user_group_link', class: 'btn btn-primary' %>
</li>
<% end %>
<% end %>

<% if @user_groups.any? %>
<table class="index" id='listing_user_groups'>
<colgroup>
<col style="width: 40%">
<col style="width: 20%">
</colgroup>
<thead>
<tr data-hook="admin_user_groups_index_headers">
<th><%= Spree::UserGroup.human_attribute_name(:group_name) %></th>
<th data-hook="admin_user_groups_index_header_actions" class="actions"></th>
</tr>
</thead>
<tbody>
<% @user_groups.each do |user_group| %>
<tr id="<%= spree_dom_id user_group %>" data-hook="admin_user_groups_index_rows">
<td><%= link_to user_group.try(:group_name), edit_admin_user_group_path(user_group) %></td>
<td data-hook="admin_user_groups_index_row_actions" class="actions">
<% if can?(:update, user_group) %>
<%= link_to_edit user_group, no_text: true %>
<% end %>

<% if can?(:destroy, user_group) %>
<%= link_to_delete user_group, no_text: true %>
<% end %>
</td>
</tr>
<% end %>
</tbody>
</table>
<% else %>
<div class="no-objects-found">
<%= render 'spree/admin/shared/no_objects_found',
resource: Spree::UserGroup,
new_resource_url: new_object_url %>
</div>
<% end %>
24 changes: 24 additions & 0 deletions backend/app/views/spree/admin/user_groups/new.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<% admin_breadcrumb(link_to plural_resource_name(Spree::LegacyUser), spree.admin_users_path) %>
<% admin_breadcrumb(link_to plural_resource_name(Spree::UserGroup), spree.admin_user_groups_path) %>
<% admin_breadcrumb(t('spree.new_user_group')) %>

<% content_for :page_actions do %>
<% end %>

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

<div data-hook="admin_user_group_new_form">
<%= form_for [:admin, @user_group] do |f| %>
<fieldset class="no-border-top">
<%= render partial: 'form', locals: { f: f } %>

<div class="clear"></div>

<div data-hook="admin_user_group_new_form_buttons">
<%= render partial: 'spree/admin/shared/new_resource_links' %>
</div>
</fieldset>
<% end %>
</div>
13 changes: 13 additions & 0 deletions backend/app/views/spree/admin/users/_form.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,16 @@
<% end %>
</div>
</div>

<% if can?(:update, @user) && can?(:manage, :user_group) %>
<fieldset data-hook="admin_user_user_group" id="admin_user_edit_user_group">
<legend><%= t('spree.admin.user.user_group') %></legend>
<div>
<%= f.field_container :user_group_id do %>
<%= f.label :user_group_id, t('spree.admin.user.user_group') %>
<%= f.collection_select :user_group_id, Spree::UserGroup.all, :id, :group_name, { include_blank: true }, { class: 'custom-select' } %>
<%= f.error_message_on :user_group_id %>
<% end %>
</div>
</fieldset>
<% end %>
1 change: 1 addition & 0 deletions backend/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@

resources :zones

resources :user_groups
resources :tax_categories

resources :products do
Expand Down
16 changes: 16 additions & 0 deletions backend/lib/spree/backend_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -234,8 +234,24 @@ def menu_items
label: :users,
icon: admin_updated_navbar ? 'ri-user-line' : 'user',
match_path: %r{/(users|store_credits)},
data_hook: :admin_users_sub_tabs,
partial: 'spree/admin/shared/users_sub_menu',
condition: -> { Spree.user_class && can?(:admin, Spree.user_class) },
url: :admin_users_path,
children: [
MenuItem.new(
label: :users,
condition: -> { Spree.user_class && can?(:admin, Spree.user_class) },
url: :admin_users_path
),
MenuItem.new(
label: :user_groups,
condition: -> {
can?(:admin, Spree::UserGroup)
},
url: :admin_user_groups_path
),
]
),
MenuItem.new(
label: :settings,
Expand Down
Loading