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.
Files changed (138) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +26 -0
  5. data/Appraisals +23 -0
  6. data/CHANGELOG.md +122 -0
  7. data/CONTRIBUTING.md +62 -0
  8. data/Gemfile +7 -0
  9. data/Gemfile.lock +167 -0
  10. data/LICENSE +9 -0
  11. data/MIT-LICENSE +20 -0
  12. data/README.md +326 -0
  13. data/Rakefile +20 -0
  14. data/TODO +42 -0
  15. data/acl9.gemspec +27 -0
  16. data/bin/appraisal +16 -0
  17. data/bin/bundler +16 -0
  18. data/bin/cc-tddium-post-worker +16 -0
  19. data/bin/erubis +16 -0
  20. data/bin/rackup +16 -0
  21. data/bin/rails +16 -0
  22. data/bin/rake +16 -0
  23. data/bin/sprockets +16 -0
  24. data/bin/tapout +16 -0
  25. data/bin/thor +16 -0
  26. data/bin/tilt +16 -0
  27. data/bin/yard +16 -0
  28. data/bin/yardoc +16 -0
  29. data/bin/yri +16 -0
  30. data/gemfiles/.bundle/config +2 -0
  31. data/gemfiles/rails_5.0.gemfile +10 -0
  32. data/gemfiles/rails_5.1.gemfile +10 -0
  33. data/gemfiles/rails_5.2.gemfile +9 -0
  34. data/gemfiles/rails_6.0.gemfile +9 -0
  35. data/gemfiles/rails_6.1.gemfile +9 -0
  36. data/gemfiles/rails_7.0.gemfile +9 -0
  37. data/lib/acl9/controller_extensions/dsl_base.rb +212 -0
  38. data/lib/acl9/controller_extensions/generators.rb +166 -0
  39. data/lib/acl9/controller_extensions.rb +85 -0
  40. data/lib/acl9/helpers.rb +49 -0
  41. data/lib/acl9/model_extensions/for_object.rb +74 -0
  42. data/lib/acl9/model_extensions/for_subject.rb +232 -0
  43. data/lib/acl9/model_extensions.rb +136 -0
  44. data/lib/acl9/prepositions.rb +18 -0
  45. data/lib/acl9/version.rb +3 -0
  46. data/lib/acl9.rb +78 -0
  47. data/lib/generators/acl9/setup/USAGE +35 -0
  48. data/lib/generators/acl9/setup/setup_generator.rb +122 -0
  49. data/lib/generators/acl9/setup/templates/create_role_tables.rb +31 -0
  50. data/lib/generators/acl9/setup/templates/role.rb +3 -0
  51. data/test/config_test.rb +55 -0
  52. data/test/controller_extensions/actions_test.rb +199 -0
  53. data/test/controller_extensions/anon_test.rb +39 -0
  54. data/test/controller_extensions/base.rb +96 -0
  55. data/test/controller_extensions/basics_test.rb +44 -0
  56. data/test/controller_extensions/conditions_test.rb +48 -0
  57. data/test/controller_extensions/method_test.rb +70 -0
  58. data/test/controller_extensions/multi_match_test.rb +142 -0
  59. data/test/controller_extensions/multiple_role_arguments_test.rb +136 -0
  60. data/test/controller_extensions/prepositions_test.rb +108 -0
  61. data/test/controller_extensions/pseudo_role_test.rb +26 -0
  62. data/test/controller_extensions/role_test.rb +75 -0
  63. data/test/controllers/acl_action_override_test.rb +24 -0
  64. data/test/controllers/acl_arguments_test.rb +5 -0
  65. data/test/controllers/acl_block_test.rb +5 -0
  66. data/test/controllers/acl_boolean_method_test.rb +5 -0
  67. data/test/controllers/acl_helper_method_test.rb +29 -0
  68. data/test/controllers/acl_ivars_test.rb +15 -0
  69. data/test/controllers/acl_method2_test.rb +6 -0
  70. data/test/controllers/acl_method_test.rb +6 -0
  71. data/test/controllers/acl_object_hash_test.rb +18 -0
  72. data/test/controllers/acl_query_method_named_test.rb +9 -0
  73. data/test/controllers/acl_query_method_test.rb +9 -0
  74. data/test/controllers/acl_query_method_with_lambda_test.rb +9 -0
  75. data/test/controllers/acl_query_mixin.rb +54 -0
  76. data/test/controllers/acl_subject_method_test.rb +15 -0
  77. data/test/controllers/arguments_checking_test.rb +43 -0
  78. data/test/dummy/app/assets/config/manifest.js +0 -0
  79. data/test/dummy/app/controllers/acl_action_override.rb +15 -0
  80. data/test/dummy/app/controllers/acl_arguments.rb +10 -0
  81. data/test/dummy/app/controllers/acl_block.rb +6 -0
  82. data/test/dummy/app/controllers/acl_boolean_method.rb +23 -0
  83. data/test/dummy/app/controllers/acl_helper_method.rb +11 -0
  84. data/test/dummy/app/controllers/acl_ivars.rb +17 -0
  85. data/test/dummy/app/controllers/acl_method.rb +6 -0
  86. data/test/dummy/app/controllers/acl_method2.rb +6 -0
  87. data/test/dummy/app/controllers/acl_objects_hash.rb +10 -0
  88. data/test/dummy/app/controllers/acl_query_method.rb +9 -0
  89. data/test/dummy/app/controllers/acl_query_method_named.rb +15 -0
  90. data/test/dummy/app/controllers/acl_query_method_with_lambda.rb +9 -0
  91. data/test/dummy/app/controllers/acl_subject_method.rb +16 -0
  92. data/test/dummy/app/controllers/application_controller.rb +13 -0
  93. data/test/dummy/app/controllers/empty_controller.rb +5 -0
  94. data/test/dummy/app/helpers/application_helper.rb +2 -0
  95. data/test/dummy/app/helpers/some_helper.rb +8 -0
  96. data/test/dummy/app/models/.keep +0 -0
  97. data/test/dummy/app/models/access.rb +3 -0
  98. data/test/dummy/app/models/account.rb +3 -0
  99. data/test/dummy/app/models/bar.rb +3 -0
  100. data/test/dummy/app/models/concerns/.keep +0 -0
  101. data/test/dummy/app/models/foo.rb +3 -0
  102. data/test/dummy/app/models/foo_bar.rb +3 -0
  103. data/test/dummy/app/models/other/foo.rb +5 -0
  104. data/test/dummy/app/models/other/role.rb +5 -0
  105. data/test/dummy/app/models/other/user.rb +5 -0
  106. data/test/dummy/app/models/role.rb +3 -0
  107. data/test/dummy/app/models/string_object_role.rb +3 -0
  108. data/test/dummy/app/models/string_user.rb +3 -0
  109. data/test/dummy/app/models/user.rb +3 -0
  110. data/test/dummy/app/models/uuid.rb +4 -0
  111. data/test/dummy/config/application.rb +23 -0
  112. data/test/dummy/config/boot.rb +4 -0
  113. data/test/dummy/config/database.yml +25 -0
  114. data/test/dummy/config/environment.rb +5 -0
  115. data/test/dummy/config/environments/development.rb +37 -0
  116. data/test/dummy/config/environments/test.rb +40 -0
  117. data/test/dummy/config/initializers/assets.rb +8 -0
  118. data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
  119. data/test/dummy/config/initializers/cookies_serializer.rb +3 -0
  120. data/test/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  121. data/test/dummy/config/initializers/inflections.rb +16 -0
  122. data/test/dummy/config/initializers/mime_types.rb +4 -0
  123. data/test/dummy/config/initializers/secrets.rb +1 -0
  124. data/test/dummy/config/initializers/session_store.rb +3 -0
  125. data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
  126. data/test/dummy/config/locales/en.yml +23 -0
  127. data/test/dummy/config/routes.rb +14 -0
  128. data/test/dummy/config.ru +4 -0
  129. data/test/dummy/db/migrate/20141117132218_create_tables.rb +149 -0
  130. data/test/helpers/helper_test.rb +89 -0
  131. data/test/models/roles_test.rb +369 -0
  132. data/test/models/roles_with_custom_association_names_test.rb +28 -0
  133. data/test/models/roles_with_custom_class_names_test.rb +28 -0
  134. data/test/models/system_roles_test.rb +22 -0
  135. data/test/models/users_roles_and_subjects_with_namespaced_class_names_test.rb +30 -0
  136. data/test/test_helper.rb +94 -0
  137. data/test/version_test.rb +7 -0
  138. metadata +321 -0
