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.
Files changed (141) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +22 -0
  5. data/Appraisals +11 -0
  6. data/CHANGELOG.md +114 -0
  7. data/CONTRIBUTING.md +62 -0
  8. data/Gemfile +9 -0
  9. data/Gemfile.lock +141 -0
  10. data/LICENSE +9 -0
  11. data/README.md +308 -0
  12. data/Rakefile +9 -27
  13. data/acl9.gemspec +29 -0
  14. data/bin/appraisal +16 -0
  15. data/bin/bundler +16 -0
  16. data/bin/cc-tddium-post-worker +16 -0
  17. data/bin/erubis +16 -0
  18. data/bin/rackup +16 -0
  19. data/bin/rails +16 -0
  20. data/bin/rake +16 -0
  21. data/bin/sprockets +16 -0
  22. data/bin/tapout +16 -0
  23. data/bin/thor +16 -0
  24. data/bin/tilt +16 -0
  25. data/bin/yard +16 -0
  26. data/bin/yardoc +16 -0
  27. data/bin/yri +16 -0
  28. data/gemfiles/rails_4.0.gemfile +10 -0
  29. data/gemfiles/rails_4.1.gemfile +10 -0
  30. data/gemfiles/rails_4.2.gemfile +10 -0
  31. data/lib/acl9/controller_extensions/dsl_base.rb +36 -55
  32. data/lib/acl9/controller_extensions/generators.rb +1 -1
  33. data/lib/acl9/controller_extensions.rb +1 -1
  34. data/lib/acl9/helpers.rb +12 -5
  35. data/lib/acl9/model_extensions/for_object.rb +20 -5
  36. data/lib/acl9/model_extensions/for_subject.rb +48 -21
  37. data/lib/acl9/model_extensions.rb +22 -25
  38. data/lib/acl9/prepositions.rb +18 -0
  39. data/lib/acl9/version.rb +3 -0
  40. data/lib/acl9.rb +36 -10
  41. data/lib/generators/acl9/setup/USAGE +35 -0
  42. data/lib/generators/acl9/setup/setup_generator.rb +115 -0
  43. data/lib/generators/acl9/setup/templates/create_role_tables.rb +22 -0
  44. data/lib/generators/acl9/setup/templates/role.rb +3 -0
  45. data/test/config_test.rb +55 -0
  46. data/test/controller_extensions/actions_test.rb +199 -0
  47. data/test/controller_extensions/anon_test.rb +39 -0
  48. data/test/controller_extensions/base.rb +96 -0
  49. data/test/controller_extensions/basics_test.rb +44 -0
  50. data/test/controller_extensions/conditions_test.rb +48 -0
  51. data/test/controller_extensions/method_test.rb +70 -0
  52. data/test/controller_extensions/multi_match_test.rb +142 -0
  53. data/test/controller_extensions/multiple_role_arguments_test.rb +135 -0
  54. data/test/controller_extensions/prepositions_test.rb +108 -0
  55. data/test/controller_extensions/pseudo_role_test.rb +26 -0
  56. data/test/controller_extensions/role_test.rb +75 -0
  57. data/test/controllers/acl_action_override_test.rb +24 -0
  58. data/test/controllers/acl_arguments_test.rb +5 -0
  59. data/test/controllers/acl_block_test.rb +5 -0
  60. data/test/controllers/acl_boolean_method_test.rb +5 -0
  61. data/test/controllers/acl_helper_method_test.rb +26 -0
  62. data/test/controllers/acl_ivars_test.rb +15 -0
  63. data/test/controllers/acl_method2_test.rb +6 -0
  64. data/test/controllers/acl_method_test.rb +6 -0
  65. data/test/controllers/acl_object_hash_test.rb +18 -0
  66. data/test/controllers/acl_query_method_named_test.rb +9 -0
  67. data/test/controllers/acl_query_method_test.rb +9 -0
  68. data/test/controllers/acl_query_method_with_lambda_test.rb +9 -0
  69. data/test/controllers/acl_query_mixin.rb +51 -0
  70. data/test/controllers/acl_subject_method_test.rb +15 -0
  71. data/test/controllers/arguments_checking_test.rb +43 -0
  72. data/test/dummy/app/controllers/acl_action_override.rb +15 -0
  73. data/test/dummy/app/controllers/acl_arguments.rb +10 -0
  74. data/test/dummy/app/controllers/acl_block.rb +6 -0
  75. data/test/dummy/app/controllers/acl_boolean_method.rb +23 -0
  76. data/test/dummy/app/controllers/acl_helper_method.rb +11 -0
  77. data/test/dummy/app/controllers/acl_ivars.rb +17 -0
  78. data/test/dummy/app/controllers/acl_method.rb +6 -0
  79. data/test/dummy/app/controllers/acl_method2.rb +6 -0
  80. data/test/dummy/app/controllers/acl_objects_hash.rb +10 -0
  81. data/test/dummy/app/controllers/acl_query_method.rb +9 -0
  82. data/test/dummy/app/controllers/acl_query_method_named.rb +13 -0
  83. data/test/dummy/app/controllers/acl_query_method_with_lambda.rb +9 -0
  84. data/test/dummy/app/controllers/acl_subject_method.rb +16 -0
  85. data/test/dummy/app/controllers/application_controller.rb +7 -0
  86. data/test/dummy/app/controllers/empty_controller.rb +5 -0
  87. data/test/dummy/app/helpers/application_helper.rb +2 -0
  88. data/test/dummy/app/helpers/some_helper.rb +8 -0
  89. data/test/dummy/app/models/.keep +0 -0
  90. data/test/dummy/app/models/access.rb +3 -0
  91. data/test/dummy/app/models/account.rb +3 -0
  92. data/test/dummy/app/models/bar.rb +3 -0
  93. data/test/dummy/app/models/concerns/.keep +0 -0
  94. data/test/dummy/app/models/foo.rb +3 -0
  95. data/test/dummy/app/models/foo_bar.rb +3 -0
  96. data/test/dummy/app/models/other/foo.rb +5 -0
  97. data/test/dummy/app/models/other/role.rb +5 -0
  98. data/test/dummy/app/models/other/user.rb +5 -0
  99. data/test/dummy/app/models/role.rb +3 -0
  100. data/test/dummy/app/models/user.rb +3 -0
  101. data/test/dummy/app/models/uuid.rb +4 -0
  102. data/test/dummy/config/application.rb +23 -0
  103. data/test/dummy/config/boot.rb +4 -0
  104. data/test/dummy/config/database.yml +25 -0
  105. data/test/dummy/config/environment.rb +5 -0
  106. data/test/dummy/config/environments/development.rb +37 -0
  107. data/test/dummy/config/environments/production.rb +78 -0
  108. data/test/dummy/config/environments/test.rb +40 -0
  109. data/test/dummy/config/initializers/assets.rb +8 -0
  110. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  111. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  112. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  113. data/test/dummy/config/initializers/inflections.rb +16 -0
  114. data/test/dummy/config/initializers/mime_types.rb +4 -0
  115. data/test/dummy/config/initializers/secrets.rb +1 -0
  116. data/test/dummy/config/initializers/session_store.rb +3 -0
  117. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  118. data/test/dummy/config/locales/en.yml +23 -0
  119. data/test/dummy/config/routes.rb +3 -0
  120. data/test/dummy/config.ru +4 -0
  121. data/test/dummy/db/migrate/20141117132218_create_tables.rb +99 -0
  122. data/test/helpers/helper_test.rb +89 -0
  123. data/test/models/roles_test.rb +357 -0
  124. data/test/models/roles_with_custom_association_names_test.rb +28 -0
  125. data/test/models/roles_with_custom_class_names_test.rb +28 -0
  126. data/test/models/system_roles_test.rb +22 -0
  127. data/test/models/users_roles_and_subjects_with_namespaced_class_names_test.rb +30 -0
  128. data/test/test_helper.rb +80 -20
  129. data/test/version_test.rb +7 -0
  130. metadata +290 -71
  131. data/CHANGELOG.textile +0 -46
  132. data/README.textile +0 -903
  133. data/VERSION.yml +0 -5
  134. data/lib/acl9/config.rb +0 -11
  135. data/test/access_control_test.rb +0 -338
  136. data/test/dsl_base_test.rb +0 -795
  137. data/test/helpers_test.rb +0 -134
  138. data/test/roles_test.rb +0 -355
  139. data/test/support/controllers.rb +0 -207
  140. data/test/support/models.rb +0 -59
  141. 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
