careacademy-acl9 3.3.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 +7 -0
- data/.gitignore +24 -0
- data/.ruby-version +1 -0
- data/.travis.yml +26 -0
- data/Appraisals +23 -0
- data/CHANGELOG.md +122 -0
- data/CONTRIBUTING.md +62 -0
- data/Gemfile +7 -0
- data/Gemfile.lock +167 -0
- data/LICENSE +9 -0
- data/MIT-LICENSE +20 -0
- data/README.md +326 -0
- data/Rakefile +20 -0
- data/TODO +42 -0
- data/acl9.gemspec +27 -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/.bundle/config +2 -0
- data/gemfiles/rails_5.0.gemfile +10 -0
- data/gemfiles/rails_5.1.gemfile +10 -0
- data/gemfiles/rails_5.2.gemfile +9 -0
- data/gemfiles/rails_6.0.gemfile +9 -0
- data/gemfiles/rails_6.1.gemfile +9 -0
- data/gemfiles/rails_7.0.gemfile +9 -0
- data/lib/acl9/controller_extensions/dsl_base.rb +212 -0
- data/lib/acl9/controller_extensions/generators.rb +166 -0
- data/lib/acl9/controller_extensions.rb +85 -0
- data/lib/acl9/helpers.rb +49 -0
- data/lib/acl9/model_extensions/for_object.rb +74 -0
- data/lib/acl9/model_extensions/for_subject.rb +232 -0
- data/lib/acl9/model_extensions.rb +136 -0
- data/lib/acl9/prepositions.rb +18 -0
- data/lib/acl9/version.rb +3 -0
- data/lib/acl9.rb +78 -0
- data/lib/generators/acl9/setup/USAGE +35 -0
- data/lib/generators/acl9/setup/setup_generator.rb +122 -0
- data/lib/generators/acl9/setup/templates/create_role_tables.rb +31 -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 +136 -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 +29 -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 +54 -0
- data/test/controllers/acl_subject_method_test.rb +15 -0
- data/test/controllers/arguments_checking_test.rb +43 -0
- data/test/dummy/app/assets/config/manifest.js +0 -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 +15 -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 +13 -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/string_object_role.rb +3 -0
- data/test/dummy/app/models/string_user.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/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 +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/db/migrate/20141117132218_create_tables.rb +149 -0
- data/test/helpers/helper_test.rb +89 -0
- data/test/models/roles_test.rb +369 -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 +94 -0
- data/test/version_test.rb +7 -0
- metadata +321 -0
@@ -0,0 +1,212 @@
|
|
1
|
+
require_relative "../prepositions"
|
2
|
+
|
3
|
+
module Acl9
|
4
|
+
module Dsl
|
5
|
+
class Base
|
6
|
+
include Prepositions
|
7
|
+
|
8
|
+
attr_reader :allows, :denys
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
@default_action = nil
|
12
|
+
@allows = []
|
13
|
+
@denys = []
|
14
|
+
@original_args = args
|
15
|
+
@action_clause = nil
|
16
|
+
end
|
17
|
+
|
18
|
+
def acl_block!(&acl_block)
|
19
|
+
instance_eval(&acl_block)
|
20
|
+
end
|
21
|
+
|
22
|
+
def default_action
|
23
|
+
@default_action.nil? ? :deny : @default_action
|
24
|
+
end
|
25
|
+
|
26
|
+
def allowance_expression
|
27
|
+
allowed_expr = @allows.any? ? @allows.map { |clause| "(#{clause})" }.join(' || ') : 'false'
|
28
|
+
not_denied_expr = @denys.any? ? @denys.map { |clause| "!(#{clause})" }.join(' && ') : 'true'
|
29
|
+
|
30
|
+
[allowed_expr, not_denied_expr].
|
31
|
+
map { |expr| "(#{expr})" }.
|
32
|
+
join(default_action == :deny ? ' && ' : ' || ')
|
33
|
+
end
|
34
|
+
|
35
|
+
alias to_s allowance_expression
|
36
|
+
|
37
|
+
protected
|
38
|
+
|
39
|
+
def default(default_action)
|
40
|
+
raise ArgumentError, "default can only be called once in access_control block" if @default_action
|
41
|
+
|
42
|
+
unless [:allow, :deny].include? default_action
|
43
|
+
raise ArgumentError, "invalid value for default (can be :allow or :deny)"
|
44
|
+
end
|
45
|
+
|
46
|
+
@default_action = default_action
|
47
|
+
end
|
48
|
+
|
49
|
+
def allow(*args)
|
50
|
+
@current_rule = :allow
|
51
|
+
_parse_and_add_rule(*args)
|
52
|
+
end
|
53
|
+
|
54
|
+
def deny(*args)
|
55
|
+
@current_rule = :deny
|
56
|
+
_parse_and_add_rule(*args)
|
57
|
+
end
|
58
|
+
|
59
|
+
def actions(*args, &block)
|
60
|
+
raise ArgumentError, "actions should receive at least 1 action as argument" if args.size < 1
|
61
|
+
|
62
|
+
subsidiary = self.class.new(*@original_args)
|
63
|
+
|
64
|
+
class <<subsidiary
|
65
|
+
def actions(*args)
|
66
|
+
raise ArgumentError, "You cannot use actions inside another actions block"
|
67
|
+
end
|
68
|
+
|
69
|
+
def default(*args)
|
70
|
+
raise ArgumentError, "You cannot use default inside an actions block"
|
71
|
+
end
|
72
|
+
|
73
|
+
def _set_action_clause(only, except)
|
74
|
+
raise ArgumentError, "You cannot use :only (:to) or :except inside actions block" if only || except
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
subsidiary.acl_block!(&block)
|
79
|
+
action_check = _action_check_expression(args)
|
80
|
+
squash = lambda { |rules| action_check + ' && ' + _either_of(rules) }
|
81
|
+
|
82
|
+
@allows << squash.call(subsidiary.allows) if subsidiary.allows.size > 0
|
83
|
+
@denys << squash.call(subsidiary.denys) if subsidiary.denys.size > 0
|
84
|
+
end
|
85
|
+
|
86
|
+
alias action actions
|
87
|
+
|
88
|
+
def logged_in; false end
|
89
|
+
def anonymous; nil end
|
90
|
+
def all; true end
|
91
|
+
|
92
|
+
alias everyone all
|
93
|
+
alias everybody all
|
94
|
+
alias anyone all
|
95
|
+
|
96
|
+
def _permitted_allow_deny_option!(key)
|
97
|
+
raise ArgumentError, "#{key} is not a valid option" unless [:to, :only, :except, :if, :unless, *VALID_PREPOSITIONS].include?(key.to_sym)
|
98
|
+
end
|
99
|
+
|
100
|
+
def _retrieve_only options
|
101
|
+
only = [ options.delete(:only) ].flatten.compact
|
102
|
+
only |= [ options.delete(:to) ].flatten.compact
|
103
|
+
only if only.present?
|
104
|
+
end
|
105
|
+
|
106
|
+
def _parse_and_add_rule(*args)
|
107
|
+
options = args.extract_options!
|
108
|
+
options.keys.each { |key| _permitted_allow_deny_option!(key) }
|
109
|
+
|
110
|
+
_set_action_clause( _retrieve_only(options), options.delete(:except))
|
111
|
+
|
112
|
+
object_s = _role_object_s(options)
|
113
|
+
|
114
|
+
role_checks = args.map do |who|
|
115
|
+
case who
|
116
|
+
when anonymous then "#{_subject_ref}.nil?"
|
117
|
+
when logged_in then "!#{_subject_ref}.nil?"
|
118
|
+
when all then "true"
|
119
|
+
else
|
120
|
+
"!#{_subject_ref}.nil? && #{_subject_ref}.has_role?('#{who}'#{object_s})"
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
[:if, :unless].each do |cond|
|
125
|
+
val = options[cond]
|
126
|
+
raise ArgumentError, "#{cond} option must be a Symbol" if val && !val.is_a?(Symbol)
|
127
|
+
end
|
128
|
+
|
129
|
+
condition = [
|
130
|
+
(_method_ref(options[:if]) if options[:if]),
|
131
|
+
("!#{_method_ref(options[:unless])}" if options[:unless])
|
132
|
+
].compact.join(' && ')
|
133
|
+
|
134
|
+
condition = nil if condition.blank?
|
135
|
+
|
136
|
+
_add_rule(case role_checks.size
|
137
|
+
when 0
|
138
|
+
raise ArgumentError, "allow/deny should have at least 1 argument"
|
139
|
+
when 1 then role_checks.first
|
140
|
+
else
|
141
|
+
_either_of(role_checks)
|
142
|
+
end, condition)
|
143
|
+
end
|
144
|
+
|
145
|
+
def _either_of(exprs)
|
146
|
+
clause = exprs.map { |expr| "(#{expr})" }.join(' || ')
|
147
|
+
return "(#{clause})"
|
148
|
+
end
|
149
|
+
|
150
|
+
def _add_rule(what, condition)
|
151
|
+
anded = [what] + [@action_clause, condition].compact
|
152
|
+
anded[0] = "(#{anded[0]})" if anded.size > 1
|
153
|
+
|
154
|
+
(@current_rule == :allow ? @allows : @denys) << anded.join(' && ')
|
155
|
+
end
|
156
|
+
|
157
|
+
def _set_action_clause(only, except)
|
158
|
+
raise ArgumentError, "both :only (:to) and :except cannot be specified in the rule" if only && except
|
159
|
+
|
160
|
+
@action_clause = nil
|
161
|
+
action_list = only || except
|
162
|
+
return unless action_list
|
163
|
+
|
164
|
+
expr = _action_check_expression(action_list)
|
165
|
+
@action_clause = only ? "#{expr}" : "!#{expr}"
|
166
|
+
end
|
167
|
+
|
168
|
+
def _action_check_expression(action_list)
|
169
|
+
unless action_list.is_a?(Array)
|
170
|
+
action_list = [ action_list.to_s ]
|
171
|
+
end
|
172
|
+
|
173
|
+
case action_list.size
|
174
|
+
when 0 then "true"
|
175
|
+
when 1 then "(#{_action_ref} == '#{action_list.first}')"
|
176
|
+
else
|
177
|
+
set_of_actions = "Set.new([" + action_list.map { |act| "'#{act}'"}.join(',') + "])"
|
178
|
+
|
179
|
+
"#{set_of_actions}.include?(#{_action_ref})"
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
def _role_object_s(options)
|
184
|
+
object = _by_preposition options
|
185
|
+
|
186
|
+
case object
|
187
|
+
when Class then ", #{object}"
|
188
|
+
when Symbol then ", #{_object_ref object}"
|
189
|
+
when nil then ""
|
190
|
+
else
|
191
|
+
raise ArgumentError, "object specified by preposition can only be a Class or a Symbol"
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def _subject_ref
|
196
|
+
raise
|
197
|
+
end
|
198
|
+
|
199
|
+
def _object_ref(object)
|
200
|
+
raise
|
201
|
+
end
|
202
|
+
|
203
|
+
def _action_ref
|
204
|
+
raise
|
205
|
+
end
|
206
|
+
|
207
|
+
def _method_ref(method)
|
208
|
+
raise
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
@@ -0,0 +1,166 @@
|
|
1
|
+
require_relative "dsl_base"
|
2
|
+
|
3
|
+
module Acl9
|
4
|
+
module Dsl
|
5
|
+
module Generators
|
6
|
+
class BaseGenerator < Acl9::Dsl::Base
|
7
|
+
def initialize(*args)
|
8
|
+
@subject_method = args[0]
|
9
|
+
|
10
|
+
super
|
11
|
+
end
|
12
|
+
|
13
|
+
protected
|
14
|
+
|
15
|
+
def _access_denied
|
16
|
+
"raise Acl9::AccessDenied"
|
17
|
+
end
|
18
|
+
|
19
|
+
def _subject_ref
|
20
|
+
"#{_controller_ref}send(:#{@subject_method})"
|
21
|
+
end
|
22
|
+
|
23
|
+
def _object_ref(object)
|
24
|
+
"#{_controller_ref}instance_variable_get('@#{object}')"
|
25
|
+
end
|
26
|
+
|
27
|
+
def _action_ref
|
28
|
+
"#{_controller_ref}action_name"
|
29
|
+
end
|
30
|
+
|
31
|
+
def _method_ref(method)
|
32
|
+
"#{_controller_ref}send(:#{method})"
|
33
|
+
end
|
34
|
+
|
35
|
+
def _controller_ref
|
36
|
+
@controller ? "#{@controller}." : ''
|
37
|
+
end
|
38
|
+
|
39
|
+
def install_on(controller_class, options)
|
40
|
+
debug_dump(controller_class) if options[:debug]
|
41
|
+
end
|
42
|
+
|
43
|
+
def debug_dump(klass)
|
44
|
+
return unless logger
|
45
|
+
logger.debug "=== Acl9 access_control expression dump (#{klass.to_s})"
|
46
|
+
logger.debug self.to_s
|
47
|
+
logger.debug "======"
|
48
|
+
end
|
49
|
+
|
50
|
+
def logger
|
51
|
+
ActionController::Base.logger
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class FilterLambda < BaseGenerator
|
56
|
+
def initialize(subject_method)
|
57
|
+
super
|
58
|
+
|
59
|
+
@controller = 'controller'
|
60
|
+
end
|
61
|
+
|
62
|
+
def install_on(controller_class, options)
|
63
|
+
super
|
64
|
+
|
65
|
+
controller_class.send(:before_action, options, &self.to_proc)
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_proc
|
69
|
+
code = <<-RUBY
|
70
|
+
lambda do |controller|
|
71
|
+
unless #{allowance_expression}
|
72
|
+
#{_access_denied}
|
73
|
+
end
|
74
|
+
end
|
75
|
+
RUBY
|
76
|
+
|
77
|
+
self.instance_eval(code, __FILE__, __LINE__)
|
78
|
+
rescue SyntaxError
|
79
|
+
raise FilterSyntaxError, code
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
################################################################
|
84
|
+
|
85
|
+
class FilterMethod < BaseGenerator
|
86
|
+
def initialize(subject_method, method_name)
|
87
|
+
super
|
88
|
+
|
89
|
+
@method_name = method_name
|
90
|
+
@controller = nil
|
91
|
+
end
|
92
|
+
|
93
|
+
def install_on(controller_class, options)
|
94
|
+
super
|
95
|
+
_add_method(controller_class)
|
96
|
+
controller_class.send(:before_action, @method_name, options)
|
97
|
+
end
|
98
|
+
|
99
|
+
protected
|
100
|
+
|
101
|
+
def _add_method(controller_class)
|
102
|
+
code = self.to_method_code
|
103
|
+
controller_class.send(:class_eval, code, __FILE__, __LINE__)
|
104
|
+
rescue SyntaxError
|
105
|
+
raise FilterSyntaxError, code
|
106
|
+
end
|
107
|
+
|
108
|
+
def to_method_code
|
109
|
+
<<-RUBY
|
110
|
+
def #{@method_name}
|
111
|
+
unless #{allowance_expression}
|
112
|
+
#{_access_denied}
|
113
|
+
end
|
114
|
+
end
|
115
|
+
RUBY
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
################################################################
|
120
|
+
|
121
|
+
class BooleanMethod < FilterMethod
|
122
|
+
def install_on(controller_class, opts)
|
123
|
+
debug_dump(controller_class) if opts[:debug]
|
124
|
+
|
125
|
+
_add_method(controller_class)
|
126
|
+
|
127
|
+
if opts[:helper]
|
128
|
+
controller_class.send(:helper_method, @method_name)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
protected
|
133
|
+
|
134
|
+
def to_method_code
|
135
|
+
<<-RUBY
|
136
|
+
def #{@method_name}(*args)
|
137
|
+
options = args.extract_options!
|
138
|
+
|
139
|
+
unless args.size <= 1
|
140
|
+
raise ArgumentError, "call #{@method_name} with 0, 1 or 2 arguments"
|
141
|
+
end
|
142
|
+
|
143
|
+
self.action_name = args.first.to_s if args.present?
|
144
|
+
|
145
|
+
return #{allowance_expression}
|
146
|
+
end
|
147
|
+
RUBY
|
148
|
+
end
|
149
|
+
|
150
|
+
def _object_ref(object)
|
151
|
+
"(options[:#{object}] || #{super})"
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
################################################################
|
156
|
+
|
157
|
+
class HelperMethod < BooleanMethod
|
158
|
+
def initialize(subject_method, method)
|
159
|
+
super
|
160
|
+
|
161
|
+
@controller = 'controller'
|
162
|
+
end
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
require_relative "controller_extensions/generators"
|
2
|
+
|
3
|
+
module Acl9
|
4
|
+
module ControllerExtensions
|
5
|
+
def self.included(base)
|
6
|
+
base.extend(ClassMethods)
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def access_control(*args, &block)
|
11
|
+
opts = args.extract_options!
|
12
|
+
|
13
|
+
case args.size
|
14
|
+
when 0 then true
|
15
|
+
when 1
|
16
|
+
meth = args.first
|
17
|
+
|
18
|
+
if meth.is_a? Symbol
|
19
|
+
opts[:as_method] = meth
|
20
|
+
else
|
21
|
+
raise ArgumentError, "access_control argument must be a :symbol!"
|
22
|
+
end
|
23
|
+
else
|
24
|
+
raise ArgumentError, "Invalid arguments for access_control"
|
25
|
+
end
|
26
|
+
|
27
|
+
subject_method = opts[:subject_method] || Acl9::config[:default_subject_method]
|
28
|
+
|
29
|
+
raise ArgumentError, "Block must be supplied to access_control" unless block
|
30
|
+
|
31
|
+
filter = opts[:filter]
|
32
|
+
filter = true if filter.nil?
|
33
|
+
|
34
|
+
case helper = opts[:helper]
|
35
|
+
when true
|
36
|
+
raise ArgumentError, "you should specify :helper => :method_name" if !opts[:as_method]
|
37
|
+
when nil then nil
|
38
|
+
else
|
39
|
+
if opts[:as_method]
|
40
|
+
raise ArgumentError, "you can't specify both method name and helper name"
|
41
|
+
else
|
42
|
+
opts[:as_method] = helper
|
43
|
+
filter = false
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
method = opts[:as_method]
|
48
|
+
|
49
|
+
query_method_available = true
|
50
|
+
generator = case
|
51
|
+
when method && filter
|
52
|
+
Acl9::Dsl::Generators::FilterMethod.new(subject_method, method)
|
53
|
+
when method && !filter
|
54
|
+
query_method_available = false
|
55
|
+
Acl9::Dsl::Generators::BooleanMethod.new(subject_method, method)
|
56
|
+
else
|
57
|
+
Acl9::Dsl::Generators::FilterLambda.new(subject_method)
|
58
|
+
end
|
59
|
+
|
60
|
+
generator.acl_block!(&block)
|
61
|
+
|
62
|
+
generator.install_on(self, opts)
|
63
|
+
|
64
|
+
if query_method_available && (query_method = opts.delete(:query_method))
|
65
|
+
case query_method
|
66
|
+
when true
|
67
|
+
if method
|
68
|
+
query_method = "#{method}?"
|
69
|
+
else
|
70
|
+
raise ArgumentError, "You must specify :query_method as Symbol"
|
71
|
+
end
|
72
|
+
when Symbol, String
|
73
|
+
# okay here
|
74
|
+
else
|
75
|
+
raise ArgumentError, "Invalid value for :query_method"
|
76
|
+
end
|
77
|
+
|
78
|
+
second_generator = Acl9::Dsl::Generators::BooleanMethod.new(subject_method, query_method)
|
79
|
+
second_generator.acl_block!(&block)
|
80
|
+
second_generator.install_on(self, opts)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/lib/acl9/helpers.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
module Acl9
|
2
|
+
module Helpers
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def access_control(method, opts = {}, &block)
|
9
|
+
subject_method = opts.delete(:subject_method) || Acl9::config[:default_subject_method]
|
10
|
+
raise ArgumentError, "Block must be supplied to access_control" unless block
|
11
|
+
|
12
|
+
generator = Acl9::Dsl::Generators::HelperMethod.new(subject_method, method)
|
13
|
+
|
14
|
+
generator.acl_block!(&block)
|
15
|
+
generator.install_on(self, opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
|
20
|
+
# Usage:
|
21
|
+
#
|
22
|
+
# <%=show_to(:owner, :supervisor, :of => :account) do %>
|
23
|
+
# <%= 'hello' %>
|
24
|
+
# <% end %>
|
25
|
+
#
|
26
|
+
def show_to(*args, &block)
|
27
|
+
user = send(Acl9.config[:default_subject_method])
|
28
|
+
return if user.nil?
|
29
|
+
|
30
|
+
has_any = false
|
31
|
+
|
32
|
+
if args.last.is_a?(Hash)
|
33
|
+
an_obj = args.pop.values.first
|
34
|
+
has_any = args.detect { |role| user.has_role?(role, an_obj) }
|
35
|
+
else
|
36
|
+
has_any = args.detect { |role| user.has_role?(role) }
|
37
|
+
end
|
38
|
+
|
39
|
+
if has_any
|
40
|
+
begin
|
41
|
+
capture( &block )
|
42
|
+
rescue NoMethodError
|
43
|
+
yield( :block )
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module Acl9
|
2
|
+
module ModelExtensions
|
3
|
+
module ForObject
|
4
|
+
##
|
5
|
+
# Role check.
|
6
|
+
#
|
7
|
+
# @return [Boolean] Returns true if +subject+ has a role +role_name+ on this object.
|
8
|
+
#
|
9
|
+
# @param [Symbol,String] role_name Role name
|
10
|
+
# @param [Subject] subject Subject to add role for
|
11
|
+
# @see Acl9::ModelExtensions::Subject#has_role?
|
12
|
+
def accepts_role?(role_name, subject)
|
13
|
+
if not subject.nil?
|
14
|
+
return subject.has_role? role_name, self
|
15
|
+
end
|
16
|
+
false
|
17
|
+
end
|
18
|
+
|
19
|
+
##
|
20
|
+
# Add role on the object to specified subject.
|
21
|
+
#
|
22
|
+
# @param [Symbol,String] role_name Role name
|
23
|
+
# @param [Subject] subject Subject to add role for
|
24
|
+
# @see Acl9::ModelExtensions::Subject#has_role!
|
25
|
+
def accepts_role!(role_name, subject)
|
26
|
+
if not subject.nil?
|
27
|
+
return subject.has_role! role_name, self
|
28
|
+
end
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Free specified subject of a role on this object.
|
34
|
+
#
|
35
|
+
# @param [Symbol,String] role_name Role name
|
36
|
+
# @param [Subject] subject Subject to remove role from
|
37
|
+
# @see Acl9::ModelExtensions::Subject#has_no_role!
|
38
|
+
def accepts_no_role!(role_name, subject)
|
39
|
+
if not subject.nil?
|
40
|
+
return subject.has_no_role! role_name, self
|
41
|
+
end
|
42
|
+
false
|
43
|
+
end
|
44
|
+
|
45
|
+
##
|
46
|
+
# Are there any roles for the specified +subject+ on this object?
|
47
|
+
#
|
48
|
+
# @param [Subject] subject Subject to query roles
|
49
|
+
# @return [Boolean] Returns true if +subject+ has any roles on this object.
|
50
|
+
# @see Acl9::ModelExtensions::Subject#has_roles_for?
|
51
|
+
def accepts_roles_by?(subject)
|
52
|
+
if not subject.nil?
|
53
|
+
return subject.has_roles_for? self
|
54
|
+
end
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
alias :accepts_role_by? :accepts_roles_by?
|
59
|
+
|
60
|
+
##
|
61
|
+
# Which roles does +subject+ have on this object?
|
62
|
+
#
|
63
|
+
# @return [Array<Role>] Role instances, associated both with +subject+ and +object+
|
64
|
+
# @param [Subject] subject Subject to query roles
|
65
|
+
# @see Acl9::ModelExtensions::Subject#roles_for
|
66
|
+
def accepted_roles_by(subject)
|
67
|
+
if not subject.nil?
|
68
|
+
return subject.roles_for self
|
69
|
+
end
|
70
|
+
false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|