acl9 0.12.0 → 2.1.2
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 +7 -0
- data/.gitignore +21 -0
- data/.ruby-version +1 -0
- data/.travis.yml +22 -0
- data/Appraisals +11 -0
- data/CHANGELOG.md +114 -0
- data/CONTRIBUTING.md +62 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +141 -0
- data/LICENSE +9 -0
- data/README.md +308 -0
- data/Rakefile +9 -27
- data/acl9.gemspec +29 -0
- data/bin/appraisal +16 -0
- data/bin/bundler +16 -0
- data/bin/cc-tddium-post-worker +16 -0
- data/bin/erubis +16 -0
- data/bin/rackup +16 -0
- data/bin/rails +16 -0
- data/bin/rake +16 -0
- data/bin/sprockets +16 -0
- data/bin/tapout +16 -0
- data/bin/thor +16 -0
- data/bin/tilt +16 -0
- data/bin/yard +16 -0
- data/bin/yardoc +16 -0
- data/bin/yri +16 -0
- data/gemfiles/rails_4.0.gemfile +10 -0
- data/gemfiles/rails_4.1.gemfile +10 -0
- data/gemfiles/rails_4.2.gemfile +10 -0
- data/lib/acl9/controller_extensions/dsl_base.rb +36 -55
- data/lib/acl9/controller_extensions/generators.rb +1 -1
- data/lib/acl9/controller_extensions.rb +1 -1
- data/lib/acl9/helpers.rb +12 -5
- data/lib/acl9/model_extensions/for_object.rb +20 -5
- data/lib/acl9/model_extensions/for_subject.rb +48 -21
- data/lib/acl9/model_extensions.rb +22 -25
- data/lib/acl9/prepositions.rb +18 -0
- data/lib/acl9/version.rb +3 -0
- data/lib/acl9.rb +36 -10
- data/lib/generators/acl9/setup/USAGE +35 -0
- data/lib/generators/acl9/setup/setup_generator.rb +115 -0
- data/lib/generators/acl9/setup/templates/create_role_tables.rb +22 -0
- data/lib/generators/acl9/setup/templates/role.rb +3 -0
- data/test/config_test.rb +55 -0
- data/test/controller_extensions/actions_test.rb +199 -0
- data/test/controller_extensions/anon_test.rb +39 -0
- data/test/controller_extensions/base.rb +96 -0
- data/test/controller_extensions/basics_test.rb +44 -0
- data/test/controller_extensions/conditions_test.rb +48 -0
- data/test/controller_extensions/method_test.rb +70 -0
- data/test/controller_extensions/multi_match_test.rb +142 -0
- data/test/controller_extensions/multiple_role_arguments_test.rb +135 -0
- data/test/controller_extensions/prepositions_test.rb +108 -0
- data/test/controller_extensions/pseudo_role_test.rb +26 -0
- data/test/controller_extensions/role_test.rb +75 -0
- data/test/controllers/acl_action_override_test.rb +24 -0
- data/test/controllers/acl_arguments_test.rb +5 -0
- data/test/controllers/acl_block_test.rb +5 -0
- data/test/controllers/acl_boolean_method_test.rb +5 -0
- data/test/controllers/acl_helper_method_test.rb +26 -0
- data/test/controllers/acl_ivars_test.rb +15 -0
- data/test/controllers/acl_method2_test.rb +6 -0
- data/test/controllers/acl_method_test.rb +6 -0
- data/test/controllers/acl_object_hash_test.rb +18 -0
- data/test/controllers/acl_query_method_named_test.rb +9 -0
- data/test/controllers/acl_query_method_test.rb +9 -0
- data/test/controllers/acl_query_method_with_lambda_test.rb +9 -0
- data/test/controllers/acl_query_mixin.rb +51 -0
- data/test/controllers/acl_subject_method_test.rb +15 -0
- data/test/controllers/arguments_checking_test.rb +43 -0
- data/test/dummy/app/controllers/acl_action_override.rb +15 -0
- data/test/dummy/app/controllers/acl_arguments.rb +10 -0
- data/test/dummy/app/controllers/acl_block.rb +6 -0
- data/test/dummy/app/controllers/acl_boolean_method.rb +23 -0
- data/test/dummy/app/controllers/acl_helper_method.rb +11 -0
- data/test/dummy/app/controllers/acl_ivars.rb +17 -0
- data/test/dummy/app/controllers/acl_method.rb +6 -0
- data/test/dummy/app/controllers/acl_method2.rb +6 -0
- data/test/dummy/app/controllers/acl_objects_hash.rb +10 -0
- data/test/dummy/app/controllers/acl_query_method.rb +9 -0
- data/test/dummy/app/controllers/acl_query_method_named.rb +13 -0
- data/test/dummy/app/controllers/acl_query_method_with_lambda.rb +9 -0
- data/test/dummy/app/controllers/acl_subject_method.rb +16 -0
- data/test/dummy/app/controllers/application_controller.rb +7 -0
- data/test/dummy/app/controllers/empty_controller.rb +5 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/helpers/some_helper.rb +8 -0
- data/test/dummy/app/models/.keep +0 -0
- data/test/dummy/app/models/access.rb +3 -0
- data/test/dummy/app/models/account.rb +3 -0
- data/test/dummy/app/models/bar.rb +3 -0
- data/test/dummy/app/models/concerns/.keep +0 -0
- data/test/dummy/app/models/foo.rb +3 -0
- data/test/dummy/app/models/foo_bar.rb +3 -0
- data/test/dummy/app/models/other/foo.rb +5 -0
- data/test/dummy/app/models/other/role.rb +5 -0
- data/test/dummy/app/models/other/user.rb +5 -0
- data/test/dummy/app/models/role.rb +3 -0
- data/test/dummy/app/models/user.rb +3 -0
- data/test/dummy/app/models/uuid.rb +4 -0
- data/test/dummy/config/application.rb +23 -0
- data/test/dummy/config/boot.rb +4 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +37 -0
- data/test/dummy/config/environments/production.rb +78 -0
- data/test/dummy/config/environments/test.rb +40 -0
- data/test/dummy/config/initializers/assets.rb +8 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
- data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
- data/test/dummy/config/initializers/inflections.rb +16 -0
- data/test/dummy/config/initializers/mime_types.rb +4 -0
- data/test/dummy/config/initializers/secrets.rb +1 -0
- data/test/dummy/config/initializers/session_store.rb +3 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +23 -0
- data/test/dummy/config/routes.rb +3 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20141117132218_create_tables.rb +99 -0
- data/test/helpers/helper_test.rb +89 -0
- data/test/models/roles_test.rb +357 -0
- data/test/models/roles_with_custom_association_names_test.rb +28 -0
- data/test/models/roles_with_custom_class_names_test.rb +28 -0
- data/test/models/system_roles_test.rb +22 -0
- data/test/models/users_roles_and_subjects_with_namespaced_class_names_test.rb +30 -0
- data/test/test_helper.rb +80 -20
- data/test/version_test.rb +7 -0
- metadata +290 -71
- data/CHANGELOG.textile +0 -46
- data/README.textile +0 -903
- data/VERSION.yml +0 -5
- data/lib/acl9/config.rb +0 -11
- data/test/access_control_test.rb +0 -338
- data/test/dsl_base_test.rb +0 -795
- data/test/helpers_test.rb +0 -134
- data/test/roles_test.rb +0 -355
- data/test/support/controllers.rb +0 -207
- data/test/support/models.rb +0 -59
- data/test/support/schema.rb +0 -92
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
require_relative "../prepositions"
|
|
2
|
+
|
|
1
3
|
module Acl9
|
|
2
4
|
module Dsl
|
|
3
5
|
class Base
|
|
6
|
+
include Prepositions
|
|
7
|
+
|
|
4
8
|
attr_reader :allows, :denys
|
|
5
9
|
|
|
6
10
|
def initialize(*args)
|
|
7
11
|
@default_action = nil
|
|
8
|
-
|
|
9
12
|
@allows = []
|
|
10
|
-
@denys
|
|
11
|
-
|
|
13
|
+
@denys = []
|
|
12
14
|
@original_args = args
|
|
13
15
|
end
|
|
14
16
|
|
|
@@ -17,21 +19,12 @@ module Acl9
|
|
|
17
19
|
end
|
|
18
20
|
|
|
19
21
|
def default_action
|
|
20
|
-
|
|
22
|
+
@default_action.nil? ? :deny : @default_action
|
|
21
23
|
end
|
|
22
24
|
|
|
23
25
|
def allowance_expression
|
|
24
|
-
allowed_expr
|
|
25
|
-
|
|
26
|
-
else
|
|
27
|
-
"false"
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
not_denied_expr = if @denys.size > 0
|
|
31
|
-
@denys.map { |clause| "!(#{clause})" }.join(' && ')
|
|
32
|
-
else
|
|
33
|
-
"true"
|
|
34
|
-
end
|
|
26
|
+
allowed_expr = @allows.any? ? @allows.map { |clause| "(#{clause})" }.join(' || ') : 'false'
|
|
27
|
+
not_denied_expr = @denys.any? ? @denys.map { |clause| "!(#{clause})" }.join(' && ') : 'true'
|
|
35
28
|
|
|
36
29
|
[allowed_expr, not_denied_expr].
|
|
37
30
|
map { |expr| "(#{expr})" }.
|
|
@@ -76,18 +69,14 @@ module Acl9
|
|
|
76
69
|
raise ArgumentError, "You cannot use default inside an actions block"
|
|
77
70
|
end
|
|
78
71
|
|
|
79
|
-
def _set_action_clause(
|
|
80
|
-
raise ArgumentError, "You cannot use :to
|
|
72
|
+
def _set_action_clause(only, except)
|
|
73
|
+
raise ArgumentError, "You cannot use :only (:to) or :except inside actions block" if only || except
|
|
81
74
|
end
|
|
82
75
|
end
|
|
83
76
|
|
|
84
77
|
subsidiary.acl_block!(&block)
|
|
85
|
-
|
|
86
78
|
action_check = _action_check_expression(args)
|
|
87
|
-
|
|
88
|
-
squash = lambda do |rules|
|
|
89
|
-
_either_of(rules) + ' && ' + action_check
|
|
90
|
-
end
|
|
79
|
+
squash = lambda { |rules| action_check + ' && ' + _either_of(rules) }
|
|
91
80
|
|
|
92
81
|
@allows << squash.call(subsidiary.allows) if subsidiary.allows.size > 0
|
|
93
82
|
@denys << squash.call(subsidiary.denys) if subsidiary.denys.size > 0
|
|
@@ -103,20 +92,31 @@ module Acl9
|
|
|
103
92
|
alias everybody all
|
|
104
93
|
alias anyone all
|
|
105
94
|
|
|
95
|
+
def _permitted_allow_deny_option!(key)
|
|
96
|
+
raise ArgumentError, "#{key} is not a valid option" unless [:to, :only, :except, :if, :unless, *VALID_PREPOSITIONS].include?(key.to_sym)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def _retrieve_only options
|
|
100
|
+
only = [ options.delete(:only) ].flatten.compact
|
|
101
|
+
only |= [ options.delete(:to) ].flatten.compact
|
|
102
|
+
only if only.present?
|
|
103
|
+
end
|
|
104
|
+
|
|
106
105
|
def _parse_and_add_rule(*args)
|
|
107
106
|
options = args.extract_options!
|
|
107
|
+
options.keys.each { |key| _permitted_allow_deny_option!(key) }
|
|
108
108
|
|
|
109
|
-
_set_action_clause(options
|
|
109
|
+
_set_action_clause( _retrieve_only(options), options.delete(:except))
|
|
110
110
|
|
|
111
111
|
object = _role_object(options)
|
|
112
112
|
|
|
113
113
|
role_checks = args.map do |who|
|
|
114
114
|
case who
|
|
115
|
-
when anonymous
|
|
116
|
-
when logged_in
|
|
117
|
-
when all
|
|
115
|
+
when anonymous then "#{_subject_ref}.nil?"
|
|
116
|
+
when logged_in then "!#{_subject_ref}.nil?"
|
|
117
|
+
when all then "true"
|
|
118
118
|
else
|
|
119
|
-
"!#{_subject_ref}.nil? && #{_subject_ref}.has_role?('#{who
|
|
119
|
+
"!#{_subject_ref}.nil? && #{_subject_ref}.has_role?('#{who}', #{object})"
|
|
120
120
|
end
|
|
121
121
|
end
|
|
122
122
|
|
|
@@ -153,21 +153,15 @@ module Acl9
|
|
|
153
153
|
(@current_rule == :allow ? @allows : @denys) << anded.join(' && ')
|
|
154
154
|
end
|
|
155
155
|
|
|
156
|
-
def _set_action_clause(
|
|
157
|
-
raise ArgumentError, "both :to and :except cannot be specified in the rule" if
|
|
158
|
-
|
|
159
|
-
@action_clause = nil
|
|
156
|
+
def _set_action_clause(only, except)
|
|
157
|
+
raise ArgumentError, "both :only (:to) and :except cannot be specified in the rule" if only && except
|
|
160
158
|
|
|
161
|
-
|
|
159
|
+
@action_clause = nil
|
|
160
|
+
action_list = only || except
|
|
162
161
|
return unless action_list
|
|
163
162
|
|
|
164
163
|
expr = _action_check_expression(action_list)
|
|
165
|
-
|
|
166
|
-
@action_clause = if to
|
|
167
|
-
"#{expr}"
|
|
168
|
-
else
|
|
169
|
-
"!#{expr}"
|
|
170
|
-
end
|
|
164
|
+
@action_clause = only ? "#{expr}" : "!#{expr}"
|
|
171
165
|
end
|
|
172
166
|
|
|
173
167
|
def _action_check_expression(action_list)
|
|
@@ -185,26 +179,13 @@ module Acl9
|
|
|
185
179
|
end
|
|
186
180
|
end
|
|
187
181
|
|
|
188
|
-
VALID_PREPOSITIONS = %w(of for in on at by).freeze unless defined? VALID_PREPOSITIONS
|
|
189
|
-
|
|
190
182
|
def _role_object(options)
|
|
191
|
-
object =
|
|
192
|
-
|
|
193
|
-
VALID_PREPOSITIONS.each do |prep|
|
|
194
|
-
if options[prep.to_sym]
|
|
195
|
-
raise ArgumentError, "You may only use one preposition to specify object" if object
|
|
196
|
-
|
|
197
|
-
object = options[prep.to_sym]
|
|
198
|
-
end
|
|
199
|
-
end
|
|
183
|
+
object = _by_preposition options
|
|
200
184
|
|
|
201
185
|
case object
|
|
202
|
-
when Class
|
|
203
|
-
|
|
204
|
-
when
|
|
205
|
-
_object_ref object
|
|
206
|
-
when nil
|
|
207
|
-
"nil"
|
|
186
|
+
when Class then object.to_s
|
|
187
|
+
when Symbol then _object_ref object
|
|
188
|
+
when nil then "nil"
|
|
208
189
|
else
|
|
209
190
|
raise ArgumentError, "object specified by preposition can only be a Class or a Symbol"
|
|
210
191
|
end
|
data/lib/acl9/helpers.rb
CHANGED
|
@@ -19,13 +19,13 @@ module Acl9
|
|
|
19
19
|
|
|
20
20
|
# Usage:
|
|
21
21
|
#
|
|
22
|
-
#
|
|
22
|
+
# <%=show_to(:owner, :supervisor, :of => :account) do %>
|
|
23
23
|
# <%= 'hello' %>
|
|
24
|
-
#
|
|
24
|
+
# <% end %>
|
|
25
25
|
#
|
|
26
26
|
def show_to(*args, &block)
|
|
27
|
-
user =
|
|
28
|
-
return
|
|
27
|
+
user = send(Acl9.config[:default_subject_method])
|
|
28
|
+
return if user.nil?
|
|
29
29
|
|
|
30
30
|
has_any = false
|
|
31
31
|
|
|
@@ -36,7 +36,14 @@ module Acl9
|
|
|
36
36
|
has_any = args.detect { |role| user.has_role?(role) }
|
|
37
37
|
end
|
|
38
38
|
|
|
39
|
-
has_any
|
|
39
|
+
if has_any
|
|
40
|
+
begin
|
|
41
|
+
capture( &block )
|
|
42
|
+
rescue NoMethodError
|
|
43
|
+
yield( :block )
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
40
47
|
end
|
|
41
48
|
end
|
|
42
49
|
end
|
|
@@ -10,7 +10,10 @@ module Acl9
|
|
|
10
10
|
# @param [Subject] subject Subject to add role for
|
|
11
11
|
# @see Acl9::ModelExtensions::Subject#has_role?
|
|
12
12
|
def accepts_role?(role_name, subject)
|
|
13
|
-
subject.
|
|
13
|
+
if not subject.nil?
|
|
14
|
+
return subject.has_role? role_name, self
|
|
15
|
+
end
|
|
16
|
+
false
|
|
14
17
|
end
|
|
15
18
|
|
|
16
19
|
##
|
|
@@ -20,7 +23,10 @@ module Acl9
|
|
|
20
23
|
# @param [Subject] subject Subject to add role for
|
|
21
24
|
# @see Acl9::ModelExtensions::Subject#has_role!
|
|
22
25
|
def accepts_role!(role_name, subject)
|
|
23
|
-
subject.
|
|
26
|
+
if not subject.nil?
|
|
27
|
+
return subject.has_role! role_name, self
|
|
28
|
+
end
|
|
29
|
+
false
|
|
24
30
|
end
|
|
25
31
|
|
|
26
32
|
##
|
|
@@ -30,7 +36,10 @@ module Acl9
|
|
|
30
36
|
# @param [Subject] subject Subject to remove role from
|
|
31
37
|
# @see Acl9::ModelExtensions::Subject#has_no_role!
|
|
32
38
|
def accepts_no_role!(role_name, subject)
|
|
33
|
-
subject.
|
|
39
|
+
if not subject.nil?
|
|
40
|
+
return subject.has_no_role! role_name, self
|
|
41
|
+
end
|
|
42
|
+
false
|
|
34
43
|
end
|
|
35
44
|
|
|
36
45
|
##
|
|
@@ -40,7 +49,10 @@ module Acl9
|
|
|
40
49
|
# @return [Boolean] Returns true if +subject+ has any roles on this object.
|
|
41
50
|
# @see Acl9::ModelExtensions::Subject#has_roles_for?
|
|
42
51
|
def accepts_roles_by?(subject)
|
|
43
|
-
subject.
|
|
52
|
+
if not subject.nil?
|
|
53
|
+
return subject.has_roles_for? self
|
|
54
|
+
end
|
|
55
|
+
false
|
|
44
56
|
end
|
|
45
57
|
|
|
46
58
|
alias :accepts_role_by? :accepts_roles_by?
|
|
@@ -52,7 +64,10 @@ module Acl9
|
|
|
52
64
|
# @param [Subject] subject Subject to query roles
|
|
53
65
|
# @see Acl9::ModelExtensions::Subject#roles_for
|
|
54
66
|
def accepted_roles_by(subject)
|
|
55
|
-
subject.
|
|
67
|
+
if not subject.nil?
|
|
68
|
+
return subject.roles_for self
|
|
69
|
+
end
|
|
70
|
+
false
|
|
56
71
|
end
|
|
57
72
|
end
|
|
58
73
|
end
|
|
@@ -1,6 +1,10 @@
|
|
|
1
|
+
require_relative "../prepositions"
|
|
2
|
+
|
|
1
3
|
module Acl9
|
|
2
4
|
module ModelExtensions
|
|
3
5
|
module ForSubject
|
|
6
|
+
include Prepositions
|
|
7
|
+
|
|
4
8
|
##
|
|
5
9
|
# Role check.
|
|
6
10
|
#
|
|
@@ -17,7 +21,7 @@ module Acl9
|
|
|
17
21
|
#
|
|
18
22
|
# In this case manager is anyone who "manages" at least one object.
|
|
19
23
|
#
|
|
20
|
-
# However, if protect_global_roles option set to +true+, you'll need to
|
|
24
|
+
# However, if protect_global_roles option set to +true+, you'll need to
|
|
21
25
|
# explicitly grant global role with same name.
|
|
22
26
|
#
|
|
23
27
|
# Acl9.config[:protect_global_roles] = true
|
|
@@ -26,7 +30,7 @@ module Acl9
|
|
|
26
30
|
# user.has_role!(:manager)
|
|
27
31
|
# user.has_role?(:manager) # => true
|
|
28
32
|
#
|
|
29
|
-
# protect_global_roles option is +false+ by default as for now, but this
|
|
33
|
+
# protect_global_roles option is +false+ by default as for now, but this
|
|
30
34
|
# may change in future!
|
|
31
35
|
#
|
|
32
36
|
# @return [Boolean] Whether +self+ has a role +role_name+ on +object+.
|
|
@@ -35,12 +39,15 @@ module Acl9
|
|
|
35
39
|
#
|
|
36
40
|
# @see Acl9::ModelExtensions::Object#accepts_role?
|
|
37
41
|
def has_role?(role_name, object = nil)
|
|
42
|
+
role_name = normalize role_name
|
|
43
|
+
object = _by_preposition object
|
|
44
|
+
|
|
38
45
|
!! if object.nil? && !::Acl9.config[:protect_global_roles]
|
|
39
|
-
self.
|
|
40
|
-
self.
|
|
46
|
+
self._role_objects.find_by_name(role_name.to_s) ||
|
|
47
|
+
self._role_objects.member?(get_role(role_name, nil))
|
|
41
48
|
else
|
|
42
49
|
role = get_role(role_name, object)
|
|
43
|
-
role && self.
|
|
50
|
+
role && self._role_objects.exists?(role.id)
|
|
44
51
|
end
|
|
45
52
|
end
|
|
46
53
|
|
|
@@ -51,6 +58,9 @@ module Acl9
|
|
|
51
58
|
# @param [Object] object Object to add a role for
|
|
52
59
|
# @see Acl9::ModelExtensions::Object#accepts_role!
|
|
53
60
|
def has_role!(role_name, object = nil)
|
|
61
|
+
role_name = normalize role_name
|
|
62
|
+
object = _by_preposition object
|
|
63
|
+
|
|
54
64
|
role = get_role(role_name, object)
|
|
55
65
|
|
|
56
66
|
if role.nil?
|
|
@@ -63,7 +73,7 @@ module Acl9
|
|
|
63
73
|
role = self._auth_role_class.create(role_attrs)
|
|
64
74
|
end
|
|
65
75
|
|
|
66
|
-
self.
|
|
76
|
+
self._role_objects << role if role && !self._role_objects.exists?(role.id)
|
|
67
77
|
end
|
|
68
78
|
|
|
69
79
|
##
|
|
@@ -73,6 +83,8 @@ module Acl9
|
|
|
73
83
|
# @param [Object] object Object to remove a role on
|
|
74
84
|
# @see Acl9::ModelExtensions::Object#accepts_no_role!
|
|
75
85
|
def has_no_role!(role_name, object = nil)
|
|
86
|
+
role_name = normalize role_name
|
|
87
|
+
object = _by_preposition object
|
|
76
88
|
delete_role(get_role(role_name, object))
|
|
77
89
|
end
|
|
78
90
|
|
|
@@ -83,7 +95,7 @@ module Acl9
|
|
|
83
95
|
# @return [Boolean] Returns true if +self+ has any roles on +object+.
|
|
84
96
|
# @see Acl9::ModelExtensions::Object#accepts_roles_by?
|
|
85
97
|
def has_roles_for?(object)
|
|
86
|
-
!!self.
|
|
98
|
+
!!self._role_objects.detect(&role_selecting_lambda(object))
|
|
87
99
|
end
|
|
88
100
|
|
|
89
101
|
alias :has_role_for? :has_roles_for?
|
|
@@ -100,7 +112,7 @@ module Acl9
|
|
|
100
112
|
#
|
|
101
113
|
# user.roles_for(product).map(&:name).sort #=> role names in alphabetical order
|
|
102
114
|
def roles_for(object)
|
|
103
|
-
self.
|
|
115
|
+
self._role_objects.select(&role_selecting_lambda(object))
|
|
104
116
|
end
|
|
105
117
|
|
|
106
118
|
##
|
|
@@ -119,7 +131,7 @@ module Acl9
|
|
|
119
131
|
# self.roles.each { |role| delete_role(role) }
|
|
120
132
|
#
|
|
121
133
|
# doesn't work. seems like a bug in ActiveRecord
|
|
122
|
-
self.
|
|
134
|
+
self._role_objects.map(&:id).each do |role_id|
|
|
123
135
|
delete_role self._auth_role_class.find(role_id)
|
|
124
136
|
end
|
|
125
137
|
end
|
|
@@ -134,13 +146,14 @@ module Acl9
|
|
|
134
146
|
lambda { |role| role.authorizable.nil? }
|
|
135
147
|
else
|
|
136
148
|
lambda do |role|
|
|
137
|
-
role.
|
|
149
|
+
auth_id = role.authorizable_id.kind_of?(String) ? object.id.to_s : object.id
|
|
150
|
+
role.authorizable_type == object.class.base_class.to_s && role.authorizable_id == auth_id
|
|
138
151
|
end
|
|
139
152
|
end
|
|
140
153
|
end
|
|
141
154
|
|
|
142
155
|
def get_role(role_name, object)
|
|
143
|
-
role_name = role_name
|
|
156
|
+
role_name = normalize role_name
|
|
144
157
|
|
|
145
158
|
cond = case object
|
|
146
159
|
when Class
|
|
@@ -154,31 +167,45 @@ module Acl9
|
|
|
154
167
|
]
|
|
155
168
|
end
|
|
156
169
|
|
|
157
|
-
self._auth_role_class.
|
|
170
|
+
if self._auth_role_class.respond_to?(:where)
|
|
171
|
+
self._auth_role_class.where(cond).first
|
|
172
|
+
else
|
|
173
|
+
self._auth_role_class.find(:first, :conditions => cond)
|
|
174
|
+
end
|
|
158
175
|
end
|
|
159
176
|
|
|
160
177
|
def delete_role(role)
|
|
161
178
|
if role
|
|
162
|
-
self.
|
|
163
|
-
|
|
164
|
-
|
|
179
|
+
if ret = self._role_objects.delete(role)
|
|
180
|
+
if role.send(self._auth_subject_class_name.demodulize.tableize).empty?
|
|
181
|
+
ret &&= role.destroy unless role.respond_to?(:system?) && role.system?
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
ret
|
|
165
185
|
end
|
|
166
186
|
end
|
|
167
|
-
|
|
187
|
+
|
|
188
|
+
def normalize role_name
|
|
189
|
+
Acl9.config[:normalize_role_names] ? role_name.to_s.underscore.singularize : role_name.to_s
|
|
190
|
+
end
|
|
191
|
+
|
|
168
192
|
protected
|
|
169
193
|
|
|
194
|
+
def _by_preposition object
|
|
195
|
+
object.is_a?(Hash) ? super : object
|
|
196
|
+
end
|
|
197
|
+
|
|
170
198
|
def _auth_role_class
|
|
171
199
|
self.class._auth_role_class_name.constantize
|
|
172
200
|
end
|
|
173
|
-
|
|
201
|
+
|
|
174
202
|
def _auth_role_assoc
|
|
175
|
-
|
|
203
|
+
self.class._auth_role_assoc_name
|
|
176
204
|
end
|
|
177
205
|
|
|
178
|
-
def
|
|
179
|
-
|
|
206
|
+
def _role_objects
|
|
207
|
+
send(self._auth_role_assoc)
|
|
180
208
|
end
|
|
181
|
-
|
|
182
209
|
end
|
|
183
210
|
end
|
|
184
211
|
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:
|
|
@@ -24,7 +24,7 @@ module Acl9
|
|
|
24
24
|
# end
|
|
25
25
|
#
|
|
26
26
|
# user = User.new
|
|
27
|
-
# user.
|
|
27
|
+
# user.role_objects #=> returns Role objects, associated with the user
|
|
28
28
|
# user.has_role!(...)
|
|
29
29
|
# user.has_no_role!(...)
|
|
30
30
|
#
|
|
@@ -33,12 +33,13 @@ module Acl9
|
|
|
33
33
|
# @see Acl9::ModelExtensions::Subject
|
|
34
34
|
#
|
|
35
35
|
def acts_as_authorization_subject(options = {})
|
|
36
|
-
|
|
36
|
+
assoc = options[:association_name] || Acl9::config[:default_association_name]
|
|
37
37
|
role = options[:role_class_name] || Acl9::config[:default_role_class_name]
|
|
38
|
-
join_table = options[:join_table_name] || Acl9::config[:default_join_table_name] ||
|
|
39
|
-
|
|
38
|
+
join_table = options[:join_table_name] || Acl9::config[:default_join_table_name] || self.table_name_prefix + [undecorated_table_name(self.to_s), undecorated_table_name(role)].sort.join("_") + self.table_name_suffix
|
|
39
|
+
|
|
40
|
+
has_and_belongs_to_many assoc.to_sym, :class_name => role, :join_table => join_table
|
|
40
41
|
|
|
41
|
-
|
|
42
|
+
before_destroy :has_no_roles!
|
|
42
43
|
|
|
43
44
|
cattr_accessor :_auth_role_class_name, :_auth_subject_class_name,
|
|
44
45
|
:_auth_role_assoc_name
|
|
@@ -74,28 +75,22 @@ module Acl9
|
|
|
74
75
|
def acts_as_authorization_object(options = {})
|
|
75
76
|
subject = options[:subject_class_name] || Acl9::config[:default_subject_class_name]
|
|
76
77
|
subj_table = subject.constantize.table_name
|
|
77
|
-
subj_col = subject.underscore
|
|
78
78
|
|
|
79
|
-
role
|
|
80
|
-
role_table = role.constantize.table_name
|
|
79
|
+
role = options[:role_class_name] || Acl9::config[:default_role_class_name]
|
|
81
80
|
|
|
82
|
-
|
|
83
|
-
FROM #{subj_table}
|
|
84
|
-
INNER JOIN #{role_table}_#{subj_table} ON #{subj_col}_id = #{subj_table}.id
|
|
85
|
-
INNER JOIN #{role_table} ON #{role_table}.id = #{role.underscore}_id
|
|
86
|
-
EOS
|
|
81
|
+
has_many :accepted_roles, :as => :authorizable, :class_name => role, :dependent => :destroy
|
|
87
82
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
AND authorizable_id = #{column_for_attribute(self.class.primary_key).text? ? "'#{id}'": id}
|
|
91
|
-
EOS
|
|
83
|
+
subj_assoc = "assoc_#{subj_table}".to_sym
|
|
84
|
+
has_many subj_assoc, -> { distinct.readonly }, source: subj_table.to_sym, through: :accepted_roles
|
|
92
85
|
|
|
93
|
-
|
|
86
|
+
define_method subj_table.to_sym do |role_name=nil|
|
|
87
|
+
rel = send subj_assoc
|
|
94
88
|
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
89
|
+
if role_name
|
|
90
|
+
rel = rel.where role.constantize.table_name.to_sym => { name: role_name }
|
|
91
|
+
end
|
|
92
|
+
rel
|
|
93
|
+
end
|
|
99
94
|
|
|
100
95
|
include Acl9::ModelExtensions::ForObject
|
|
101
96
|
end
|
|
@@ -126,7 +121,9 @@ module Acl9
|
|
|
126
121
|
def acts_as_authorization_role(options = {})
|
|
127
122
|
subject = options[:subject_class_name] || Acl9::config[:default_subject_class_name]
|
|
128
123
|
join_table = options[:join_table_name] || Acl9::config[:default_join_table_name] ||
|
|
129
|
-
|
|
124
|
+
self.table_name_prefix + [undecorated_table_name(self.to_s), undecorated_table_name(subject)].sort.join("_") + self.table_name_suffix
|
|
125
|
+
# comment out use deprecated API
|
|
126
|
+
#join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(subject))
|
|
130
127
|
|
|
131
128
|
has_and_belongs_to_many subject.demodulize.tableize.to_sym,
|
|
132
129
|
:class_name => subject,
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
module Acl9
|
|
2
|
+
module Prepositions
|
|
3
|
+
VALID_PREPOSITIONS = %i(of for in on at by).freeze unless defined? VALID_PREPOSITIONS
|
|
4
|
+
|
|
5
|
+
def _by_preposition options
|
|
6
|
+
object = nil
|
|
7
|
+
|
|
8
|
+
VALID_PREPOSITIONS.each do |prep|
|
|
9
|
+
if options[prep]
|
|
10
|
+
raise ArgumentError, "You may only use one preposition to specify object" if object
|
|
11
|
+
|
|
12
|
+
object = options[prep]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
object
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
data/lib/acl9/version.rb
ADDED
data/lib/acl9.rb
CHANGED
|
@@ -1,16 +1,42 @@
|
|
|
1
|
-
require
|
|
1
|
+
require 'acl9/version'
|
|
2
|
+
require 'acl9/model_extensions'
|
|
3
|
+
require 'acl9/controller_extensions'
|
|
4
|
+
require 'acl9/helpers'
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
module Acl9
|
|
7
|
+
CONFIG = {
|
|
8
|
+
:default_role_class_name => 'Role',
|
|
9
|
+
:default_subject_class_name => 'User',
|
|
10
|
+
:default_subject_method => :current_user,
|
|
11
|
+
:default_association_name => :role_objects,
|
|
12
|
+
:default_join_table_name => nil,
|
|
13
|
+
:protect_global_roles => true,
|
|
14
|
+
:normalize_role_names => true,
|
|
15
|
+
}.freeze
|
|
5
16
|
|
|
6
|
-
|
|
7
|
-
end
|
|
17
|
+
class Config < Struct.new(*CONFIG.keys )
|
|
18
|
+
def [] k; send k.to_sym; end
|
|
19
|
+
def []= k, v; send "#{k}=", v; end
|
|
20
|
+
def reset!
|
|
21
|
+
Acl9::CONFIG.each do |k,v|
|
|
22
|
+
send "#{k}=", v
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def merge! h
|
|
27
|
+
h.each { |k,v| self[k.to_sym] = v }
|
|
28
|
+
end
|
|
29
|
+
end
|
|
8
30
|
|
|
31
|
+
@@config = Config.new( *CONFIG.values_at(*Config.members))
|
|
9
32
|
|
|
10
|
-
|
|
11
|
-
require File.join(File.dirname(__FILE__), 'acl9', 'controller_extensions')
|
|
12
|
-
require File.join(File.dirname(__FILE__), 'acl9', 'helpers')
|
|
33
|
+
mattr_reader :config
|
|
13
34
|
|
|
14
|
-
|
|
15
|
-
|
|
35
|
+
def self.configure
|
|
36
|
+
yield config
|
|
37
|
+
end
|
|
16
38
|
end
|
|
39
|
+
|
|
40
|
+
ActiveRecord::Base.send(:include, Acl9::ModelExtensions)
|
|
41
|
+
AbstractController::Base.send :include, Acl9::ControllerExtensions
|
|
42
|
+
Acl9Helpers = Acl9::Helpers unless defined?(Acl9Helpers)
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Installs the basic framework for Acl9. Creates the necessary migration for
|
|
3
|
+
your new roles table and the join table for associating roles with users.
|
|
4
|
+
|
|
5
|
+
The optional arguments are as follows:
|
|
6
|
+
|
|
7
|
+
subject: if you want something other than 'User'
|
|
8
|
+
role: if you want something other than 'Role'
|
|
9
|
+
objects: space separated list of class names of objects that you can
|
|
10
|
+
attach roles to (see the docs)
|
|
11
|
+
|
|
12
|
+
Examples:
|
|
13
|
+
`rails g acl9:setup`
|
|
14
|
+
|
|
15
|
+
This will create:
|
|
16
|
+
Migration: db/migrate/XXX_create_role_tables.rb
|
|
17
|
+
Role Model: app/models/role.rb
|
|
18
|
+
Config: config/initializers/acl9.rb
|
|
19
|
+
|
|
20
|
+
And it will update (or create a skeleton):
|
|
21
|
+
Subject Model: app/models/user.rb
|
|
22
|
+
|
|
23
|
+
`rails g acl9:setup account permission school classroom department`
|
|
24
|
+
|
|
25
|
+
This will create:
|
|
26
|
+
Migration: db/migrate/XXX_create_permission_tables.rb
|
|
27
|
+
Role Model: app/models/permission.rb
|
|
28
|
+
Config: config/initializers/acl9.rb
|
|
29
|
+
|
|
30
|
+
And it will update (or create a skeleton):
|
|
31
|
+
Subject Model: app/models/account.rb
|
|
32
|
+
Object Models: app/models/school.rb
|
|
33
|
+
app/models/classroom.rb
|
|
34
|
+
app/models/department.rb
|
|
35
|
+
|