qm-acts-as-generic-controller 0.1.16 → 0.1.17

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.
data/Rakefile CHANGED
@@ -10,7 +10,7 @@ begin
10
10
  gemspec.email = "marcin@saepia.net"
11
11
  gemspec.homepage = "http://q.saepia.net"
12
12
  gemspec.authors = ["Marcin Lewandowski"]
13
- gemspec.version = "0.1.16"
13
+ gemspec.version = "0.1.17"
14
14
  gemspec.files = Rake::FileList.new [ "MIT-LICENSE", "Rakefile", "lib/*", "app/views/generic_controller/*" ]
15
15
  gemspec.add_dependency "qui-common-helpers", ">= 0.0.8"
16
16
  gemspec.add_dependency "qui-index-table", ">= 0.0.8"
@@ -48,7 +48,7 @@
48
48
  <%- tab_headers = {} -%>
49
49
  <%- record.class.generic_field_associations.each do |k,v| -%>
50
50
  <%- if current_user.respond_to? "has_privileges?" -%>
51
- <%- has_privileges = current_user.has_privileges?(:class_name => v[:class_name], :generic_action => :index_any) -%>
51
+ <%- has_privileges = current_user.has_privileges?(:class_name => v[:class_name], :generic_action => :index_any) || current_user.has_privileges?(:class_name => v[:class_name], :generic_action => :index_created)-%>
52
52
  <%- has_privileges_to_generic_create = current_user.has_privileges?(:class_name => v[:class_name], :generic_action => :create) -%>
53
53
  <%- else -%>
54
54
  <%- has_privileges = true -%>
@@ -63,14 +63,8 @@
63
63
 
64
64
  <%- end -%>
65
65
 
66
- <%- if v[:class_name].respond_to? :limit_for_user -%>
67
- <%- tab_headers[k] = t(:"#{section_prefix}tabs.#{table_name}.#{k}") + " (#{record.send(k).limit_for_user(current_user).count})" %>
68
- <%= render :partial => "generic_controller/index_table", :locals => { :records => record.send(k).limit_for_user(current_user), :class_name => v[:class_name] } %>
69
-
70
- <%- else -%>
71
- <%- tab_headers[k] = t(:"#{section_prefix}tabs.#{table_name}.#{k}") + " (#{record.send(k).count})" %>
72
- <%= render :partial => "generic_controller/index_table", :locals => { :records => record.send(k), :class_name => v[:class_name] } %>
73
- <%- end -%>
66
+ <%- tab_headers[k] = t(:"#{section_prefix}tabs.#{table_name}.#{k}") + " (#{record.send(k).limit_with_security_scheme(:user => current_user).size})" %>
67
+ <%= render :partial => "generic_controller/index_table", :locals => { :records => record.send(k).limit_with_security_scheme(:user => current_user), :class_name => v[:class_name] } %>
74
68
 
75
69
  <%- end -%>
76
70
  <%- end -%>
@@ -36,38 +36,14 @@ module QM
36
36
  module InstanceMethods
37
37
  def index
38
38
  unless instance_variable_defined?(plural_variable)
39
- if params[:scopes] and params[:scopes].is_a?(Array)
40
- valid_scopes = params[:scopes].uniq.each{ |scope| scope if model.generic_named_scopes.has_key? scope.to_sym }.compact
41
- if valid_scopes.size > 0
42
- if defined?(current_user) and model.respond_to? :limit_for_user
43
- data = eval "model.#{valid_scopes.join(".")}.limit_for_user(#{current_user})"
44
- else
45
- data = eval "model.#{valid_scopes.join(".")}"
46
- end
47
- else
48
- if defined?(current_user) and model.respond_to? :limit_for_user
49
- data = model.limit_for_user(current_user)
50
- else
51
- data = model.all
52
- end
53
- end
54
- else
55
- if defined?(current_user) and model.respond_to? :limit_for_user
56
- data = model.limit_for_user(current_user)
57
- else
58
- data = model.all
59
- end
60
- end
61
-
62
-
63
- instance_variable_set(plural_variable, data)
39
+ instance_variable_set(plural_variable, model.limit_with_security_scheme(:user => current_user))
64
40
  end
65
41
 
66
42
  respond_to do |format|
67
43
  format.html
