forest_liana 6.6.0 → 7.0.0.beta.3
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/controllers/forest_liana/application_controller.rb +2 -2
- data/app/controllers/forest_liana/associations_controller.rb +1 -1
- data/app/controllers/forest_liana/base_controller.rb +1 -1
- data/app/controllers/forest_liana/resources_controller.rb +7 -6
- data/app/serializers/forest_liana/intercom_attribute_serializer.rb +1 -1
- data/app/serializers/forest_liana/intercom_conversation_serializer.rb +1 -1
- data/app/serializers/forest_liana/mixpanel_event_serializer.rb +1 -1
- data/app/serializers/forest_liana/serializer_factory.rb +1 -1
- data/app/serializers/forest_liana/stat_serializer.rb +1 -1
- data/app/serializers/forest_liana/stripe_bank_account_serializer.rb +1 -1
- data/app/serializers/forest_liana/stripe_card_serializer.rb +1 -1
- data/app/serializers/forest_liana/stripe_invoice_serializer.rb +1 -1
- data/app/serializers/forest_liana/stripe_payment_serializer.rb +1 -1
- data/app/serializers/forest_liana/stripe_subscription_serializer.rb +1 -1
- data/app/services/forest_liana/apimap_sorter.rb +1 -0
- data/app/services/forest_liana/permissions_checker.rb +40 -34
- data/app/services/forest_liana/permissions_formatter.rb +1 -1
- data/app/services/forest_liana/permissions_getter.rb +1 -4
- 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 +2 -2
- 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/permissions_checker_acl_disabled_spec.rb +45 -69
- data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +39 -63
- data/spec/services/forest_liana/permissions_checker_live_queries_spec.rb +3 -3
- data/spec/services/forest_liana/permissions_formatter_spec.rb +11 -11
- data/spec/services/forest_liana/smart_action_field_validator_spec.rb +70 -0
- metadata +119 -117
- 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
@@ -13,7 +13,7 @@ module ForestLiana
|
|
13
13
|
'actions' => convert_actions_permissions_to_new_format(permissions[collection_name]['actions'])
|
14
14
|
}
|
15
15
|
|
16
|
-
permissions_new_format['renderings'][rendering_id][collection_name] = { '
|
16
|
+
permissions_new_format['renderings'][rendering_id][collection_name] = { 'segments' => permissions[collection_name]['segments'] }
|
17
17
|
}
|
18
18
|
|
19
19
|
permissions_new_format
|
@@ -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
|
@@ -139,7 +139,7 @@ module ForestLiana
|
|
139
139
|
|
140
140
|
# Monkey patch the find_serializer_class_name method to specify the
|
141
141
|
# good serializer to use.
|
142
|
-
::JSONAPI::Serializer.class_eval do
|
142
|
+
::ForestAdmin::JSONAPI::Serializer.class_eval do
|
143
143
|
def self.find_serializer_class_name(record, options)
|
144
144
|
if record.respond_to?(:jsonapi_serializer_class_name)
|
145
145
|
record.jsonapi_serializer_class_name.to_s
|
@@ -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
|
@@ -75,7 +75,7 @@ module ForestLiana
|
|
75
75
|
"users" => nil
|
76
76
|
},
|
77
77
|
},
|
78
|
-
"
|
78
|
+
"segments" => nil
|
79
79
|
},
|
80
80
|
"no_rights_collection" => {
|
81
81
|
"collection" => {
|
@@ -93,7 +93,7 @@ module ForestLiana
|
|
93
93
|
"users" => nil
|
94
94
|
}
|
95
95
|
},
|
96
|
-
"
|
96
|
+
"segments" => nil
|
97
97
|
},
|
98
98
|
},
|
99
99
|
"meta" => {
|
@@ -146,6 +146,8 @@ module ForestLiana
|
|
146
146
|
|
147
147
|
context 'with permissions coming from 2 different renderings' do
|
148
148
|
let(:collection_name) { 'custom' }
|
149
|
+
|
150
|
+
let(:segments_permissions) { nil }
|
149
151
|
let(:api_permissions_rendering_1) {
|
150
152
|
{
|
151
153
|
"data" => {
|
@@ -160,7 +162,7 @@ module ForestLiana
|
|
160
162
|
"searchToEdit" => true
|
161
163
|
},
|
162
164
|
"actions" => { },
|
163
|
-
"
|
165
|
+
"segments" => segments_permissions
|
164
166
|
},
|
165
167
|
},
|
166
168
|
"meta" => {
|
@@ -190,11 +192,11 @@ module ForestLiana
|
|
190
192
|
end
|
191
193
|
|
192
194
|
|
193
|
-
context '
|
195
|
+
context 'renderings cache' do
|
194
196
|
let(:fake_ressource) { collection_name }
|
195
197
|
let(:rendering_id) { 1 }
|
196
198
|
let(:collection_name) { 'custom' }
|
197
|
-
let(:
|
199
|
+
let(:segments_permissions) { { rendering_id => { 'custom' => nil } } }
|
198
200
|
let(:api_permissions) {
|
199
201
|
{
|
200
202
|
"data" => {
|
@@ -209,7 +211,7 @@ module ForestLiana
|
|
209
211
|
"searchToEdit" => true
|
210
212
|
},
|
211
213
|
"actions" => { },
|
212
|
-
"
|
214
|
+
"segments" => nil
|
213
215
|
},
|
214
216
|
},
|
215
217
|
"meta" => {
|
@@ -217,11 +219,11 @@ module ForestLiana
|
|
217
219
|
}
|
218
220
|
}
|
219
221
|
}
|
220
|
-
let(:
|
222
|
+
let(:api_permissions_rendering_only) {
|
221
223
|
{
|
222
224
|
"data" => {
|
223
225
|
'collections' => { },
|
224
|
-
'renderings' =>
|
226
|
+
'renderings' => segments_permissions
|
225
227
|
},
|
226
228
|
"meta" => {
|
227
229
|
"rolesACLActivated" => false
|
@@ -233,13 +235,13 @@ module ForestLiana
|
|
233
235
|
# clones is called to duplicate the returned value and not use to same (which results in an error
|
234
236
|
# as the permissions is edited through the formatter)
|
235
237
|
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(rendering_id) { api_permissions.clone }
|
236
|
-
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).and_return(
|
238
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(rendering_id, rendering_specific_only: true).and_return(api_permissions_rendering_only)
|
237
239
|
end
|
238
240
|
|
239
241
|
context 'when checking once for authorization' do
|
240
242
|
context 'when checking browseEnabled' do
|
241
243
|
context 'when expiration value is set to its default' do
|
242
|
-
it 'should not call the API to refresh the
|
244
|
+
it 'should not call the API to refresh the renderings cache' do
|
243
245
|
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
244
246
|
|
245
247
|
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
@@ -254,7 +256,7 @@ module ForestLiana
|
|
254
256
|
described_class.empty_cache
|
255
257
|
end
|
256
258
|
|
257
|
-
it 'should call the API to refresh the
|
259
|
+
it 'should call the API to refresh the renderings cache' do
|
258
260
|
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
259
261
|
|
260
262
|
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
@@ -263,7 +265,7 @@ module ForestLiana
|
|
263
265
|
end
|
264
266
|
end
|
265
267
|
|
266
|
-
# Only browse permission requires
|
268
|
+
# Only browse permission requires segments
|
267
269
|
context 'when checking exportEnabled' do
|
268
270
|
context 'when expiration value is set in the past' do
|
269
271
|
before do
|
@@ -273,7 +275,7 @@ module ForestLiana
|
|
273
275
|
end
|
274
276
|
end
|
275
277
|
|
276
|
-
it 'should NOT call the API to refresh the
|
278
|
+
it 'should NOT call the API to refresh the renderings cache' do
|
277
279
|
described_class.new(fake_ressource, 'exportEnabled', rendering_id, user_id: user_id).is_authorized?
|
278
280
|
|
279
281
|
expect(ForestLiana::PermissionsGetter).to have_received(:get_permissions_for_rendering).with(rendering_id).once
|
@@ -284,8 +286,8 @@ module ForestLiana
|
|
284
286
|
|
285
287
|
context 'when checking twice for authorization' do
|
286
288
|
context 'on the same rendering' do
|
287
|
-
context 'when
|
288
|
-
it 'should NOT call the API to refresh the
|
289
|
+
context 'when renderings permission has NOT expired' do
|
290
|
+
it 'should NOT call the API to refresh the renderings permissions' do
|
289
291
|
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
290
292
|
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
291
293
|
|
@@ -294,14 +296,14 @@ module ForestLiana
|
|
294
296
|
end
|
295
297
|
end
|
296
298
|
|
297
|
-
context 'when
|
299
|
+
context 'when renderings permission has expired' do
|
298
300
|
before do
|
299
301
|
allow(ENV).to receive(:[]).with('FOREST_PERMISSIONS_EXPIRATION_IN_SECONDS').and_return('-1')
|
300
302
|
# Needed to enforce ENV stub
|
301
303
|
described_class.empty_cache
|
302
304
|
end
|
303
305
|
|
304
|
-
it 'should call the API to refresh the
|
306
|
+
it 'should call the API to refresh the renderings permissions' do
|
305
307
|
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
306
308
|
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
307
309
|
|
@@ -313,7 +315,7 @@ module ForestLiana
|
|
313
315
|
|
314
316
|
context 'on two different renderings' do
|
315
317
|
let(:other_rendering_id) { 2 }
|
316
|
-
let(:
|
318
|
+
let(:api_permissions_rendering_only) {
|
317
319
|
{
|
318
320
|
"data" => {
|
319
321
|
'collections' => { },
|
@@ -330,10 +332,10 @@ module ForestLiana
|
|
330
332
|
|
331
333
|
before do
|
332
334
|
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(other_rendering_id).and_return(api_permissions_copy)
|
333
|
-
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(other_rendering_id, rendering_specific_only: true).and_return(
|
335
|
+
allow(ForestLiana::PermissionsGetter).to receive(:get_permissions_for_rendering).with(other_rendering_id, rendering_specific_only: true).and_return(api_permissions_rendering_only)
|
334
336
|
end
|
335
337
|
|
336
|
-
it 'should not call the API to refresh the
|
338
|
+
it 'should not call the API to refresh the rederings permissions' do
|
337
339
|
described_class.new(fake_ressource, 'browseEnabled', rendering_id, user_id: user_id).is_authorized?
|
338
340
|
described_class.new(fake_ressource, 'browseEnabled', other_rendering_id, user_id: user_id).is_authorized?
|
339
341
|
|
@@ -350,7 +352,7 @@ module ForestLiana
|
|
350
352
|
# Resource is only used to retrieve the collection name as it's stubbed it does not
|
351
353
|
# need to be defined
|
352
354
|
let(:fake_ressource) { collection_name }
|
353
|
-
let(:default_rendering_id) {
|
355
|
+
let(:default_rendering_id) { 1 }
|
354
356
|
let(:api_permissions) { default_api_permissions }
|
355
357
|
let(:collection_name) { 'all_rights_collection' }
|
356
358
|
|
@@ -380,14 +382,14 @@ module ForestLiana
|
|
380
382
|
describe 'browseEnabled permission' do
|
381
383
|
let(:collection_name) { 'custom' }
|
382
384
|
subject { described_class.new(fake_ressource, 'browseEnabled', default_rendering_id, user_id: user_id) }
|
383
|
-
let(:
|
385
|
+
let(:segments_permissions) { nil }
|
384
386
|
let(:default_api_permissions) {
|
385
387
|
{
|
386
388
|
"data" => {
|
387
389
|
"custom" => {
|
388
390
|
"collection" => collection_permissions,
|
389
391
|
"actions" => { },
|
390
|
-
"
|
392
|
+
"segments" => segments_permissions
|
391
393
|
},
|
392
394
|
},
|
393
395
|
"meta" => {
|
@@ -480,6 +482,26 @@ module ForestLiana
|
|
480
482
|
end
|
481
483
|
end
|
482
484
|
|
485
|
+
context 'when segments are defined' do
|
486
|
+
let(:segments_permissions) { ['SELECT * FROM products;', 'SELECT * FROM sellers;'] }
|
487
|
+
let(:collection_list_parameters) { { :user_id => "1", :segmentQuery => segmentQuery } }
|
488
|
+
|
489
|
+
context 'when segments are passing validation' do
|
490
|
+
let(:segmentQuery) { 'SELECT * FROM products;' }
|
491
|
+
it 'should return true' do
|
492
|
+
expect(subject.is_authorized?).to be true
|
493
|
+
end
|
494
|
+
end
|
495
|
+
|
496
|
+
context 'when segments are NOT passing validation' do
|
497
|
+
let(:segmentQuery) { 'SELECT * FROM rockets WHERE name = "Starship";' }
|
498
|
+
it 'should return false' do
|
499
|
+
expect(subject.is_authorized?).to be false
|
500
|
+
end
|
501
|
+
end
|
502
|
+
|
503
|
+
end
|
504
|
+
|
483
505
|
context 'when user has not the required permission' do
|
484
506
|
let(:collection_permissions) {
|
485
507
|
{
|
@@ -498,52 +520,6 @@ module ForestLiana
|
|
498
520
|
end
|
499
521
|
end
|
500
522
|
|
501
|
-
context 'when scopes are defined' do
|
502
|
-
let(:scope_permissions) { { 'dynamicScopesValues' => {}, 'filter' => { 'aggregator' => 'and', 'conditions' => [condition] } }}
|
503
|
-
let(:collection_list_parameters) { { :user_id => "1", :filters => JSON.generate(condition) } }
|
504
|
-
|
505
|
-
context 'when scopes are passing validation' do
|
506
|
-
context 'when scope value is a string' do
|
507
|
-
let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => true } }
|
508
|
-
|
509
|
-
it 'should return true' do
|
510
|
-
expect(subject.is_authorized?).to be true
|
511
|
-
end
|
512
|
-
end
|
513
|
-
|
514
|
-
context 'when scope value is a boolean' do
|
515
|
-
let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => 'true' } }
|
516
|
-
|
517
|
-
it 'should return true' do
|
518
|
-
expect(subject.is_authorized?).to be true
|
519
|
-
end
|
520
|
-
end
|
521
|
-
end
|
522
|
-
|
523
|
-
context 'when scopes are NOT passing validation' do
|
524
|
-
let(:condition) { { 'field' => 'field_1', 'operator' => 'equal', 'value' => true } }
|
525
|
-
let(:other_condition) {
|
526
|
-
{
|
527
|
-
aggregator: 'and',
|
528
|
-
conditions: [
|
529
|
-
{ field: 'name', value: 'john', operator: 'equal' },
|
530
|
-
{ field: 'price', value: '2500', operator: 'equal' }
|
531
|
-
]
|
532
|
-
}
|
533
|
-
}
|
534
|
-
let(:collection_list_parameters) {
|
535
|
-
{
|
536
|
-
:user_id => "1",
|
537
|
-
:filters => JSON.generate(other_condition)
|
538
|
-
}
|
539
|
-
}
|
540
|
-
|
541
|
-
|
542
|
-
it 'should return false' do
|
543
|
-
expect(subject.is_authorized?).to be false
|
544
|
-
end
|
545
|
-
end
|
546
|
-
end
|
547
523
|
end
|
548
524
|
end
|
549
525
|
|