@@ -0,0 +1,232 @@
1
+ require_relative "../prepositions"
2
+
3
+ module Acl9
4
+ module ModelExtensions
5
+ module ForSubject
6
+ include Prepositions
7
+
8
+ DEFAULT = Class.new do
9
+ def default?
10
+ true
11
+ end
12
+ end.new.freeze
13
+
14
+ ##
15
+ # Role check.
16
+ #
17
+ # There is a global option, +Acl9.config[:protect_global_roles]+, which governs
18
+ # this method behavior.
19
+ #
20
+ # If protect_global_roles is +false+, an object role is automatically counted
21
+ # as global role. E.g.
22
+ #
23
+ # Acl9.config[:protect_global_roles] = false
24
+ # user.has_role!(:manager, @foo)
25
+ # user.has_role?(:manager, @foo) # => true
26
+ # user.has_role?(:manager) # => true
27
+ #
28
+ # In this case manager is anyone who "manages" at least one object.
29
+ #
30
+ # However, if protect_global_roles option set to +true+, you'll need to
31
+ # explicitly grant global role with same name.
32
+ #
33
+ # Acl9.config[:protect_global_roles] = true
34
+ # user.has_role!(:manager, @foo)
35
+ # user.has_role?(:manager) # => false
36
+ # user.has_role!(:manager)
37
+ # user.has_role?(:manager) # => true
38
+ #
39
+ # protect_global_roles option is +false+ by default as for now, but this
40
+ # may change in future!
41
+ #
42
+ # @return [Boolean] Whether +self+ has a role +role_name+ on +object+.
43
+ # @param [Symbol,String] role_name Role name
44
+ # @param [Object] object Object to query a role on
45
+ #
46
+ # @see Acl9::ModelExtensions::Object#accepts_role?
47
+ def has_role?(role_name, object = default)
48
+ check! object
49
+ role_name = normalize role_name
50
+ object = _by_preposition object
51
+
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))
55
+ else
56
+ role = get_role(role_name, object)
57
+ role && _role_objects.exists?(role.id)
58
+ end
59
+ end
60
+
61
+ ##
62
+ # Add specified role on +object+ to +self+.
63
+ #
64
+ # @param [Symbol,String] role_name Role name
65
+ # @param [Object] object Object to add a role for
66
+ # @see Acl9::ModelExtensions::Object#accepts_role!
67
+ def has_role!(role_name, object = default)
68
+ check! object
69
+ role_name = normalize role_name
70
+ object = _by_preposition object
71
+
72
+ role = get_role(role_name, object)
73
+
74
+ if role.nil?
75
+ role_attrs = case object
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 })
80
+
81
+ role = _auth_role_class.create(role_attrs)
82
+ end
83
+
84
+ _role_objects << role if role && !_role_objects.exists?(role.id)
85
+ end
86
+
87
+ ##
88
+ # Free +self+ from a specified role on +object+.
89
+ #
90
+ # @param [Symbol,String] role_name Role name
91
+ # @param [Object] object Object to remove a role on
92
+ # @see Acl9::ModelExtensions::Object#accepts_no_role!
93
+ def has_no_role!(role_name, object = default)
94
+ check! object
95
+ role_name = normalize role_name
96
+ object = _by_preposition object
97
+ delete_role(get_role(role_name, object))
98
+ end
99
+
100
+ ##
101
+ # Are there any roles for +self+ on +object+?
102
+ #
103
+ # @param [Object] object Object to query roles
104
+ # @return [Boolean] Returns true if +self+ has any roles on +object+.
105
+ # @see Acl9::ModelExtensions::Object#accepts_roles_by?
106
+ def has_roles_for?(object)
107
+ check! object
108
+ !!_role_objects.detect(&role_selecting_lambda(object))
109
+ end
110
+
111
+ alias :has_role_for? :has_roles_for?
112
+
113
+ ##
114
+ # Which roles does +self+ have on +object+?
115
+ #
116
+ # @return [Array<Role>] Role instances, associated both with +self+ and +object+
117
+ # @param [Object] object Object to query roles
118
+ # @see Acl9::ModelExtensions::Object#accepted_roles_by
119
+ # @example
120
+ # user = User.find(...)
121
+ # product = Product.find(...)
122
+ #
123
+ # user.roles_for(product).map(&:name).sort #=> role names in alphabetical order
124
+ def roles_for(object)
125
+ check! object
126
+ _role_objects.select(&role_selecting_lambda(object))
127
+ end
128
+
129
+ ##
130
+ # Unassign any roles on +object+ from +self+.
131
+ #
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
135
+ roles_for(object).each { |role| delete_role(role) }
136
+ end
137
+
138
+ ##
139
+ # Unassign all roles from +self+.
140
+ def has_no_roles!
141
+ # for some reason simple
142
+ #
143
+ # roles.each { |role| delete_role(role) }
144
+ #
145
+ # doesn't work. seems like a bug in ActiveRecord
146
+ _role_objects.map(&:id).each do |role_id|
147
+ delete_role _auth_role_class.find(role_id)
148
+ end
149
+ end
150
+
151
+ private
152
+
153
+ def role_selecting_lambda(object)
154
+ case object
155
+ when Class
156
+ lambda { |role| role.authorizable_type == object.to_s }
157
+ when default
158
+ lambda { |role| role.authorizable.nil? }
159
+ else
160
+ lambda do |role|
161
+ auth_id = role.authorizable_id.kind_of?(String) ? object.id.to_s : object.id
162
+ role.authorizable_type == object.class.base_class.to_s && role.authorizable_id == auth_id
163
+ end
164
+ end
165
+ end
166
+
167
+ def get_role(role_name, object = default)
168
+ check! object
169
+ role_name = normalize role_name
170
+
171
+ cond = case object
172
+ when Class
173
+ [ 'name = ? and authorizable_type = ? and authorizable_id IS NULL', role_name, object.to_s ]
174
+ when default
175
+ [ 'name = ? and authorizable_type IS NULL and authorizable_id IS NULL', role_name ]
176
+ else
177
+ [
178
+ 'name = ? and authorizable_type = ? and authorizable_id = ?',
179
+ role_name, object.class.base_class.to_s, object.id
180
+ ]
181
+ end
182
+
183
+ if _auth_role_class.respond_to?(:where)
184
+ _auth_role_class.where(cond).first
185
+ else
186
+ _auth_role_class.find(:first, :conditions => cond)
187
+ end
188
+ end
189
+
190
+ def delete_role(role)
191
+ if role
192
+ if ret = _role_objects.delete(role)
193
+ if role.send(_auth_subject_class_name.demodulize.tableize).empty?
194
+ ret &&= role.destroy unless role.respond_to?(:system?) && role.system?
195
+ end
196
+ end
197
+ ret
198
+ end
199
+ end
200
+
201
+ def normalize role_name
202
+ Acl9.config[:normalize_role_names] ? role_name.to_s.underscore.singularize : role_name.to_s
203
+ end
204
+
205
+ private
206
+
207
+ def check! object
208
+ raise NilObjectError if object.nil?
209
+ end
210
+
211
+ def _by_preposition object
212
+ object.is_a?(Hash) ? super : object
213
+ end
214
+
215
+ def _auth_role_class
216
+ self.class._auth_role_class_name.constantize
217
+ end
218
+
219
+ def _auth_role_assoc
220
+ self.class._auth_role_assoc_name
221
+ end
222
+
223
+ def _role_objects
224
+ send(_auth_role_assoc)
225
+ end
226
+
227
+ def default
228
+ DEFAULT
229
+ end
230
+ end
231
+ end
232
+ end
@@ -0,0 +1,136 @@
1
+ require_relative "model_extensions/for_subject"
2
+ require_relative "model_extensions/for_object"
3
+
4
+ module Acl9
5
+ module ModelExtensions #:nodoc:
6
+ def self.included(base)
7
+ base.extend(ClassMethods)
8
+ end
9
+
10
+ module ClassMethods
11
+ # Add #has_role? and other role methods to the class.
12
+ # Makes a class a auth. subject class.
13
+ #
14
+ # @param [Hash] options the options for tuning
15
+ # @option options [String] :role_class_name (Acl9::config[:default_role_class_name])
16
+ # Class name of the role class (e.g. 'AccountRole')
17
+ # @option options [String] :join_table_name (Acl9::config[:default_join_table_name])
18
+ # Join table name (e.g. 'accounts_account_roles')
19
+ # @option options [String] :association_name (Acl9::config[:default_association_name])
20
+ # Association name (e.g. ':roles')
21
+ # @example
22
+ # class User < ActiveRecord::Base
23
+ # acts_as_authorization_subject
24
+ # end
25
+ #
26
+ # user = User.new
27
+ # user.role_objects #=> returns Role objects, associated with the user
28
+ # user.has_role!(...)
29
+ # user.has_no_role!(...)
30
+ #
31
+ # # other functions from Acl9::ModelExtensions::Subject are made available
32
+ #
33
+ # @see Acl9::ModelExtensions::Subject
34
+ #
35
+ def acts_as_authorization_subject(options = {})
36
+ assoc = options[:association_name] || Acl9::config[:default_association_name]
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] || 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
41
+
42
+ before_destroy :has_no_roles!
43
+
44
+ cattr_accessor :_auth_role_class_name, :_auth_subject_class_name,
45
+ :_auth_role_assoc_name
46
+
47
+ self._auth_role_class_name = role
48
+ self._auth_subject_class_name = self.to_s
49
+ self._auth_role_assoc_name = assoc
50
+
51
+ include Acl9::ModelExtensions::ForSubject
52
+ end
53
+
54
+ # Add role query and set methods to the class (making it an auth object class).
55
+ #
56
+ # @param [Hash] options the options for tuning
57
+ # @option options [String] :subject_class_name (Acl9::config[:default_subject_class_name])
58
+ # Subject class name (e.g. 'User', or 'Account)
59
+ # @option options [String] :role_class_name (Acl9::config[:default_role_class_name])
60
+ # Role class name (e.g. 'AccountRole')
61
+ # @example
62
+ # class Product < ActiveRecord::Base
63
+ # acts_as_authorization_object
64
+ # end
65
+ #
66
+ # product = Product.new
67
+ # product.accepted_roles #=> returns Role objects, associated with the product
68
+ # product.users #=> returns User objects, associated with the product
69
+ # product.accepts_role!(...)
70
+ # product.accepts_no_role!(...)
71
+ # # other functions from Acl9::ModelExtensions::Object are made available
72
+ #
73
+ # @see Acl9::ModelExtensions::Object
74
+ #
75
+ def acts_as_authorization_object(options = {})
76
+ subject = options[:subject_class_name] || Acl9::config[:default_subject_class_name]
77
+ subj_table = subject.constantize.table_name
78
+
79
+ role = options[:role_class_name] || Acl9::config[:default_role_class_name]
80
+
81
+ has_many :accepted_roles, :as => :authorizable, :class_name => role, :dependent => :destroy
82
+
83
+ subj_assoc = "assoc_#{subj_table}".to_sym
84
+ has_many subj_assoc, -> { distinct.readonly }, source: subj_table.to_sym, through: :accepted_roles
85
+
86
+ define_method subj_table.to_sym do |role_name=nil|
87
+ rel = send subj_assoc
88
+
89
+ if role_name
90
+ rel = rel.where role.constantize.table_name.to_sym => { name: role_name }
91
+ end
92
+ rel
93
+ end
94
+
95
+ include Acl9::ModelExtensions::ForObject
96
+ end
97
+
98
+ # Make a class an auth role class.
99
+ #
100
+ # You'll probably never create or use objects of this class directly.
101
+ # Various auth. subject and object methods will do that for you
102
+ # internally.
103
+ #
104
+ # @param [Hash] options the options for tuning
105
+ # @option options [String] :subject_class_name (Acl9::config[:default_subject_class_name])
106
+ # Subject class name (e.g. 'User', or 'Account)
107
+ # @option options [String] :join_table_name (Acl9::config[:default_join_table_name])
108
+ # Join table name (e.g. 'accounts_account_roles')
109
+ #
110
+ # @example
111
+ # class Role < ActiveRecord::Base
112
+ # acts_as_authorization_role
113
+ # end
114
+ #
115
+ # @see Acl9::ModelExtensions::Subject#has_role!
116
+ # @see Acl9::ModelExtensions::Subject#has_role?
117
+ # @see Acl9::ModelExtensions::Subject#has_no_role!
118
+ # @see Acl9::ModelExtensions::Object#accepts_role!
119
+ # @see Acl9::ModelExtensions::Object#accepts_role?
120
+ # @see Acl9::ModelExtensions::Object#accepts_no_role!
121
+ def acts_as_authorization_role(options = {})
122
+ subject = options[:subject_class_name] || Acl9::config[:default_subject_class_name]
123
+ join_table = options[:join_table_name] || Acl9::config[:default_join_table_name] ||
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))
127
+
128
+ has_and_belongs_to_many subject.demodulize.tableize.to_sym,
129
+ :class_name => subject,
130
+ :join_table => join_table
131
+
132
+ belongs_to :authorizable, polymorphic: true, optional: true
133
+ end
134
+ end
135
+ end
136
+ end
@@ -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 = "3.3.0"
3
+ end
data/lib/acl9.rb ADDED
@@ -0,0 +1,78 @@
1
+ require 'acl9/version'
2
+ require 'acl9/model_extensions'
3
+ require 'acl9/controller_extensions'
4
+ require 'acl9/helpers'
5
+
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
16
+
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
30
+
31
+ @@config = Config.new( *CONFIG.values_at(*Config.members))
32
+
33
+ mattr_reader :config
34
+
35
+ def self.configure
36
+ yield config
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
+
74
+ end
75
+
76
+ ActiveRecord::Base.send(:include, Acl9::ModelExtensions)
77
+ AbstractController::Base.send :include, Acl9::ControllerExtensions
78
+ 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
+
@@ -0,0 +1,122 @@
1
+ require "rails/generators/active_record"
2
+
3
+ module Acl9
4
+ class SetupGenerator < Rails::Generators::Base
5
+ include ActiveRecord::Generators::Migration
6
+
7
+ source_root File.expand_path('../templates', __FILE__)
8
+
9
+ argument :arg_subject, type: :string, default: 'user', banner: "subject"
10
+ argument :arg_role, type: :string, default: 'role', banner: "role"
11
+ argument :arg_objects, type: :array, default: [], banner: "objects..."
12
+
13
+ def create_migration_file
14
+ migration_template "create_role_tables.rb", File.join(db_migrate_path, "create_#{role_name}_tables.rb")
15
+ end
16
+
17
+ def create_models
18
+ template "role.rb", "app/models/#{role_name}.rb"
19
+
20
+ objects.each do |object|
21
+ my_inject "app/models/#{object}.rb", object.classify, " #{object_helper}\n"
22
+ end
23
+
24
+ my_inject "app/models/#{subject_name}.rb", subject_class_name, " #{subject_helper}\n"
25
+ end
26
+
27
+ def create_initializer
28
+ initializer "acl9.rb" do
29
+ <<-RUBY.strip_heredoc
30
+ # See https://github.com/be9/acl9#configuration for details
31
+ #
32
+ # Acl9.configure do |c|
33
+ # c.default_role_class_name = 'Role'
34
+ # c.default_subject_class_name = 'User'
35
+ # c.default_subject_method = :current_user
36
+ # c.default_association_name = :role_objects
37
+ # c.default_join_table_name = nil
38
+ # c.protect_global_roles = true
39
+ # c.normalize_role_names = true
40
+ # end
41
+ RUBY
42
+ end
43
+ end
44
+
45
+ private
46
+ def role_name
47
+ arg_role.underscore.singularize
48
+ end
49
+
50
+ def role_table_name
51
+ role_name.tableize
52
+ end
53
+
54
+ def role_class_name
55
+ role_name.classify
56
+ end
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
+
66
+ def habtm_table
67
+ Acl9.config.default_join_table_name || [ subject_name, role_name ].map(&:pluralize).sort.join('_')
68
+ end
69
+
70
+ def subject_helper
71
+ "acts_as_authorization_subject" + ( subject_options ? " #{subject_options}" : '' )
72
+ end
73
+
74
+ def object_helper
75
+ "acts_as_authorization_object" + ( object_options ? " #{object_options}" : '' )
76
+ end
77
+
78
+ def role_helper
79
+ "acts_as_authorization_role" + ( role_options ? " #{role_options}" : '' )
80
+ end
81
+
82
+ def my_inject file_name, class_name, string
83
+ inject_into_class file_name, class_name, string
84
+ rescue Errno::ENOENT
85
+ create_file file_name do
86
+ <<-RUBY.strip_heredoc
87
+ class #{class_name} < ActiveRecord::Base
88
+ #{string}
89
+ end
90
+ RUBY
91
+ end
92
+ end
93
+
94
+ def role_options
95
+ if defined?(Acl9::config) && Acl9::config[:default_subject_class_name].to_s.classify != subject_class_name
96
+ "subject_class_name: #{subject_class_name}"
97
+ end
98
+ end
99
+
100
+ def subject_options
101
+ if defined?(Acl9::config) && Acl9::config[:default_role_class_name].to_s.classify != role_class_name
102
+ "role_class_name: #{role_class_name}"
103
+ end
104
+ end
105
+
106
+ def object_options
107
+ [ role_options, subject_options ].compact.join ', '
108
+ end
109
+
110
+ def subject_name
111
+ @subject_name ||= arg_subject.underscore.singularize
112
+ end
113
+
114
+ def objects
115
+ @objects ||= arg_objects.map{|o|o.underscore.singularize}
116
+ end
117
+
118
+ def subject_class_name
119
+ subject_name.classify
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,31 @@
1
+ class Create<%= role_class_name %>Tables < ActiveRecord::Migration[<%= ActiveRecord::Migration.current_version %>]
2
+ def change
3
+ create_table :<%= role_table_name %> do |t|
4
+ t.string :name, null: false
5
+ <% if r5? %>
6
+ t.references :authorizable, polymorphic: true
7
+ <% else %>
8
+ t.string :authorizable_type, null: true
9
+ t.integer :authorizable_id, null: true
10
+ <% end %>
11
+ t.boolean :system, default: false, null: false
12
+ t.timestamps null: false
13
+ end
14
+
15
+ add_index :<%= role_table_name %>, :name
16
+
17
+ <% unless r5? %>
18
+ add_index :<%= role_table_name %>, [:authorizable_type, :authorizable_id]
19
+ <% end -%>
20
+
21
+ create_table :<%= habtm_table %>, id: false do |t|
22
+ t.references :<%= subject_name %>, null: false
23
+ t.references :<%= role_name %>, null: false
24
+ end
25
+
26
+ <% unless r5? %>
27
+ add_index :<%= habtm_table %>, :<%= subject_name %>_id
28
+ add_index :<%= habtm_table %>, :<%= role_name %>_id
29
+ <% end %>
30
+ end
31
+ end
@@ -0,0 +1,3 @@
1
+ class <%= role_class_name %> < <%= model_base_name %>
2
+ <%= role_helper %>
3
+ end