effective_roles 1.5.1 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|