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.
Files changed (52) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +3 -0
  3. data/.ruby-version +1 -1
  4. data/.travis.yml +27 -11
  5. data/Appraisals +13 -6
  6. data/Gemfile +0 -2
  7. data/Gemfile.lock +125 -112
  8. data/README.md +11 -4
  9. data/Rakefile +0 -2
  10. data/acl9.gemspec +1 -3
  11. data/gemfiles/.bundle/config +2 -0
  12. data/gemfiles/rails_5.0.gemfile +10 -0
  13. data/gemfiles/rails_5.1.gemfile +10 -0
  14. data/gemfiles/{rails_4.0.gemfile → rails_5.2.gemfile} +2 -4
  15. data/gemfiles/{rails_4.1.gemfile → rails_6.0.gemfile} +2 -4
  16. data/gemfiles/{rails_4.2.gemfile → rails_6.1.gemfile} +2 -4
  17. data/lib/acl9.rb +40 -0
  18. data/lib/acl9/controller_extensions.rb +1 -1
  19. data/lib/acl9/controller_extensions/dsl_base.rb +8 -7
  20. data/lib/acl9/controller_extensions/generators.rb +4 -35
  21. data/lib/acl9/model_extensions.rb +3 -3
  22. data/lib/acl9/model_extensions/for_subject.rb +52 -31
  23. data/lib/acl9/version.rb +1 -1
  24. data/lib/generators/acl9/setup/setup_generator.rb +10 -3
  25. data/lib/generators/acl9/setup/templates/create_role_tables.rb +10 -1
  26. data/lib/generators/acl9/setup/templates/role.rb +1 -1
  27. data/test/controller_extensions/actions_test.rb +1 -1
  28. data/test/controller_extensions/multiple_role_arguments_test.rb +11 -10
  29. data/test/controllers/acl_action_override_test.rb +4 -4
  30. data/test/controllers/acl_helper_method_test.rb +6 -3
  31. data/test/controllers/acl_ivars_test.rb +2 -2
  32. data/test/controllers/acl_object_hash_test.rb +1 -1
  33. data/test/controllers/acl_query_mixin.rb +5 -2
  34. data/test/controllers/acl_subject_method_test.rb +1 -1
  35. data/test/controllers/arguments_checking_test.rb +4 -4
  36. data/test/dummy/app/assets/config/manifest.js +0 -0
  37. data/test/dummy/app/controllers/acl_action_override.rb +5 -5
  38. data/test/dummy/app/controllers/acl_boolean_method.rb +6 -6
  39. data/test/dummy/app/controllers/acl_ivars.rb +3 -3
  40. data/test/dummy/app/controllers/acl_query_method_named.rb +2 -0
  41. data/test/dummy/app/controllers/application_controller.rb +6 -0
  42. data/test/dummy/app/controllers/empty_controller.rb +1 -1
  43. data/test/dummy/app/models/string_object_role.rb +3 -0
  44. data/test/dummy/app/models/string_user.rb +3 -0
  45. data/test/dummy/app/models/uuid.rb +1 -1
  46. data/test/dummy/config/environments/test.rb +2 -2
  47. data/test/dummy/config/routes.rb +12 -1
  48. data/test/dummy/db/migrate/20141117132218_create_tables.rb +68 -18
  49. data/test/models/roles_test.rb +13 -1
  50. data/test/test_helper.rb +31 -28
  51. metadata +26 -29
  52. data/test/dummy/config/environments/production.rb +0 -78
@@ -0,0 +1,10 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "http://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "byebug"
7
+ gem "rails", "~> 5.1.0"
8
+ gem "sqlite3", "~> 1.3.6", :group => :development
9
+
10
+ gemspec path: "../"
@@ -3,9 +3,7 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
- gem "tapout"
7
- gem "minitap"
8
6
  gem "byebug"
9
- gem "rails", "~> 4.0.0"
7
+ gem "rails", "~> 5.2.0"
10
8
 
