jsonapi-authorization 0.5.0 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 29b3ceafd8c61b2dfe1d2ac684714569d8cb70a2
4
- data.tar.gz: 5fc76942b71575e6cfd4b0700c0d26572d681c65
3
+ metadata.gz: 47495edb7695129cd3ddd577ce547db63df70b4f
4
+ data.tar.gz: 68f2686dfa2143ec831816e39b02a1c2170ec3a0
5
5
  SHA512:
6
- metadata.gz: 037b2a7cb5a7418d18c848a0044ca1c93d81386c897253713137323221ebdfdedc9b69609d0e177299939ce0b83ce2ab541bad9a53ffa29a3a72750483ce19e8
7
- data.tar.gz: 51fb54f0056bfedd6caf847cd00012cf1c45cc04897004c4e6546c78d25fa38177fcfbf1e7e02f0ff17b293679bfea85f88d9b67e490f2883c9f35a1db0b04ae
6
+ metadata.gz: 79314420e9e62352436beca771f31823a9fc2bfb72122deada6a4bac09941ee4593b9f468747392ddfbe0169a6737f1d7b93a3b17c486000fcf223ca8faf1f19
7
+ data.tar.gz: 87389fd2aa637d0233666f747fab5c8aaded2371594d09915879d70d6d6e0120327b9a2cf3bd00bea35d17036cb34705aeeea7a7338f98024a9fecb8f5d2fcc5
data/bin/console CHANGED
@@ -1,6 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  require "bundler/setup"
4
+ require "rails/all"
4
5
  require "jsonapi/authorization"
5
6
 
6
7
  # You can add fixtures and/or initialization code here to make experimenting
@@ -10,5 +11,5 @@ require "jsonapi/authorization"
10
11
  # require "pry"
11
12
  # Pry.start
12
13
 
13
- require "irb"
14
- IRB.start
14
+ require "pry"
15
+ Pry.start
@@ -17,6 +17,32 @@ module JSONAPI
17
17
  set_callback :remove_to_many_relationship_operation, :before, :authorize_remove_to_many_relationship
18
18
  set_callback :remove_to_one_relationship_operation, :before, :authorize_remove_to_one_relationship
19
19
 
20
+ [
21
+ :find_operation,
22
+ :show_operation,
23
+ :show_related_resource_operation,
24
+ :show_related_resources_operation,
25
+ :create_resource_operation,
26
+ :replace_fields_operation
27
+ ].each do |op_name|
28
+ set_callback op_name, :after, :authorize_include_directive
29
+ end
30
+
31
+ def authorize_include_directive
32
+ return if @result.is_a?(::JSONAPI::ErrorsOperationResult)
33
+ resources = Array.wrap(
34
+ if @result.respond_to?(:resources)
35
+ @result.resources
36
+ elsif @result.respond_to?(:resource)
37
+ @result.resource
38
+ end
39
+ )
40
+
41
+ resources.each do |resource|
42
+ authorize_model_includes(resource._model)
43
+ end
44
+ end
45
+
20
46
  def authorize_find
21
47
  authorizer.find(@operation.resource_klass._model_class)
22
48
  end
@@ -209,8 +235,12 @@ module JSONAPI
209
235
  end
210
236
  end
211
237
 
238
+ def resource_class_for_relationship(assoc_name)
239
+ @operation.resource_klass._relationship(assoc_name).resource_klass
240
+ end
241
+
212
242
  def model_class_for_relationship(assoc_name)
213
- @operation.resource_klass._relationship(assoc_name).resource_klass._model_class
243
+ resource_class_for_relationship(assoc_name)._model_class
214
244
  end
215
245
 
216
246
  def related_models
@@ -218,13 +248,71 @@ module JSONAPI
218
248
  return [] if data.nil?
219
249
 
220
250
  [:to_one, :to_many].flat_map do |rel_type|
221
- data[rel_type].flat_map do |assoc_name, assoc_ids|
222
- assoc_klass = model_class_for_relationship(assoc_name)
223
- # TODO: find_by_key?
224
- assoc_klass.find(assoc_ids)
251
+ data[rel_type].flat_map do |assoc_name, assoc_value|
252
+ case assoc_value
253
+ when Hash # polymorphic relationship
254
+ resource_class = @operation.resource_klass.resource_for(assoc_value[:type].to_s)
255
+ resource_class.find_by_key(assoc_value[:id], context: @operation.options[:context])._model
256
+ else
257
+ resource_class = resource_class_for_relationship(assoc_name)
258
+ primary_key = resource_class._primary_key
259
+ resource_class._model_class.where(primary_key => assoc_value)
260
+ end
225
261
  end
