From 3bdfc556804c30499453af2dfeb60b978b589a34 Mon Sep 17 00:00:00 2001
From: chapsjust <2238424@carrefour.cegepvicto.ca>
Date: Mon, 2 Mar 2026 21:52:38 -0500
Subject: [PATCH] fix role
---
app/controllers/users_controller.rb | 8 +-
app/models/user.rb | 17 +++-
app/views/shared/_settings_nav.html.erb | 25 +++--
app/views/users/_role_select.html.erb | 6 +-
docs/WHITELABEL.md | 2 -
lib/ability.rb | 130 +++++++++++++++---------
lib/whitelabel.rb | 121 ++++++++++++++++++++++
7 files changed, 238 insertions(+), 71 deletions(-)
diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb
index 9affdf4c..e8b62205 100644
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -16,6 +16,9 @@ class UsersController < ApplicationController
@users.active.where.not(role: 'integration')
end
+ # Restrict visibility to roles at or below the current user's rank.
+ @users = @users.where(role: Whitelabel.manageable_roles(current_user.role))
+
@pagy, @users = pagy(@users.preload(account: :account_accesses).where(account: current_account).order(id: :desc))
end
@@ -40,7 +43,7 @@ class UsersController < ApplicationController
end
@user.password = SecureRandom.hex if @user.password.blank?
- @user.role = User::ADMIN_ROLE unless role_valid?(@user.role)
+ @user.role = User.admin_role unless role_valid?(@user.role)
if @user.save
UserMailer.invitation_email(@user).deliver_later!
@@ -92,7 +95,8 @@ class UsersController < ApplicationController
private
def role_valid?(role)
- User::ROLES.include?(role)
+ # Role must exist AND be at or below the current user's own rank.
+ Whitelabel.manageable_roles(current_user.role).include?(role.to_s)
end
def build_user
diff --git a/app/models/user.rb b/app/models/user.rb
index 2950aeec..77537d61 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -53,6 +53,17 @@ class User < ApplicationRecord
USER_ROLE = 'user'
].freeze
+ # Config-driven role list. Falls back to ROLES constant if no config.
+ def self.available_roles
+ Whitelabel.roles
+ rescue StandardError
+ ROLES
+ end
+
+ def self.admin_role
+ available_roles.first
+ end
+
EMAIL_REGEXP = /[^@;,<>\s]+@[^@;,<>\s]+/
FULL_EMAIL_REGEXP =
@@ -72,12 +83,12 @@ class User < ApplicationRecord
devise :two_factor_authenticatable, :recoverable, :rememberable, :validatable, :trackable, :lockable
- attribute :role, :string, default: ADMIN_ROLE
+ attribute :role, :string, default: -> { User.admin_role }
attribute :uuid, :string, default: -> { SecureRandom.uuid }
scope :active, -> { where(archived_at: nil) }
scope :archived, -> { where.not(archived_at: nil) }
- scope :admins, -> { where(role: ADMIN_ROLE) }
+ scope :admins, -> { where(role: admin_role) }
validates :email, format: { with: /\A[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,}\z/ }
@@ -96,7 +107,7 @@ class User < ApplicationRecord
def sidekiq?
return true if Rails.env.development?
- role == 'admin'
+ role == User.admin_role
end
def self.sign_in_after_reset_password
diff --git a/app/views/shared/_settings_nav.html.erb b/app/views/shared/_settings_nav.html.erb
index de66f062..105d5c66 100644
--- a/app/views/shared/_settings_nav.html.erb
+++ b/app/views/shared/_settings_nav.html.erb
@@ -6,54 +6,57 @@
<%= t('settings') %>
+ <%# Profile is always visible — personal section %>
<%= link_to t('profile'), settings_profile_index_path, class: 'text-base hover:bg-base-300' %>
-
- <%= link_to t('account'), settings_account_path, class: 'text-base hover:bg-base-300' %>
-
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'account') %>
+
+ <%= link_to t('account'), settings_account_path, class: 'text-base hover:bg-base-300' %>
+
+ <% end %>
<% unless Docuseal.multitenant? %>
- <% if can?(:read, EncryptedConfig.new(key: EncryptedConfig::EMAIL_SMTP_KEY, account: current_account)) && ENV['SMTP_ADDRESS'].blank? && true_user == current_user %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'email') && can?(:read, EncryptedConfig.new(key: EncryptedConfig::EMAIL_SMTP_KEY, account: current_account)) && ENV['SMTP_ADDRESS'].blank? && true_user == current_user %>
<%= link_to t('email'), settings_email_index_path, class: 'text-base hover:bg-base-300' %>
<% end %>
- <% if can?(:read, EncryptedConfig.new(key: EncryptedConfig::FILES_STORAGE_KEY, account: current_account)) && true_user == current_user %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'storage') && can?(:read, EncryptedConfig.new(key: EncryptedConfig::FILES_STORAGE_KEY, account: current_account)) && true_user == current_user %>
<%= link_to t('storage'), settings_storage_index_path, class: 'text-base hover:bg-base-300' %>
<% end %>
<% end %>
- <% if can?(:read, AccountConfig) %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'notifications') && can?(:read, AccountConfig) %>
<%= link_to t('notifications'), settings_notifications_path, class: 'text-base hover:bg-base-300' %>
<% end %>
- <% if can?(:read, EncryptedConfig.new(key: EncryptedConfig::ESIGN_CERTS_KEY, account: current_account)) %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'esign') && can?(:read, EncryptedConfig.new(key: EncryptedConfig::ESIGN_CERTS_KEY, account: current_account)) %>
<%= link_to t('e_signature'), settings_esign_path, class: 'text-base hover:bg-base-300' %>
<% end %>
- <% if can?(:read, AccountConfig) %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'personalization') && can?(:read, AccountConfig) %>
<%= link_to t('personalization'), settings_personalization_path, class: 'text-base hover:bg-base-300' %>
<% end %>
- <% if can?(:read, User) %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'users') && can?(:read, User) %>
<%= link_to t('users'), settings_users_path, class: 'text-base hover:bg-base-300' %>
<% end %>
<%= render 'shared/settings_nav_extra' %>
<% if Docuseal.demo? || !Docuseal.multitenant? %>
- <% if can?(:read, AccessToken) && current_user.role != User::USER_ROLE %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'api') && can?(:read, AccessToken) %>
<%= link_to 'API', settings_api_index_path, class: 'text-base hover:bg-base-300' %>
<% end %>
<% end %>
<% if Docuseal.demo? || !Docuseal.multitenant? || (current_user != true_user && !current_account.testing?) %>
- <% if can?(:read, WebhookUrl) %>
+ <% if Whitelabel.setting_section_visible?(current_user.role, 'webhooks') && can?(:read, WebhookUrl) %>
<%= link_to 'Webhooks', settings_webhooks_path, class: 'text-base hover:bg-base-300' %>
diff --git a/app/views/users/_role_select.html.erb b/app/views/users/_role_select.html.erb
index 7aa6ce0a..b7915280 100644
--- a/app/views/users/_role_select.html.erb
+++ b/app/views/users/_role_select.html.erb
@@ -1,9 +1,9 @@
<%= f.label :role, class: 'label' %>
<%= f.select :role, nil, {}, class: 'base-select' do %>
-
-
-
+ <% Whitelabel.manageable_roles(current_user.role).each do |role_slug| %>
+
+ <% end %>
<% end %>
<% if Docuseal.multitenant? %>