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
@@ -0,0 +1,250 @@
1
+ module ActiveAcl #:nodoc:
2
+ module Acts #:nodoc:
3
+ module AccessObject #:nodoc:
4
+
5
+ # handels grouped objects
6
+ # the group is a nested_set
7
+ class ObjectHandler #:nodoc:
8
+ attr_reader :klass,:group_class_name,:join_table,:group_table_name,
9
+ :foreign_key,:association_foreign_key
10
+ def initialize(klass,options={})
11
+ @klass = klass
12
+ if options[:grouped_by]
13
+ @group_class_name = options[:grouped_by].to_s.classify
14
+ @group_table_name=@group_class_name.constantize.table_name
15
+ @join_table = options[:join_table] || [klass.name.pluralize.underscore.gsub(/\//,'_'), group_class_name.pluralize.underscore.gsub(/\//,'_')].sort.join('_')
16
+ @foreign_key = options[:foreign_key] || "#{klass.name.demodulize.underscore}_id"
17
+ @association_foreign_key = options[:association_foreign_key] || "#{group_class_name.demodulize.underscore}_id"
18
+ @habtm = options[:habtm] || (options[:grouped_by].to_s.demodulize.singularize != options[:grouped_by].to_s.demodulize)
19
+ end
20
+
21
+ #set the SQL fragments
22
+ requester_query
23
+ target_query
24
+ end
25
+ def habtm?
26
+ @habtm
27
+ end
28
+ def grouped?
29
+ !!@group_class_name
30
+ end
31
+
32
+ def klass_name
33
+ klass.base_class.name
34
+ end
35
+ def group_handler
36
+ ActiveAcl::GROUP_CLASSES[@group_class_name]
37
+ end
38
+
39
+ #checks the privilege of a requester on a target (optional)
40
+ def has_privilege?(requester,privilege,target=nil)
41
+ value = get_cached(requester,privilege,target)
42
+
43
+ return value unless value.nil? #got the cached and return
44
+ #todo check cash l2
45
+
46
+ vars={'requester_id' => requester.id}
47
+ sql = ''
48
+ sql << query_r_select
49
+ if target
50
+ t_handler=target.active_acl_handler
51
+
52
+ sql << t_handler.query_t_select
53
+ sql << "\n WHERE "
54
+ sql << query_r_where_3d
55
+ sql << t_handler.query_t_where
56
+ sql << "\n ORDER BY "
57
+
58
+ #TODO: ordering is a mess (use an array?)
59
+ order = (grouped? ? order_by_3d : [])
60
+ if t_handler.grouped?
61
+ order << "(CASE WHEN t_g_links.acl_id IS NULL THEN 0 ELSE 1 END) ASC"
62
+ order << t_handler.group_handler.order_by(target,true)
63
+ end
64
+ order << 'acls.updated_at DESC'
65
+ sql << order.join(',')
66
+
67
+ sql << " LIMIT 1"
68
+ vars['privilege_id'] = privilege.id
69
+ vars['target_id'] = target.id
70
+ vars['target_type'] = target.class.base_class.name
71
+ else
72
+ sql << " WHERE "
73
+ sql << query_r_where_2d
74
+ sql << "\n ORDER BY "
75
+ sql << order_by_2d
76
+ end
77
+
78
+ #replacing the vars in the SQL
79
+ sql=sql.gsub(/%{[^}]+}/) do |var|
80
+ vars[var[2..-2]] || var
81
+ end
82
+
83
+ results = ActiveAcl::OPTIONS[:db].query(sql) #get the query from the db
84
+ value=set_cached(requester,privilege,target,results)
85
+ return value
86
+ end
87
+ #gets the instance cache from the background store or a hash
88
+ def get_instance_cache(requester)
89
+ cache.get(requester_cache_id(requester)) || {}
90
+ end
91
+ #destroy the 2nd level cache
92
+ def delete_cached(requester)
93
+ cache.delete(requester_cache_id(requester))
94
+ end
95
+
96
+ attr_reader :query_t_select,:query_t_where
97
+
98
+ #Things go private from here ----------------
99
+ private
100
+ def cache
101
+ ActiveAcl::OPTIONS[:cache]
102
+ end
103
+
104
+ #builds a instance_cache key for a query
105
+ def query_id(requester,privilege,target)
106
+ privilege_id = (privilege.kind_of?(ActiveAcl::Privilege) ? privilege.id : privilege)
107
+ [privilege_id, klass.base_class.name, requester.id, (target ? target.class.base_class.name : ''), (target ? target.id.to_s : '')].join('-')
108
+ end
109
+
110
+ #builds the cache key for a requester for beackground cache
111
+ def requester_cache_id(requester)
112
+ 'active_acl_instance-' + klass.base_class.name + '-' + requester.id.to_s
113
+ end
114
+
115
+ # Caching is done on different levels:
116
+ # Requesting a 2d privilege should fill the instance cache with all 2d privileges
117
+ # Requesting a 3d should be stored in the instance cache
118
+ # changing the instance cache stores it to the backstore (if any exists)
119
+ def get_cached(requester,privilege,target)
120
+
121
+ instance_cache=requester.active_acl_instance_cache
122
+ q_id=query_id(requester,privilege,target)
123
+ # try to get from instance cache
124
+ if (value=instance_cache[q_id]).nil? #cache miss?
125
+ if target.nil? && requester.active_acl_cached_2d?
126
+ Rails.logger.debug 'ACTIVE_ACL::INSTANCE_CACHE::DENY ' + q_id
127
+ return false #it should be cached but it's not there: DENY
128
+ else
129
+ return nil #we don't cache all 3d acl: DB LOOKUP
130
+ end
131
+ else #found in cache: return the results
132
+ Rails.logger.debug 'ACTIVE_ACL::INSTANCE_CACHE::' + (value ? 'GRANT ' : 'DENY ') + q_id
133
+ return value
134
+ end
135
+ nil
136
+ end
137
+
138
+ def set_cached(requester,privilege,target,results)
139
+
140
+ this_query_id=query_id(requester,privilege,target)
141
+ instance_cache=requester.active_acl_instance_cache
142
+
143
+ if target.nil? #no target? then results are all 2d privileges of the requester
144
+ last_privilege_value = nil
145
+ results.each do |row|
146
+ if row['privilege_id'] != last_privilege_value
147
+ last_privilege_value = row['privilege_id']
148
+ q_id=query_id(requester,privilege,target)
149
+ #TODO: put the into the db handler
150
+ v=((row['allow'] == '1') or (row['allow'] == 't'))
151
+ instance_cache[q_id] = v
152
+ end
153
+ end
154
+ requester.active_acl_cached_2d! #mark the cache as cached (at least 2d)
155
+ # the result should be in the cache now or we return false
156
+ value=instance_cache[this_query_id] || false
157
+ else #3d request?
158
+ if results.empty?
159
+ value=false
160
+ instance_cache[this_query_id] = value
161
+ else #3d and a hit
162
+ value = ((results[0]['allow'].to_s == '1') or (results[0]['allow'].to_s == 't'))
163
+ instance_cache[this_query_id] = value
164
+ end
165
+ end
166
+ raise "something went realy wrong!" if value.nil?
167
+
168
+ #cache the whole instance cache
169
+ cache.set(requester_cache_id(requester),instance_cache,ActiveAcl::OPTIONS[:cache_privilege_timeout])
170
+
171
+ value
172
+ end
173
+
174
+ # build ACL query strings once,
175
+ # so we don't need to do this on every request
176
+ # SQL:
177
+ # we always need acl,and privileges, and requester_links
178
+ # we need the target_links if its a 3d query
179
+ # we need the target_groups if the it's a 3d query and the target is grouped
180
+ # we need the requester_groups if the requester is grouped
181
+ # the ordering depens on 2d/3d
182
+ # We'll build the SQL on demand and cache it so it'll
183
+ # be a function of: requester,target,privilege
184
+ attr_reader :query_r_select, :query_r_where_2d, :query_r_where_3d, :order_by_3d,:order_by_2d
185
+ def requester_query
186
+ @query_r_select = <<-QUERY
187
+ SELECT acls.id, acls.allow, privileges.id AS privilege_id FROM #{ActiveAcl::OPTIONS[:acls_table]} acls
188
+ LEFT JOIN #{ActiveAcl::OPTIONS[:acls_privileges_table]} acls_privileges ON acls_privileges.acl_id=acls.id
189
+ LEFT JOIN #{ActiveAcl::OPTIONS[:privileges_table]} privileges ON privileges.id = acls_privileges.privilege_id
190
+ LEFT JOIN #{ActiveAcl::OPTIONS[:requester_links_table]} r_links ON r_links.acl_id=acls.id
191
+ QUERY
192
+ if grouped?
193
+ requester_groups_table = group_class_name.constantize.table_name
194
+ requester_group_type = group_class_name.constantize.name
195
+
196
+ @query_r_select << "
197
+ LEFT JOIN #{ActiveAcl::OPTIONS[:requester_group_links_table]} r_g_links ON acls.id = r_g_links.acl_id AND r_g_links.requester_group_type = '#{requester_group_type}'
198
+ LEFT JOIN #{requester_groups_table} r_groups ON r_g_links.requester_group_id = r_groups.id
199
+ "
200
+ end
201
+
202
+ @query_r_where_3d = "acls.enabled = #{klass.connection.quote(true)} AND (privileges.id = %{privilege_id}) "
203
+ @query_r_where_2d = "acls.enabled = #{klass.connection.quote(true)}"
204
+ query = " AND ((r_links.requester_id=%{requester_id}
205
+ AND r_links.requester_type='#{klass.base_class.name}')"
206
+ if grouped?
207
+
208
+ query << " OR (r_g_links.requester_group_id IN #{group_handler.group_sql(self)})) "
209
+ else
210
+ query << ")"
211
+ end
212
+ @query_r_where_3d << query
213
+ @query_r_where_2d << query
214
+
215
+
216
+ #@query_r_where_2d << '(t_g_links.acl_id IS NULL)) '
217
+ @order_by_3d = []
218
+ @order_by_3d << "(CASE WHEN r_g_links.acl_id IS NULL THEN 0 ELSE 1 END) ASC"
219
+ @order_by_3d << group_handler.order_by(self) if grouped?
220
+
221
+
222
+
223
+ #TODO ordering of groups
224
+ @order_by_2d = 'privileges.id,'
225
+ @order_by_2d << "(CASE WHEN r_g_links.acl_id IS NULL THEN 0 ELSE 1 END) ASC," if grouped?
226
+ @order_by_2d << "acls.updated_at DESC"
227
+ end
228
+
229
+ def target_query
230
+ @query_t_select = " LEFT JOIN #{ActiveAcl::OPTIONS[:target_links_table]} t_links ON t_links.acl_id=acls.id"
231
+ if grouped?
232
+ target_groups_table = @group_class_name.constantize.table_name
233
+ target_group_type = @group_class_name.constantize.name
234
+
235
+ @query_t_select << " LEFT JOIN #{ActiveAcl::OPTIONS[:target_group_links_table]} t_g_links ON t_g_links.acl_id=acls.id
236
+ AND t_g_links.target_group_type = '#{target_group_type}'
237
+ LEFT JOIN #{target_groups_table} t_groups ON t_groups.id=t_g_links.target_group_id"
238
+ end
239
+ @query_t_where = " AND ((t_links.target_id=%{target_id}
240
+ AND t_links.target_type = '%{target_type}' )"
241
+ if grouped?
242
+ @query_t_where << " OR t_g_links.target_group_id IN #{group_handler.group_sql(self,true)})"
243
+ else
244
+ @query_t_where << ")"
245
+ end
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end
@@ -1,5 +1,3 @@
1
- #require 'active_support'
2
- #require 'action_view'
3
1
 