68
44
  format.xml {
69
45
  if defined?(current_user) and current_user.respond_to? :privileged_attributes
70
- render :xml => instance_variable_get(plural_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id])
46
+ render :xml => instance_variable_get(plural_variable).to_xml(:only => current_user_xml_privileged_attributes)
71
47
  else
72
48
  render :xml => instance_variable_get(plural_variable)
73
49
  end
@@ -76,15 +52,16 @@ module QM
76
52
  end
77
53
 
78
54
  def show
79
-
80
55
  instance_variable_set(singular_variable, model.find(params[:id])) unless instance_variable_defined?(singular_variable)
81
56
 
57
+ check_generic_actions or return
58
+
82
59
  respond_to do |format|
83
- format.html
60
+ format.html
84
61
 
85
62
  format.xml {
86
63
  if defined?(current_user) and current_user.respond_to? :privileged_attributes
87
- render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id])
64
+ render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user_xml_privileged_attributes)
88
65
  else
89
66
  render :xml => instance_variable_get(singular_variable)
90
67
  end
@@ -94,6 +71,8 @@ module QM
94
71
 
95
72
  def edit
96
73
  instance_variable_set(singular_variable, model.find(params[:id])) unless instance_variable_defined?(singular_variable)
74
+
75
+ check_generic_actions or return
97
76
  end
98
77
 
99
78
  def new
@@ -103,7 +82,7 @@ module QM
103
82
  format.html
104
83
  format.xml {
105
84
  if defined?(current_user) and current_user.respond_to? :privileged_attributes
106
- render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id])
85
+ render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user_xml_privileged_attributes)
107
86
  else
108
87
  render :xml => instance_variable_get(singular_variable)
109
88
  end
@@ -137,7 +116,7 @@ module QM
137
116
  end
138
117
  }
139
118
 
140
- format.xml { render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id]), :status => :created, :location => [ section, instance_variable_get(singular_variable) ] }
119
+ format.xml { render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user_xml_privileged_attributes), :status => :created, :location => [ section, instance_variable_get(singular_variable) ] }
141
120
 
142
121
 
143
122
  else
@@ -157,9 +136,9 @@ module QM
157
136
 
158
137
  format.xml {
159
138
  if defined?(current_user) and current_user.respond_to? :privileged_attributes
160
- render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id]), :status => :created, :location => instance_variable_get(singular_variable)
139
+ render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user_xml_privileged_attributes), :status => :created, :location => instance_variable_get(singular_variable)
161
140
  else
162
- render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id]), :status => :created, :location => instance_variable_get(singular_variable)
141
+ render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user_xml_privileged_attributes), :status => :created, :location => instance_variable_get(singular_variable)
163
142
  end
164
143
  }
165
144
  end
@@ -174,7 +153,7 @@ module QM
174
153
  }
175
154
  format.xml {
176
155
  if defined?(current_user) and current_user.respond_to? :privileged_attributes
177
- render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id]), :status => :unprocessable_entity
156
+ render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user_xml_privileged_attributes), :status => :unprocessable_entity
178
157
  else
179
158
  render :xml => instance_variable_get(singular_variable), :status => :unprocessable_entity
180
159
  end
@@ -186,6 +165,8 @@ module QM
186
165
  def update
187
166
  instance_variable_set(singular_variable, model.find(params[:id])) unless instance_variable_defined?(singular_variable)
188
167
 
168
+ check_generic_actions or return
169
+
189
170
  remove_unprivileged_keys_from_params
190
171
 
191
172
  instance_variable_get(singular_variable).update_attributes params[singular_variable(true)]
@@ -212,7 +193,7 @@ module QM
212
193
  }
213
194
  format.xml {
214
195
  if defined?(current_user) and current_user.respond_to? :privileged_attributes
215
- render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user.privileged_attributes(model, :read, true) + [:id]), :status => :unprocessable_entity
196
+ render :xml => instance_variable_get(singular_variable).to_xml(:only => current_user_xml_privileged_attributes), :status => :unprocessable_entity
216
197
  else
217
198
  render :xml => instance_variable_get(singular_variable), :status => :unprocessable_entity
218
199
  end
@@ -223,6 +204,9 @@ module QM
223
204
 
224
205
  def destroy
