jsonapi-authorization 0.8.2 → 1.0.0.alpha1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.all-contributorsrc +109 -0
- data/.travis.yml +3 -8
- data/Gemfile +1 -3
- data/README.md +45 -0
- data/jsonapi-authorization.gemspec +1 -1
- data/lib/jsonapi/authorization/authorizing_processor.rb +70 -40
- data/lib/jsonapi/authorization/default_pundit_authorizer.rb +58 -31
- data/lib/jsonapi/authorization/version.rb +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50a06e5fdcd473f0bcd5ea8b1881d11933476d6c
|
4
|
+
data.tar.gz: 4bef789a4172b7c93a0ee20092e2da33fe2704dd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 36ae7c80e93eb5cc1f07be3f14869723982419681cd15f6d71b760d78a53305f3824b90f1edd71fc1dd4c8fd26f04ae51a0a26e9e92abb1396ff5944f06a7718
|
7
|
+
data.tar.gz: 0f91ba98fc0774febee9634c7e0ee28bbf0cd7f9e69703dd0b5b7f0f1e48132ffd446d0e9be4a6c1f8b7797e699b49bcb4b37b6bf989fef27c05dc523ff31bf2
|
data/.all-contributorsrc
ADDED
@@ -0,0 +1,109 @@
|
|
1
|
+
{
|
2
|
+
"projectName": "jsonapi-authorization",
|
3
|
+
"projectOwner": "Venuu",
|
4
|
+
"files": [
|
5
|
+
"README.md"
|
6
|
+
],
|
7
|
+
"imageSize": 100,
|
8
|
+
"commit": true,
|
9
|
+
"contributors": [
|
10
|
+
{
|
11
|
+
"login": "valscion",
|
12
|
+
"name": "Vesa Laakso",
|
13
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/482561?v=3",
|
14
|
+
"profile": "http://vesalaakso.com",
|
15
|
+
"contributions": [
|
16
|
+
"code",
|
17
|
+
"doc",
|
18
|
+
"infra",
|
19
|
+
"test",
|
20
|
+
"bug",
|
21
|
+
"question",
|
22
|
+
"review"
|
23
|
+
]
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"login": "lime",
|
27
|
+
"name": "Emil Sågfors",
|
28
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/562204?v=3",
|
29
|
+
"profile": "https://github.com/lime",
|
30
|
+
"contributions": [
|
31
|
+
"code",
|
32
|
+
"doc",
|
33
|
+
"infra",
|
34
|
+
"test",
|
35
|
+
"bug",
|
36
|
+
"question",
|
37
|
+
"review"
|
38
|
+
]
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"login": "matthias-g",
|
42
|
+
"name": "Matthias Grundmann",
|
43
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/1591161?v=3",
|
44
|
+
"profile": "https://github.com/matthias-g",
|
45
|
+
"contributions": [
|
46
|
+
"code",
|
47
|
+
"doc",
|
48
|
+
"test",
|
49
|
+
"question"
|
50
|
+
]
|
51
|
+
},
|
52
|
+
{
|
53
|
+
"login": "thibaudgg",
|
54
|
+
"name": "Thibaud Guillaume-Gentil",
|
55
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/1322?v=3",
|
56
|
+
"profile": "http://thibaud.gg",
|
57
|
+
"contributions": [
|
58
|
+
"code"
|
59
|
+
]
|
60
|
+
},
|
61
|
+
{
|
62
|
+
"login": "acid",
|
63
|
+
"name": "Daniel Schweighöfer",
|
64
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/71660?v=3",
|
65
|
+
"profile": "http://netsteward.net",
|
66
|
+
"contributions": [
|
67
|
+
"code"
|
68
|
+
]
|
69
|
+
},
|
70
|
+
{
|
71
|
+
"login": "bsofiato",
|
72
|
+
"name": "Bruno Sofiato",
|
73
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/5076967?v=3",
|
74
|
+
"profile": "https://github.com/bsofiato",
|
75
|
+
"contributions": [
|
76
|
+
"code"
|
77
|
+
]
|
78
|
+
},
|
79
|
+
{
|
80
|
+
"login": "arcreative",
|
81
|
+
"name": "Adam Robertson",
|
82
|
+
"avatar_url": "https://avatars.githubusercontent.com/u/1896026?v=3",
|
83
|
+
"profile": "https://github.com/arcreative",
|
84
|
+
"contributions": [
|
85
|
+
"doc"
|
86
|
+
]
|
87
|
+
},
|
88
|
+
{
|
89
|
+
"login": "gnfisher",
|
90
|
+
"name": "Greg Fisher",
|
91
|
+
"avatar_url": "https://avatars3.githubusercontent.com/u/4742306?v=3",
|
92
|
+
"profile": "https://github.com/gnfisher",
|
93
|
+
"contributions": [
|
94
|
+
"code",
|
95
|
+
"test"
|
96
|
+
]
|
97
|
+
},
|
98
|
+
{
|
99
|
+
"login": "handlers",
|
100
|
+
"name": "Sam",
|
101
|
+
"avatar_url": "https://avatars3.githubusercontent.com/u/370182?v=3",
|
102
|
+
"profile": "http://samlh.com",
|
103
|
+
"contributions": [
|
104
|
+
"code",
|
105
|
+
"test"
|
106
|
+
]
|
107
|
+
}
|
108
|
+
]
|
109
|
+
}
|
data/.travis.yml
CHANGED
@@ -2,18 +2,13 @@ language: ruby
|
|
2
2
|
cache: bundler
|
3
3
|
sudo: false
|
4
4
|
env:
|
5
|
-
- JSONAPI_RESOURCES_VERSION=0.
|
6
|
-
- JSONAPI_RESOURCES_VERSION=0.
|
7
|
-
- JSONAPI_RESOURCES_VERSION=master RAILS_VERSION=4.2.0
|
8
|
-
- JSONAPI_RESOURCES_VERSION=master RAILS_VERSION=4.1.0
|
5
|
+
- JSONAPI_RESOURCES_VERSION=0.9 RAILS_VERSION=4.1.0
|
6
|
+
- JSONAPI_RESOURCES_VERSION=0.9 RAILS_VERSION=4.2.0
|
9
7
|
rvm:
|
10
8
|
- 2.1.2
|
11
9
|
before_install: gem install bundler -v 1.11.2
|
12
10
|
notifications:
|
13
11
|
email: false
|
14
|
-
matrix:
|
15
|
-
allow_failures:
|
16
|
-
- env: JSONAPI_RESOURCES_VERSION=master RAILS_VERSION=4.2.0
|
17
|
-
- env: JSONAPI_RESOURCES_VERSION=master RAILS_VERSION=4.1.0
|
18
12
|
script:
|
19
13
|
- ./bin/phare
|
14
|
+
- bundle exec rake
|
data/Gemfile
CHANGED
@@ -18,10 +18,8 @@ else
|
|
18
18
|
end
|
19
19
|
|
20
20
|
case jsonapi_resources_version
|
21
|
-
when 'master'
|
22
|
-
gem 'jsonapi-resources', git: 'https://github.com/cerebris/jsonapi-resources.git'
|
23
21
|
when 'default'
|
24
|
-
gem 'jsonapi-resources', '0.
|
22
|
+
gem 'jsonapi-resources', '0.9'
|
25
23
|
else
|
26
24
|
gem 'jsonapi-resources', jsonapi_resources_version
|
27
25
|
end
|
data/README.md
CHANGED
@@ -91,6 +91,39 @@ class BaseResource < JSONAPI::Resource
|
|
91
91
|
end
|
92
92
|
```
|
93
93
|
|
94
|
+
### Policies
|
95
|
+
|
96
|
+
To check whether an action is allowed JSONAPI::Authorization calls the respective actions of your pundit policies
|
97
|
+
(`index?`, `show?`, `create?`, `update?`, `destroy?`).
|
98
|
+
|
99
|
+
For relationship operations by default `update?` is being called for all affected resources.
|
100
|
+
For a finer grained control you can define `add_to_<relation>?`, `replace_<relation>?`, and `remove_from_<relation>?`
|
101
|
+
as the following example shows.
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
class ArticlePolicy
|
105
|
+
|
106
|
+
# (...)
|
107
|
+
|
108
|
+
def add_to_comments?(new_comments)
|
109
|
+
record.published && new_comments.all? { |comment| comment.author == user }
|
110
|
+
end
|
111
|
+
|
112
|
+
def replace_comments?(new_comments)
|
113
|
+
allowed = record.comments.all? { |comment| new_comments.include?(comment) || add_to_comments?([comment])}
|
114
|
+
allowed && new_comments.all? { |comment| record.comments.include?(comment) || remove_from_comments?(comment) }
|
115
|
+
end
|
116
|
+
|
117
|
+
def remove_from_comments?(comment)
|
118
|
+
comment.author == user || user.admin?
|
119
|
+
end
|
120
|
+
end
|
121
|
+
```
|
122
|
+
|
123
|
+
Caveat: In case a relationship is modifiable through multiple ways it is your responsibility to ensure consistency.
|
124
|
+
For example if you have a many-to-many relationship with users and projects make sure that
|
125
|
+
`ProjectPolicy#add_to_users?(users)` and `UserPolicy#add_to_projects?(projects)` match up.
|
126
|
+
|
94
127
|
## Configuration
|
95
128
|
|
96
129
|
You can use a custom authorizer class by specifying a configure block in an initializer file. If using a custom authorizer class, be sure to require them at the top of the initializer before usage.
|
@@ -138,3 +171,15 @@ Originally based on discussion and code samples by [@barelyknown](https://github
|
|
138
171
|
Bug reports and pull requests are welcome on GitHub at https://github.com/venuu/jsonapi-authorization.
|
139
172
|
|
140
173
|
[issues]: https://github.com/venuu/jsonapi-authorization/issues
|
174
|
+
|
175
|
+
## Contributors
|
176
|
+
|
177
|
+
Thanks goes to these wonderful people ([emoji key](https://github.com/kentcdodds/all-contributors#emoji-key)):
|
178
|
+
|
179
|
+
<!-- ALL-CONTRIBUTORS-LIST:START - Do not remove or modify this section -->
|
180
|
+
| [<img src="https://avatars.githubusercontent.com/u/482561?v=3" width="100px;"/><br /><sub>Vesa Laakso</sub>](http://vesalaakso.com)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=valscion) [📖](https://github.com/Venuu/jsonapi-authorization/commits?author=valscion) 🚇 [⚠️](https://github.com/Venuu/jsonapi-authorization/commits?author=valscion) [🐛](https://github.com/Venuu/jsonapi-authorization/issues?q=author%3Avalscion) 💬 👀 | [<img src="https://avatars.githubusercontent.com/u/562204?v=3" width="100px;"/><br /><sub>Emil Sågfors</sub>](https://github.com/lime)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=lime) [📖](https://github.com/Venuu/jsonapi-authorization/commits?author=lime) 🚇 [⚠️](https://github.com/Venuu/jsonapi-authorization/commits?author=lime) [🐛](https://github.com/Venuu/jsonapi-authorization/issues?q=author%3Alime) 💬 👀 | [<img src="https://avatars.githubusercontent.com/u/1591161?v=3" width="100px;"/><br /><sub>Matthias Grundmann</sub>](https://github.com/matthias-g)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=matthias-g) [📖](https://github.com/Venuu/jsonapi-authorization/commits?author=matthias-g) [⚠️](https://github.com/Venuu/jsonapi-authorization/commits?author=matthias-g) 💬 | [<img src="https://avatars.githubusercontent.com/u/1322?v=3" width="100px;"/><br /><sub>Thibaud Guillaume-Gentil</sub>](http://thibaud.gg)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=thibaudgg) | [<img src="https://avatars.githubusercontent.com/u/71660?v=3" width="100px;"/><br /><sub>Daniel Schweighöfer</sub>](http://netsteward.net)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=acid) | [<img src="https://avatars.githubusercontent.com/u/5076967?v=3" width="100px;"/><br /><sub>Bruno Sofiato</sub>](https://github.com/bsofiato)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=bsofiato) | [<img src="https://avatars.githubusercontent.com/u/1896026?v=3" width="100px;"/><br /><sub>Adam Robertson</sub>](https://github.com/arcreative)<br />[📖](https://github.com/Venuu/jsonapi-authorization/commits?author=arcreative) |
|
181
|
+
| :---: | :---: | :---: | :---: | :---: | :---: | :---: |
|
182
|
+
| [<img src="https://avatars3.githubusercontent.com/u/4742306?v=3" width="100px;"/><br /><sub>Greg Fisher</sub>](https://github.com/gnfisher)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=gnfisher) [⚠️](https://github.com/Venuu/jsonapi-authorization/commits?author=gnfisher) | [<img src="https://avatars3.githubusercontent.com/u/370182?v=3" width="100px;"/><br /><sub>Sam</sub>](http://samlh.com)<br />[💻](https://github.com/Venuu/jsonapi-authorization/commits?author=handlers) [⚠️](https://github.com/Venuu/jsonapi-authorization/commits?author=handlers) |
|
183
|
+
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
184
|
+
|
185
|
+
This project follows the [all-contributors](https://github.com/kentcdodds/all-contributors) specification. Contributions of any kind welcome!
|
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
18
|
spec.require_paths = ["lib"]
|
19
19
|
|
20
|
-
spec.add_dependency "jsonapi-resources", "~> 0.
|
20
|
+
spec.add_dependency "jsonapi-resources", "~> 0.9"
|
21
21
|
spec.add_dependency "pundit", "~> 1.0"
|
22
22
|
|
23
23
|
spec.add_development_dependency "bundler", "~> 1.11"
|
@@ -12,10 +12,10 @@ module JSONAPI
|
|
12
12
|
set_callback :remove_resource, :before, :authorize_remove_resource
|
13
13
|
set_callback :replace_fields, :before, :authorize_replace_fields
|
14
14
|
set_callback :replace_to_one_relationship, :before, :authorize_replace_to_one_relationship
|
15
|
-
set_callback :create_to_many_relationship, :before, :authorize_create_to_many_relationship
|
16
|
-
set_callback :replace_to_many_relationship, :before, :authorize_replace_to_many_relationship
|
17
|
-
set_callback :remove_to_many_relationship, :before, :authorize_remove_to_many_relationship
|
18
15
|
set_callback :remove_to_one_relationship, :before, :authorize_remove_to_one_relationship
|
16
|
+
set_callback :create_to_many_relationships, :before, :authorize_create_to_many_relationships
|
17
|
+
set_callback :replace_to_many_relationships, :before, :authorize_replace_to_many_relationships
|
18
|
+
set_callback :remove_to_many_relationships, :before, :authorize_remove_to_many_relationships
|
19
19
|
|
20
20
|
[
|
21
21
|
:find,
|
@@ -107,13 +107,11 @@ module JSONAPI
|
|
107
107
|
params[:resource_id],
|
108
108
|
context: context
|
109
109
|
)._model
|
110
|
-
|
111
|
-
authorizer.replace_fields(source_record, related_models)
|
110
|
+
authorizer.replace_fields(source_record, related_models_with_context)
|
112
111
|
end
|
113
112
|
|
114
113
|
def authorize_create_resource
|
115
|
-
source_class =
|
116
|
-
|
114
|
+
source_class = resource_klass._model_class
|
117
115
|
authorizer.create_resource(source_class, related_models)
|
118
116
|
end
|
119
117
|
|
@@ -127,91 +125,95 @@ module JSONAPI
|
|
127
125
|
end
|
128
126
|
|
129
127
|
def authorize_replace_to_one_relationship
|
128
|
+
return authorize_remove_to_one_relationship if params[:key_value].nil?
|
129
|
+
|
130
130
|
source_resource = @resource_klass.find_by_key(
|
131
131
|
params[:resource_id],
|
132
132
|
context: context
|
133
133
|
)
|
134
134
|
source_record = source_resource._model
|
135
135
|
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
new_related_record = new_related_resource._model unless new_related_resource.nil?
|
146
|
-
end
|
136
|
+
relationship_type = params[:relationship_type].to_sym
|
137
|
+
new_related_resource = @resource_klass
|
138
|
+
._relationship(relationship_type)
|
139
|
+
.resource_klass
|
140
|
+
.find_by_key(
|
141
|
+
params[:key_value],
|
142
|
+
context: context
|
143
|
+
)
|
144
|
+
new_related_record = new_related_resource._model unless new_related_resource.nil?
|
147
145
|
|
148
146
|
authorizer.replace_to_one_relationship(
|
149
147
|
source_record,
|
150
|
-
|
151
|
-
|
148
|
+
new_related_record,
|
149
|
+
relationship_type
|
152
150
|
)
|
153
151
|
end
|
154
152
|
|
155
|
-
def
|
153
|
+
def authorize_create_to_many_relationships
|
156
154
|
source_record = @resource_klass.find_by_key(
|
157
155
|
params[:resource_id],
|
158
156
|
context: context
|
159
157
|
)._model
|
160
158
|
|
161
|
-
|
162
|
-
|
159
|
+
relationship_type = params[:relationship_type].to_sym
|
160
|
+
related_models = model_class_for_relationship(relationship_type).find(params[:data])
|
163
161
|
|
164
|
-
authorizer.create_to_many_relationship(source_record, related_models)
|
162
|
+
authorizer.create_to_many_relationship(source_record, related_models, relationship_type)
|
165
163
|
end
|
166
164
|
|
167
|
-
def
|
165
|
+
def authorize_replace_to_many_relationships
|
168
166
|
source_resource = @resource_klass.find_by_key(
|
169
167
|
params[:resource_id],
|
170
168
|
context: context
|
171
169
|
)
|
172
170
|
source_record = source_resource._model
|
173
171
|
|
174
|
-
|
172
|
+
relationship_type = params[:relationship_type].to_sym
|
173
|
+
new_related_records = model_class_for_relationship(relationship_type).find(params[:data])
|
175
174
|
|
176
175
|
authorizer.replace_to_many_relationship(
|
177
176
|
source_record,
|
178
|
-
|
177
|
+
new_related_records,
|
178
|
+
relationship_type
|
179
179
|
)
|
180
180
|
end
|
181
181
|
|
182
|
-
def
|
182
|
+
def authorize_remove_to_many_relationships
|
183
183
|
source_resource = @resource_klass.find_by_key(
|
184
184
|
params[:resource_id],
|
185
185
|
context: context
|
186
186
|
)
|
187
187
|
source_record = source_resource._model
|
188
188
|
|
189
|
-
|
190
|
-
|
189
|
+
relationship_type = params[:relationship_type].to_sym
|
190
|
+
|
191
|
+
related_resources = @resource_klass
|
192
|
+
._relationship(relationship_type)
|
191
193
|
.resource_klass
|
192
|
-
.
|
193
|
-
params[:
|
194
|
+
.find_by_keys(
|
195
|
+
params[:associated_keys],
|
194
196
|
context: context
|
195
197
|
)
|
196
|
-
|
198
|
+
|
199
|
+
related_records = related_resources.map(&:_model)
|
197
200
|
|
198
201
|
authorizer.remove_to_many_relationship(
|
199
202
|
source_record,
|
200
|
-
|
203
|
+
related_records,
|
204
|
+
relationship_type
|
201
205
|
)
|
202
206
|
end
|
203
207
|
|
204
208
|
def authorize_remove_to_one_relationship
|
205
|
-
|
209
|
+
source_record = @resource_klass.find_by_key(
|
206
210
|
params[:resource_id],
|
207
211
|
context: context
|
208
|
-
)
|
212
|
+
)._model
|
209
213
|
|
210
|
-
|
214
|
+
relationship_type = params[:relationship_type].to_sym
|
211
215
|
|
212
|
-
source_record
|
213
|
-
related_record = related_resource._model unless related_resource.nil?
|
214
|
-
authorizer.remove_to_one_relationship(source_record, related_record)
|
216
|
+
authorizer.remove_to_one_relationship(source_record, relationship_type)
|
215
217
|
end
|
216
218
|
|
217
219
|
private
|
@@ -259,6 +261,34 @@ module JSONAPI
|
|
259
261
|
end
|
260
262
|
end
|
261
263
|
|
264
|
+
def related_models_with_context
|
265
|
+
data = params[:data]
|
266
|
+
return { relationship: nil, relation_name: nil, records: nil } if data.nil?
|
267
|
+
|
268
|
+
[:to_one, :to_many].flat_map do |rel_type|
|
269
|
+
data[rel_type].flat_map do |assoc_name, assoc_value|
|
270
|
+
related_models =
|
271
|
+
case assoc_value
|
272
|
+
when Hash # polymorphic relationship
|
273
|
+
resource_class = @resource_klass.resource_for(assoc_value[:type].to_s)
|
274
|
+
resource_class.find_by_key(assoc_value[:id], context: context)._model
|
275
|
+
when Array
|
276
|
+
resource_class = resource_class_for_relationship(assoc_name)
|
277
|
+
resource_class.find_by_keys(assoc_value, context: context).map(&:_model)
|
278
|
+
else
|
279
|
+
resource_class = resource_class_for_relationship(assoc_name)
|
280
|
+
resource_class.find_by_key(assoc_value[:id], context: context)._model
|
281
|
+
end
|
282
|
+
|
283
|
+
{
|
284
|
+
relation_type: rel_type,
|
285
|
+
relation_name: assoc_name,
|
286
|
+
records: related_models
|
287
|
+
}
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
262
292
|
def authorize_model_includes(source_record)
|
263
293
|
if params[:include_directives]
|
264
294
|
params[:include_directives].model_includes.each do |include_item|
|
@@ -86,17 +86,11 @@ module JSONAPI
|
|
86
86
|
# ==== Parameters
|
87
87
|
#
|
88
88
|
# * +source_record+ - The record to be modified
|
89
|
-
# * +
|
90
|
-
#
|
91
|
-
|
92
|
-
#--
|
93
|
-
# TODO: Should probably take old records as well
|
94
|
-
def replace_fields(source_record, new_related_records)
|
89
|
+
# * +related_records_with_context+ - A hash with the association type,
|
90
|
+
# the relationship name, an Array of new related records.
|
91
|
+
def replace_fields(source_record, related_records_with_context)
|
95
92
|
::Pundit.authorize(user, source_record, 'update?')
|
96
|
-
|
97
|
-
new_related_records.each do |record|
|
98
|
-
::Pundit.authorize(user, record, 'update?')
|
99
|
-
end
|
93
|
+
authorize_related_records(source_record, related_records_with_context)
|
100
94
|
end
|
101
95
|
|
102
96
|
# <tt>POST /resources</tt>
|
@@ -131,11 +125,11 @@ module JSONAPI
|
|
131
125
|
# ==== Parameters
|
132
126
|
#
|
133
127
|
# * +source_record+ - The record whose relationship is modified
|
134
|
-
# * +
|
135
|
-
# * +
|
136
|
-
|
137
|
-
|
138
|
-
|
128
|
+
# * +new_related_record+ - The new record replacing the old record
|
129
|
+
# * +relationship_type+ - The relationship type
|
130
|
+
def replace_to_one_relationship(source_record, new_related_record, relationship_type)
|
131
|
+
relationship_method = "replace_#{relationship_type}?"
|
132
|
+
authorize_relationship_operation(source_record, relationship_method, new_related_record)
|
139
133
|
end
|
140
134
|
|
141
135
|
# <tt>POST /resources/:id/relationships/other-resources</tt>
|
@@ -146,8 +140,10 @@ module JSONAPI
|
|
146
140
|
#
|
147
141
|
# * +source_record+ - The record whose relationship is modified
|
148
142
|
# * +new_related_records+ - The new records to be added to the association
|
149
|
-
|
150
|
-
|
143
|
+
# * +relationship_type+ - The relationship type
|
144
|
+
def create_to_many_relationship(source_record, new_related_records, relationship_type)
|
145
|
+
relationship_method = "add_to_#{relationship_type}?"
|
146
|
+
authorize_relationship_operation(source_record, relationship_method, new_related_records)
|
151
147
|
end
|
152
148
|
|
153
149
|
# <tt>PATCH /resources/:id/relationships/other-resources</tt>
|
@@ -159,36 +155,37 @@ module JSONAPI
|
|
159
155
|
# * +source_record+ - The record whose relationship is modified
|
160
156
|
# * +new_related_records+ - The new records replacing the entire +has_many+
|
161
157
|
# association
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
158
|
+
# * +relationship_type+ - The relationship type
|
159
|
+
def replace_to_many_relationship(source_record, new_related_records, relationship_type)
|
160
|
+
relationship_method = "replace_#{relationship_type}?"
|
161
|
+
authorize_relationship_operation(source_record, relationship_method, new_related_records)
|
166
162
|
end
|
167
163
|
|
168
164
|
# <tt>DELETE /resources/:id/relationships/other-resources</tt>
|
169
165
|
#
|
170
|
-
# A request to
|
171
|
-
#
|
172
|
-
# NOTE: this is called once per related record, not all at once
|
166
|
+
# A request to disassociate elements of a +has_many+ association
|
173
167
|
#
|
174
168
|
# ==== Parameters
|
175
169
|
#
|
176
170
|
# * +source_record+ - The record whose relationship is modified
|
177
|
-
# * +
|
178
|
-
|
179
|
-
|
171
|
+
# * +related_records+ - The records which will be disassociated from +source_record+
|
172
|
+
# * +relationship_type+ - The relationship type
|
173
|
+
def remove_to_many_relationship(source_record, related_records, relationship_type)
|
174
|
+
relationship_method = "remove_from_#{relationship_type}?"
|
175
|
+
authorize_relationship_operation(source_record, relationship_method, related_records)
|
180
176
|
end
|
181
177
|
|
182
178
|
# <tt>DELETE /resources/:id/relationships/another-resource</tt>
|
183
179
|
#
|
184
|
-
# A request to
|
180
|
+
# A request to disassociate a +has_one+ association
|
185
181
|
#
|
186
182
|
# ==== Parameters
|
187
183
|
#
|
188
184
|
# * +source_record+ - The record whose relationship is modified
|
189
|
-
# * +
|
190
|
-
def remove_to_one_relationship(
|
191
|
-
|
185
|
+
# * +relationship_type+ - The relationship type
|
186
|
+
def remove_to_one_relationship(source_record, relationship_type)
|
187
|
+
relationship_method = "remove_#{relationship_type}?"
|
188
|
+
authorize_relationship_operation(source_record, relationship_method)
|
192
189
|
end
|
193
190
|
|
194
191
|
# Any request including <tt>?include=other-resources</tt>
|
@@ -224,6 +221,36 @@ module JSONAPI
|
|
224
221
|
def include_has_one_resource(_source_record, related_record)
|
225
222
|
::Pundit.authorize(user, related_record, 'show?')
|
226
223
|
end
|
224
|
+
|
225
|
+
private
|
226
|
+
|
227
|
+
def authorize_relationship_operation(source_record, relationship_method, *args)
|
228
|
+
policy = ::Pundit.policy(user, source_record)
|
229
|
+
if policy.respond_to?(relationship_method)
|
230
|
+
unless policy.public_send(relationship_method, *args)
|
231
|
+
raise ::Pundit::NotAuthorizedError,
|
232
|
+
query: relationship_method,
|
233
|
+
record: source_record,
|
234
|
+
policy: policy
|
235
|
+
end
|
236
|
+
else
|
237
|
+
::Pundit.authorize(user, source_record, 'update?')
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
def authorize_related_records(source_record, related_records_with_context)
|
242
|
+
related_records_with_context.each do |data|
|
243
|
+
relation_type = data[:relation_type]
|
244
|
+
relation_name = data[:relation_name]
|
245
|
+
records = data[:records]
|
246
|
+
case relation_type
|
247
|
+
when :to_many
|
248
|
+
replace_to_many_relationship(source_record, records, relation_name)
|
249
|
+
when :to_one
|
250
|
+
replace_to_one_relationship(source_record, records, relation_name)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
227
254
|
end
|
228
255
|
end
|
229
256
|
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.
|
4
|
+
version: 1.0.0.alpha1
|
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: 2017-
|
12
|
+
date: 2017-04-12 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: jsonapi-resources
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: 0.
|
20
|
+
version: '0.9'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: 0.
|
27
|
+
version: '0.9'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: pundit
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -187,6 +187,7 @@ executables: []
|
|
187
187
|
extensions: []
|
188
188
|
extra_rdoc_files: []
|
189
189
|
files:
|
190
|
+
- ".all-contributorsrc"
|
190
191
|
- ".editorconfig"
|
191
192
|
- ".gitignore"
|
192
193
|
- ".rspec"
|
@@ -224,9 +225,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
224
225
|
version: '0'
|
225
226
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
226
227
|
requirements:
|
227
|
-
- - "
|
228
|
+
- - ">"
|
228
229
|
- !ruby/object:Gem::Version
|
229
|
-
version:
|
230
|
+
version: 1.3.1
|
230
231
|
requirements: []
|
231
232
|
rubyforge_project:
|
232
233
|
rubygems_version: 2.2.2
|