4
2
  class ActionController::Base
5
3
  # Get the access object for the current action.
@@ -14,7 +12,7 @@ class ActionController::Base
14
12
 
15
13
  # Overrides method_added, so the needed ActiveAcl::ControllerAction is loaded/created
16
14
  # when the action gets added to the controller.
17
- def self.method_added(action)
15
+ def self.method_added(action) #:nodoc:
18
16
  method_added_before_active_acl_controller_action_loading(action)
19
17
  ActiveAcl::CONTROLLERS[self.name] ||= {}
20
18
 
@@ -9,10 +9,10 @@ class ::Module
9
9
  result = []
10
10
  constant.is_a?(Hash) ? constant_hash = constant : constant_hash = {constant.to_s => nil}
11
11
  constant_hash.each_pair do |constant_name, description|
12
- if !const_defined?(constant_name.to_s) or force_reload
12
+ if !const_defined?(constant_name.to_s) || force_reload
13
13
  remove_const(constant_name.to_s) if const_defined?(constant_name.to_s)
14
14
  privilege = ActiveAcl::Privilege.find_by_section_and_value(self.name, constant_name.to_s)
15
- privilege = ActiveAcl::Privilege.create(:section => self.name, :value => constant_name.to_s, :description => description) unless privilege
15
+ privilege = ActiveAcl::Privilege.create!(:section => self.name, :value => constant_name.to_s, :description => description) unless privilege
16
16
  const_set(constant_name.to_s, privilege)
