Class: HasHelpers::UserRestrictions
- Inherits:
-
Object
- Object
- HasHelpers::UserRestrictions
- Includes:
- CanCan::Ability, Concerns::RestrictionsParseable
- Defined in:
- lib/has_helpers/utils/user_restrictions.rb
Overview
Resolves and queries the resource-level restrictions of a user, and exposes
them through the CanCanCan interface (can?/cannot?).
Uses a restrictions-based model (negative permissions): the restrictions_hash
on the user's primary user_organization defines what the user CANNOT do.
An empty restrictions hash means the user is unrestricted (can :manage, :all).
This class includes CanCan::Ability and mirrors frameworkhq's Ability:
a single catch-all can block delegates each check to the negative
restricted? query, and results are memoized per (subject, action) within the
instance (see memoized_permissions). Build one instance per request and reuse
it — the authorize lambda and host ::Ability subclasses do exactly this.
The hash is keyed by application name and may hold restrictions for several
host apps at once (e.g. AgenciesHQ, ReadyGOP, Reports, HQAdmin). Each host
passes its own keys via app_keys (looked up first), or relies on
case-insensitive matching against application / the PsqlHq client_app
variable.
Payload shape (populated by hqadmin during the login sync; may arrive multi-encoded as JSON text — see RestrictionsParseable):
{
"AppName" => {
"Client" => {
"restriction_operations" => ["View", "Create"], # operations the user CANNOT do
"resource_type" => "Base",
"alias_name" => "Customer", # optional: alternate resource name
"nested_resources" => [...] # optional: NOT consumed here
}
}
}
Usage:
restrictions = HasHelpers::UserRestrictions.new(user, app_keys: ["MyApp"])
restrictions.empty? # => true if unrestricted
restrictions.can?(:read, "Client") # => false if View/Read restricted
restrictions.restricted?(:read, "Client") # => true if View/Read restricted
restrictions.restricted_resource_names # => ["Client", ...] (read-restricted)
Constant Summary collapse
- READ_OPERATIONS =
Operations that block reading a resource.
%w[View Read].freeze
- OPERATION_MAP =
Maps CanCanCan-style action names to the restriction operation names stored in the DB. Read-like actions match both "View" and "Read".
{ "read" => READ_OPERATIONS, "view" => READ_OPERATIONS, "create" => ["Create"].freeze, "update" => ["Update"].freeze, "destroy" => ["Delete"].freeze, "delete" => ["Delete"].freeze, "export" => ["Export"].freeze, "merge" => ["Merge"].freeze }.freeze
- ACTION_ALIASES =
UI/action aliases (the standard frameworkhq set) mapped to the canonical action that
OPERATION_MAPunderstands. CanCanCan passes the ORIGINAL action to a catch-allcanblock (not the one expanded byalias_action), so the block normalizes through this map before delegating torestricted?. Thealias_actiondeclarations inability_aliases!mirror this and cover the rest of the CanCanCan API (e.g.cannot?). Keeping both in sync is intentional — do not remove either. { cards: :read, download: :read, favorite: :read, copy: :create, delete: :destroy, edit: :update, email: :export, re_run: :update }.freeze
Instance Attribute Summary collapse
-
#app_keys ⇒ Object
readonly
Returns the value of attribute app_keys.
-
#application ⇒ Object
readonly
Returns the value of attribute application.
-
#user ⇒ Object
readonly
Returns the value of attribute user.
Instance Method Summary collapse
- #empty? ⇒ Boolean
-
#initialize(user, application: nil, app_keys: []) ⇒ UserRestrictions
constructor
A new instance of UserRestrictions.
-
#restricted?(action, resource) ⇒ Boolean
Returns true if the given action is restricted for the resource.
-
#restricted_resource_names(operations: READ_OPERATIONS) ⇒ Object
Names of the resources restricted for any of the given operations.
-
#restrictions ⇒ Object
Restrictions hash for the resolved application, keyed by resource name.
Constructor Details
#initialize(user, application: nil, app_keys: []) ⇒ UserRestrictions
Returns a new instance of UserRestrictions.
87 88 89 90 91 92 93 94 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 87 def initialize(user, application: nil, app_keys: []) @user = user @application = application @app_keys = Array(app_keys) ability_aliases! end |
Instance Attribute Details
#app_keys ⇒ Object (readonly)
Returns the value of attribute app_keys.
85 86 87 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 85 def app_keys @app_keys end |
#application ⇒ Object (readonly)
Returns the value of attribute application.
85 86 87 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 85 def application @application end |
#user ⇒ Object (readonly)
Returns the value of attribute user.
85 86 87 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 85 def user @user end |
Instance Method Details
#empty? ⇒ Boolean
103 104 105 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 103 def empty? restrictions.blank? end |
#restricted?(action, resource) ⇒ Boolean
Returns true if the given action is restricted for the resource. action: CanCanCan-style (:read, :create, ...); resource: String, Class, or an object responding to :klass (e.g. HasReports::Resource).
110 111 112 113 114 115 116 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 110 def restricted?(action, resource) resource_info = find_resource_info(resource) return false if resource_info.blank? operations = Array(resource_info["restriction_operations"]).map(&:to_s) (normalize_operations(action) & operations).any? end |
#restricted_resource_names(operations: READ_OPERATIONS) ⇒ Object
Names of the resources restricted for any of the given operations.
119 120 121 122 123 124 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 119 def restricted_resource_names(operations: READ_OPERATIONS) ops = Array(operations).map(&:to_s) restrictions.select do |_name, info| info.is_a?(Hash) && (Array(info["restriction_operations"]).map(&:to_s) & ops).any? end.keys end |
#restrictions ⇒ Object
Restrictions hash for the resolved application, keyed by resource name.
97 98 99 100 101 |
# File 'lib/has_helpers/utils/user_restrictions.rb', line 97 def restrictions return @restrictions if defined?(@restrictions) @restrictions = restrictions_for_app end |