forest_admin_agent 1.9.1 → 1.10.0
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/lib/forest_admin_agent/http/router.rb +1 -0
- data/lib/forest_admin_agent/routes/resources/update_field.rb +140 -0
- data/lib/forest_admin_agent/utils/id.rb +1 -1
- data/lib/forest_admin_agent/utils/schema/schema_emitter.rb +1 -1
- data/lib/forest_admin_agent/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7e8e0238988884b3db56ac66a0478dc662ea5fed4377d50b2de685f414c455cb
|
4
|
+
data.tar.gz: 7986a7262febae19442a08d0916362edd97ff655d2fad7f688d43babc14e8af1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d1f931091e7e9e836208337f190bc0442e7543e55afd232ffc2c98331823f1f235fa71eeae574b13a907009756783fd3d17592fe7540f091a827cee9a2e44ad2
|
7
|
+
data.tar.gz: 69f51337fc2eb92f6eba5f0c0d1decd260f61bb2703975336cec22c857452bb87ecbc5bc1a914444e5ec38a9052430df35f579124c3ac7a55cef61fd21a0152a
|
@@ -20,6 +20,7 @@ module ForestAdminAgent
|
|
20
20
|
Resources::Show.new.routes,
|
21
21
|
Resources::Store.new.routes,
|
22
22
|
Resources::Update.new.routes,
|
23
|
+
Resources::UpdateField.new.routes,
|
23
24
|
Resources::Related::CsvRelated.new.routes,
|
24
25
|
Resources::Related::ListRelated.new.routes,
|
25
26
|
Resources::Related::CountRelated.new.routes,
|
@@ -0,0 +1,140 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'jsonapi-serializers'
|
4
|
+
|
5
|
+
module ForestAdminAgent
|
6
|
+
module Routes
|
7
|
+
module Resources
|
8
|
+
class UpdateField < AbstractAuthenticatedRoute
|
9
|
+
include ForestAdminAgent::Builder
|
10
|
+
include ForestAdminDatasourceToolkit::Components::Query
|
11
|
+
include ForestAdminDatasourceToolkit::Validations
|
12
|
+
include ForestAdminDatasourceToolkit::Schema
|
13
|
+
|
14
|
+
def setup_routes
|
15
|
+
add_route(
|
16
|
+
'forest_update_field',
|
17
|
+
'put',
|
18
|
+
'/:collection_name/:id/relationships/:field_name/:index',
|
19
|
+
->(args) { handle_request(args) }
|
20
|
+
)
|
21
|
+
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def handle_request(args = {})
|
26
|
+
build(args)
|
27
|
+
|
28
|
+
record_id = Utils::Id.unpack_id(@collection, args[:params]['id'], with_key: true)
|
29
|
+
field_name = args[:params]['field_name']
|
30
|
+
array_index = parse_index(args[:params]['index'])
|
31
|
+
|
32
|
+
@permissions.can?(:edit, @collection)
|
33
|
+
|
34
|
+
field_schema = @collection.schema[:fields][field_name]
|
35
|
+
validate_array_field!(field_schema, field_name)
|
36
|
+
|
37
|
+
record = fetch_record(record_id)
|
38
|
+
|
39
|
+
array = record[field_name]
|
40
|
+
validate_array_value!(array, field_name, array_index)
|
41
|
+
|
42
|
+
new_value = parse_value_from_body(args[:params], field_schema)
|
43
|
+
|
44
|
+
updated_array = array.dup
|
45
|
+
updated_array[array_index] = new_value
|
46
|
+
|
47
|
+
scope = @permissions.get_scope(@collection)
|
48
|
+
condition_tree = ConditionTree::ConditionTreeFactory.match_records(@collection, [record_id])
|
49
|
+
filter = ForestAdminDatasourceToolkit::Components::Query::Filter.new(
|
50
|
+
condition_tree: ConditionTree::ConditionTreeFactory.intersect([condition_tree, scope])
|
51
|
+
)
|
52
|
+
@collection.update(@caller, filter, { field_name => updated_array })
|
53
|
+
|
54
|
+
records = @collection.list(@caller, filter, ProjectionFactory.all(@collection))
|
55
|
+
|
56
|
+
{
|
57
|
+
name: args[:params]['collection_name'],
|
58
|
+
content: JSONAPI::Serializer.serialize(
|
59
|
+
records[0],
|
60
|
+
is_collection: false,
|
61
|
+
class_name: @collection.name,
|
62
|
+
serializer: Serializer::ForestSerializer
|
63
|
+
)
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def parse_index(index_param)
|
70
|
+
index = Integer(index_param)
|
71
|
+
raise Http::Exceptions::ValidationError, 'Index must be non-negative' if index.negative?
|
72
|
+
|
73
|
+
index
|
74
|
+
rescue ArgumentError
|
75
|
+
raise Http::Exceptions::ValidationError, "Invalid index: #{index_param}"
|
76
|
+
end
|
77
|
+
|
78
|
+
def validate_array_field!(field_schema, field_name)
|
79
|
+
FieldValidator.validate(@collection, field_name)
|
80
|
+
return if field_schema.column_type.to_s.start_with?('[')
|
81
|
+
|
82
|
+
raise Http::Exceptions::ValidationError,
|
83
|
+
"Field '#{field_name}' is not an array (type: #{field_schema.column_type})"
|
84
|
+
rescue ForestAdminDatasourceToolkit::Exceptions::ValidationError => e
|
85
|
+
raise Http::Exceptions::NotFoundError, e.message if e.message.include?('not found')
|
86
|
+
|
87
|
+
raise Http::Exceptions::ValidationError, e.message
|
88
|
+
end
|
89
|
+
|
90
|
+
def fetch_record(record_id)
|
91
|
+
scope = @permissions.get_scope(@collection)
|
92
|
+
condition_tree = ConditionTree::ConditionTreeFactory.match_records(@collection, [record_id])
|
93
|
+
filter = ForestAdminDatasourceToolkit::Components::Query::Filter.new(
|
94
|
+
condition_tree: ConditionTree::ConditionTreeFactory.intersect([condition_tree, scope])
|
95
|
+
)
|
96
|
+
records = @collection.list(@caller, filter, ProjectionFactory.all(@collection))
|
97
|
+
|
98
|
+
raise Http::Exceptions::NotFoundError, 'Record not found' unless records&.any?
|
99
|
+
|
100
|
+
records[0]
|
101
|
+
end
|
102
|
+
|
103
|
+
def validate_array_value!(array, field_name, array_index)
|
104
|
+
unless array.is_a?(Array)
|
105
|
+
raise Http::Exceptions::UnprocessableError,
|
106
|
+
"Field '#{field_name}' value is not an array (got: #{array.class})"
|
107
|
+
end
|
108
|
+
|
109
|
+
return unless array_index >= array.length
|
110
|
+
|
111
|
+
raise Http::Exceptions::ValidationError,
|
112
|
+
"Index #{array_index} out of bounds for array of length #{array.length}"
|
113
|
+
end
|
114
|
+
|
115
|
+
def parse_value_from_body(params, field_schema)
|
116
|
+
body = params[:data] || {}
|
117
|
+
value = body.dig(:attributes, 'value') || body.dig(:attributes, :value)
|
118
|
+
|
119
|
+
coerce_value(value, field_schema.column_type)
|
120
|
+
end
|
121
|
+
|
122
|
+
def coerce_value(value, column_type)
|
123
|
+
return value unless column_type.to_s.start_with?('[') && column_type.to_s.end_with?(']')
|
124
|
+
|
125
|
+
element_type = column_type.to_s[1..-2]
|
126
|
+
|
127
|
+
if element_type == 'Number' && value.is_a?(String)
|
128
|
+
begin
|
129
|
+
return Float(value)
|
130
|
+
rescue ArgumentError
|
131
|
+
raise Http::Exceptions::ValidationError, "Cannot coerce '#{value}' to Number - wrong type"
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
value
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
@@ -27,7 +27,7 @@ module ForestAdminAgent
|
|
27
27
|
field = collection.schema[:fields][pk_name]
|
28
28
|
value = primary_key_values[index]
|
29
29
|
casted_value = field.column_type == 'Number' ? value.to_i : value
|
30
|
-
ForestAdminDatasourceToolkit::Validations::FieldValidator.validate_value(
|
30
|
+
ForestAdminDatasourceToolkit::Validations::FieldValidator.validate_value(pk_name, field, casted_value)
|
31
31
|
|
32
32
|
[pk_name, casted_value]
|
33
33
|
end.to_h
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forest_admin_agent
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthieu
|
@@ -264,6 +264,7 @@ files:
|
|
264
264
|
- lib/forest_admin_agent/routes/resources/show.rb
|
265
265
|
- lib/forest_admin_agent/routes/resources/store.rb
|
266
266
|
- lib/forest_admin_agent/routes/resources/update.rb
|
267
|
+
- lib/forest_admin_agent/routes/resources/update_field.rb
|
267
268
|
- lib/forest_admin_agent/routes/security/authentication.rb
|
268
269
|
- lib/forest_admin_agent/routes/security/scope_invalidation.rb
|
269
270
|
- lib/forest_admin_agent/routes/system/health_check.rb
|