17
17
  result << privilege
18
18
  end
data/lib/active_acl.rb CHANGED
@@ -1,26 +1,32 @@
1
1
  module ActiveAcl
2
+
3
+
2
4
  end
3
5
 
4
6
  # plugin dependency
5
7
  require 'has_many_polymorphs'
6
8
 
7
- ActiveAcl::CONTROLLERS = {}
8
-
9
9
  require 'active_acl/options'
10
+ require 'active_acl/base'
11
+
10
12
  require 'active_acl/privilege_const_set'
13
+ require 'active_acl/grant'
14
+
15
+ require 'active_acl/handler/object_handler'
16
+ require 'active_acl/handler/nested_set'
11
17
  require 'active_acl/db/active_record_adapter'
12
18
  require 'active_acl/cache/no_cache_adapter'
13
19
  require 'active_acl/load_controller_actions'
14
20
  require 'active_acl/acts_as_access_object'
15
21
  require 'active_acl/acts_as_access_group'
16
-
17
22
  require 'active_acl/load_files_from'
18
23
 
24
+
19
25
  # call class so its loaded and registered as access object
20
26
  # wrap in rescue block so migrations don't fail
21
27
  begin
22
28
  ActiveAcl::ControllerAction
23
29
  ActiveAcl::ControllerGroup
