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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69b23785cf391fb245efbf6488e58fb19bbbc010e9dac0a91574412684e89129
4
- data.tar.gz: 26d9dd7b466009b8a09182dec02778b729e58b83c7b717811c45dca5ce6cc032
3
+ metadata.gz: 6be4888e921b11142c5bc7774e6a0c9ce9a91b7e0b8ceb8a812cff8e297b540a
4
+ data.tar.gz: '043584e75c96d49b34a4ab6ec0e0f0315700eb86a7d061fb03de66c095840b1c'
5
5
  SHA512:
6
- metadata.gz: e216bb8280e6adc87f2ab5f4c0d1a2937306ba1237aedcc9b80375a742227bcdf2187e74b573691324f55d9ef13843b397c25348d442a3e211eda2d8c20cb06c
7
- data.tar.gz: a3e736ae280744d93d65f9592ff9b9475f1f2b22b24790ee37b202ad361f0f192ff0a2bf87dd2669327492b24d2afee3000130af925d38788879512e086da24e
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.reduce({}) do |p, c|
31
- ForestLiana::WidgetsHelper.set_field_widget(c)
32
- p.update(c[:field] => c.merge!(value: nil))
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
- fields = fields.reduce({}) do |p, c|
39
- field = c.permit!.to_h.symbolize_keys
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
- p.update(c[:field] => field)
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, formatted_fields, action)
47
- if result.nil? || !result.is_a?(Hash)
48
- return render status: 500, json: { error: 'Error in smart action load hook: hook must return an object' }
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
- is_same_data_structure = ForestLiana::IsSameDataStructureHelper::Analyser.new(formatted_fields, result, 1)
51
- unless is_same_data_structure.perform
52
- return render status: 500, json: { error: 'Error in smart action hook: fields must be unchanged (no addition nor deletion allowed)' }
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 = action.fields.map do |field|
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
- # Transform fields from array to an object to ease usage in hook, adds null value.
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, formatted_fields, action)
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
- else
101
- # Transform fields from array to an object to ease usage in hook.
102
- context = get_smart_action_change_ctx(params[:fields])
103
- formatted_fields = context[:fields].clone # clone for following test on is_same_data_structure
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
- # Call the user-defined change hook.
106
- result = action.hooks[:change][params[:changedField]].(context)
116
+ # Get the smart action hook change context
117
+ context = get_smart_action_change_ctx(params[:fields], params[:changedField])
107
118
 
108
- handle_result(result, formatted_fields, action)
109
- end
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
@@ -52,6 +52,7 @@ module ForestLiana
52
52
  'description',
53
53
  'position',
54
54
  'widget',
55
+ 'hook',
55
56
  ]
56
57
  KEYS_SEGMENT = ['name']
57
58
 
@@ -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'] = {:load => load, :change => change}
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
@@ -1,3 +1,3 @@
1
1
  module ForestLiana
2
- VERSION = "7.0.0.beta.1"
2
+ VERSION = "7.0.0.beta.2"
3
3
  end
@@ -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
- 'foo' => -> (context) {
54
- fields = context[:fields]
55
- fields['foo'][:value] = 'baz'
56
- return fields
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
- 'foo' => -> (context) {
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
- context[:fields]['baz'] = foo.clone.update({field: 'baz'})
81
- context[:fields]
81
+ {}
82
82
  },
83
83
  :change => {
84
- 'foo' => -> (context) {
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
- 'foo' => -> (context) {
96
+ 'on_foo_changed' => -> (context) {
97
97
  fields = context[:fields]
98
- fields['enum'][:enums] = %w[c d e]
99
- return fields
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
- 'foo' => -> (context) {
111
+ 'on_foo_changed' => -> (context) {
111
112
  fields = context[:fields]
112
- fields['multipleEnum'][:enums] = %w[c d z]
113
- return fields
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
- end
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.1
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-01 00:00:00.000000000 Z
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