225
206
  instance_variable_set(singular_variable, model.find(params[:id])) unless instance_variable_defined?(singular_variable)
207
+
208
+ check_generic_actions or return
209
+
226
210
  instance_variable_get(singular_variable).destroy
227
211
 
228
212
  flash[:notice] = :destroyedAsFlash
@@ -235,11 +219,11 @@ module QM
235
219
 
236
220
  protected
237
221
  def save_creator
238
- instance_variable_get(singular_variable).send("creator_#{current_user.class.to_s.tableize.singularize}_id=", current_user.id) if defined?(current_user) and instance_variable_get(singular_variable).respond_to? "creator_#{current_user.class.to_s.tableize.singularize}_id="
222
+ instance_variable_get(singular_variable).send("#{creator_column}=", current_user.id) if defined?(current_user) and instance_variable_get(singular_variable).respond_to? "#{creator_column}="
239
223
  end
240
224
 
241
225
  def save_updator
242
- instance_variable_get(singular_variable).send("updator_#{current_user.class.to_s.tableize.singularize}_id=", current_user.id) if defined?(current_user) and instance_variable_get(singular_variable).respond_to? "updator_#{current_user.class.to_s.tableize.singularize}_id="
226
+ instance_variable_get(singular_variable).send("#{updator_column}=", current_user.id) if defined?(current_user) and instance_variable_get(singular_variable).respond_to? "#{updator_column}="
243
227
  end
244
228
 
245
229
  def model
@@ -255,6 +239,29 @@ module QM
255
239
  end
256
240
 
257
241
 
242
+ def check_generic_actions
243
+ if has_creator?
244
+ action = case params[:action].to_sym
245
+ when :show
246
+ :show_created
247
+ when :edit
248
+ :update_created
249
+ when :update
250
+ :update_created
251
+ when :destroy
252
+ :delete_created
253
+ end
254
+
255
+ if not current_user.has_privileges?({:class_name => model, :generic_action => "#{params[:action]}_any".to_sym}) and current_user.has_privileges?({:class_name => model, :generic_action => action.to_sym}) and instance_variable_get(singular_variable).send(creator_column) != current_user.id
256
+
257
+ logger.warn "Security warning: User #{current_user.login} has #{action} privileges, but there is a creator's ID mismatch (current user: #{current_user.id}, record: #{instance_variable_get(singular_variable).send(creator_column)}. Action #{params[:action]} on #{model} was stopped."
258
+ render_generic_forbidden
259
+ return false
260
+ end
261
+ end
262
+ true
263
+ end
264
+
258
265
  def check_generic_privileges
259
266
  return true unless defined?(current_user)
260
267
  return true unless current_user.respond_to? "has_privileges?"
@@ -262,24 +269,38 @@ module QM
262
269
  action = params[:action].to_sym
263
270
  action = case action
264
271
  when :index
265
- :index_any
272
+ [ :index_any, :index_created ] # Limited access to the elements should be provided by limit_for_user, which (TODO) should be automatically generated
266
273
  when :show
267
- :show_any
274
+ [ :show_any, :show_created ]
268
275
  when :edit
269
- :update_any
276
+ [ :update_any, :update_created ]
270
277
  when :update
271
- :update_any
278
+ [ :update_any, :update_created ]
272
279
  when :create
273
280
  :create
274
281
  when :destroy
275
- :delete_any
282
+ [ :delete_any, :delete_created ]
276
283
  end
277
284
 
278
- unless current_user.has_privileges? :class_name => model, :action => action
279
- logger.info "Security warning: User #{current_user.login} has not enough privileges to perform action #{action} on #{model}"
285
+ if action.is_a? Array
286
+ has_privileges = false
287
+ action.each do |a|
288
+ if current_user.has_privileges? :class_name => model, :generic_action => a
289
+ has_privileges = true
290
+ break
291
+ end
292
+ end
293
+ else
294
+ has_privileges = current_user.has_privileges? :class_name => model, :generic_action => action
295
+ end
296
+
297
+ unless has_privileges
298
+ logger.warn "Security warning: User #{current_user.login} has not enough privileges to perform action #{params[:action]} on #{model}"
280
299
  render_generic_forbidden
300
+ return false
281
301
  end
282
302
 
303
+ true
283
304
  end
284
305
 
