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.
|
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
|
-
<%-
|
67
|
-
|
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
|
-
|
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 =>
|
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 =>
|
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 =>
|
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 =>
|
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 =>
|
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 =>
|
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 =>
|
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 =>
|
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("
|
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("
|
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
|
-
|
279
|
-
|
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.
|
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:
|
4
|
+
hash: 57
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 0.1.
|
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-
|
18
|
+
date: 2011-01-10 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|