activeaclplus 0.3.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (33) hide show
  1. data/CHANGELOG +12 -0
  2. data/README.rdoc +125 -49
  3. data/Rakefile +13 -14
  4. data/{generators/active_acl/templates → app}/controllers/privileges_controller.rb +1 -1
  5. data/{lib → app/models}/active_acl/acl.rb +5 -5
  6. data/{lib → app/models}/active_acl/acl_section.rb +3 -3
  7. data/{lib → app/models}/active_acl/controller_action.rb +1 -1
  8. data/{lib → app/models}/active_acl/controller_group.rb +1 -1
  9. data/{lib → app/models}/active_acl/privilege.rb +0 -0
  10. data/{lib → app/models}/active_acl/requester_group_link.rb +0 -0
  11. data/{lib → app/models}/active_acl/requester_link.rb +0 -0
  12. data/{lib → app/models}/active_acl/target_group_link.rb +0 -0
  13. data/{lib → app/models}/active_acl/target_link.rb +0 -0
  14. data/{generators/active_acl/templates/views → app/view}/privileges/_privilege_form.rhtml +0 -0
  15. data/{generators/active_acl/templates/views → app/view}/privileges/edit.rhtml +0 -0
  16. data/{generators/active_acl/templates/views → app/view}/privileges/list.rhtml +0 -0
  17. data/db/migrate/001_base_table_setup.rb +7 -4
  18. data/init.rb +7 -1
  19. data/lib/active_acl/acts_as_access_group.rb +17 -22
  20. data/lib/active_acl/acts_as_access_object.rb +41 -208
  21. data/lib/active_acl/base.rb +17 -0
  22. data/lib/active_acl/cache/memcache_adapter.rb +12 -10
  23. data/lib/active_acl/cache/no_cache_adapter.rb +5 -5
  24. data/lib/active_acl/db/active_record_adapter.rb +3 -3
  25. data/lib/active_acl/db/mysql_adapter.rb +2 -2
  26. data/lib/active_acl/grant.rb +38 -0
  27. data/lib/active_acl/handler/nested_set.rb +33 -0
  28. data/lib/active_acl/handler/object_handler.rb +250 -0
  29. data/lib/active_acl/load_controller_actions.rb +1 -3
  30. data/lib/active_acl/privilege_const_set.rb +2 -2
  31. data/lib/active_acl.rb +11 -5
  32. metadata +35 -27
  33. data/generators/active_acl/active_acl_generator.rb +0 -29
data/CHANGELOG CHANGED
@@ -1,5 +1,17 @@
1
1
  ActiveAcl rails authorization system
2
2
 
