fun_with_json_api 0.0.5 → 0.0.6.pre.alpha.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/config/locales/fun_with_json_api.en.yml +3 -0
- data/lib/fun_with_json_api/attributes/relationship.rb +11 -3
- data/lib/fun_with_json_api/attributes/relationship_collection.rb +21 -6
- data/lib/fun_with_json_api/deserializer.rb +12 -1
- data/lib/fun_with_json_api/deserializer_class_methods.rb +27 -17
- data/lib/fun_with_json_api/exceptions/unauthorized_resource.rb +16 -0
- data/lib/fun_with_json_api/find_collection_from_document.rb +9 -33
- data/lib/fun_with_json_api/find_resource_from_document.rb +10 -3
- data/lib/fun_with_json_api/schema_validators/check_collection_has_all_members.rb +67 -0
- data/lib/fun_with_json_api/schema_validators/check_collection_is_authorized.rb +63 -0
- data/lib/fun_with_json_api/schema_validators/check_relationships.rb +2 -2
- data/lib/fun_with_json_api/schema_validators/check_resource_is_authorized.rb +50 -0
- data/lib/fun_with_json_api/version.rb +1 -1
- data/spec/dummy/log/test.log +34269 -0
- data/spec/fun_with_json_api/deserializer_spec.rb +52 -10
- data/spec/fun_with_json_api/find_collection_from_document_spec.rb +82 -4
- data/spec/fun_with_json_api/find_resource_from_document_spec.rb +36 -2
- data/spec/fun_with_json_api/schema_validators/check_relationships_spec.rb +2 -2
- data/spec/fun_with_json_api_spec.rb +68 -0
- metadata +8 -4
@@ -458,7 +458,7 @@ describe FunWithJsonApi::Deserializer do
|
|
458
458
|
expect(payload.status).to eq '404'
|
459
459
|
expect(payload.code).to eq 'missing_relationship'
|
460
460
|
expect(payload.title).to eq 'Unable to find the requested relationship'
|
461
|
-
expect(payload.pointer).to eq '/data/relationships/example/id'
|
461
|
+
expect(payload.pointer).to eq '/data/relationships/example/data/id'
|
462
462
|
expect(payload.detail).to eq "Unable to find 'persons' with matching id: \"foobar\""
|
463
463
|
end
|
464
464
|
end
|
@@ -495,12 +495,54 @@ describe FunWithJsonApi::Deserializer do
|
|
495
495
|
end.create
|
496
496
|
end
|
497
497
|
|
498
|
-
|
499
|
-
author_a
|
500
|
-
author_b
|
501
|
-
|
502
|
-
|
503
|
-
|
498
|
+
context 'with multiple resources' do
|
499
|
+
let!(:author_a) { ARModels::Author.create(id: 1, code: 'foobar') }
|
500
|
+
let!(:author_b) { ARModels::Author.create(id: 2, code: 'blargh') }
|
501
|
+
|
502
|
+
context 'when all resources are authorised' do
|
503
|
+
before do
|
504
|
+
resource_authorizer = double(:resource_authorizer)
|
505
|
+
allow(resource_authorizer).to receive(:call).and_return(true)
|
506
|
+
allow(deserializer.relationship_for(:examples).deserializer).to(
|
507
|
+
receive(:resource_authorizer).and_return(resource_authorizer)
|
508
|
+
)
|
509
|
+
end
|
510
|
+
|
511
|
+
it 'finds a resource by the defined id_param and returns the resource id' do
|
512
|
+
expect(deserializer.parse_example_ids(%w(foobar blargh))).to eq(
|
513
|
+
[author_a.id, author_b.id]
|
514
|
+
)
|
515
|
+
end
|
516
|
+
end
|
517
|
+
|
518
|
+
context 'when a resource is not authorised' do
|
519
|
+
before do
|
520
|
+
resource_authorizer = double(:resource_authorizer)
|
521
|
+
allow(resource_authorizer).to receive(:call).and_return(false)
|
522
|
+
allow(resource_authorizer).to receive(:call).with(author_b).and_return(false)
|
523
|
+
allow(resource_authorizer).to receive(:call).with(author_a).and_return(true)
|
524
|
+
allow(deserializer.relationship_for(:examples).deserializer).to(
|
525
|
+
receive(:resource_authorizer).and_return(resource_authorizer)
|
526
|
+
)
|
527
|
+
end
|
528
|
+
|
529
|
+
it 'raises a UnauthorisedResource when unable to find a single resource' do
|
530
|
+
expect do
|
531
|
+
deserializer.parse_example_ids %w(foobar blargh)
|
532
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnauthorisedResource) do |e|
|
533
|
+
expect(e.payload.size).to eq 1
|
534
|
+
|
535
|
+
payload = e.payload.first
|
536
|
+
expect(payload.status).to eq '403'
|
537
|
+
expect(payload.code).to eq 'unauthorized_resource'
|
538
|
+
expect(payload.title).to eq 'Unable to access the requested resource'
|
539
|
+
expect(payload.pointer).to eq '/data/relationships/examples/data/1/id'
|
540
|
+
expect(payload.detail).to eq(
|
541
|
+
"Unable to assign the requested 'persons' (blargh) to the current resource"
|
542
|
+
)
|
543
|
+
end
|
544
|
+
end
|
545
|
+
end
|
504
546
|
end
|
505
547
|
|
506
548
|
it 'raises a MissingRelationship when unable to find a single resource' do
|
@@ -516,7 +558,7 @@ describe FunWithJsonApi::Deserializer do
|
|
516
558
|
expect(payload.status).to eq '404'
|
517
559
|
expect(payload.code).to eq 'missing_relationship'
|
518
560
|
expect(payload.title).to eq 'Unable to find the requested relationship'
|
519
|
-
expect(payload.pointer).to eq '/data/relationships/examples/1/id'
|
561
|
+
expect(payload.pointer).to eq '/data/relationships/examples/data/1/id'
|
520
562
|
expect(payload.detail).to eq "Unable to find 'persons' with matching id: \"blargh\""
|
521
563
|
end
|
522
564
|
end
|
@@ -534,14 +576,14 @@ describe FunWithJsonApi::Deserializer do
|
|
534
576
|
expect(payload_a.status).to eq '404'
|
535
577
|
expect(payload_a.code).to eq 'missing_relationship'
|
536
578
|
expect(payload_a.title).to eq 'Unable to find the requested relationship'
|
537
|
-
expect(payload_a.pointer).to eq '/data/relationships/examples/0/id'
|
579
|
+
expect(payload_a.pointer).to eq '/data/relationships/examples/data/0/id'
|
538
580
|
expect(payload_a.detail).to eq "Unable to find 'persons' with matching id: \"foobar\""
|
539
581
|
|
540
582
|
payload_b = e.payload.last
|
541
583
|
expect(payload_b.status).to eq '404'
|
542
584
|
expect(payload_b.code).to eq 'missing_relationship'
|
543
585
|
expect(payload_b.title).to eq 'Unable to find the requested relationship'
|
544
|
-
expect(payload_b.pointer).to eq '/data/relationships/examples/1/id'
|
586
|
+
expect(payload_b.pointer).to eq '/data/relationships/examples/data/1/id'
|
545
587
|
expect(payload_b.detail).to eq "Unable to find 'persons' with matching id: \"blargh\""
|
546
588
|
end
|
547
589
|
end
|
@@ -19,8 +19,41 @@ describe FunWithJsonApi::FindCollectionFromDocument do
|
|
19
19
|
.and_return([resource])
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
context 'when the resource is authorised' do
|
23
|
+
before do
|
24
|
+
resource_authorizer = double(:resource_authorizer)
|
25
|
+
allow(resource_authorizer).to receive(:call).with(resource).and_return(true)
|
26
|
+
allow(deserializer).to receive(:resource_authorizer).and_return(resource_authorizer)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns the resource in a array' do
|
30
|
+
expect(subject).to eq [resource]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when the resource is unauthorised' do
|
35
|
+
before do
|
36
|
+
resource_authorizer = double(:resource_authorizer)
|
37
|
+
allow(resource_authorizer).to receive(:call).with(resource).and_return(false)
|
38
|
+
allow(deserializer).to receive(:resource_authorizer).and_return(resource_authorizer)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'raises a UnauthorisedResource error' do
|
42
|
+
expect do
|
43
|
+
subject
|
44
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnauthorisedResource) do |e|
|
45
|
+
expect(e.payload.size).to eq 1
|
46
|
+
|
47
|
+
payload = e.payload.first
|
48
|
+
expect(payload.status).to eq '403'
|
49
|
+
expect(payload.code).to eq 'unauthorized_resource'
|
50
|
+
expect(payload.title).to eq 'Unable to access the requested resource'
|
51
|
+
expect(payload.detail).to eq(
|
52
|
+
"Unable to assign the requested 'person' (42) to the current resource"
|
53
|
+
)
|
54
|
+
expect(payload.pointer).to eq '/data/0/id'
|
55
|
+
end
|
56
|
+
end
|
24
57
|
end
|
25
58
|
end
|
26
59
|
|
@@ -74,8 +107,53 @@ describe FunWithJsonApi::FindCollectionFromDocument do
|
|
74
107
|
.and_return([resource_a, resource_b, resource_c])
|
75
108
|
end
|
76
109
|
|
77
|
-
|
78
|
-
|
110
|
+
context 'when all resources are authorised' do
|
111
|
+
before do
|
112
|
+
resource_authorizer = double(:resource_authorizer)
|
113
|
+
[resource_a, resource_b, resource_c].each do |resource|
|
114
|
+
allow(resource_authorizer).to receive(:call).with(resource).and_return(true)
|
115
|
+
end
|
116
|
+
allow(deserializer).to receive(:resource_authorizer).and_return(resource_authorizer)
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'returns all resources in a array' do
|
120
|
+
expect(subject).to eq [resource_a, resource_b, resource_c]
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'when there are unauthorised resources' do
|
125
|
+
before do
|
126
|
+
resource_authorizer = double(:resource_authorizer)
|
127
|
+
allow(resource_authorizer).to receive(:call).and_return(false)
|
128
|
+
allow(resource_authorizer).to receive(:call).with(resource_b).and_return(true)
|
129
|
+
allow(deserializer).to receive(:resource_authorizer).and_return(resource_authorizer)
|
130
|
+
end
|
131
|
+
|
132
|
+
it 'raises a UnauthorisedResource error' do
|
133
|
+
expect do
|
134
|
+
subject
|
135
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnauthorisedResource) do |e|
|
136
|
+
expect(e.payload.size).to eq 2
|
137
|
+
|
138
|
+
payload = e.payload.first
|
139
|
+
expect(payload.status).to eq '403'
|
140
|
+
expect(payload.code).to eq 'unauthorized_resource'
|
141
|
+
expect(payload.title).to eq 'Unable to access the requested resource'
|
142
|
+
expect(payload.detail).to eq(
|
143
|
+
"Unable to assign the requested 'person' (42) to the current resource"
|
144
|
+
)
|
145
|
+
expect(payload.pointer).to eq '/data/0/id'
|
146
|
+
|
147
|
+
payload = e.payload.second
|
148
|
+
expect(payload.status).to eq '403'
|
149
|
+
expect(payload.code).to eq 'unauthorized_resource'
|
150
|
+
expect(payload.title).to eq 'Unable to access the requested resource'
|
151
|
+
expect(payload.detail).to eq(
|
152
|
+
"Unable to assign the requested 'person' (44) to the current resource"
|
153
|
+
)
|
154
|
+
expect(payload.pointer).to eq '/data/2/id'
|
155
|
+
end
|
156
|
+
end
|
79
157
|
end
|
80
158
|
end
|
81
159
|
|
@@ -19,10 +19,44 @@ describe FunWithJsonApi::FindResourceFromDocument do
|
|
19
19
|
.and_return(resource)
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
|
22
|
+
context 'when the resource is authorised' do
|
23
|
+
before do
|
24
|
+
resource_authorizer = double(:resource_authorizer)
|
25
|
+
allow(resource_authorizer).to receive(:call).with(resource).and_return(true)
|
26
|
+
allow(deserializer).to receive(:resource_authorizer).and_return(resource_authorizer)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'returns the resource' do
|
30
|
+
expect(subject).to eq resource
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when the resource is unauthorised' do
|
35
|
+
before do
|
36
|
+
resource_authorizer = double(:resource_authorizer)
|
37
|
+
allow(resource_authorizer).to receive(:call).with(resource).and_return(false)
|
38
|
+
allow(deserializer).to receive(:resource_authorizer).and_return(resource_authorizer)
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'raises a UnauthorisedResource error' do
|
42
|
+
expect do
|
43
|
+
subject
|
44
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnauthorisedResource) do |e|
|
45
|
+
expect(e.payload.size).to eq 1
|
46
|
+
|
47
|
+
payload = e.payload.first
|
48
|
+
expect(payload.status).to eq '403'
|
49
|
+
expect(payload.code).to eq 'unauthorized_resource'
|
50
|
+
expect(payload.title).to eq 'Unable to access the requested resource'
|
51
|
+
expect(payload.detail).to eq(
|
52
|
+
"Unable to assign the requested 'person' (42) to the current resource"
|
53
|
+
)
|
54
|
+
expect(payload.pointer).to eq '/data/id'
|
55
|
+
end
|
56
|
+
end
|
24
57
|
end
|
25
58
|
end
|
59
|
+
|
26
60
|
context 'when a resource cannot be found' do
|
27
61
|
let!(:resource) { double('resource') }
|
28
62
|
before do
|
@@ -45,7 +45,7 @@ describe FunWithJsonApi::SchemaValidators::CheckRelationships do
|
|
45
45
|
|
46
46
|
payload = e.payload.first
|
47
47
|
expect(payload.code).to eq 'invalid_relationship_type'
|
48
|
-
expect(payload.pointer).to eq '/data/relationships/foobar/type'
|
48
|
+
expect(payload.pointer).to eq '/data/relationships/foobar/data/type'
|
49
49
|
expect(payload.title).to eq(
|
50
50
|
'Request json_api relationship type does not match expected resource'
|
51
51
|
)
|
@@ -97,7 +97,7 @@ describe FunWithJsonApi::SchemaValidators::CheckRelationships do
|
|
97
97
|
|
98
98
|
payload = e.payload.first
|
99
99
|
expect(payload.code).to eq 'invalid_relationship_type'
|
100
|
-
expect(payload.pointer).to eq '/data/relationships/foobar/0/type'
|
100
|
+
expect(payload.pointer).to eq '/data/relationships/foobar/data/0/type'
|
101
101
|
expect(payload.title).to eq(
|
102
102
|
'Request json_api relationship type does not match expected resource'
|
103
103
|
)
|
@@ -127,6 +127,74 @@ describe FunWithJsonApi do
|
|
127
127
|
comment_ids: [5, 12]
|
128
128
|
)
|
129
129
|
end
|
130
|
+
it 'allows for a relationship resource to be authorized' do
|
131
|
+
post = ARModels::Post.create(id: 1)
|
132
|
+
ARModels::Author.create(id: 9)
|
133
|
+
|
134
|
+
post_json = {
|
135
|
+
'data': {
|
136
|
+
'type': 'posts',
|
137
|
+
'id': '1',
|
138
|
+
'relationships': {
|
139
|
+
'author': {
|
140
|
+
'data': { 'type': 'person', 'id': '9' }
|
141
|
+
}
|
142
|
+
}
|
143
|
+
}
|
144
|
+
}
|
145
|
+
|
146
|
+
expect do
|
147
|
+
described_class.deserialize(
|
148
|
+
post_json,
|
149
|
+
ARModels::PostDeserializer,
|
150
|
+
post,
|
151
|
+
author: { resource_authorizer: ->(author) { author.id != 9 } }
|
152
|
+
)
|
153
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnauthorisedResource) do |e|
|
154
|
+
expect(e.payload.size).to eq 1
|
155
|
+
expect(e.payload.first.pointer).to eq '/data/relationships/author/data/id'
|
156
|
+
end
|
157
|
+
end
|
158
|
+
it 'allows for relationship collections to be authorized' do
|
159
|
+
post = ARModels::Post.create(id: 1)
|
160
|
+
ARModels::Author.create(id: 9)
|
161
|
+
ARModels::Comment.create(id: 5, contents: 'Blargh')
|
162
|
+
ARModels::Comment.create(id: 12, contents: 'Foobar')
|
163
|
+
|
164
|
+
post_json = {
|
165
|
+
'data': {
|
166
|
+
'type': 'posts',
|
167
|
+
'id': '1',
|
168
|
+
'attributes': {
|
169
|
+
'title': 'Rails is Omakase',
|
170
|
+
'body': 'This is my post body'
|
171
|
+
},
|
172
|
+
'relationships': {
|
173
|
+
'author': {
|
174
|
+
'data': { 'type': 'person', 'id': '9' }
|
175
|
+
},
|
176
|
+
'comments': {
|
177
|
+
'data': [
|
178
|
+
{ 'type': 'comments', 'id': '5' },
|
179
|
+
{ 'type': 'comments', 'id': '12' }
|
180
|
+
]
|
181
|
+
}
|
182
|
+
}
|
183
|
+
}
|
184
|
+
}
|
185
|
+
|
186
|
+
expect do
|
187
|
+
described_class.deserialize(
|
188
|
+
post_json,
|
189
|
+
ARModels::PostDeserializer,
|
190
|
+
post,
|
191
|
+
comments: { resource_authorizer: ->(comment) { comment.contents == 'Foobar' } }
|
192
|
+
)
|
193
|
+
end.to raise_error(FunWithJsonApi::Exceptions::UnauthorisedResource) do |e|
|
194
|
+
expect(e.payload.size).to eq 1
|
195
|
+
expect(e.payload.first.pointer).to eq '/data/relationships/comments/data/0/id'
|
196
|
+
end
|
197
|
+
end
|
130
198
|
end
|
131
199
|
end
|
132
200
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fun_with_json_api
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6.pre.alpha.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Morrall
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-03-
|
11
|
+
date: 2016-03-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -178,6 +178,7 @@ files:
|
|
178
178
|
- lib/fun_with_json_api/exceptions/invalid_relationship_type.rb
|
179
179
|
- lib/fun_with_json_api/exceptions/missing_relationship.rb
|
180
180
|
- lib/fun_with_json_api/exceptions/missing_resource.rb
|
181
|
+
- lib/fun_with_json_api/exceptions/unauthorized_resource.rb
|
181
182
|
- lib/fun_with_json_api/exceptions/unknown_attribute.rb
|
182
183
|
- lib/fun_with_json_api/exceptions/unknown_relationship.rb
|
183
184
|
- lib/fun_with_json_api/find_collection_from_document.rb
|
@@ -186,9 +187,12 @@ files:
|
|
186
187
|
- lib/fun_with_json_api/railtie.rb
|
187
188
|
- lib/fun_with_json_api/schema_validator.rb
|
188
189
|
- lib/fun_with_json_api/schema_validators/check_attributes.rb
|
190
|
+
- lib/fun_with_json_api/schema_validators/check_collection_has_all_members.rb
|
191
|
+
- lib/fun_with_json_api/schema_validators/check_collection_is_authorized.rb
|
189
192
|
- lib/fun_with_json_api/schema_validators/check_document_id_matches_resource.rb
|
190
193
|
- lib/fun_with_json_api/schema_validators/check_document_type_matches_resource.rb
|
191
194
|
- lib/fun_with_json_api/schema_validators/check_relationships.rb
|
195
|
+
- lib/fun_with_json_api/schema_validators/check_resource_is_authorized.rb
|
192
196
|
- lib/fun_with_json_api/version.rb
|
193
197
|
- lib/tasks/fun_with_json_api_tasks.rake
|
194
198
|
- spec/dummy/README.rdoc
|
@@ -257,9 +261,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
257
261
|
version: '0'
|
258
262
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
259
263
|
requirements:
|
260
|
-
- - "
|
264
|
+
- - ">"
|
261
265
|
- !ruby/object:Gem::Version
|
262
|
-
version:
|
266
|
+
version: 1.3.1
|
263
267
|
requirements: []
|
264
268
|
rubyforge_project:
|
265
269
|
rubygems_version: 2.5.2
|