acl9 2.1.0 → 3.2.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/.gitignore +3 -0
- data/.ruby-version +1 -1
- data/.travis.yml +27 -11
- data/Appraisals +13 -6
- data/Gemfile +0 -2
- data/Gemfile.lock +125 -112
- data/README.md +11 -4
- data/Rakefile +0 -2
- data/acl9.gemspec +1 -3
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/rails_5.0.gemfile +10 -0
- data/gemfiles/rails_5.1.gemfile +10 -0
- data/gemfiles/{rails_4.0.gemfile → rails_5.2.gemfile} +2 -4
- data/gemfiles/{rails_4.1.gemfile → rails_6.0.gemfile} +2 -4
- data/gemfiles/{rails_4.2.gemfile → rails_6.1.gemfile} +2 -4
- data/lib/acl9.rb +40 -0
- data/lib/acl9/controller_extensions.rb +1 -1
- data/lib/acl9/controller_extensions/dsl_base.rb +8 -7
- data/lib/acl9/controller_extensions/generators.rb +4 -35
- data/lib/acl9/model_extensions.rb +3 -3
- data/lib/acl9/model_extensions/for_subject.rb +52 -31
- data/lib/acl9/version.rb +1 -1
- data/lib/generators/acl9/setup/setup_generator.rb +10 -3
- data/lib/generators/acl9/setup/templates/create_role_tables.rb +10 -1
- data/lib/generators/acl9/setup/templates/role.rb +1 -1
- data/test/controller_extensions/actions_test.rb +1 -1
- data/test/controller_extensions/multiple_role_arguments_test.rb +11 -10
- data/test/controllers/acl_action_override_test.rb +4 -4
- data/test/controllers/acl_helper_method_test.rb +6 -3
- data/test/controllers/acl_ivars_test.rb +2 -2
- data/test/controllers/acl_object_hash_test.rb +1 -1
- data/test/controllers/acl_query_mixin.rb +5 -2
- data/test/controllers/acl_subject_method_test.rb +1 -1
- data/test/controllers/arguments_checking_test.rb +4 -4
- data/test/dummy/app/assets/config/manifest.js +0 -0
- data/test/dummy/app/controllers/acl_action_override.rb +5 -5
- data/test/dummy/app/controllers/acl_boolean_method.rb +6 -6
- data/test/dummy/app/controllers/acl_ivars.rb +3 -3
- data/test/dummy/app/controllers/acl_query_method_named.rb +2 -0
- data/test/dummy/app/controllers/application_controller.rb +6 -0
- data/test/dummy/app/controllers/empty_controller.rb +1 -1
- data/test/dummy/app/models/string_object_role.rb +3 -0
- data/test/dummy/app/models/string_user.rb +3 -0
- data/test/dummy/app/models/uuid.rb +1 -1
- data/test/dummy/config/environments/test.rb +2 -2
- data/test/dummy/config/routes.rb +12 -1
- data/test/dummy/db/migrate/20141117132218_create_tables.rb +68 -18
- data/test/models/roles_test.rb +13 -1
- data/test/test_helper.rb +31 -28
- metadata +26 -29
- data/test/dummy/config/environments/production.rb +0 -78
data/lib/acl9.rb
CHANGED
@@ -22,6 +22,10 @@ module Acl9
|
|
22
22
|
send "#{k}=", v
|
23
23
|
end
|
24
24
|
end
|
25
|
+
|
26
|
+
def merge! h
|
27
|
+
h.each { |k,v| self[k.to_sym] = v }
|
28
|
+
end
|
25
29
|
end
|
26
30
|
|
27
31
|
@@config = Config.new( *CONFIG.values_at(*Config.members))
|
@@ -31,6 +35,42 @@ module Acl9
|
|
31
35
|
def self.configure
|
32
36
|
yield config
|
33
37
|
end
|
38
|
+
|
39
|
+
class ArgumentError < ArgumentError; end
|
40
|
+
class RuntimeError < RuntimeError; end
|
41
|
+
class NilObjectError < RuntimeError; end
|
42
|
+
|
43
|
+
##
|
44
|
+
# This exception is raised whenever ACL block finds that the current user
|
45
|
+
# is not authorized for the controller action he wants to execute.
|
46
|
+
# @example How to catch this exception in ApplicationController
|
47
|
+
# class ApplicationController < ActionController::Base
|
48
|
+
# rescue_from 'Acl9::AccessDenied', :with => :access_denied
|
49
|
+
#
|
50
|
+
# # ...other stuff...
|
51
|
+
# private
|
52
|
+
#
|
53
|
+
# def access_denied
|
54
|
+
# if current_user
|
55
|
+
# # It's presumed you have a template with words of pity and regret
|
56
|
+
# # for unhappy user who is not authorized to do what he wanted
|
57
|
+
# render :template => 'home/access_denied'
|
58
|
+
# else
|
59
|
+
# # In this case user has not even logged in. Might be OK after login.
|
60
|
+
# flash[:notice] = 'Access denied. Try to log in first.'
|
61
|
+
# redirect_to login_path
|
62
|
+
# end
|
63
|
+
# end
|
64
|
+
# end
|
65
|
+
#
|
66
|
+
class AccessDenied < RuntimeError; end
|
67
|
+
|
68
|
+
##
|
69
|
+
# This exception is raised when acl9 has generated invalid code for the
|
70
|
+
# filtering method or block. Should never happen, and it's a bug when it
|
71
|
+
# happens.
|
72
|
+
class FilterSyntaxError < ArgumentError; end
|
73
|
+
|
34
74
|
end
|
35
75
|
|
36
76
|
ActiveRecord::Base.send(:include, Acl9::ModelExtensions)
|
@@ -1,4 +1,4 @@
|
|
1
|
-
|
1
|
+
require_relative "../prepositions"
|
2
2
|
|
3
3
|
module Acl9
|
4
4
|
module Dsl
|
@@ -12,6 +12,7 @@ module Acl9
|
|
12
12
|
@allows = []
|
13
13
|
@denys = []
|
14
14
|
@original_args = args
|
15
|
+
@action_clause = nil
|
15
16
|
end
|
16
17
|
|
17
18
|
def acl_block!(&acl_block)
|
@@ -108,7 +109,7 @@ module Acl9
|
|
108
109
|
|
109
110
|
_set_action_clause( _retrieve_only(options), options.delete(:except))
|
110
111
|
|
111
|
-
|
112
|
+
object_s = _role_object_s(options)
|
112
113
|
|
113
114
|
role_checks = args.map do |who|
|
114
115
|
case who
|
@@ -116,7 +117,7 @@ module Acl9
|
|
116
117
|
when logged_in then "!#{_subject_ref}.nil?"
|
117
118
|
when all then "true"
|
118
119
|
else
|
119
|
-
"!#{_subject_ref}.nil? && #{_subject_ref}.has_role?('#{who}'
|
120
|
+
"!#{_subject_ref}.nil? && #{_subject_ref}.has_role?('#{who}'#{object_s})"
|
120
121
|
end
|
121
122
|
end
|
122
123
|
|
@@ -179,13 +180,13 @@ module Acl9
|
|
179
180
|
end
|
180
181
|
end
|
181
182
|
|
182
|
-
def
|
183
|
+
def _role_object_s(options)
|
183
184
|
object = _by_preposition options
|
184
185
|
|
185
186
|
case object
|
186
|
-
when Class then object
|
187
|
-
when Symbol then _object_ref object
|
188
|
-
when nil then "
|
187
|
+
when Class then ", #{object}"
|
188
|
+
when Symbol then ", #{_object_ref object}"
|
189
|
+
when nil then ""
|
189
190
|
else
|
190
191
|
raise ArgumentError, "object specified by preposition can only be a Class or a Symbol"
|
191
192
|
end
|
@@ -1,37 +1,6 @@
|
|
1
|
-
|
1
|
+
require_relative "dsl_base"
|
2
2
|
|
3
3
|
module Acl9
|
4
|
-
##
|
5
|
-
# This exception is raised whenever ACL block finds that the current user
|
6
|
-
# is not authorized for the controller action he wants to execute.
|
7
|
-
# @example How to catch this exception in ApplicationController
|
8
|
-
# class ApplicationController < ActionController::Base
|
9
|
-
# rescue_from 'Acl9::AccessDenied', :with => :access_denied
|
10
|
-
#
|
11
|
-
# # ...other stuff...
|
12
|
-
# private
|
13
|
-
#
|
14
|
-
# def access_denied
|
15
|
-
# if current_user
|
16
|
-
# # It's presumed you have a template with words of pity and regret
|
17
|
-
# # for unhappy user who is not authorized to do what he wanted
|
18
|
-
# render :template => 'home/access_denied'
|
19
|
-
# else
|
20
|
-
# # In this case user has not even logged in. Might be OK after login.
|
21
|
-
# flash[:notice] = 'Access denied. Try to log in first.'
|
22
|
-
# redirect_to login_path
|
23
|
-
# end
|
24
|
-
# end
|
25
|
-
# end
|
26
|
-
#
|
27
|
-
class AccessDenied < StandardError; end
|
28
|
-
|
29
|
-
##
|
30
|
-
# This exception is raised when acl9 has generated invalid code for the
|
31
|
-
# filtering method or block. Should never happen, and it's a bug when it
|
32
|
-
# happens.
|
33
|
-
class FilterSyntaxError < StandardError; end
|
34
|
-
|
35
4
|
module Dsl
|
36
5
|
module Generators
|
37
6
|
class BaseGenerator < Acl9::Dsl::Base
|
@@ -93,7 +62,7 @@ module Acl9
|
|
93
62
|
def install_on(controller_class, options)
|
94
63
|
super
|
95
64
|
|
96
|
-
controller_class.send(:
|
65
|
+
controller_class.send(:before_action, options, &self.to_proc)
|
97
66
|
end
|
98
67
|
|
99
68
|
def to_proc
|
@@ -124,7 +93,7 @@ module Acl9
|
|
124
93
|
def install_on(controller_class, options)
|
125
94
|
super
|
126
95
|
_add_method(controller_class)
|
127
|
-
controller_class.send(:
|
96
|
+
controller_class.send(:before_action, @method_name, options)
|
128
97
|
end
|
129
98
|
|
130
99
|
protected
|
@@ -171,7 +140,7 @@ module Acl9
|
|
171
140
|
raise ArgumentError, "call #{@method_name} with 0, 1 or 2 arguments"
|
172
141
|
end
|
173
142
|
|
174
|
-
action_name = args.
|
143
|
+
self.action_name = args.first.to_s if args.present?
|
175
144
|
|
176
145
|
return #{allowance_expression}
|
177
146
|
end
|
@@ -1,5 +1,5 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require_relative "model_extensions/for_subject"
|
2
|
+
require_relative "model_extensions/for_object"
|
3
3
|
|
4
4
|
module Acl9
|
5
5
|
module ModelExtensions #:nodoc:
|
@@ -129,7 +129,7 @@ module Acl9
|
|
129
129
|
:class_name => subject,
|
130
130
|
:join_table => join_table
|
131
131
|
|
132
|
-
belongs_to :authorizable, :
|
132
|
+
belongs_to :authorizable, polymorphic: true, optional: true
|
133
133
|
end
|
134
134
|
end
|
135
135
|
end
|
@@ -1,10 +1,16 @@
|
|
1
|
-
|
1
|
+
require_relative "../prepositions"
|
2
2
|
|
3
3
|
module Acl9
|
4
4
|
module ModelExtensions
|
5
5
|
module ForSubject
|
6
6
|
include Prepositions
|
7
7
|
|
8
|
+
DEFAULT = Class.new do
|
9
|
+
def default?
|
10
|
+
true
|
11
|
+
end
|
12
|
+
end.new.freeze
|
13
|
+
|
8
14
|
##
|
9
15
|
# Role check.
|
10
16
|
#
|
@@ -38,16 +44,17 @@ module Acl9
|
|
38
44
|
# @param [Object] object Object to query a role on
|
39
45
|
#
|
40
46
|
# @see Acl9::ModelExtensions::Object#accepts_role?
|
41
|
-
def has_role?(role_name, object =
|
47
|
+
def has_role?(role_name, object = default)
|
48
|
+
check! object
|
42
49
|
role_name = normalize role_name
|
43
50
|
object = _by_preposition object
|
44
51
|
|
45
|
-
!! if object
|
46
|
-
|
47
|
-
|
52
|
+
!! if object == default && !::Acl9.config[:protect_global_roles]
|
53
|
+
_role_objects.find_by_name(role_name.to_s) ||
|
54
|
+
_role_objects.member?(get_role(role_name, object))
|
48
55
|
else
|
49
56
|
role = get_role(role_name, object)
|
50
|
-
role &&
|
57
|
+
role && _role_objects.exists?(role.id)
|
51
58
|
end
|
52
59
|
end
|
53
60
|
|
@@ -57,7 +64,8 @@ module Acl9
|
|
57
64
|
# @param [Symbol,String] role_name Role name
|
58
65
|
# @param [Object] object Object to add a role for
|
59
66
|
# @see Acl9::ModelExtensions::Object#accepts_role!
|
60
|
-
def has_role!(role_name, object =
|
67
|
+
def has_role!(role_name, object = default)
|
68
|
+
check! object
|
61
69
|
role_name = normalize role_name
|
62
70
|
object = _by_preposition object
|
63
71
|
|
@@ -65,15 +73,15 @@ module Acl9
|
|
65
73
|
|
66
74
|
if role.nil?
|
67
75
|
role_attrs = case object
|
68
|
-
when Class
|
69
|
-
when
|
70
|
-
else
|
71
|
-
end.merge(
|
76
|
+
when Class then { :authorizable_type => object.to_s }
|
77
|
+
when default then {}
|
78
|
+
else { :authorizable => object }
|
79
|
+
end.merge({ :name => role_name.to_s })
|
72
80
|
|
73
|
-
role =
|
81
|
+
role = _auth_role_class.create(role_attrs)
|
74
82
|
end
|
75
83
|
|
76
|
-
|
84
|
+
_role_objects << role if role && !_role_objects.exists?(role.id)
|
77
85
|
end
|
78
86
|
|
79
87
|
##
|
@@ -82,7 +90,8 @@ module Acl9
|
|
82
90
|
# @param [Symbol,String] role_name Role name
|
83
91
|
# @param [Object] object Object to remove a role on
|
84
92
|
# @see Acl9::ModelExtensions::Object#accepts_no_role!
|
85
|
-
def has_no_role!(role_name, object =
|
93
|
+
def has_no_role!(role_name, object = default)
|
94
|
+
check! object
|
86
95
|
role_name = normalize role_name
|
87
96
|
object = _by_preposition object
|
88
97
|
delete_role(get_role(role_name, object))
|
@@ -95,7 +104,8 @@ module Acl9
|
|
95
104
|
# @return [Boolean] Returns true if +self+ has any roles on +object+.
|
96
105
|
# @see Acl9::ModelExtensions::Object#accepts_roles_by?
|
97
106
|
def has_roles_for?(object)
|
98
|
-
|
107
|
+
check! object
|
108
|
+
!!_role_objects.detect(&role_selecting_lambda(object))
|
99
109
|
end
|
100
110
|
|
101
111
|
alias :has_role_for? :has_roles_for?
|
@@ -112,14 +122,16 @@ module Acl9
|
|
112
122
|
#
|
113
123
|
# user.roles_for(product).map(&:name).sort #=> role names in alphabetical order
|
114
124
|
def roles_for(object)
|
115
|
-
|
125
|
+
check! object
|
126
|
+
_role_objects.select(&role_selecting_lambda(object))
|
116
127
|
end
|
117
128
|
|
118
129
|
##
|
119
130
|
# Unassign any roles on +object+ from +self+.
|
120
131
|
#
|
121
|
-
# @param [Object,
|
122
|
-
def has_no_roles_for!(object =
|
132
|
+
# @param [Object,default] object Object to unassign roles for. Empty args means unassign global roles.
|
133
|
+
def has_no_roles_for!(object = default)
|
134
|
+
check! object
|
123
135
|
roles_for(object).each { |role| delete_role(role) }
|
124
136
|
end
|
125
137
|
|
@@ -128,11 +140,11 @@ module Acl9
|
|
128
140
|
def has_no_roles!
|
129
141
|
# for some reason simple
|
130
142
|
#
|
131
|
-
#
|
143
|
+
# roles.each { |role| delete_role(role) }
|
132
144
|
#
|
133
145
|
# doesn't work. seems like a bug in ActiveRecord
|
134
|
-
|
135
|
-
delete_role
|
146
|
+
_role_objects.map(&:id).each do |role_id|
|
147
|
+
delete_role _auth_role_class.find(role_id)
|
136
148
|
end
|
137
149
|
end
|
138
150
|
|
@@ -142,7 +154,7 @@ module Acl9
|
|
142
154
|
case object
|
143
155
|
when Class
|
144
156
|
lambda { |role| role.authorizable_type == object.to_s }
|
145
|
-
when
|
157
|
+
when default
|
146
158
|
lambda { |role| role.authorizable.nil? }
|
147
159
|
else
|
148
160
|
lambda do |role|
|
@@ -152,13 +164,14 @@ module Acl9
|
|
152
164
|
end
|
153
165
|
end
|
154
166
|
|
155
|
-
def get_role(role_name, object)
|
167
|
+
def get_role(role_name, object = default)
|
168
|
+
check! object
|
156
169
|
role_name = normalize role_name
|
157
170
|
|
158
171
|
cond = case object
|
159
172
|
when Class
|
160
173
|
[ 'name = ? and authorizable_type = ? and authorizable_id IS NULL', role_name, object.to_s ]
|
161
|
-
when
|
174
|
+
when default
|
162
175
|
[ 'name = ? and authorizable_type IS NULL and authorizable_id IS NULL', role_name ]
|
163
176
|
else
|
164
177
|
[
|
@@ -167,17 +180,17 @@ module Acl9
|
|
167
180
|
]
|
168
181
|
end
|
169
182
|
|
170
|
-
if
|
171
|
-
|
183
|
+
if _auth_role_class.respond_to?(:where)
|
184
|
+
_auth_role_class.where(cond).first
|
172
185
|
else
|
173
|
-
|
186
|
+
_auth_role_class.find(:first, :conditions => cond)
|
174
187
|
end
|
175
188
|
end
|
176
189
|
|
177
190
|
def delete_role(role)
|
178
191
|
if role
|
179
|
-
if ret =
|
180
|
-
if role.send(
|
192
|
+
if ret = _role_objects.delete(role)
|
193
|
+
if role.send(_auth_subject_class_name.demodulize.tableize).empty?
|
181
194
|
ret &&= role.destroy unless role.respond_to?(:system?) && role.system?
|
182
195
|
end
|
183
196
|
end
|
@@ -189,7 +202,11 @@ module Acl9
|
|
189
202
|
Acl9.config[:normalize_role_names] ? role_name.to_s.underscore.singularize : role_name.to_s
|
190
203
|
end
|
191
204
|
|
192
|
-
|
205
|
+
private
|
206
|
+
|
207
|
+
def check! object
|
208
|
+
raise NilObjectError if object.nil?
|
209
|
+
end
|
193
210
|
|
194
211
|
def _by_preposition object
|
195
212
|
object.is_a?(Hash) ? super : object
|
@@ -204,7 +221,11 @@ module Acl9
|
|
204
221
|
end
|
205
222
|
|
206
223
|
def _role_objects
|
207
|
-
send(
|
224
|
+
send(_auth_role_assoc)
|
225
|
+
end
|
226
|
+
|
227
|
+
def default
|
228
|
+
DEFAULT
|
208
229
|
end
|
209
230
|
end
|
210
231
|
end
|
data/lib/acl9/version.rb
CHANGED
@@ -10,9 +10,8 @@ module Acl9
|
|
10
10
|
argument :arg_role, type: :string, default: 'role', banner: "role"
|
11
11
|
argument :arg_objects, type: :array, default: [], banner: "objects..."
|
12
12
|
|
13
|
-
def
|
14
|
-
|
15
|
-
template "create_role_tables.rb", "db/migrate/#{next_migration_number}_create_#{role_name}_tables.rb"
|
13
|
+
def create_migration_file
|
14
|
+
migration_template "create_role_tables.rb", File.join(db_migrate_path, "create_#{role_name}_tables.rb")
|
16
15
|
end
|
17
16
|
|
18
17
|
def create_models
|
@@ -56,6 +55,14 @@ module Acl9
|
|
56
55
|
role_name.classify
|
57
56
|
end
|
58
57
|
|
58
|
+
def model_base_name
|
59
|
+
r5? ? ApplicationRecord : ActiveRecord::Base
|
60
|
+
end
|
61
|
+
|
62
|
+
def r5?
|
63
|
+
Rails.gem_version >= Gem::Version.new(5)
|
64
|
+
end
|
65
|
+
|
59
66
|
def habtm_table
|
60
67
|
Acl9.config.default_join_table_name || [ subject_name, role_name ].map(&:pluralize).sort.join('_')
|
61
68
|
end
|