226
262
  end
227
263
  end
264
+
265
+ def authorize_model_includes(source_record)
266
+ if @request.include_directives
267
+ @request.include_directives.model_includes.each do |include_item|
268
+ authorize_include_item(@operation.resource_klass, source_record, include_item)
269
+ end
270
+ end
271
+ end
272
+
273
+ def authorize_include_item(resource_klass, source_record, include_item)
274
+ case include_item
275
+ when Hash
276
+ # e.g. {articles: [:comments, :author]} when ?include=articles.comments,articles.author
277
+ include_item.each do |rel_name, deep|
278
+ authorize_include_item(resource_klass, source_record, rel_name)
279
+ relationship = resource_klass._relationship(rel_name)
280
+ next_resource_klass = relationship.resource_klass
281
+ Array.wrap(
282
+ source_record.public_send(
283
+ relationship.relation_name(@operation.options[:context])
284
+ )
285
+ ).each do |next_source_record|
286
+ deep.each do |next_include_item|
287
+ authorize_include_item(
288
+ next_resource_klass,
289
+ next_source_record,
290
+ next_include_item
291
+ )
292
+ end
293
+ end
294
+ end
295
+ when Symbol
296
+ relationship = resource_klass._relationship(include_item)
297
+ case relationship
298
+ when JSONAPI::Relationship::ToOne
299
+ related_record = source_record.public_send(
300
+ relationship.relation_name(@operation.options[:context])
301
+ )
302
+ return if related_record.nil?
303
+ authorizer.include_has_one_resource(source_record, related_record)
304
+ when JSONAPI::Relationship::ToMany
305
+ authorizer.include_has_many_resource(
306
+ source_record,
307
+ relationship.resource_klass._model_class
308
+ )
309
+ else
310
+ raise "Unexpected relationship type: #{relationship.inspect}"
311
+ end
312
+ else
313
+ raise "Unknown include directive: #{include_item}"
314
+ end
315
+ end
228
316
  end
229
317
  end
230
318
  end
@@ -190,6 +190,40 @@ module JSONAPI
190
190
  def remove_to_one_relationship(source_record, related_record)
191
191
  raise NotImplementedError
192
192
  end
193
+
194
+ # Any request including <tt>?include=other-resources</tt>
195
+ #
196
+ # This will be called for each has_many relationship if the include goes
197
+ # deeper than one level until some authorization fails or the include
198
+ # directive has been travelled completely.
199
+ #
200
+ # We can't pass all the records of a +has_many+ association here due to
201
+ # performance reasons, so the class is passed instead.
202
+ #
203
+ # ==== Parameters
204
+ #
205
+ # * +source_record+ — The source relationship record, e.g. an Article in
206
+ # article.comments check
207
+ # * +record_class+ - The underlying record class for the relationships
208
+ # resource.
209
+ def include_has_many_resource(source_record, record_class)
210
+ ::Pundit.authorize(user, record_class, 'index?')
211
+ end
212
+
213
+ # Any request including <tt>?include=another-resource</tt>
214
+ #
215
+ # This will be called for each has_one relationship if the include goes
216
+ # deeper than one level until some authorization fails or the include
217
+ # directive has been travelled completely.
218
+ #
219
+ # ==== Parameters
220
+ #
221
+ # * +source_record+ — The source relationship record, e.g. an Article in
222
+ # article.author check
223
+ # * +related_record+ - The associated record to return
224
+ def include_has_one_resource(source_record, related_record)
225
+ ::Pundit.authorize(user, related_record, 'show?')
226
+ end
193
227
  end
194
228
  end
195
229
  end
@@ -1,5 +1,5 @@
1
1
  module JSONAPI
2
2
  module Authorization
3
- VERSION = "0.5.0".freeze
3
+ VERSION = "0.6.0".freeze
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jsonapi-authorization
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vesa Laakso
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-01-28 00:00:00.000000000 Z
12
+ date: 2016-03-08 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: jsonapi-resources