jsonapi-authorization 0.8.2 → 1.0.0.alpha1
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.
- 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
|