11
- gemspec :path => "../"
9
+ gemspec path: "../"
@@ -3,9 +3,7 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
- gem "tapout"
7
- gem "minitap"
8
6
  gem "byebug"
9
- gem "rails", "~> 4.1.0"
7
+ gem "rails", "~> 6.0.0"
10
8
 
11
- gemspec :path => "../"
9
+ gemspec path: "../"
@@ -3,9 +3,7 @@
3
3
  source "http://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
- gem "tapout"
7
- gem "minitap"
8
6
  gem "byebug"
9
- gem "rails", "~> 4.2.0"
7
+ gem "rails", "~> 6.1.0"
10
8
 
11
- gemspec :path => "../"
9
+ gemspec path: "../"
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
- 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
@@ -1,4 +1,4 @@
1
- require File.expand_path '../../prepositions', __FILE__
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
- object = _role_object(options)
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}', #{object})"
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 _role_object(options)
183
+ def _role_object_s(options)
183
184
  object = _by_preposition options
184
185
 
185
186
  case object
186
- when Class then object.to_s
187
- when Symbol then _object_ref object
188
- when nil then "nil"
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
- require File.join(File.dirname(__FILE__), 'dsl_base')
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(:before_filter, options, &self.to_proc)
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(:before_filter, @method_name, options)
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.empty? ? self.action_name : args.first.to_s
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
- 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:
@@ -129,7 +129,7 @@ module Acl9
129
129
  :class_name => subject,
130
130
  :join_table => join_table
131
131
 
132
- belongs_to :authorizable, :polymorphic => true
132
+ belongs_to :authorizable, polymorphic: true, optional: true
133
133
  end
134
134
  end
135
135
  end
@@ -1,10 +1,16 @@
1
- require File.expand_path '../../prepositions', __FILE__
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 = nil)
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.nil? && !::Acl9.config[:protect_global_roles]
46
- self._role_objects.find_by_name(role_name.to_s) ||
47
- self._role_objects.member?(get_role(role_name, nil))
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 && self._role_objects.exists?(role.id)
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 = nil)
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 then { :authorizable_type => object.to_s }
69
- when nil then {}
70
- else { :authorizable => object }
71
- end.merge( { :name => role_name.to_s })
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 = self._auth_role_class.create(role_attrs)
81
+ role = _auth_role_class.create(role_attrs)
74
82
  end
75
83
 
76
- self._role_objects << role if role && !self._role_objects.exists?(role.id)
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 = nil)
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
- !!self._role_objects.detect(&role_selecting_lambda(object))
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
- self._role_objects.select(&role_selecting_lambda(object))
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,nil] object Object to unassign roles for. +nil+ means unassign global roles.
122
- def has_no_roles_for!(object = nil)
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
- # self.roles.each { |role| delete_role(role) }
143
+ # roles.each { |role| delete_role(role) }
132
144
  #
133
145
  # doesn't work. seems like a bug in ActiveRecord
134
- self._role_objects.map(&:id).each do |role_id|
135
- delete_role self._auth_role_class.find(role_id)
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 nil
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 nil
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 self._auth_role_class.respond_to?(:where)
171
- self._auth_role_class.where(cond).first
183
+ if _auth_role_class.respond_to?(:where)
184
+ _auth_role_class.where(cond).first
172
185
  else
173
- self._auth_role_class.find(:first, :conditions => cond)
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 = self._role_objects.delete(role)
180
- if role.send(self._auth_subject_class_name.demodulize.tableize).empty?
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
- protected
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(self._auth_role_assoc)
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
@@ -1,3 +1,3 @@
1
1
  module Acl9
2
- VERSION = "2.1.0"
2
+ VERSION = "3.2.0"
3
3
  end
@@ -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 create_migration
14
- next_migration_number = self.class.next_migration_number( File.expand_path( '../db/migrate', __FILE__))
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