24
- rescue
25
- nil
30
+ rescue StandardError => e
31
+ puts "Error #{e.message} #{e.backtrace.join("\n")}(need migrations?)"
26
32
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: activeaclplus
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Peter Schrammel
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2008-12-07 00:00:00 +01:00
13
+ date: 2009-03-04 00:00:00 +01:00
14
14
  default_executable:
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
@@ -30,8 +30,10 @@ executables: []
30
30
 
31
31
  extensions: []
32
32
 
33
- extra_rdoc_files: []
34
-
33
+ extra_rdoc_files:
34
+ - README.rdoc
35
+ - LICENSE
36
+ - CHANGELOG
35
37
  files:
36
38
  - lib/active_acl
37
39
  - lib/active_acl/db
@@ -40,45 +42,51 @@ files:
40
42
  - lib/active_acl/cache
41
43
  - lib/active_acl/cache/no_cache_adapter.rb
42
44
  - lib/active_acl/cache/memcache_adapter.rb
43
- - lib/active_acl/target_group_link.rb
44
- - lib/active_acl/controller_action.rb
45
- - lib/active_acl/acl_section.rb
45
+ - lib/active_acl/handler
46
+ - lib/active_acl/handler/object_handler.rb
47
+ - lib/active_acl/handler/nested_set.rb
46
48
  - lib/active_acl/load_files_from.rb
47
- - lib/active_acl/acts_as_access_object.rb
48
- - lib/active_acl/privilege.rb
49
49
  - lib/active_acl/options.rb
50
- - lib/active_acl/requester_link.rb
51
- - lib/active_acl/controller_group.rb
52
- - lib/active_acl/acl.rb
53
50
  - lib/active_acl/load_controller_actions.rb
54
- - lib/active_acl/target_link.rb
55
51
  - lib/active_acl/privilege_const_set.rb
56
- - lib/active_acl/requester_group_link.rb
57
52
  - lib/active_acl/acts_as_access_group.rb
53
+ - lib/active_acl/acts_as_access_object.rb
54
+ - lib/active_acl/grant.rb
55
+ - lib/active_acl/base.rb
58
56
  - lib/active_acl.rb