3
+ Version 0.4.0 - 2008/03/08
4
+ - complete rewrite of the SQL generation
5
+ - abstraction of the grouping
6
+ - added #grant_privilege
7
+ - dropped test, moving to rspec
8
+ - allows ungrouped requesters/targets
9
+ - propper namespace handling of options (THANKS http://github.com/garytaylor)
10
+
11
+ Version 0.3.1 - 2008/12/11
12
+ - forgot active_acl.rb in gem
13
+ - fixed generator
14
+
3
15
  Version 0.3.0 - 2008/12/07
4
16
  - Renamed Project to ActiveACLPlus
5
17
  - code cleanup
data/README.rdoc CHANGED
@@ -2,7 +2,8 @@
2
2
  The ActiveAclPlus plugin implements a flexible, fast and easy to use generic access control system.
3
3
 
4
4
  ==License
5
- ActiveAclPlus is released under the LGPL[http://www.opensource.org/licenses/lgpl-license.php] (Gnu Lesser General Public License) - see the included LICENSE file, too.
5
+ ActiveAclPlus is released under the LGPL[http://www.opensource.org/licenses/lgpl-license.php]
6
+ (Gnu Lesser General Public License) - see the included LICENSE file, too.
6
7
 
7
8
  ==Features
8
9
  * ease of use - uses polymorphic collections for associations.
@@ -10,11 +11,10 @@ ActiveAclPlus is released under the LGPL[http://www.opensource.org/licenses/lgpl
10
11
  * scalable - there are no real benchmarks yet. But the system design is based on http://phpgacl.sourceforge.net, adding object orientation, polymorphism and two levels of caching. PhpGacl claims "A real-world working version with many added layers of complexity supports over 60,000 Accounts, 200 Groups and 300 ACO's." Tests on my dev notebook show 10 - 30 times performance improvements compared to active_rbac.
11
12
  * caching - uses instance caching and optionally stores permission results in memcached using timeouts.
12
13
  * flexible - grants simple (2D, like <code>current_user.has_permission?(User::LOGIN)</code>) and object level (3D, like <code>admin.has_permission?(Forum::ADMIN, :on => team_forum)</code>) permissions. Can assign and request permissions to and from every ActiveRecord model. No "hardcoded" permissions - all permissions can be assigned at runtime.
13
- * grouping - permissions are inherited at target and requester side through groups. Every model implementing an SQL nested set tree may be used as a group.
14
+ * grouping - permissions can be inherited at target and requester side through groups. Every model implementing an SQL nested set tree may be used as a group.
14
15
  * ControllerAction model loader: It maps controller actions to the DB so they can be used in permission assignment. The access object is available via calling <code>current_action</code> on the controller.
15
16
  * exchangeable DB interface: ActiveRecord and direct MySQL adapter available
16
17
  * supports namespaced models and single table inheritance (STI)
17
- * 100 % C0 code coverage on unit tests
18
18
 
19
19
  ==Limitations
20
20
  * At present only one grouping type per model is supported. This could be changed on request but I don't see a use case for it yet.
@@ -25,41 +25,76 @@ ActiveAclPlus is released under the LGPL[http://www.opensource.org/licenses/lgpl
25
25
  ActiveAclPlus uses the has_many_polymorphs[http://www.agilewebdevelopment.com/plugins/restful_authentication] plugin. Make shure you've got a recent version, old versions have bugs affecting active_acl_plus.
26
26
  !!Be sure you have the paches for 2.1, see: http://rubyforge.org/forum/forum.php?thread_id=26041&forum_id=16450
27
27
 
28
- ./script/plugin install git://github.com/popel/active_acl_plus.git
28
+ ./script/plugin install git://github.com/popel/active_acl_plus.git
29
29
 
30
- generators XXX
30
+ or
31
31
 
32
+ sudo gem install activeaclplus
33
+
34
+ or from a github repository.
35
+
36
+ If you want to use grouped access objects you should install some kind of nested_set plugin
37
+ (awesome_nested_set,better_nested_set,...).
32
38
  ==Short summary
33
- The ActiveAclPlus system consists of access objects, organized by access groups, that request privileges on each other. Allowing or denying access to a privilege is controlled by ACL (access control list entry) objects. Access objects and access groups can be instances of arbitrary ActiveRecord model classes enhanced by acts_as_access_object and acts_as_access_group. They are associated to ACL entries via polymorphic associations.
39
+ The ActiveAclPlus system consists of access objects, which can be organized by access groups,
40
+ that request privileges on each other. Allowing or denying access to a privilege is controlled by
41
+ ACL (access control list entry) objects. Access objects and access groups can be instances of arbitrary
42
+ ActiveRecord model classes enhanced by acts_as_access_object and acts_as_access_group. They are associated
43
+ to ACL entries via polymorphic associations.
34
44
 
35
45
  ===Access objects
36
- These are basically requesters and targets in the permission system, as for example a User or a Forum model object. In this case a user could act as a requester ("do I have privilege Y?") or target ("does access object X have privilege Y on me?"). A Forum would most certainly be only used as a target, but all access objects can theoretically be used as both requesters and targets. Access objects use the acts_as_access_object macro inside their definition. This registers the model with the ACL system and enhances it with methods like has_privilege?.
46
+ These are basically requesters and targets in the permission system, as for example a User or a Forum model object.
47
+ In this case a user could act as a requester ("do I have privilege Y?") or target ("does access object X have
48
+ privilege Y on me?"). A Forum would most certainly be only used as a target, but all access objects can theoretically
49
+ be used as both requesters and targets. Access objects use the acts_as_access_object macro inside their definition.
50
+ This registers the model with the ACL system and enhances it with methods like has_privilege?.
37
51
 
38
- Every model class must specify an association that is used as the "grouping type" to it. So User may declare has_and_belongs_to_many :user_groups and use acts_as_access_object :grouped_by => :user_groups. You can use a has_and_belongs_to_many or a belongs_to association for this. Common mapping attributes (:join_table, :foreign_key etc.) are supported.
52
+ See: ActiveAcl::Acts::AccessObject::ClassMethods, ActiveAcl::Acts::AccessObject::InstanceMethods,
53
+ ActiveAcl::Acts::AccessObject::SingletonMethods, ActiveAcl::Acts::Grant
39
54
 
40
55
 
41
- ===Access groups
42
- The access group model needs to implement a tree with nested set semantics having a "left" and "right" column, e.g. by using the built-in acts_as_nested_set or the much more recommended acts_as_betted_nested_set plugin. Groups are declared with acts_as_access_group.
56
+ Every access object class can specify an association that is used as the "grouping type" to it. So User may declare
57
+ has_and_belongs_to_many :user_groups and use acts_as_access_object :grouped_by => :user_groups. You can use
58
+ a has_and_belongs_to_many or a belongs_to association for this. Common mapping attributes
59
+ (:join_table, :foreign_key etc.) are supported.
43
60
 
44
- Groups may be used to specify inheritance hierarchies for permissions. So you could have a 'registered users' group as a subgroup of the 'users' group and assign the privilege to log in to this group via an ACL entry. Every user belonging to this group will now be granted the privilege to log in. Then you could add a subgroup to registerd users, 'banned users', and deny the log in privilege for this group. Every user added to this group would now be unable to log in, regardless of beeing in 'registered users' or not, as 'banned users' would override the permission settings of 'registered users'.
61
+ ===Access groups
62
+ The access group model needs to implement a tree with nested set semantics having a "left" and "right"
63
+ column, e.g. by using the built-in acts_as_nested_set or the much more recommended acts_as_betted_nested_set
64
+ plugin. Groups are declared with acts_as_access_group.
45
65
 
66
+ Groups may be used to specify inheritance hierarchies for permissions. So you could have a 'registered users'
67
+ group as a subgroup of the 'users' group and assign the privilege to log in to this group via an ACL entry.
68
+ Every user belonging to this group will now be granted the privilege to log in. Then you could add a subgroup
69
+ to registerd users, 'banned users', and deny the log in privilege for this group. Every user added to this
70
+ group would now be unable to log in, regardless of beeing in 'registered users' or not, as 'banned users' would
71
+ override the permission settings of 'registered users'.
46
72
 
47
73
  ===Privileges
48
- A privilege object is an object for the thing we wish to define a permission for. So User::LOGIN could be a privilege object for checking a users permission to log in, while Forum::ADMIN might define administration rights on a forum.
49
-
50
- A privilege object itself is little more than it’s name and id and is usually bound to a constant inside the application, as it is not expected to change at runtime. Privileges are usually created by the developer in the source code and not in the admin frontend, as creating new privilege objects that have no meaning (by code that checks for them) would be pointless.
74
+ A privilege object is an object for the thing we wish to define a permission for. So User::LOGIN could be a
75
+ privilege object for checking a users permission to log in, while Forum::ADMIN might define administration rights on a forum.
51
76
 
77
+ A privilege object itself is little more than it’s name and id and is usually bound to a constant inside the
78
+ application, as it is not expected to change at runtime. Privileges are usually created by the developer in
79
+ the source code and not in the admin frontend, as creating new privilege objects that have no meaning (by code
80
+ that checks for them) would be pointless.
52
81
 
53
82
  ===Access Control List (ACL) entries
54
- ACL entries are the glue between all these objects, defining which requesters and requester groups have access to which privileges, optionally defining target objects and target groups as well. ACL entries are organized by ACL sections, for better overview in the admin screens.
55
-
83
+ ACL entries are the glue between all these objects, defining which requesters and requester groups have access
84
+ to which privileges, optionally defining target objects and target groups as well. ACL entries are organized by
85
+ ACL sections, for better overview in the admin screens.
56
86
 
57
87
  ==Usage
58
88
  ===In short
59
- "No access defined" for a privilege evaluates to "deny". This may be overriden by an explicit "allow" or "deny". Privileges are inherited in requestor and target groups, this means you can override them in subgroups again. Privileges directly assigned to an object always supercede those assigned to groups.
89
+ "No access defined" for a privilege evaluates to "deny". This may be overriden by an explicit "allow" or "deny".
90
+ Privileges are inherited in requestor and target groups, this means you can override them in subgroups again.
91
+ Privileges directly assigned to an object always supercede those assigned to groups.
60
92
 
61
93
  ===Simple (2D) permissions
62
- We want all registered users to be able to log in. We create the User model, the UserGroup model and the User::LOGIN privilege object as described above. Then we create a new ACL entry, set 'allow' to true, add the "registered users" group as requester group, User::LOGIN as privilege and we are done. Every user assigned to "registered users" or a subgroup of it will now be granted access by calling <code>my_user.has_privilege?(User::LOGIN)</code>.
94
+ We want all registered users to be able to log in. We create the User model, the UserGroup model and the
95
+ User::LOGIN privilege object as described above. Then we create a new ACL entry, set 'allow' to true, add
96
+ the "registered users" group as requester group, User::LOGIN as privilege and we are done. Every user assigned
97
+ to "registered users" or a subgroup of it will now be granted access by calling <code>my_user.has_privilege?(User::LOGIN)</code>.
63
98
 
64
99
  ====Simple permissions example
65
100
 
@@ -78,22 +113,29 @@ We want all registered users to be able to log in. We create the User model, the
78
113
  # assume 'registered_users' exists and users 'john' and 'dr_evil' are members of it but 'anonymous' is not.
79
114
  registered_users = UserGroup.find_by_name('registered_users')
80
115
 
116
+ the hard way:
81
117
  acl = ActiveAcl::Acl.create :section => ActiveAcl::AclSection.create(:description => 'users')
82
118
 
83
119
  acl.allow = true # true is default
84
120
  acl.privileges << User::LOGIN
85
- acl.note="login"
121
+ acl.iname="login"
86
122
  acl.save
87
123
 
88
124
  acl.requester_groups << registered_users
89
125
 
126
+ or much easier:
127
+
128
+ registered_users.grant_privilege!(User::LOGIN,:section_name => 'users',:acl_name => 'login')
129
+
90
130
  john.has_privilege?(User::LOGIN) #=> true
91
131
  dr_evil.has_privilege?(User::LOGIN) #=> true
92
132
 
93
133
  anonymous.has_privilege?(User::LOGIN) #=> false
94
134
 
95
135
  ===Overriding permissions
96
- We want to ban specific users from our site. We create another ACL entry, assign the User::LOGIN privilege object, set 'allow' to false and then assign these users as requesters to the ACL entry. The direct permission assignment on the objects overrides the 'allow login' ACL entry from above.
136
+ We want to ban specific users from our site. We create another ACL entry, assign the User::LOGIN privilege
137
+ object, set 'allow' to false and then assign these users as requesters to the ACL entry. The direct
138
+ permission assignment on the objects overrides the 'allow login' ACL entry from above.
97
139
 
98
140
  ====Overriding permissions example
99
141
 
@@ -109,11 +151,17 @@ We want to ban specific users from our site. We create another ACL entry, assign
109
151
  dr_evil.has_privilege?(User::LOGIN) #=> false
110
152
 
111
153
  ===Object level (3D) permissions
112
- We want to assign forum permissions. We have several privileges (Forum::ADMIN, Forum::READ, Forum::POST etc.), the afore mentioned User and UserGroup models as well as a Forum and a Category model for grouping the forums.
154
+ We want to assign forum permissions. We have several privileges (Forum::ADMIN, Forum::READ, Forum::POST etc.),
155
+ the afore mentioned User and UserGroup models as well as a Forum and a Category model for grouping the forums.
113
156
 
114
- If we want to check if a certain user may read in a certain forum, it is not sufficient to check <code>test_user.has_privilege?(Forum::READ)</code> as the target object - in this case a forum - is needed to make a decision. The code to do the check is like <code>test_user.has_privilege?(Forum::READ, :on => teamforum)</code>.
157
+ If we want to check if a certain user may read in a certain forum, it is not sufficient to check
158
+ <code>test_user.has_privilege?(Forum::READ)</code> as the target object - in this case a forum - is needed
159
+ to make a decision. The code to do the check is like <code>test_user.has_privilege?(Forum::READ, :on => teamforum)</code>.
115
160
 
116
- To make this work you create a new ACL entry, add Forum::POST and Forum::READ as privileges, set 'allow' to true, add the registered users group as a requester group and the public forums category as a target group to the acl. Now every user belonging to the registered users group or a subgroup of it gains post and read privileges on all forums of the public forums category or a subcategory of it.
161
+ To make this work you create a new ACL entry, add Forum::POST and Forum::READ as privileges, set 'allow' to
162
+ true, add the registered users group as a requester group and the public forums category as a target group
163
+ to the acl. Now every user belonging to the registered users group or a subgroup of it gains post and read
164
+ privileges on all forums of the public forums category or a subcategory of it.
117
165
 
118
166
  ====Object level permissions example
119
167
 
@@ -152,43 +200,71 @@ To make this work you create a new ACL entry, add Forum::POST and Forum::READ as
152
200
  anonymous.has_privilege?(Forum::READ, :on => speakers) #=> false
153
201
 
154
202
  ==CAUTION
155
- Do not create ACL entries that are on different branches of the inheritance hierarchy and have allow/deny set differently on the same privilege objects. This way it's impossible to tell which permission should take precedence. At present this is by creation date, later entries superceding older ones, but this is most certainly not what you want.
156
-
157
- Error checking for conflicting ACL entries is high up on the ToDo list.
203
+ Do not create ACL entries that are on different branches of the inheritance hierarchy and have
204
+ allow/deny set differently on the same privilege objects. This way it's impossible to tell which
205
+ permission should take precedence. At present this is by creation date, later entries superceding older
206
+ ones, but this is most certainly not what you want.
158
207
 
159
208
  ==Controller Actions
160
- Defining permissions on controller actions (like "may user x execute AdminController.list ?") is quite a common case but we are facing a problem here: Controller actions have no corresponding DB models so permissions on them can't be easily defined.
209
+ Defining permissions on controller actions (like "may user x execute AdminController.list ?") is quite a
210
+ common case but we are facing a problem here: Controller actions have no corresponding DB models so
211
+ permissions on them can't be easily defined.
161
212
 
162
- ActiveAclPlus solves this by adding a ControllerAction and ControllerGroup model. For every public controller method (=action) there is one ControllerAction object in the DB.
213
+ ActiveAclPlus solves this by adding a ControllerAction and ControllerGroup model. For every public
214
+ controller method (=action) there is one ControllerAction object in the DB.
163
215
 
164
- On application startup, the plugin loader checks all controller files in app/controllers and loads or creates a ControllerAction object for every action it finds. These objects get cached in a hash in the ActiveAclPlus module. Every controller now has a method <code>current_action</code> that looks up and returns the access object for the current action, so it can be used for access checks like <code>current_user.has_privilege?(ActiveAcl::ControllerAction::EXECUTE, :on => current_action)</code>.
216
+ On application startup, the plugin loader checks all controller files in app/controllers and loads
217
+ or creates a ControllerAction object for every action it finds. These objects get cached in a hash
218
+ in the ActiveAclPlus module. Every controller now has a method <code>current_action</code> that looks
219
+ up and returns the access object for the current action, so it can be used for access checks like
220
+ <code>current_user.has_privilege?(ActiveAcl::ControllerAction::EXECUTE, :on => current_action)</code>.
165
221
 
166
222
  This works nicely for before_filters with authorization checks.
167
223
 
168
- A word on the load mechanism: If the action has no corresponding DB entry (it's looked up on method creation by controller and action name) the loader searches for a controller group with the same name as the controller. If it is found, the action is created and assigned to this group. Else the controller group is created as a subgroup to the "unassigned controller actions" group (this name can be changed in the options) and the unassigned action is added to the controller group.
224
+ A word on the load mechanism: If the action has no corresponding DB entry (it's looked up on method creation
225
+ by controller and action name) the loader searches for a controller group with the same name as the
226
+ controller. If it is found, the action is created and assigned to this group. Else the controller group
227
+ is created as a subgroup to the "unassigned controller actions" group (this name can be changed in the
228
+ options) and the unassigned action is added to the controller group.
169
229
 
170
- So you are free on how to organize your controllers. Maybe create an admin group and a public group and move controllers as a subgroup inside them?
230
+ So you are free on how to organize your controllers. Maybe create an admin group and a public group and
231
+ move controllers as a subgroup inside them?
171
232
 
172
233
  ==Caching
173
- The plugin provides two levels of caching. The instance cache is a hash inside the access object. The object first tries to serve a permission request from the instance cache. If it is not found and a simple permission is requested, the query fetches all simple permissions of the object and puts them in the instance cache. The reason for this is that there is no noticable speed penalty in fetching all 2D permissions at once compared to fetching only one, so this will save time and DB IO later on. Complex 3D queries are fetched independently and also saved to the instance cache. The instance cache lives inside the access object, so it has it's lifetime, too - which in rails usually is no more than a single request.
174
-
175
- The second level cache tries to overcome this limitation by putting the instance cache of an access object in an external cache. It tries to get the instance cache from there if it is not set, and sets it if it was changed. The only real implementation for now is with the memcache daemon. The second level cache uses a timeout (which can be defined in the options) to expire the cached permissions.
176
-
177
- Instance and second level cache can be expired explicitly by calling <code>clear_cached_permissions</code> on the access object. Calling <code>reload</code> on the object also purges the caches.
234
+ The plugin provides two levels of caching. The instance cache is a hash inside the access object. The object
235
+ first tries to serve a permission request from the instance cache. If it is not found and a simple permission
236
+ is requested, the query fetches all simple permissions (2D) of the object and puts them in the instance cache. The
237
+ reason for this is that there is no noticable speed penalty in fetching all 2D permissions at once compared to
238
+ fetching only one, so this will save time and DB IO later on. Complex 3D queries are fetched independently
239
+ and also saved to the instance cache. The instance cache lives inside the access object, so it has it's
240
+ lifetime, too - which in rails usually is no more than a single request.
241
+
242
+ The second level cache tries to overcome this limitation by putting the instance cache of an access object
243
+ in an external cache. It tries to get the instance cache from there if it is not set, and sets it if it was
244
+ changed. The only real implementation for now is with the memcache daemon. The second level cache uses a timeout
245
+ (which can be defined in the options) to expire the cached permissions.
246
+
247
+ Instance and second level cache can be expired explicitly by calling <code>active_acl_clear_cache!</code>
248
+ on the access object. Calling <code>reload</code> on the object also purges the caches.
178
249
 
179
250
  See ActiveAcl::Cache::MemcacheAdapter on how to set it up.
180
251
 
181
252
 
182
253
  ==Preloader
183
- The plugin includes a <code>load_files_from filenames</code> function. It can be used to preload source files (and therefore the classes in it) from an application path and should be used from environment.rb.
254
+ The plugin includes a <code>load_files_from filenames</code> function. It can be used to preload source files
255
+ (and therefore the classes in it) from an application path and should be used from environment.rb.
184
256
 
185
257
  load_files_from("#{RAILS_ROOT}/app/controllers/**/[^.]*.rb")
186
258
  load_files_from("#{RAILS_ROOT}/app/models/**/[^.]*.rb")
187
259
 
188
- will load all models and controllers inside these folders and their subfolders. This way you can be shure they are registered with the ACL system at rails boot time - else they will be registered when they are called for the first time. This means that new controllers will not show up in the admin screens until they were accessed if not using the preloader.
260
+ will load all models and controllers inside these folders and their subfolders. This way you can be shure they
261
+ are registered with the ACL system at rails boot time - else they will be registered when they are called for
262
+ the first time. This means that new controllers will not show up in the admin screens until they were accessed
263
+ if not using the preloader.
189
264
 
190
265
  ==Options
191
- <code>ActiveAcl::OPTIONS</code> is an array that can be used to override various options for the system by setting the values in environment.rb. <code>ActiveAcl::DEFAULT_OPTIONS</code> is as follows:
266
+ <code>ActiveAcl::OPTIONS</code> is an array that can be used to override various options for the system by setting
267
+ the values in environment.rb. <code>ActiveAcl::DEFAULT_OPTIONS</code> is as follows:
192
268
 
193
269
  DEFAULT_OPTIONS = {
194
270
  :acl_sections_table => 'acl_sections',
@@ -202,7 +278,8 @@ will load all models and controllers inside these folders and their subfolders.
202
278
  :controller_actions_table => 'controller_actions',
203
279
  :controller_groups_table => 'controller_groups',
204
280
 
205
- :controllers_group_name => 'unassigned_controller_actions', # the name of the base group that newly created controller groups get assigned to
281
+ :controllers_group_name => 'unassigned_controller_actions', # the name of the base group
282
+ # that newly created controller groups get assigned to
206
283
  :controller_group_name_suffix => '_controller', # name suffix for generated controller groups
207
284
 
208
285
  :cache_permission_timeout => 10, # timeout in seconds for the second level cache
@@ -212,30 +289,29 @@ will load all models and controllers inside these folders and their subfolders.
212
289
  }
213
290
 
214
291
  ==Tests
215
- See: http://github.com/popel/active_acl_plus_test/tree/master for more info.
292
+ Not anymore, sorry. I'm using RSpec for testing. A repository
293
+ is/will be setup at http://github.com/popel/active_acl_plus_rspec/tree/master . Check it out and move it to "spec". Run
294
+ rake spec
216
295
 
217
296
  ==Credits
218
297
  * Gregor Melhorn implemented this and maintained it up to Version 0.2.1. Thanks for releasing this!
219
- * Evan for writing that great polymorph plugin and beeing so kind to add namespace and tablename support on my request.
298
+ * Evan for writing that great polymorph plugin and beeing so kind to add namespace and tablename support on Gregor's request.
220
299
  * ReinH and markmeves for great support and suggestions at the rubyonrails channel on freenode.org.
221
300
  * http://phpgacl.sourceforge.net as a great source of inspiration
222
- * Obrie for writing plugin_migrations and loaded_plugins and also very nice support when I got stuck with using them.
301
+ * Obrie for writing plugin_migrations and loaded_plugins and also very nice support when Gregor got stuck with using them.
223
302
 
224
303
  ==ToDo/Ideas
225
304
 
226
305
  in no particular order, just a reminder...
227
306
 
307
+ * add materialized_tree_support
308
+ * use Moneta as key/value store
228
309
  * direct PostgreSQL interface
229
- * example on how to integrate with acts_as_authenticated
310
+ * example on how to integrate with authentication
230
311
  * example on controller actions
231
- * make grouping optional
232
- * add interface generators (started)
233
312
  * error checking for conflicting ACL entries
234
- * permissions should have more attributes (like :until,:left_boni,...)
235
313
  * get all permissions for a requester within a section
236
314
  * get all permissions of a requester (with one query)
237
315
  * get all permissions of a requester on a target (with one query)
238
316
  * get all requester with a given privilege on a target (one query)
239
317
  * get all targets on which a requester has a certain privilege (one query)
240
-
241
-
data/Rakefile CHANGED
@@ -18,13 +18,8 @@ Rake::GemPackageTask.new(PKG_GEM) do |p|
18
18
  p.need_zip = true
19
19
  end
20
20
 
21
- desc 'Default: run unit tests.'
22
- task :default => :test
23
-
24
- #desc "Publish the beta gem"
25
- #task :pgem => [:package] do
26
- # Rake::SshFilePublisher.new("pluginaweek@pluginaweek.org", "/home/pluginaweek/gems.pluginaweek.org/gems", "pkg", "#{PKG_FILE_NAME}.gem").upload
27
- #end
21
+ desc 'Default: run specs'
22
+ task :default => :spec
28
23
 
29
24
  desc "Publish the API documentation"
30
25
  task :pdoc => [:rdoc] do
@@ -67,11 +62,16 @@ task :coverage_diff do
67
62
  sh "#{RCOV} --rails -T -Ilib -x db/**/* --text-coverage-diff ../../../coverage/active_acl/coverage.info --output ../../../coverage/active_acl test/all_tests.rb"
68
63
  end
69
64
 
70
- desc 'Test the active_acl_plus plugin.'
71
- Rake::TestTask.new(:test) do |t|
72
- t.libs << 'lib'
73
- t.pattern = 'test/unit/**/*_test.rb'
74
- t.verbose = true
65
+ begin #no spec or spec-rails? ok no tasks
66
+ require 'spec/rake/spectask'
67
+
68
+ desc 'Test the active_acl_plus plugin.'
69
+ Spec::Rake::SpecTask.new(:spec) do |t|
70
+ #t.spec_opts = ['--options', "\"#{RAILS_ROOT}/spec/spec.opts\""]
71
+ t.spec_files = FileList['spec/**/*_spec.rb']
72
+ end
73
+ rescue LoadError => e
74
+ puts "No spec tasks! - gem install rspec-rails (#{__FILE__})"
75
75
  end
76
76
 
77
77
  desc 'Generate documentation for the active_acl_plus plugin.'
@@ -79,6 +79,5 @@ Rake::RDocTask.new(:rdoc) do |rdoc|
79
79
  rdoc.rdoc_dir = 'rdoc'
80
80
  rdoc.title = 'ActiveAclPlus'
81
81
  rdoc.options << '--line-numbers' << '--inline-source'
82
- rdoc.rdoc_files.include('README')
83
- rdoc.rdoc_files.include('lib/**/*.rb')
82
+ rdoc.rdoc_files.include('README.rdoc','lib/**/*.rb','app/**/*.rb')
84
83
  end
@@ -1,4 +1,4 @@
1
- class <%= privileges_class_name %> < ApplicationController
1
+ class PrivilegesController < ApplicationController
2
2
  verify :method => :post, :only => [ :create, :update],
3
3
  :redirect_to => { :action => :list }
4
4
 
@@ -14,8 +14,8 @@ module ActiveAcl
14
14
  has_many :requester_group_links, :dependent => :delete_all,:class_name => 'ActiveAcl::RequesterGroupLink'
15
15
  has_many :target_group_links, :dependent => :delete_all,:class_name => 'ActiveAcl::TargetGroupLink'
16
16
 
17
- validates_uniqueness_of :note
18
- validates_presence_of :note
17
+ validates_uniqueness_of :iname
18
+ validates_presence_of :iname
19
19
 
20
20
  def self.reloadable? #:nodoc:
21
21
  return false
@@ -23,11 +23,11 @@ module ActiveAcl
23
23
 
24
24
  # used as instance description in admin screen
25
25
  def active_acl_description
26
- if note
26
+ if iname
27
27
  if section
28
- '/' + section.description + '/' + note
28
+ '/' + section.description + '/' + iname
29
29
  else
30
- return note
30
+ return iname
31
31
  end
32
32
  else
33
33
  return nil
@@ -6,11 +6,11 @@ module ActiveAcl
6
6
 
7
7
  has_many :members, :class_name => 'ActiveAcl::Acl', :foreign_key => 'section_id'
8
8
 
9
- validates_presence_of :description
10
- validates_uniqueness_of :description
9
+ validates_presence_of :iname
10
+ validates_uniqueness_of :iname
11
11
 
12
12
  # Make shure there are no associated acls before destroying a section
13
- def before_destroy
13
+ def before_destroy #:nodoc:
14
14
  if members.empty?
15
15
  true
16
16
  else
@@ -3,7 +3,7 @@
3
3
  class ActiveAcl::ControllerAction < ActiveRecord::Base
4
4
  set_table_name ActiveAcl::OPTIONS[:controller_actions_table]
5
5
  privilege_const_set('EXECUTE')
6
-
6
+
7
7
  belongs_to :controller_group, :class_name => 'ActiveAcl::ControllerGroup'
8
8
  acts_as_access_object :grouped_by => :"active_acl/controller_group"
9
9
  validates_presence_of :action, :controller, :controller_group
@@ -3,7 +3,7 @@ class ActiveAcl::ControllerGroup < ActiveRecord::Base
3
3
  set_table_name ActiveAcl::OPTIONS[:controller_groups_table]
4
4
  acts_as_nested_set
5
5
  has_many :controller_actions,:class_name => 'ActiveAcl::ControllerAction'
6
- acts_as_access_group
6
+ acts_as_access_group :type => ActiveAcl::Acts::AccessGroup::NestedSet
7
7
 
8
8
  validates_presence_of :description
9
9
 
File without changes
File without changes
File without changes
File without changes
@@ -2,22 +2,25 @@ class BaseTableSetup < ActiveRecord::Migration
2
2
  def self.up
3
3
  create_table ActiveAcl::OPTIONS[:acls_table] do |t|
4
4
  t.column :section_id, :int
5
+ t.column :iname, :string,:null => false
5
6
  t.column :allow, :boolean, :null => false, :default => true
6
7
  t.column :enabled, :boolean, :null => false, :default => true
7
- t.column :note, :string, :null => true
8
+ t.column :description, :text, :null => true
8
9
  t.column :updated_at, :datetime, :null => false
9
10
  end
10
11
 
11
12
  add_index ActiveAcl::OPTIONS[:acls_table], :enabled
12
13
  add_index ActiveAcl::OPTIONS[:acls_table], :section_id
13
14
  add_index ActiveAcl::OPTIONS[:acls_table], :updated_at
14
- add_index ActiveAcl::OPTIONS[:acls_table], :note, :unique
15
+ add_index ActiveAcl::OPTIONS[:acls_table], :iname, :unique
16
+
15
17
 
16
18
  create_table ActiveAcl::OPTIONS[:acl_sections_table] do |t|
17
- t.column :description, :string, :limit => 230, :null => false
19
+ t.column :iname, :string, :null => false
20
+ t.column :description, :text, :null => true
18
21
  end
19
22
 
20
- add_index ActiveAcl::OPTIONS[:acl_sections_table], :description, :unique
23
+ add_index ActiveAcl::OPTIONS[:acl_sections_table], :iname, :unique
21
24
 
22
25
  create_table ActiveAcl::OPTIONS[:privileges_table] do |t|
23
26
  t.column :section, :string, :limit => 230, :null => false
data/init.rb CHANGED
@@ -1 +1,7 @@
1
- require 'active_acl'
1
+ raise "This Rails version is not supported by ActiveAclPlus" if Rails.version < "2.1.0"
2
+
3
+ if Rails.version < "2.3.0"
4
+ model_path=File.join(File.dirname(__FILE__),'app','models')
5
+ ActiveSupport::Dependencies.load_paths << model_path
6
+ end
7
+ require 'active_acl'
@@ -7,38 +7,33 @@ module ActiveAcl #:nodoc:
7
7
  def self.included(base)
8
8
  base.extend(ClassMethods)
9
9
  end
10
-
10
+
11
11
  module ClassMethods
12
- # Extend self with access group capabilites. See README for details
13
- # on usage. Accepts the following options as a hash:
14
- # left_column:: name of the left column for nested set functionality, default :lft
15
- # right_column:: name of the right column for nested set functionality, default :rgt
16
- # Don't use 'left' and 'right' as column names - these are reserved words in most DBMS.
12
+ # Extend self with access group capabilites.
13
+ # Options can be:
14
+ # type:: is mandatory and is one of the group handler classes
15
+ # left_column:: for ActiveAcl::Acts::AccessGroup::NestedSet grouped objects
16
+ # right_column:: for ActiveAcl::Acts::AccessGroup::NestedSet grouped objects
17
+
17
18
  def acts_as_access_group(options = {})
18
- configuration = {:left_column => :lft, :right_column => :rgt,
19
- :controller => ActiveAcl::OPTIONS[:default_group_selector_controller],
20
- :action => ActiveAcl::OPTIONS[:default_group_selector_action]}
21
- configuration.update(options) if options.is_a?(Hash)
22
- ActiveAcl::GROUP_CLASSES[self.name] = configuration
19
+ type=options.delete(:type) || ActiveAcl::Acts::AccessGroup::NestedSet
20
+ ActiveAcl::GROUP_CLASSES[self.name] = type.new(options)
21
+
22
+ include ActiveAcl::Acts::Grant
23
+ include InstanceMethods
24
+ extend SingletonMethods
23
25
 
24
- from_classes = ActiveAcl::GROUP_CLASSES.keys.collect do |x|
25
- x.split('::').join('/').underscore.pluralize.to_sym
26
- end
27
-
28
26
  ActiveAcl::Acl.instance_eval do
29
- has_many_polymorphs :requester_groups, {:from => from_classes,
27
+ has_many_polymorphs :requester_groups, {:from => ActiveAcl.from_classes,
30
28
  :through => :"active_acl/requester_group_links",
31
29
  :rename_individual_collections => true}
32
-
33
- has_many_polymorphs :target_groups, {:from => from_classes,
30
+
31
+ has_many_polymorphs :target_groups, {:from => ActiveAcl.from_classes,
34
32
  :through => :"active_acl/target_group_links",
35
33
  :rename_individual_collections => true}
36
34
  end
37
35
 
38
- include InstanceMethods
39
- extend SingletonMethods
40
-
41
- end
36
+ end
42
37
  end
43
38
 
44
39
  module SingletonMethods