285
306
  def check_limit_for_user
@@ -290,14 +311,32 @@ module QM
290
311
  if defined?(current_user) and current_user.respond_to? :privileged_attributes
291
312
  params[singular_variable(true)].keys.each do |key|
292
313
  if not current_user.privileged_attributes(model, :write).include?(key) and (model.generic_field_associations.has_key?(key.to_sym) and not current_user.privileged_attributes(model, :write).include?(model.generic_field_associations[key.to_sym][:foreign_key]))
293
- logger.info "Security warning: Deleting key '#{key}' from params hash, because user #{current_user.login} has not enough privileges to modify that attribute"
314
+ logger.warn "Security warning: Deleting key '#{key}' from params hash, because user #{current_user.login} has not enough privileges to modify that attribute"
294
315
  params[singular_variable(true)].delete key
295
316
  end
296
317
  end
297
318
  end
298
319
  end
299
320
 
321
+ def current_user_xml_privileged_attributes
322
+ current_user.privileged_attributes(model, :read, true) + [:id]
323
+ end
300
324
 
325
+ def creator_column
326
+ "creator_#{current_user.class.to_s.tableize.singularize}_id"
327
+ end
328
+
329
+ def has_creator?
330
+ model.columns_hash.has_key? creator_column
331
+ end
332
+
333
+ def updator_column
334
+ "updator_#{current_user.class.to_s.tableize.singularize}_id"
335
+ end
336
+
337
+ def has_updator?
338
+ model.columns_hash.has_key? updator_column
339
+ end
301
340
 
302
341
  def render_generic_forbidden
303
342
  # FIXME TODO render something more nice to user
@@ -3,10 +3,36 @@ module QM
3
3
  module ModelIncludes
4
4
  def self.included(base) # :nodoc:
5
5
  base.extend ClassMethods
6
-
7
6
  end
8
7
 
9
8
  module ClassMethods
9
+ def limit_with_security_scheme(options)
10
+ # options[:user] - current user that performs the query
11
+
12
+ raise ArgumentError, "You must pass options[:user] to limit_with_security_scheme" unless options.has_key? :user
13
+
14
+ # Return empty set if user has no privileges at all (nor index_any and index_created)
15
+ return [] if !options[:user].has_privileges?(:class_name => self, :generic_action => :index_any) && !options[:user].has_privileges?(:class_name => self, :generic_action => :index_created)
16
+
17
+ creator_column = "creator_#{options[:user].class.to_s.tableize.singularize}_id"
18
+ should_limit_index_for_created = columns_hash.has_key?(creator_column) && options[:user].respond_to?(:has_privileges?) && !options[:user].has_privileges?(:class_name => self, :generic_action => :index_any) && options[:user].has_privileges?(:class_name => self, :generic_action => :index_created)
19
+
20
+
21
+ if respond_to? :limit_for_user
22
+ if should_limit_index_for_created
23
+ limit_for_user(options[:user]).find(:all, :conditions => { creator_column => options[:user].id })
24
+ else
25
+ limit_for_user(options[:user])
26
+ end
27
+ else
28
+ if should_limit_index_for_created
29
+ find(:all, :conditions => { creator_column => options[:user].id })
30
+ else
31
+ all
32
+ end
33
+ end
34
+ end
35
+
10
36
  def generic_field_associations
11
37
  @generic_field_associations || {}
12
38
  end
@@ -62,8 +88,6 @@ module QM
62
88
 
63
89
  super name, options, &block
64
90
  end
65
-
66
-
67
91
 
68
92
  def generic_actions(options = {})
69
93
  @generic_actions ||= {}
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: qm-acts-as-generic-controller
3
3
  version: !ruby/object:Gem::Version
4
- hash: 59
4
+ hash: 57
5
5
  prerelease: false
6
6
  segments:
7
7
  - 0
8
8
  - 1
9
- - 16
10
- version: 0.1.16
9
+ - 17
10
+ version: 0.1.17
11
11
  platform: ruby
12
12
  authors:
13
13
  - Marcin Lewandowski
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-01-07 00:00:00 +01:00
18
+ date: 2011-01-10 00:00:00 +01:00
19
19
  default_executable:
20
20
  dependencies:
21
21
  - !ruby/object:Gem::Dependency