59
57
  - tasks/active_acl_base_tasks.rake
60
- - generators/active_acl
61
- - generators/active_acl/templates
62
- - generators/active_acl/templates/controllers
63
- - generators/active_acl/templates/controllers/privileges_controller.rb
64
- - generators/active_acl/templates/views
65
- - generators/active_acl/templates/views/privileges
66
- - generators/active_acl/templates/views/privileges/list.rhtml
67
- - generators/active_acl/templates/views/privileges/edit.rhtml
68
- - generators/active_acl/templates/views/privileges/_privilege_form.rhtml
69
- - generators/active_acl/active_acl_generator.rb
70
58
  - db/migrate
71
59
  - db/migrate/001_base_table_setup.rb
60
+ - app/models
61
+ - app/models/active_acl
62
+ - app/models/active_acl/acl_section.rb
63
+ - app/models/active_acl/controller_group.rb
64
+ - app/models/active_acl/privilege.rb
65
+ - app/models/active_acl/requester_group_link.rb
66
+ - app/models/active_acl/requester_link.rb
67
+ - app/models/active_acl/target_group_link.rb
68
+ - app/models/active_acl/target_link.rb
69
+ - app/models/active_acl/controller_action.rb
70
+ - app/models/active_acl/acl.rb
71
+ - app/controllers
72
+ - app/controllers/privileges_controller.rb
73
+ - app/view
74
+ - app/view/privileges
75
+ - app/view/privileges/list.rhtml
76
+ - app/view/privileges/edit.rhtml
77
+ - app/view/privileges/_privilege_form.rhtml
72
78
  - init.rb
73
79
  - install.rb
74
- - LICENSE
75
80
  - Rakefile
76
81
  - README.rdoc
82
+ - LICENSE
77
83
  - CHANGELOG
78
84
  has_rdoc: true
79
85
  homepage: http://activeaclplus.rubyforge.org/
80
86
  post_install_message:
81
87
  rdoc_options:
88
+ - --title
89
+ - Active Acl Plus
82
90
  - --main
83
91
  - README.rdoc
84
92
  require_paths:
@@ -98,9 +106,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
106
  requirements: []
99
107
 
100
108
  rubyforge_project: activeaclplus
101
- rubygems_version: 1.2.0
109
+ rubygems_version: 1.3.1
102
110
  signing_key:
103
111
  specification_version: 2
104
- summary: activeaclplus 0.3.0
112
+ summary: A new Version (0.4.0) of ActiveAclPlus is available.
105
113
  test_files: []
106
114
 
@@ -1,29 +0,0 @@
1
- class ActiveAclGenerator < Rails::Generator::Base
2
- attr_accessor :privileges_class_name, :privileges_file_name, :privileges_view_dir
3
-
4
- def initialize(*runtime_args)
5
- super(*runtime_args)
6
- @privileges_class_name = (args[0] || 'PrivilegesController')
7
- @privileges_file_name = @privileges_class_name.underscore
8
- @privileges_view_dir = File.join('app', 'views', @privileges_file_name.gsub('_controller', ''))
9
- end
10
-
11
- def manifest
12
- record do |m|
13
- # Stylesheet, controllers and public directories.
14
- m.directory File.join('public', 'stylesheets')
15
- m.directory File.join('app', 'controllers')
16
- m.directory File.join('app', 'views')
17
- m.directory privileges_view_dir
18
-
19
- m.template 'controllers/privileges_controller.rb', File.join('app', 'controllers', "#{privileges_file_name}.rb")
20
- m.file 'views/privileges/_privilege_form.rhtml', File.join(privileges_view_dir, '_privilege_form.rhtml')
21
- m.file 'views/privileges/edit.rhtml', File.join(privileges_view_dir, 'edit.rhtml')
22
- m.file 'views/privileges/list.rhtml', File.join(privileges_view_dir, 'list.rhtml')
23
- m.migration_template('../../../db/migrate/001_base_table_setup.rb',
24
- 'db/migrate',
25
- :assigns => {:migration_name => "BaseTableSetup"},
26
- :migration_file_name => "base_table_setup")
27
- end
28
- end
29
- end