- if @default_action.nil? then :deny else @default_action end
22
+ @default_action.nil? ? :deny : @default_action
21
23
  end
22
24
 
23
25
  def allowance_expression
24
- allowed_expr = if @allows.size > 0
25
- @allows.map { |clause| "(#{clause})" }.join(' || ')
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(to, except)
80
- raise ArgumentError, "You cannot use :to/:except inside actions block" if to || except
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.delete(:to), options.delete(:except))
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() then "#{_subject_ref}.nil?"
116
- when logged_in() then "!#{_subject_ref}.nil?"
117
- when all() then "true"
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.to_s.singularize}', #{object})"
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(to, except)
157
- raise ArgumentError, "both :to and :except cannot be specified in the rule" if to && except
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
- action_list = to || except
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 = nil
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
- object.to_s
204
- when Symbol
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
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'dsl_base')
1
+ require_relative "dsl_base"
2
2
 
3
3
  module Acl9
4
4
  ##
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'controller_extensions', 'generators')
1
+ require_relative "controller_extensions/generators"
2
2
 
3
3
  module Acl9
4
4
  module ControllerExtensions
data/lib/acl9/helpers.rb CHANGED
@@ -19,13 +19,13 @@ module Acl9
19
19
 
20
20
  # Usage:
21
21
  #
