effective_roles 1.5.1 → 2.0.0
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.
- checksums.yaml +5 -5
- data/MIT-LICENSE +1 -1
- data/README.md +12 -13
- data/app/models/concerns/acts_as_role_restricted.rb +35 -13
- data/config/effective_roles.rb +8 -25
- data/lib/effective_roles.rb +53 -31
- data/lib/effective_roles/engine.rb +11 -1
- data/lib/effective_roles/set_current_user.rb +15 -0
- data/lib/effective_roles/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: c2e79ad753b38bbae083f785fe11328f944bdd41c2470751c9ab0e34249f35cc
|
4
|
+
data.tar.gz: 5846cd1d6ae353411d97e89b73e0fb97582a27a5a00a8272e2d3391a7a924287
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57c6dcaa1b1454f20f6ef6f813d9eb25fee44921cdec96b22c37e171ee8d8d52617d009fbc392847914079018c35f962b7579eb61fb99b89dbc51042f3c1fedb
|
7
|
+
data.tar.gz: 5bb3f94bce4141aa78a04968e1652824386c2dd2d9c0d1ef4af9d7db5087afdb4e084afaec10d97ac371a8a5ffb63c85002f4d1e9c7133a98763fc1cc412d0c4
|
data/MIT-LICENSE
CHANGED
data/README.md
CHANGED
@@ -41,7 +41,8 @@ Add the mixin to an existing model:
|
|
41
41
|
|
42
42
|
```ruby
|
43
43
|
class Post
|
44
|
-
acts_as_role_restricted
|
44
|
+
acts_as_role_restricted # Singular role, use radio buttons
|
45
|
+
acts_as_role_restricted multiple: true # Multiple roles. use check boxes
|
45
46
|
end
|
46
47
|
```
|
47
48
|
|
@@ -153,19 +154,15 @@ See the initializers/effective_roles.rb for more information.
|
|
153
154
|
}
|
154
155
|
```
|
155
156
|
|
156
|
-
When
|
157
|
+
When using assignable roles, you must assign the acts_as_role_restricted resource a `current_user` when saving changes to the roles or roles mask:
|
157
158
|
|
158
|
-
|
159
|
+
You can do this in one of three ways:
|
159
160
|
|
160
|
-
|
161
|
+
1. Setting resource.current_user = current_user in your controller directly.
|
162
|
+
2. Add `before_action :set_effective_roles_current_user` to your ApplicationController
|
163
|
+
3. Using `Effective::CrudController` to do this automatically.
|
161
164
|
|
162
|
-
|
163
|
-
before_filter :only => [:create, :update] do
|
164
|
-
if params[:user] && params[:user][:roles]
|
165
|
-
params[:user][:roles] = params[:user][:roles] & EffectiveRoles.assignable_roles_for(current_user, User.new()).map(&:to_s)
|
166
|
-
end
|
167
|
-
end
|
168
|
-
```
|
165
|
+
This restriction is only applied when running within the rails server. Not on rails console or db:seeds.
|
169
166
|
|
170
167
|
## Form Helper
|
171
168
|
|
@@ -173,6 +170,8 @@ If you pass current_user (or any acts_as_role_restricted object) into these help
|
|
173
170
|
|
174
171
|
### effective_form_with
|
175
172
|
|
173
|
+
Depending on your `acts_as_role_restricted multiple: ` value:
|
174
|
+
|
176
175
|
```ruby
|
177
176
|
effective_form_with(model: @user) do |f|
|
178
177
|
= f.checks :roles, EffectiveRoles.roles_collection(f.object, current_user)
|
@@ -187,12 +186,12 @@ effective_form_with(model: @user) do |f|
|
|
187
186
|
|
188
187
|
```ruby
|
189
188
|
simple_form_for @user do |f|
|
190
|
-
= f.input :roles, collection: EffectiveRoles.roles_collection(f.object), as: :check_boxes
|
189
|
+
= f.input :roles, collection: EffectiveRoles.roles_collection(f.object, current_user), as: :check_boxes
|
191
190
|
```
|
192
191
|
|
193
192
|
```ruby
|
194
193
|
simple_form_for @user do |f|
|
195
|
-
= f.input :roles, collection: EffectiveRoles.roles_collection(f.object, current_user), as: :
|
194
|
+
= f.input :roles, collection: EffectiveRoles.roles_collection(f.object, current_user), as: :radio_buttons
|
196
195
|
```
|
197
196
|
|
198
197
|
### Strong Parameters
|
@@ -6,25 +6,48 @@
|
|
6
6
|
#
|
7
7
|
# Mark your model with 'acts_as_role_restricted'
|
8
8
|
#
|
9
|
-
# and create the migration
|
9
|
+
# and create the migration to add the following field:
|
10
10
|
#
|
11
|
-
#
|
12
|
-
# roles_mask :integer, :default => 0
|
13
|
-
# end
|
11
|
+
# roles_mask :integer
|
14
12
|
#
|
15
13
|
|
16
14
|
module ActsAsRoleRestricted
|
17
15
|
extend ActiveSupport::Concern
|
18
16
|
|
19
17
|
module ActiveRecord
|
20
|
-
def acts_as_role_restricted(
|
21
|
-
@acts_as_role_restricted_opts =
|
18
|
+
def acts_as_role_restricted(multiple: false)
|
19
|
+
@acts_as_role_restricted_opts = { multiple: multiple }
|
22
20
|
include ::ActsAsRoleRestricted
|
23
21
|
end
|
24
22
|
end
|
25
23
|
|
26
24
|
included do
|
27
|
-
|
25
|
+
attr_accessor(:current_user) unless respond_to?(:current_user)
|
26
|
+
|
27
|
+
acts_as_role_restricted_options = @acts_as_role_restricted_opts.dup
|
28
|
+
self.send(:define_method, :acts_as_role_restricted_options) { acts_as_role_restricted_options }
|
29
|
+
|
30
|
+
validates :roles_mask, numericality: true, allow_nil: true
|
31
|
+
|
32
|
+
validate(if: -> { changes.include?(:roles_mask) }) do
|
33
|
+
user = current_user || EffectiveRoles.current_user || (EffectiveLogging.current_user if defined?(EffectiveLogging))
|
34
|
+
|
35
|
+
if user.blank? && EffectiveRoles.assignable_roles.present? && defined?(Rails::Server)
|
36
|
+
self.errors.add(:roles, 'current_user must be present when assigning roles')
|
37
|
+
end
|
38
|
+
|
39
|
+
roles_was = EffectiveRoles.roles_for(changes[:roles_mask].first)
|
40
|
+
changed = (roles + roles_was) - (roles & roles_was) # XOR
|
41
|
+
|
42
|
+
assignable = EffectiveRoles.assignable_roles_collection(self, user) # Returns all roles when user is blank
|
43
|
+
unauthorized = changed - assignable
|
44
|
+
|
45
|
+
authorized = roles.dup
|
46
|
+
unauthorized.each { |role| authorized.include?(role) ? authorized.delete(role) : authorized.push(role) }
|
47
|
+
|
48
|
+
self.roles_mask = EffectiveRoles.roles_mask_for(authorized)
|
49
|
+
end
|
50
|
+
|
28
51
|
end
|
29
52
|
|
30
53
|
module ClassMethods
|
@@ -45,16 +68,15 @@ module ActsAsRoleRestricted
|
|
45
68
|
|
46
69
|
def with_role_sql(*roles)
|
47
70
|
roles = roles.flatten.compact
|
48
|
-
roles = roles.first.
|
49
|
-
|
71
|
+
roles = roles.first.roles if roles.length == 1 && roles.first.respond_to?(:roles)
|
50
72
|
roles = (roles.map { |role| role.to_sym } & EffectiveRoles.roles)
|
73
|
+
|
51
74
|
roles.map { |role| "(#{self.table_name}.roles_mask & %d > 0)" % 2**EffectiveRoles.roles.index(role) }.join(' OR ')
|
52
75
|
end
|
53
76
|
|
54
77
|
def without_role(*roles)
|
55
78
|
roles = roles.flatten.compact
|
56
|
-
roles = roles.first.
|
57
|
-
|
79
|
+
roles = roles.first.roles if roles.length == 1 && roles.first.respond_to?(:roles)
|
58
80
|
roles = (roles.map { |role| role.to_sym } & EffectiveRoles.roles)
|
59
81
|
|
60
82
|
where(
|
@@ -64,11 +86,11 @@ module ActsAsRoleRestricted
|
|
64
86
|
end
|
65
87
|
|
66
88
|
def roles=(roles)
|
67
|
-
self.roles_mask =
|
89
|
+
self.roles_mask = EffectiveRoles.roles_mask_for(roles)
|
68
90
|
end
|
69
91
|
|
70
92
|
def roles
|
71
|
-
EffectiveRoles.
|
93
|
+
EffectiveRoles.roles_for(roles_mask)
|
72
94
|
end
|
73
95
|
|
74
96
|
# if user.is? :admin
|
data/config/effective_roles.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
EffectiveRoles.setup do |config|
|
2
|
-
config.roles = [:superadmin, :admin, :member] # Only add to the end of this array.
|
2
|
+
config.roles = [:superadmin, :admin, :member] # Only add to the end of this array. Never prepend roles.
|
3
3
|
|
4
4
|
# config.role_descriptions
|
5
5
|
# ========================
|
@@ -34,6 +34,13 @@ EffectiveRoles.setup do |config|
|
|
34
34
|
# When current_user is passed into a form helper function (see README.md)
|
35
35
|
# this setting determines which roles that current_user may assign
|
36
36
|
#
|
37
|
+
# you must assign current_user to all acts_as_role_restricted resources when saving changes to the roles or roles_mask.
|
38
|
+
#
|
39
|
+
# You should probably do this in your controller by one of the following methods:
|
40
|
+
# 1.) Setting resource.current_user = current_user directly.
|
41
|
+
# 2.) Using before_action :set_effective_roles_current_user
|
42
|
+
# 3.) Using Effective::CrudController does this automatically.
|
43
|
+
#
|
37
44
|
# Use this Hash syntax if you want different permissions depending on the resource being editted
|
38
45
|
#
|
39
46
|
# config.assignable_roles = {
|
@@ -56,30 +63,6 @@ EffectiveRoles.setup do |config|
|
|
56
63
|
# :member => [] # Members may not assign any roles
|
57
64
|
# }
|
58
65
|
|
59
|
-
# config.disabled_roles
|
60
|
-
# Which roles should be displayed as disabled
|
61
|
-
# =========================
|
62
|
-
# Sometimes you don't want a role to be assignable (see README.md)
|
63
|
-
# So that you can overload it yourself and assingn the role programatically
|
64
|
-
#
|
65
|
-
# Use this Hash syntax if you want different permissions depending on the resource being editted
|
66
|
-
#
|
67
|
-
# config.disabled_roles = {
|
68
|
-
# 'User' => [:member] # When editing a User object, will be unable to assign the member role
|
69
|
-
# 'Page' => [:superadmin, :admin] # When editing a Page object, will be unable to assign superadmin, admin role
|
70
|
-
# }
|
71
|
-
#
|
72
|
-
# Or just keep it simple, and use this Array syntax of permissions for every resource
|
73
|
-
#
|
74
|
-
# config.disabled_roles = [:member]
|
75
|
-
#
|
76
|
-
# or
|
77
|
-
#
|
78
|
-
# config.disabled_roles = {
|
79
|
-
# 'User' => [:member]
|
80
|
-
# }
|
81
|
-
|
82
|
-
|
83
66
|
# Authorization Method
|
84
67
|
#
|
85
68
|
# This doesn't have anything to do with the roles themselves.
|
data/lib/effective_roles.rb
CHANGED
@@ -4,12 +4,9 @@ require 'effective_roles/version'
|
|
4
4
|
module EffectiveRoles
|
5
5
|
mattr_accessor :roles
|
6
6
|
mattr_accessor :role_descriptions
|
7
|
-
|
8
|
-
mattr_accessor :layout
|
9
|
-
|
10
7
|
mattr_accessor :assignable_roles
|
11
|
-
mattr_accessor :disabled_roles
|
12
8
|
|
9
|
+
mattr_accessor :layout
|
13
10
|
mattr_accessor :authorization_method
|
14
11
|
|
15
12
|
def self.setup
|
@@ -37,6 +34,15 @@ module EffectiveRoles
|
|
37
34
|
raise Effective::AccessDenied unless authorized?(controller, action, resource)
|
38
35
|
end
|
39
36
|
|
37
|
+
# This is set by the "set_effective_roles_current_user" before_filter.
|
38
|
+
def self.current_user=(user)
|
39
|
+
@effective_roles_current_user = user
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.current_user
|
43
|
+
@effective_roles_current_user
|
44
|
+
end
|
45
|
+
|
40
46
|
# This method converts whatever is given into its roles
|
41
47
|
# Pass an object, Integer, or Symbol to find corresponding role
|
42
48
|
def self.roles_for(obj)
|
@@ -48,38 +54,67 @@ module EffectiveRoles
|
|
48
54
|
[roles.find { |role| role == obj }].compact
|
49
55
|
elsif obj.kind_of?(String)
|
50
56
|
[roles.find { |role| role == obj.to_sym }].compact
|
57
|
+
elsif obj.kind_of?(Array)
|
58
|
+
obj.map { |obj| roles_for(obj) }.flatten.compact
|
51
59
|
elsif obj.nil?
|
52
60
|
[]
|
53
61
|
else
|
54
|
-
raise 'unsupported object passed to EffectiveRoles.roles_for method.
|
62
|
+
raise 'unsupported object passed to EffectiveRoles.roles_for method. Expecting an acts_as_role_restricted object or a roles_mask integer'
|
55
63
|
end
|
56
64
|
end
|
57
65
|
|
58
66
|
# EffectiveRoles.roles_mask_for(:admin, :member)
|
59
67
|
def self.roles_mask_for(*roles)
|
60
|
-
(
|
68
|
+
roles_for(roles).map { |r| 2**EffectiveRoles.roles.index(r) }.sum
|
61
69
|
end
|
62
70
|
|
63
|
-
def self.roles_collection(
|
64
|
-
|
71
|
+
def self.roles_collection(resource, current_user = nil, only: nil, except: nil, multiple: nil)
|
72
|
+
if assignable_roles.present?
|
73
|
+
raise('expected object to respond to is_role_restricted?') unless resource.respond_to?(:is_role_restricted?)
|
74
|
+
raise('expected current_user to respond to is_role_restricted?') if current_user && !current_user.respond_to?(:is_role_restricted?)
|
75
|
+
end
|
76
|
+
|
77
|
+
only = Array(only).compact
|
78
|
+
except = Array(except).compact
|
79
|
+
multiple = resource.acts_as_role_restricted_options[:multiple] if multiple.nil?
|
80
|
+
assignable = assignable_roles_collection(resource, current_user, multiple: multiple)
|
81
|
+
|
82
|
+
roles.map do |role|
|
83
|
+
next if only.present? && !only.include?(role)
|
84
|
+
next if except.present? && except.include?(role)
|
85
|
+
|
65
86
|
[
|
66
|
-
"#{role}<p class='help-block text-muted'>#{role_description(role,
|
87
|
+
"#{role}<p class='help-block text-muted'>#{role_description(role, resource)}</p>".html_safe,
|
67
88
|
role,
|
68
|
-
({:disabled => :disabled}
|
89
|
+
({:disabled => :disabled} unless assignable.include?(role))
|
69
90
|
]
|
70
|
-
end
|
91
|
+
end.compact
|
71
92
|
end
|
72
93
|
|
73
|
-
def self.
|
74
|
-
raise 'EffectiveRoles config.assignable_roles_for must be a Hash, Array or nil' unless [Hash, Array, NilClass].include?(assignable_roles.class)
|
75
|
-
|
76
|
-
return assignable_roles if assignable_roles.kind_of?(Array)
|
94
|
+
def self.assignable_roles_collection(resource, current_user = nil, multiple: nil)
|
77
95
|
return roles if assignable_roles.nil?
|
78
|
-
return roles if !user.respond_to?(:is_role_restricted?) # All roles, if the user (or object) is not role_resticted
|
79
96
|
|
80
|
-
|
97
|
+
raise 'EffectiveRoles config.assignable_roles_for must be a Hash, Array or nil' unless [Hash, Array].include?(assignable_roles.class)
|
98
|
+
raise('expected resource to respond to is_role_restricted?') unless resource.respond_to?(:is_role_restricted?)
|
99
|
+
raise('expected current_user to respond to is_role_restricted?') if current_user && !current_user.respond_to?(:is_role_restricted?)
|
100
|
+
|
101
|
+
multiple = resource.acts_as_role_restricted_options[:multiple] if multiple.nil?
|
102
|
+
current_user ||= (EffectiveRoles.current_user || (EffectiveLogging.current_user if defined?(EffectiveLogging)))
|
103
|
+
|
104
|
+
assignable = if assignable_roles.kind_of?(Array)
|
105
|
+
assignable_roles
|
106
|
+
elsif current_user.present?
|
107
|
+
current_roles = assignable_roles[resource.try(:class).to_s] || assignable_roles || {}
|
108
|
+
current_user.roles.map { |role| current_roles[role] }.flatten.compact.uniq
|
109
|
+
else
|
110
|
+
assignable_roles[resource.try(:class).to_s] || []
|
111
|
+
end
|
112
|
+
|
113
|
+
# Check boxes
|
114
|
+
return assignable if multiple
|
81
115
|
|
82
|
-
|
116
|
+
# Radios
|
117
|
+
(resource.roles - assignable).present? ? [] : assignable
|
83
118
|
end
|
84
119
|
|
85
120
|
# This is used by the effective_roles_summary_table helper method
|
@@ -142,19 +177,6 @@ module EffectiveRoles
|
|
142
177
|
(role_descriptions[obj.try(:class).to_s] || {})[role] || role_descriptions[role] || ''
|
143
178
|
end
|
144
179
|
|
145
|
-
def self.disabled_roles_for(obj)
|
146
|
-
raise 'EffectiveRoles config.disabled_roles must be a Hash, Array or nil' unless [Hash, Array, NilClass].include?(disabled_roles.class)
|
147
|
-
|
148
|
-
case disabled_roles
|
149
|
-
when Array
|
150
|
-
disabled_roles
|
151
|
-
when Hash
|
152
|
-
Array(disabled_roles[obj.try(:class).to_s])
|
153
|
-
else
|
154
|
-
[]
|
155
|
-
end
|
156
|
-
end
|
157
|
-
|
158
180
|
def self._authorization_level(controller, role, resource, auth_method)
|
159
181
|
resource = (resource.new() rescue resource) if resource.kind_of?(ActiveRecord::Base)
|
160
182
|
|
@@ -2,7 +2,7 @@ module EffectiveRoles
|
|
2
2
|
class Engine < ::Rails::Engine
|
3
3
|
engine_name 'effective_roles'
|
4
4
|
|
5
|
-
config.autoload_paths += Dir["#{config.root}/app/models/concerns"]
|
5
|
+
config.autoload_paths += Dir["#{config.root}/app/models/concerns", "#{config.root}/lib/"]
|
6
6
|
|
7
7
|
# Include acts_as_addressable concern and allow any ActiveRecord object to call it
|
8
8
|
initializer 'effective_roles.active_record' do |app|
|
@@ -11,6 +11,16 @@ module EffectiveRoles
|
|
11
11
|
end
|
12
12
|
end
|
13
13
|
|
14
|
+
# Register the log_page_views concern so that it can be called in ActionController or elsewhere
|
15
|
+
initializer 'effective_logging.log_changes_action_controller' do |app|
|
16
|
+
Rails.application.config.to_prepare do
|
17
|
+
ActiveSupport.on_load :action_controller do
|
18
|
+
require 'effective_roles/set_current_user'
|
19
|
+
ActionController::Base.include(EffectiveRoles::SetCurrentUser::ActionController)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
14
24
|
# Set up our default configuration options.
|
15
25
|
initializer "effective_roles.defaults", :before => :load_config_initializers do |app|
|
16
26
|
eval File.read("#{config.root}/config/effective_roles.rb")
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module EffectiveRoles
|
2
|
+
module SetCurrentUser
|
3
|
+
module ActionController
|
4
|
+
|
5
|
+
# Add me to your ApplicationController
|
6
|
+
# before_action :set_effective_roles_current_user
|
7
|
+
|
8
|
+
def set_effective_roles_current_user
|
9
|
+
EffectiveRoles.current_user = current_user
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: effective_roles
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Code and Effect
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2019-05-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -46,6 +46,7 @@ files:
|
|
46
46
|
- config/routes.rb
|
47
47
|
- lib/effective_roles.rb
|
48
48
|
- lib/effective_roles/engine.rb
|
49
|
+
- lib/effective_roles/set_current_user.rb
|
49
50
|
- lib/effective_roles/version.rb
|
50
51
|
- lib/generators/effective_roles/install_generator.rb
|
51
52
|
homepage: https://github.com/code-and-effect/effective_roles
|
@@ -67,8 +68,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
67
68
|
- !ruby/object:Gem::Version
|
68
69
|
version: '0'
|
69
70
|
requirements: []
|
70
|
-
|
71
|
-
rubygems_version: 2.4.5.1
|
71
|
+
rubygems_version: 3.0.3
|
72
72
|
signing_key:
|
73
73
|
specification_version: 4
|
74
74
|
summary: Assign multiple roles to any User or other ActiveRecord object. Select only
|