deep_unrest 0.1.0 → 0.1.1
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/README.md +37 -8
- data/app/controllers/deep_unrest/application_controller.rb +3 -3
- data/lib/deep_unrest/version.rb +1 -1
- data/lib/deep_unrest.rb +54 -25
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f251e8aee5961ebae0a57cedf79dc6ce424dc2d4
|
4
|
+
data.tar.gz: a62e10cd9dfdc0f4e83dc31bef8d4bea68f5b479
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e009d9471f9661b9c178fe3f0f3fc1cbf936cfeda8c009ce24354e69dc289d56e67886433480dbb7b846a9d7c70b2b7d0f0d38612e4dbf247924e1b8b6272136
|
7
|
+
data.tar.gz: 6e577f6e6c8fb2ab6f5a5cf29d70d3255d52c9ab31644e124525acb8d497fe21212d1b5de918154d31dd7e88631c46463202bdb3c84425747e37a37d08cc0439
|
data/README.md
CHANGED
@@ -1,15 +1,21 @@
|
|
1
|
-
|
1
|
+
<img src="/docs/img/logo.jpg" width="100%">
|
2
2
|
|
3
3
|
[](https://circleci.com/gh/graveflex/deep_unrest)
|
4
4
|
[](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/coverage)
|
5
5
|
[](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/feed)
|
6
6
|
[](https://codeclimate.com/repos/591cc05fbd15c32ce10014b4/feed)
|
7
7
|
|
8
|
-
|
8
|
+
## Goals
|
9
9
|
|
10
|
-
|
10
|
+
* Allow updates and deletions of deeply nested resources
|
11
|
+
* Allow bulk updates and deletions
|
12
|
+
* Perform authorization on all affected resources
|
13
|
+
* Control which params each user is allowed to update for each resource
|
14
|
+
* Provide clear errors to the client
|
11
15
|
|
12
|
-
##
|
16
|
+
## Caveats
|
17
|
+
|
18
|
+
* This approach is not RESTful
|
13
19
|
|
14
20
|
## Installation
|
15
21
|
Add this line to your application's Gemfile:
|
@@ -49,12 +55,16 @@ $ bundle
|
|
49
55
|
# config.get_user = proc { current_admin || current_user }
|
50
56
|
|
51
57
|
# stategy that will be used to authorize the current user for each resource
|
52
|
-
|
58
|
+
config.authorization_strategy = DeepUnrest::Authorization::PunditStrategy
|
53
59
|
end
|
54
60
|
```
|
55
61
|
|
56
62
|
## Usage
|
57
63
|
|
64
|
+
For the following examples, consider this data model:
|
65
|
+
|
66
|
+
<img src="/docs/img/example-setup.jpg" width="100%">
|
67
|
+
|
58
68
|
### Example 1 - Simple Update:
|
59
69
|
Update attributes on a single `Submission` with id `123`
|
60
70
|
|
@@ -103,7 +113,7 @@ within their policy scope.
|
|
103
113
|
```
|
104
114
|
|
105
115
|
##### 405 Response:
|
106
|
-
This error will occur when a is allowed to update a resource, but not
|
116
|
+
This error will occur when a user is allowed to update a resource, but not
|
107
117
|
specified attributes of that resource.
|
108
118
|
|
109
119
|
```javascript
|
@@ -161,6 +171,7 @@ resource. The temporary ID should be surrounded in brackets (`[]`).
|
|
161
171
|
```javascript
|
162
172
|
// PATCH /deep_unrest/update
|
163
173
|
{
|
174
|
+
redirect: '/submissions/[1]',
|
164
175
|
data: [
|
165
176
|
{
|
166
177
|
path: 'submissions[1]',
|
@@ -172,6 +183,24 @@ resource. The temporary ID should be surrounded in brackets (`[]`).
|
|
172
183
|
}
|
173
184
|
```
|
174
185
|
|
186
|
+
##### 200 Response:
|
187
|
+
When a temp id (`[id]`) is present in the redirect url, the temp id will be
|
188
|
+
replaced with the id given to the new resource.
|
189
|
+
|
190
|
+
Using the example above, assuming that the `Submission` at path
|
191
|
+
`submissions[1]` was given the id `123`, the redirect request param of
|
192
|
+
`/submissions/[1]` will be replaced with `/submissions/123`.
|
193
|
+
|
194
|
+
```javascript
|
195
|
+
{
|
196
|
+
id: 123,
|
197
|
+
type: 'submissions',
|
198
|
+
attributes: {
|
199
|
+
name: 'testing'
|
200
|
+
}
|
201
|
+
}
|
202
|
+
```
|
203
|
+
|
175
204
|
##### Create Errors:
|
176
205
|
All errors regarding the new resource will use the temp ID as the path to the error.
|
177
206
|
|
@@ -192,7 +221,7 @@ example will perform the following operations:
|
|
192
221
|
|
193
222
|
* Change the `name` column of `Submission` with id `123` to `test`
|
194
223
|
* Change the `value` column of `Answer` with id `1` to `yes`
|
195
|
-
* Create a new `Answer` with a value of `
|
224
|
+
* Create a new `Answer` with a value of `no` using temp ID `[1]`
|
196
225
|
* Delete the `Answer` with id `2`
|
197
226
|
|
198
227
|
These operations will be performed within a single `ActiveRecord` transaction.
|
@@ -253,7 +282,7 @@ limited to the current user's allowed scope.
|
|
253
282
|
```
|
254
283
|
|
255
284
|
### Example 6 - Bulk Delete
|
256
|
-
The following example will delete every
|
285
|
+
The following example will delete every `Submission`.
|
257
286
|
|
258
287
|
When using an authorization strategy, the scope of the bulk delete will be
|
259
288
|
limited to the current user's allowed scope.
|
@@ -9,10 +9,10 @@ module DeepUnrest
|
|
9
9
|
|
10
10
|
def update
|
11
11
|
redirect = allowed_params[:redirect]
|
12
|
-
DeepUnrest.perform_update(allowed_params[:data],
|
13
|
-
|
12
|
+
redirect_replace = DeepUnrest.perform_update(allowed_params[:data],
|
13
|
+
current_user)
|
14
14
|
if redirect
|
15
|
-
redirect_to redirect
|
15
|
+
redirect_to redirect_replace.call(redirect)
|
16
16
|
else
|
17
17
|
render json: {}, status: 200
|
18
18
|
end
|
data/lib/deep_unrest/version.rb
CHANGED
data/lib/deep_unrest.rb
CHANGED
@@ -197,18 +197,14 @@ module DeepUnrest
|
|
197
197
|
cursor
|
198
198
|
end
|
199
199
|
|
200
|
-
def self.get_mutation_cursor(memo, cursor, addr, type, id,
|
200
|
+
def self.get_mutation_cursor(memo, cursor, addr, type, id, temp_id, scope_type)
|
201
201
|
if memo
|
202
202
|
cursor[addr] = [{}]
|
203
203
|
next_cursor = cursor[addr][0]
|
204
204
|
else
|
205
|
+
method = scope_type == :show ? :update : scope_type
|
205
206
|
cursor = {}
|
206
207
|
type_sym = type.to_sym
|
207
|
-
if destroy
|
208
|
-
method = id ? :update : :destroy_all
|
209
|
-
else
|
210
|
-
method = id ? :update : :update_all
|
211
|
-
end
|
212
208
|
klass = to_class(type)
|
213
209
|
body = {}
|
214
210
|
body[klass.primary_key.to_sym] = id if id
|
@@ -221,6 +217,7 @@ module DeepUnrest
|
|
221
217
|
method: method,
|
222
218
|
body: body
|
223
219
|
}
|
220
|
+
cursor[type_sym][:operations][id][method][:temp_id] = temp_id if temp_id
|
224
221
|
memo = cursor
|
225
222
|
next_cursor = cursor[type_sym][:operations][id][method][:body]
|
226
223
|
end
|
@@ -238,8 +235,16 @@ module DeepUnrest
|
|
238
235
|
type, id_str = rest.shift
|
239
236
|
addr = to_update_body_key(type)
|
240
237
|
id = parse_id(id_str)
|
238
|
+
scope_type = get_scope_type(id_str, rest.blank?, op[:destroy])
|
239
|
+
temp_id = scope_type == :create ? id_str : nil
|
241
240
|
|
242
|
-
memo, next_cursor = get_mutation_cursor(memo,
|
241
|
+
memo, next_cursor = get_mutation_cursor(memo,
|
242
|
+
cursor,
|
243
|
+
addr,
|
244
|
+
type,
|
245
|
+
id,
|
246
|
+
temp_id,
|
247
|
+
scope_type)
|
243
248
|
|
244
249
|
next_cursor[:id] = id if id
|
245
250
|
build_mutation_fragment(op, user, rest, memo, next_cursor, type)
|
@@ -255,22 +260,28 @@ module DeepUnrest
|
|
255
260
|
mutation.map do |_, item|
|
256
261
|
item[:operations].map do |id, ops|
|
257
262
|
ops.map do |_, action|
|
258
|
-
case action[:method]
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
263
|
+
record = case action[:method]
|
264
|
+
when :update_all
|
265
|
+
DeepUnrest.authorization_strategy
|
266
|
+
.get_authorized_scope(user, item[:klass])
|
267
|
+
.update(action[:body])
|
268
|
+
nil
|
269
|
+
when :destroy_all
|
270
|
+
DeepUnrest.authorization_strategy
|
271
|
+
.get_authorized_scope(user, item[:klass])
|
272
|
+
.destroy_all
|
273
|
+
nil
|
274
|
+
when :update
|
275
|
+
item[:klass].update(id, action[:body])
|
276
|
+
when :create
|
277
|
+
item[:klass].create(action[:body])
|
278
|
+
end
|
279
|
+
result = { record: record }
|
280
|
+
if action[:temp_id]
|
281
|
+
result[:temp_ids] = {}
|
282
|
+
result[:temp_ids][action[:temp_id]] = record.id
|
273
283
|
end
|
284
|
+
result
|
274
285
|
end
|
275
286
|
end
|
276
287
|
end
|
@@ -307,6 +318,19 @@ module DeepUnrest
|
|
307
318
|
end.flatten
|
308
319
|
end
|
309
320
|
|
321
|
+
def self.build_redirect_regex(replacements)
|
322
|
+
replacements ||= []
|
323
|
+
|
324
|
+
replace_ops = replacements.map do |k, v|
|
325
|
+
proc { |str| str.sub(k.to_s, v.to_s) }
|
326
|
+
end
|
327
|
+
|
328
|
+
proc do |str|
|
329
|
+
replace_ops.each { |op| str = op.call(str) }
|
330
|
+
str
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
310
334
|
def self.perform_update(params, user)
|
311
335
|
# identify requested scope(s)
|
312
336
|
scopes = collect_all_scopes(params)
|
@@ -321,13 +345,18 @@ module DeepUnrest
|
|
321
345
|
results = mutate(mutations, user).flatten
|
322
346
|
|
323
347
|
# check results for errors
|
324
|
-
errors = results.
|
348
|
+
errors = results.map { |res| res[:record] }
|
349
|
+
.compact
|
325
350
|
.map(&:errors)
|
326
351
|
.map(&:messages)
|
327
352
|
.reject(&:empty?)
|
328
353
|
.compact
|
329
|
-
|
330
|
-
|
354
|
+
if errors.empty?
|
355
|
+
temp_ids = results.map { |res| res[:temp_ids] }
|
356
|
+
.compact
|
357
|
+
.each_with_object({}) { |item, mem| mem.merge!(item) }
|
358
|
+
return build_redirect_regex(temp_ids)
|
359
|
+
end
|
331
360
|
|
332
361
|
# map errors to their sources
|
333
362
|
formatted_errors = { errors: map_errors_to_param_keys(scopes, errors) }
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: deep_unrest
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Lynn Hurley
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-05-
|
11
|
+
date: 2017-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|