22
- # <% show_to(:owner, :supervisor, :of => :account) do -%>
22
+ # <%=show_to(:owner, :supervisor, :of => :account) do %>
23
23
  # <%= 'hello' %>
24
- # <%- end -%>
24
+ # <% end %>
25
25
  #
26
26
  def show_to(*args, &block)
27
- user = eval(Acl9.config[:default_subject_method].to_s)
28
- return '' if user.nil?
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 ? yield(:block) : ''
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.has_role? role_name, self
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.has_role! role_name, self
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.has_no_role! role_name, self
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.has_roles_for? self
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.roles_for self
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.role_objects.find_by_name(role_name.to_s) ||
40
- self.role_objects.member?(get_role(role_name, nil))
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.role_objects.exists?(role.id)
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.role_objects << role if role && !self.role_objects.exists?(role.id)
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.role_objects.detect(&role_selecting_lambda(object))
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.role_objects.select(&role_selecting_lambda(object))
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.role_objects.map(&:id).each do |role_id|
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.authorizable_type == object.class.base_class.to_s && role.authorizable == object
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.to_s
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.first :conditions => cond
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.role_objects.delete role
163
-
164
- role.destroy if role.send(self._auth_subject_class_name.demodulize.tableize).empty?
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
- self.class._auth_role_assoc_name
203
+ self.class._auth_role_assoc_name
176
204
  end
177
205
 
178
- def role_objects
179
- send(self._auth_role_assoc)
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
- require File.join(File.dirname(__FILE__), 'model_extensions', 'for_subject')
2
- require File.join(File.dirname(__FILE__), 'model_extensions', 'for_object')
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.roles #=> returns Role objects, associated with the 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
- assoc = options[:association_name] || Acl9::config[:default_association_name]
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
- join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(role))
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
- has_and_belongs_to_many assoc, :class_name => role, :join_table => join_table
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 = options[:role_class_name] || Acl9::config[:default_role_class_name]
80
- role_table = role.constantize.table_name
79
+ role = options[:role_class_name] || Acl9::config[:default_role_class_name]
81
80
 
82
- sql_tables = <<-EOS
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
- sql_where = <<-'EOS'
89
- WHERE authorizable_type = '#{self.class.base_class.to_s}'
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
- has_many :accepted_roles, :as => :authorizable, :class_name => role, :dependent => :destroy
86
+ define_method subj_table.to_sym do |role_name=nil|
87
+ rel = send subj_assoc
94
88
 
95
- has_many :"#{subj_table}",
96
- :finder_sql => ("SELECT DISTINCT #{subj_table}.*" + sql_tables + sql_where),
97
- :counter_sql => ("SELECT COUNT(DISTINCT #{subj_table}.id)" + sql_tables + sql_where),
98
- :readonly => true
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
- join_table_name(undecorated_table_name(self.to_s), undecorated_table_name(subject))
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
@@ -0,0 +1,3 @@
1
+ module Acl9
2
+ VERSION = "2.1.2"
3
+ end
data/lib/acl9.rb CHANGED
@@ -1,16 +1,42 @@
1
- require File.join(File.dirname(__FILE__), 'acl9', 'config')
1
+ require 'acl9/version'
2
+ require 'acl9/model_extensions'
3
+ require 'acl9/controller_extensions'
4
+ require 'acl9/helpers'
2
5
 
3
- if defined? ActiveRecord::Base
4
- require File.join(File.dirname(__FILE__), 'acl9', 'model_extensions')
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
- ActiveRecord::Base.send(:include, Acl9::ModelExtensions)
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
- if defined? ActionController::Base
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
- ActionController::Base.send(:include, Acl9::ControllerExtensions)
15
- Acl9Helpers = Acl9::Helpers unless defined?(Acl9Helpers)
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
+