forest_liana 7.0.0.beta.1 → 7.0.0.beta.2
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/app/controllers/forest_liana/actions_controller.rb +44 -29
- data/app/services/forest_liana/apimap_sorter.rb +1 -0
- data/app/services/forest_liana/smart_action_field_validator.rb +49 -0
- data/config/initializers/errors.rb +17 -0
- data/lib/forest_liana/bootstrapper.rb +1 -1
- data/lib/forest_liana/schema_file_updater.rb +8 -0
- data/lib/forest_liana/version.rb +1 -1
- data/spec/lib/forest_liana/schema_file_updater_spec.rb +94 -0
- data/spec/requests/actions_controller_spec.rb +22 -20
- data/spec/services/forest_liana/smart_action_field_validator_spec.rb +70 -0
- metadata +7 -5
- data/app/helpers/forest_liana/is_same_data_structure_helper.rb +0 -44
- data/spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb +0 -87
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6be4888e921b11142c5bc7774e6a0c9ce9a91b7e0b8ceb8a812cff8e297b540a
|
4
|
+
data.tar.gz: '043584e75c96d49b34a4ab6ec0e0f0315700eb86a7d061fb03de66c095840b1c'
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: bfc23dfba08023225f17e44860caf95dc2fe041bcf81a1d61651ee96cea59563aa2c97ee6a1bcdc2e38e2e56a0f9c7c5e144b64583286af70864ec4d636a5795
|
7
|
+
data.tar.gz: 2cc2bf17cc1a235264db9981e33e99b22c23468514bf136e3379523020ca1efd906b792b46c45b6893f0edb279d8845c79e2e14ee8821ee47db6fc87d4992692
|
@@ -27,34 +27,45 @@ module ForestLiana
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def get_smart_action_load_ctx(fields)
|
30
|
-
fields = fields.
|
31
|
-
ForestLiana::WidgetsHelper.set_field_widget(
|
32
|
-
|
30
|
+
fields = fields.map do |field|
|
31
|
+
ForestLiana::WidgetsHelper.set_field_widget(field)
|
32
|
+
field[:value] = nil unless field[:value]
|
33
|
+
field
|
33
34
|
end
|
34
35
|
{:record => get_record, :fields => fields}
|
35
36
|
end
|
36
37
|
|
37
|
-
def get_smart_action_change_ctx(fields)
|
38
|
-
|
39
|
-
|
38
|
+
def get_smart_action_change_ctx(fields, field_changed)
|
39
|
+
found_field_changed = fields.find{|field| field[:field] == field_changed}
|
40
|
+
fields = fields.map do |field|
|
41
|
+
field = field.permit!.to_h.symbolize_keys
|
40
42
|
ForestLiana::WidgetsHelper.set_field_widget(field)
|
41
|
-
|
43
|
+
field
|
42
44
|
end
|
43
|
-
{:record => get_record, :fields => fields}
|
45
|
+
{:record => get_record, :field_changed => found_field_changed, :fields => fields}
|
44
46
|
end
|
45
47
|
|
46
|
-
def handle_result(result,
|
47
|
-
if result.nil? || !result.is_a?(
|
48
|
-
return render status: 500, json: { error: 'Error in smart action load hook: hook must return an
|
48
|
+
def handle_result(result, action)
|
49
|
+
if result.nil? || !result.is_a?(Array)
|
50
|
+
return render status: 500, json: { error: 'Error in smart action load hook: hook must return an array of fields' }
|
49
51
|
end
|
50
|
-
|
51
|
-
|
52
|
-
|
52
|
+
|
53
|
+
# Validate that the fields are well formed.
|
54
|
+
begin
|
55
|
+
# action.hooks[:change] is a hashmap here
|
56
|
+
# to do the validation, only the hook names are require
|
57
|
+
change_hooks_name = action.hooks[:change].nil? ? nil : action.hooks[:change].keys
|
58
|
+
ForestLiana::SmartActionFieldValidator.validate_smart_action_fields(result, action.name, change_hooks_name)
|
59
|
+
rescue ForestLiana::Errors::SmartActionInvalidFieldError => invalid_field_error
|
60
|
+
FOREST_LOGGER.warn invalid_field_error.message
|
61
|
+
rescue ForestLiana::Errors::SmartActionInvalidFieldHookError => invalid_hook_error
|
62
|
+
FOREST_LOGGER.error invalid_hook_error.message
|
63
|
+
return render status: 500, json: { error: invalid_hook_error.message }
|
53
64
|
end
|
54
65
|
|
55
66
|
# Apply result on fields (transform the object back to an array), preserve order.
|
56
|
-
fields =
|
57
|
-
updated_field = result[field[:field]
|
67
|
+
fields = result.map do |field|
|
68
|
+
updated_field = result.find{|f| f[:field] == field[:field]}
|
58
69
|
|
59
70
|
# Reset `value` when not present in `enums` (which means `enums` has changed).
|
60
71
|
if updated_field[:enums].is_a?(Array)
|
@@ -72,7 +83,7 @@ module ForestLiana
|
|
72
83
|
updated_field
|
73
84
|
end
|
74
85
|
|
75
|
-
render serializer: nil, json: { fields: fields}, status: :ok
|
86
|
+
render serializer: nil, json: { fields: fields }, status: :ok
|
76
87
|
end
|
77
88
|
|
78
89
|
def load
|
@@ -81,14 +92,13 @@ module ForestLiana
|
|
81
92
|
if !action
|
82
93
|
render status: 500, json: {error: 'Error in smart action load hook: cannot retrieve action from collection'}
|
83
94
|
else
|
84
|
-
#
|
95
|
+
# Get the smart action hook load context
|
85
96
|
context = get_smart_action_load_ctx(action.fields)
|
86
|
-
formatted_fields = context[:fields].clone # clone for following test on is_same_data_structure
|
87
97
|
|
88
98
|
# Call the user-defined load hook.
|
89
99
|
result = action.hooks[:load].(context)
|
90
100
|
|
91
|
-
handle_result(result,
|
101
|
+
handle_result(result, action)
|
92
102
|
end
|
93
103
|
end
|
94
104
|
|
@@ -96,17 +106,22 @@ module ForestLiana
|
|
96
106
|
action = get_action(params[:collectionName])
|
97
107
|
|
98
108
|
if !action
|
99
|
-
render status: 500, json: {error: 'Error in smart action change hook: cannot retrieve action from collection'}
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
109
|
+
return render status: 500, json: {error: 'Error in smart action change hook: cannot retrieve action from collection'}
|
110
|
+
elsif params[:fields].nil?
|
111
|
+
return render status: 500, json: {error: 'Error in smart action change hook: fields params is mandatory'}
|
112
|
+
elsif !params[:fields].is_a?(Array)
|
113
|
+
return render status: 500, json: {error: 'Error in smart action change hook: fields params must be an array'}
|
114
|
+
end
|
104
115
|
|
105
|
-
|
106
|
-
|
116
|
+
# Get the smart action hook change context
|
117
|
+
context = get_smart_action_change_ctx(params[:fields], params[:changedField])
|
107
118
|
|
108
|
-
|
109
|
-
|
119
|
+
field_changed_hook = context[:field_changed][:hook]
|
120
|
+
|
121
|
+
# Call the user-defined change hook.
|
122
|
+
result = action.hooks[:change][field_changed_hook].(context)
|
123
|
+
|
124
|
+
handle_result(result, action)
|
110
125
|
end
|
111
126
|
end
|
112
127
|
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class SmartActionFieldValidator
|
3
|
+
|
4
|
+
@@accepted_primitive_field_type = [
|
5
|
+
'String',
|
6
|
+
'Number',
|
7
|
+
'Date',
|
8
|
+
'Boolean',
|
9
|
+
'File',
|
10
|
+
'Enum',
|
11
|
+
'Json',
|
12
|
+
'Dateonly',
|
13
|
+
]
|
14
|
+
|
15
|
+
@@accepted_array_field_type = [
|
16
|
+
'String',
|
17
|
+
'Number',
|
18
|
+
'Date',
|
19
|
+
'boolean',
|
20
|
+
'File',
|
21
|
+
'Enum',
|
22
|
+
]
|
23
|
+
|
24
|
+
def self.validate_field(field, action_name)
|
25
|
+
raise ForestLiana::Errors::SmartActionInvalidFieldError.new(action_name, nil, "The field attribute must be defined") if !field || field[:field].nil?
|
26
|
+
raise ForestLiana::Errors::SmartActionInvalidFieldError.new(action_name, nil, "The field attribute must be a string.") if !field[:field].is_a?(String)
|
27
|
+
raise ForestLiana::Errors::SmartActionInvalidFieldError.new(action_name, field[:field], "The description attribute must be a string.") if field[:description] && !field[:description].is_a?(String)
|
28
|
+
raise ForestLiana::Errors::SmartActionInvalidFieldError.new(action_name, field[:field], "The enums attribute must be an array.") if field[:enums] && !field[:enums].is_a?(Array)
|
29
|
+
raise ForestLiana::Errors::SmartActionInvalidFieldError.new(action_name, field[:field], "The reference attribute must be a string.") if field[:reference] && !field[:reference].is_a?(String)
|
30
|
+
|
31
|
+
is_type_valid = field[:type].is_a?(Array) ?
|
32
|
+
@@accepted_array_field_type.include?(field[:type][0]) :
|
33
|
+
@@accepted_primitive_field_type.include?(field[:type])
|
34
|
+
|
35
|
+
raise ForestLiana::Errors::SmartActionInvalidFieldError.new(action_name, field[:field], "The type attribute must be a valid type. See the documentation for more information. https://docs.forestadmin.com/documentation/reference-guide/fields/create-and-manage-smart-fields#available-field-options.") if !is_type_valid
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.validate_field_change_hook(field, action_name, hooks)
|
39
|
+
raise ForestLiana::Errors::SmartActionInvalidFieldHookError.new(action_name, field[:field], field[:hook]) if field[:hook] && !hooks.find{|hook| hook == field[:hook]}
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.validate_smart_action_fields(fields, action_name, change_hooks)
|
43
|
+
fields.map{|field|
|
44
|
+
self.validate_field(field.symbolize_keys, action_name)
|
45
|
+
self.validate_field_change_hook(field.symbolize_keys, action_name, change_hooks) if change_hooks
|
46
|
+
}
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -13,6 +13,23 @@ module ForestLiana
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
+
class SmartActionInvalidFieldError < StandardError
|
17
|
+
def initialize(action_name=nil, field_name=nil, message=nil)
|
18
|
+
error_message = ""
|
19
|
+
error_message << "Error while parsing action \"#{action_name}\"" if !action_name.nil?
|
20
|
+
error_message << " on field \"#{field_name}\"" if !field_name.nil?
|
21
|
+
error_message << ": " if !field_name.nil? || !action_name.nil?
|
22
|
+
error_message << message if !message.nil?
|
23
|
+
super(error_message)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class SmartActionInvalidFieldHookError < StandardError
|
28
|
+
def initialize(action_name=nil, field_name=nil, hook_name=nil)
|
29
|
+
super("The hook \"#{hook_name}\" of \"#{field_name}\" field on the smart action \"#{action_name}\" is not defined.")
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
16
33
|
class ExpectedError < StandardError
|
17
34
|
attr_reader :error_code, :status, :message, :name
|
18
35
|
|
@@ -60,7 +60,7 @@ module ForestLiana
|
|
60
60
|
a = get_action(c, action['name'])
|
61
61
|
load = !a.hooks.nil? && a.hooks.key?(:load) && a.hooks[:load].is_a?(Proc)
|
62
62
|
change = !a.hooks.nil? && a.hooks.key?(:change) && a.hooks[:change].is_a?(Hash) ? a.hooks[:change].keys : []
|
63
|
-
action['hooks'] = {
|
63
|
+
action['hooks'] = {'load' => load, 'change' => change}
|
64
64
|
end
|
65
65
|
end
|
66
66
|
end
|
@@ -63,6 +63,7 @@ module ForestLiana
|
|
63
63
|
'description',
|
64
64
|
'position',
|
65
65
|
'widget',
|
66
|
+
'hook',
|
66
67
|
]
|
67
68
|
KEYS_SEGMENT = ['name']
|
68
69
|
|
@@ -96,6 +97,13 @@ module ForestLiana
|
|
96
97
|
end
|
97
98
|
|
98
99
|
collection['actions'] = collection['actions'].map do |action|
|
100
|
+
begin
|
101
|
+
SmartActionFieldValidator.validate_smart_action_fields(action['fields'], action['name'], action['hooks']['change'])
|
102
|
+
rescue ForestLiana::Errors::SmartActionInvalidFieldError => invalid_field_error
|
103
|
+
FOREST_LOGGER.warn invalid_field_error.message
|
104
|
+
rescue ForestLiana::Errors::SmartActionInvalidFieldHookError => invalid_hook_error
|
105
|
+
FOREST_LOGGER.error invalid_hook_error.message
|
106
|
+
end
|
99
107
|
action['fields'] = action['fields'].map { |field| field.slice(*KEYS_ACTION_FIELD) }
|
100
108
|
action.slice(*KEYS_ACTION)
|
101
109
|
end
|
data/lib/forest_liana/version.rb
CHANGED
@@ -0,0 +1,94 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
describe SchemaFileUpdater do
|
3
|
+
describe "initialize" do
|
4
|
+
describe "without any collections nor meta" do
|
5
|
+
it "should set collections as an empty array and meta as an empty object" do
|
6
|
+
schema_file_updater = ForestLiana::SchemaFileUpdater.new("test.txt", [], {})
|
7
|
+
expect(schema_file_updater.instance_variable_get(:@collections)).to eq([])
|
8
|
+
expect(schema_file_updater.instance_variable_get(:@meta)).to eq({})
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "with a given collection" do
|
13
|
+
describe "when the collection has a smart action action" do
|
14
|
+
it "should save the smart action" do
|
15
|
+
collections = [{
|
16
|
+
"fields" => [],
|
17
|
+
"actions" => [{
|
18
|
+
"fields" => [],
|
19
|
+
"name" => "test",
|
20
|
+
"hooks" => {
|
21
|
+
"change" => []
|
22
|
+
}
|
23
|
+
}],
|
24
|
+
"segments" => []
|
25
|
+
}]
|
26
|
+
schema_file_updater = ForestLiana::SchemaFileUpdater.new("test.txt", collections, {})
|
27
|
+
expect(schema_file_updater.instance_variable_get(:@collections))
|
28
|
+
.to eq(collections)
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "when a smart action field is malformed" do
|
32
|
+
it "should display a warning message" do
|
33
|
+
collections = [{
|
34
|
+
"fields" => [],
|
35
|
+
"actions" => [{
|
36
|
+
"fields" => [{}],
|
37
|
+
"name" => "test",
|
38
|
+
"hooks" => {
|
39
|
+
"change" => []
|
40
|
+
}
|
41
|
+
}],
|
42
|
+
"segments" => []
|
43
|
+
}]
|
44
|
+
allow(FOREST_LOGGER).to receive(:warn)
|
45
|
+
schema_file_updater = ForestLiana::SchemaFileUpdater.new("test.txt", collections, {})
|
46
|
+
expect(FOREST_LOGGER).to have_received(:warn).with('Error while parsing action "test": The field attribute must be defined')
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "when a smart action change field hook does not exist" do
|
51
|
+
it "should display an error message" do
|
52
|
+
collections = [{
|
53
|
+
"fields" => [],
|
54
|
+
"actions" => [{
|
55
|
+
"fields" => [{
|
56
|
+
"field" => "testField",
|
57
|
+
"hook" => "undefinedHook",
|
58
|
+
"type" => "String",
|
59
|
+
}],
|
60
|
+
"name" => "test",
|
61
|
+
"hooks" => {
|
62
|
+
"change" => []
|
63
|
+
}
|
64
|
+
}],
|
65
|
+
"segments" => []
|
66
|
+
}]
|
67
|
+
|
68
|
+
allow(FOREST_LOGGER).to receive(:error)
|
69
|
+
schema_file_updater = ForestLiana::SchemaFileUpdater.new("test.txt", collections, {})
|
70
|
+
expect(FOREST_LOGGER).to have_received(:error).with('The hook "undefinedHook" of "testField" field on the smart action "test" is not defined.')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe "perform" do
|
78
|
+
it "should call file puts with pretty printed data" do
|
79
|
+
file = instance_double(File, read: "stubbed read")
|
80
|
+
|
81
|
+
allow(File).to receive(:open).with("test.txt", "w") { |&block| block.call(file) }
|
82
|
+
|
83
|
+
schema_file_updater = ForestLiana::SchemaFileUpdater.new("test.txt", [], {})
|
84
|
+
expected_result = schema_file_updater.pretty_print({
|
85
|
+
"collections" => [],
|
86
|
+
"meta" => {}
|
87
|
+
})
|
88
|
+
|
89
|
+
expect(file).to receive(:puts).with(expected_result)
|
90
|
+
schema_file_updater.perform
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
@@ -30,6 +30,7 @@ describe 'Requesting Actions routes', :type => :request do
|
|
30
30
|
reference: nil,
|
31
31
|
description: nil,
|
32
32
|
widget: nil,
|
33
|
+
hook: 'on_foo_changed'
|
33
34
|
}
|
34
35
|
enum = {
|
35
36
|
field: 'enum',
|
@@ -50,10 +51,10 @@ describe 'Requesting Actions routes', :type => :request do
|
|
50
51
|
context[:fields]
|
51
52
|
},
|
52
53
|
:change => {
|
53
|
-
'
|
54
|
-
|
55
|
-
|
56
|
-
|
54
|
+
'on_foo_changed' => -> (context) {
|
55
|
+
foo = context[:fields].find{|field| field[:field] == 'foo'}
|
56
|
+
foo[:value] = 'baz'
|
57
|
+
context[:fields]
|
57
58
|
}
|
58
59
|
}
|
59
60
|
}
|
@@ -66,7 +67,7 @@ describe 'Requesting Actions routes', :type => :request do
|
|
66
67
|
1
|
67
68
|
},
|
68
69
|
:change => {
|
69
|
-
'
|
70
|
+
'on_foo_changed' => -> (context) {
|
70
71
|
1
|
71
72
|
}
|
72
73
|
}
|
@@ -77,11 +78,10 @@ describe 'Requesting Actions routes', :type => :request do
|
|
77
78
|
fields: [foo],
|
78
79
|
hooks: {
|
79
80
|
:load => -> (context) {
|
80
|
-
|
81
|
-
context[:fields]
|
81
|
+
{}
|
82
82
|
},
|
83
83
|
:change => {
|
84
|
-
'
|
84
|
+
'on_foo_changed' => -> (context) {
|
85
85
|
context[:fields]['baz'] = foo.clone.update({field: 'baz'})
|
86
86
|
context[:fields]
|
87
87
|
}
|
@@ -93,10 +93,11 @@ describe 'Requesting Actions routes', :type => :request do
|
|
93
93
|
fields: [foo, enum],
|
94
94
|
hooks: {
|
95
95
|
:change => {
|
96
|
-
'
|
96
|
+
'on_foo_changed' => -> (context) {
|
97
97
|
fields = context[:fields]
|
98
|
-
fields[
|
99
|
-
|
98
|
+
enum_field = fields.find{|field| field[:field] == 'enum'}
|
99
|
+
enum_field[:enums] = %w[c d e]
|
100
|
+
fields
|
100
101
|
}
|
101
102
|
}
|
102
103
|
}
|
@@ -107,10 +108,11 @@ describe 'Requesting Actions routes', :type => :request do
|
|
107
108
|
fields: [foo, multiple_enum],
|
108
109
|
hooks: {
|
109
110
|
:change => {
|
110
|
-
'
|
111
|
+
'on_foo_changed' => -> (context) {
|
111
112
|
fields = context[:fields]
|
112
|
-
fields[
|
113
|
-
|
113
|
+
enum_field = fields.find{|field| field[:field] == 'multipleEnum'}
|
114
|
+
enum_field[:enums] = %w[c d z]
|
115
|
+
fields
|
114
116
|
}
|
115
117
|
}
|
116
118
|
}
|
@@ -136,16 +138,19 @@ describe 'Requesting Actions routes', :type => :request do
|
|
136
138
|
it 'should respond 500 with bad params' do
|
137
139
|
post '/forest/actions/my_action/hooks/load', params: {}
|
138
140
|
expect(response.status).to eq(500)
|
141
|
+
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: cannot retrieve action from collection'})
|
139
142
|
end
|
140
143
|
|
141
144
|
it 'should respond 500 with bad hook result type' do
|
142
145
|
post '/forest/actions/fail_action/hooks/load', params: JSON.dump(params), headers: { 'CONTENT_TYPE' => 'application/json' }
|
143
146
|
expect(response.status).to eq(500)
|
147
|
+
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
144
148
|
end
|
145
149
|
|
146
150
|
it 'should respond 500 with bad hook result data structure' do
|
147
151
|
post '/forest/actions/cheat_action/hooks/load', params: JSON.dump(params), headers: { 'CONTENT_TYPE' => 'application/json' }
|
148
152
|
expect(response.status).to eq(500)
|
153
|
+
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
149
154
|
end
|
150
155
|
end
|
151
156
|
|
@@ -163,18 +168,15 @@ describe 'Requesting Actions routes', :type => :request do
|
|
163
168
|
end
|
164
169
|
|
165
170
|
it 'should respond 500 with bad params' do
|
166
|
-
post '/forest/actions/my_action/hooks/change', params: {}
|
171
|
+
post '/forest/actions/my_action/hooks/change', params: JSON.dump({collectionName: 'Island'}), headers: { 'CONTENT_TYPE' => 'application/json' }
|
167
172
|
expect(response.status).to eq(500)
|
173
|
+
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action change hook: fields params is mandatory'})
|
168
174
|
end
|
169
175
|
|
170
176
|
it 'should respond 500 with bad hook result type' do
|
171
177
|
post '/forest/actions/fail_action/hooks/change', params: JSON.dump(params), headers: { 'CONTENT_TYPE' => 'application/json' }
|
172
178
|
expect(response.status).to eq(500)
|
173
|
-
|
174
|
-
|
175
|
-
it 'should respond 500 with bad hook result data structure' do
|
176
|
-
post '/forest/actions/cheat_action/hooks/change', params: JSON.dump(params), headers: { 'CONTENT_TYPE' => 'application/json' }
|
177
|
-
expect(response.status).to eq(500)
|
179
|
+
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
178
180
|
end
|
179
181
|
|
180
182
|
it 'should reset value when enums has changed' do
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
describe SmartActionFieldValidator do
|
3
|
+
describe "self.validate_field" do
|
4
|
+
it "should raise an SmartActionInvalidFieldError with nil field" do
|
5
|
+
expect { SmartActionFieldValidator.validate_field(nil, "actionName") }.to raise_error(ForestLiana::Errors::SmartActionInvalidFieldError, 'Error while parsing action "actionName": The field attribute must be defined')
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should raise an SmartActionInvalidFieldError with a field that is not a string" do
|
9
|
+
expect { SmartActionFieldValidator.validate_field({
|
10
|
+
:field => 5
|
11
|
+
}, "actionName") }.to raise_error(ForestLiana::Errors::SmartActionInvalidFieldError, 'Error while parsing action "actionName": The field attribute must be a string.')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should raise an SmartActionInvalidFieldError with description that is not a string" do
|
15
|
+
expect { SmartActionFieldValidator.validate_field({
|
16
|
+
:field => "field",
|
17
|
+
:description => 5
|
18
|
+
}, "actionName") }.to raise_error(ForestLiana::Errors::SmartActionInvalidFieldError, 'Error while parsing action "actionName" on field "field": The description attribute must be a string.')
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should raise an SmartActionInvalidFieldError with an enums that is not an array" do
|
22
|
+
expect { SmartActionFieldValidator.validate_field({
|
23
|
+
:field => "field",
|
24
|
+
:enums => "NotAnArray"
|
25
|
+
}, "actionName") }.to raise_error(ForestLiana::Errors::SmartActionInvalidFieldError, 'Error while parsing action "actionName" on field "field": The enums attribute must be an array.')
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should raise an SmartActionInvalidFieldError with a reference that is not a string" do
|
29
|
+
expect { SmartActionFieldValidator.validate_field({
|
30
|
+
:field => "field",
|
31
|
+
:type => "String",
|
32
|
+
:reference => 5
|
33
|
+
}, "actionName") }.to raise_error(ForestLiana::Errors::SmartActionInvalidFieldError, 'Error while parsing action "actionName" on field "field": The reference attribute must be a string.')
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should raise an SmartActionInvalidFieldError with an invalid type" do
|
37
|
+
expect { SmartActionFieldValidator.validate_field({
|
38
|
+
:field => "field",
|
39
|
+
:type => "AbsolutelyNotAValidType"
|
40
|
+
}, "actionName") }.to raise_error(ForestLiana::Errors::SmartActionInvalidFieldError, 'Error while parsing action "actionName" on field "field": The type attribute must be a valid type. See the documentation for more information. https://docs.forestadmin.com/documentation/reference-guide/fields/create-and-manage-smart-fields#available-field-options.')
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should not raise any error when everything is configured correctly" do
|
44
|
+
expect { SmartActionFieldValidator.validate_field({
|
45
|
+
:field => "field",
|
46
|
+
:type => "String",
|
47
|
+
:description => "field description"
|
48
|
+
}, "actionName") }.not_to raise_error
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "self.validate_field_change_hook" do
|
53
|
+
it "should raise an SmartActionInvalidFieldHookError with an invalid type" do
|
54
|
+
expect { SmartActionFieldValidator.validate_field_change_hook({
|
55
|
+
:field => "field",
|
56
|
+
:type => "AbsolutelyNotAValidType",
|
57
|
+
:hook => "hookThatDoesNotExist"
|
58
|
+
}, "actionName", []) }.to raise_error(ForestLiana::Errors::SmartActionInvalidFieldHookError)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should not raise any error when everything is configured correctly" do
|
62
|
+
expect { SmartActionFieldValidator.validate_field_change_hook({
|
63
|
+
:field => "field",
|
64
|
+
:type => "AbsolutelyNotAValidType",
|
65
|
+
:hook => "on_field_changed"
|
66
|
+
}, "actionName", ["on_field_changed"]) }.not_to raise_error
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: forest_liana
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.0.0.beta.
|
4
|
+
version: 7.0.0.beta.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sandro Munda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-06-
|
11
|
+
date: 2021-06-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -225,7 +225,6 @@ files:
|
|
225
225
|
- app/helpers/forest_liana/adapter_helper.rb
|
226
226
|
- app/helpers/forest_liana/application_helper.rb
|
227
227
|
- app/helpers/forest_liana/decoration_helper.rb
|
228
|
-
- app/helpers/forest_liana/is_same_data_structure_helper.rb
|
229
228
|
- app/helpers/forest_liana/query_helper.rb
|
230
229
|
- app/helpers/forest_liana/schema_helper.rb
|
231
230
|
- app/helpers/forest_liana/widgets_helper.rb
|
@@ -283,6 +282,7 @@ files:
|
|
283
282
|
- app/services/forest_liana/schema_utils.rb
|
284
283
|
- app/services/forest_liana/scope_validator.rb
|
285
284
|
- app/services/forest_liana/search_query_builder.rb
|
285
|
+
- app/services/forest_liana/smart_action_field_validator.rb
|
286
286
|
- app/services/forest_liana/stat_getter.rb
|
287
287
|
- app/services/forest_liana/stripe_base_getter.rb
|
288
288
|
- app/services/forest_liana/stripe_invoice_getter.rb
|
@@ -368,9 +368,9 @@ files:
|
|
368
368
|
- spec/dummy/db/schema.rb
|
369
369
|
- spec/dummy/lib/forest_liana/collections/location.rb
|
370
370
|
- spec/dummy/lib/forest_liana/collections/user.rb
|
371
|
-
- spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb
|
372
371
|
- spec/helpers/forest_liana/query_helper_spec.rb
|
373
372
|
- spec/helpers/forest_liana/schema_helper_spec.rb
|
373
|
+
- spec/lib/forest_liana/schema_file_updater_spec.rb
|
374
374
|
- spec/rails_helper.rb
|
375
375
|
- spec/requests/actions_controller_spec.rb
|
376
376
|
- spec/requests/authentications_spec.rb
|
@@ -387,6 +387,7 @@ files:
|
|
387
387
|
- spec/services/forest_liana/permissions_getter_spec.rb
|
388
388
|
- spec/services/forest_liana/resources_getter_spec.rb
|
389
389
|
- spec/services/forest_liana/schema_adapter_spec.rb
|
390
|
+
- spec/services/forest_liana/smart_action_field_validator_spec.rb
|
390
391
|
- spec/spec_helper.rb
|
391
392
|
- test/dummy/README.rdoc
|
392
393
|
- test/dummy/Rakefile
|
@@ -603,13 +604,13 @@ test_files:
|
|
603
604
|
- spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb
|
604
605
|
- spec/services/forest_liana/filters_parser_spec.rb
|
605
606
|
- spec/services/forest_liana/schema_adapter_spec.rb
|
607
|
+
- spec/services/forest_liana/smart_action_field_validator_spec.rb
|
606
608
|
- spec/services/forest_liana/line_stat_getter_spec.rb
|
607
609
|
- spec/services/forest_liana/permissions_formatter_spec.rb
|
608
610
|
- spec/services/forest_liana/permissions_checker_live_queries_spec.rb
|
609
611
|
- spec/services/forest_liana/apimap_sorter_spec.rb
|
610
612
|
- spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb
|
611
613
|
- spec/config/initializers/logger_spec.rb
|
612
|
-
- spec/helpers/forest_liana/is_same_data_structure_helper_spec.rb
|
613
614
|
- spec/helpers/forest_liana/schema_helper_spec.rb
|
614
615
|
- spec/helpers/forest_liana/query_helper_spec.rb
|
615
616
|
- spec/dummy/db/schema.rb
|
@@ -663,6 +664,7 @@ test_files:
|
|
663
664
|
- spec/dummy/app/models/location.rb
|
664
665
|
- spec/dummy/app/models/island.rb
|
665
666
|
- spec/dummy/app/models/reference.rb
|
667
|
+
- spec/lib/forest_liana/schema_file_updater_spec.rb
|
666
668
|
- spec/rails_helper.rb
|
667
669
|
- spec/requests/stats_spec.rb
|
668
670
|
- spec/requests/resources_spec.rb
|
@@ -1,44 +0,0 @@
|
|
1
|
-
require 'set'
|
2
|
-
|
3
|
-
module ForestLiana
|
4
|
-
module IsSameDataStructureHelper
|
5
|
-
class Analyser
|
6
|
-
def initialize(object, other, deep = 0)
|
7
|
-
@object = object
|
8
|
-
@other = other
|
9
|
-
@deep = deep
|
10
|
-
end
|
11
|
-
|
12
|
-
def are_objects(object, other)
|
13
|
-
object && other && object.is_a?(Hash) && other.is_a?(Hash)
|
14
|
-
end
|
15
|
-
|
16
|
-
def check_keys(object, other, step = 0)
|
17
|
-
unless are_objects(object, other)
|
18
|
-
return false
|
19
|
-
end
|
20
|
-
|
21
|
-
object_keys = object.keys
|
22
|
-
other_keys = other.keys
|
23
|
-
|
24
|
-
if object_keys.length != other_keys.length
|
25
|
-
return false
|
26
|
-
end
|
27
|
-
|
28
|
-
object_keys_set = object_keys.to_set
|
29
|
-
other_keys.each { |key|
|
30
|
-
if !object_keys_set.member?(key) || (step + 1 <= @deep && !check_keys(object[key], other[key], step + 1))
|
31
|
-
return false
|
32
|
-
end
|
33
|
-
}
|
34
|
-
|
35
|
-
return true
|
36
|
-
end
|
37
|
-
|
38
|
-
def perform
|
39
|
-
check_keys(@object, @other)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
@@ -1,87 +0,0 @@
|
|
1
|
-
module ForestLiana
|
2
|
-
context 'IsSameDataStructure class' do
|
3
|
-
it 'should: be valid with simple data' do
|
4
|
-
object = {:a => 'a', :b => 'b'}
|
5
|
-
other = {:a => 'a', :b => 'b'}
|
6
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other).perform
|
7
|
-
expect(result).to be true
|
8
|
-
end
|
9
|
-
|
10
|
-
it 'should: be invalid with simple data' do
|
11
|
-
object = {:a => 'a', :b => 'b'}
|
12
|
-
other = {:a => 'a', :c => 'c'}
|
13
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other).perform
|
14
|
-
expect(result).to be false
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'should: be invalid with not same hash' do
|
18
|
-
object = {:a => 'a', :b => 'b'}
|
19
|
-
other = {:a => 'a', :b => 'b', :c => 'c'}
|
20
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other).perform
|
21
|
-
expect(result).to be false
|
22
|
-
end
|
23
|
-
|
24
|
-
it 'should: be invalid with nil' do
|
25
|
-
object = nil
|
26
|
-
other = {:a => 'a', :b => 'b', :c => 'c'}
|
27
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other).perform
|
28
|
-
expect(result).to be false
|
29
|
-
end
|
30
|
-
|
31
|
-
it 'should: be invalid with not hash' do
|
32
|
-
object = nil
|
33
|
-
other = {:a => 'a', :b => 'b', :c => 'c'}
|
34
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other).perform
|
35
|
-
expect(result).to be false
|
36
|
-
end
|
37
|
-
|
38
|
-
it 'should: be invalid with integer' do
|
39
|
-
object = 1
|
40
|
-
other = {:a => 'a', :b => 'b', :c => 'c'}
|
41
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other).perform
|
42
|
-
expect(result).to be false
|
43
|
-
end
|
44
|
-
|
45
|
-
it 'should: be invalid with string' do
|
46
|
-
object = 'a'
|
47
|
-
other = {:a => 'a', :b => 'b', :c => 'c'}
|
48
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other).perform
|
49
|
-
expect(result).to be false
|
50
|
-
end
|
51
|
-
|
52
|
-
it 'should: be valid with depth 1' do
|
53
|
-
object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
|
54
|
-
other = {:a => {:c => 'c'}, :b => {:d => 'd'}}
|
55
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
|
56
|
-
expect(result).to be true
|
57
|
-
end
|
58
|
-
|
59
|
-
it 'should: be invalid with depth 1' do
|
60
|
-
object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
|
61
|
-
other = {:a => {:c => 'c'}, :b => {:e => 'e'}}
|
62
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
|
63
|
-
expect(result).to be false
|
64
|
-
end
|
65
|
-
|
66
|
-
it 'should: be invalid with depth 1 and nil' do
|
67
|
-
object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
|
68
|
-
other = {:a => {:c => 'c'}, :b => nil}
|
69
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
|
70
|
-
expect(result).to be false
|
71
|
-
end
|
72
|
-
|
73
|
-
it 'should: be invalid with depth 1 and integer' do
|
74
|
-
object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
|
75
|
-
other = {:a => {:c => 'c'}, :b => 1}
|
76
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
|
77
|
-
expect(result).to be false
|
78
|
-
end
|
79
|
-
|
80
|
-
it 'should: be invalid with depth 1 and string' do
|
81
|
-
object = {:a => {:c => 'c'}, :b => {:d => 'd'}}
|
82
|
-
other = {:a => {:c => 'c'}, :b => 'b'}
|
83
|
-
result = IsSameDataStructureHelper::Analyser.new(object, other, 1).perform
|
84
|
-
expect(result).to be false
|
85
|
-
end
|
86
|
-
end
|
87
|
-
end
|