forest_liana 7.0.0.beta.4 → 7.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/actions_controller.rb +2 -2
- data/app/controllers/forest_liana/associations_controller.rb +2 -2
- data/app/controllers/forest_liana/resources_controller.rb +15 -6
- data/app/controllers/forest_liana/scopes_controller.rb +20 -0
- data/app/controllers/forest_liana/smart_actions_controller.rb +39 -3
- data/app/controllers/forest_liana/stats_controller.rb +5 -5
- data/app/services/forest_liana/filters_parser.rb +25 -9
- data/app/services/forest_liana/has_many_dissociator.rb +2 -2
- data/app/services/forest_liana/has_many_getter.rb +2 -2
- data/app/services/forest_liana/leaderboard_stat_getter.rb +20 -14
- data/app/services/forest_liana/line_stat_getter.rb +4 -2
- data/app/services/forest_liana/permissions_checker.rb +3 -4
- data/app/services/forest_liana/permissions_getter.rb +2 -2
- data/app/services/forest_liana/pie_stat_getter.rb +6 -3
- data/app/services/forest_liana/resource_getter.rb +6 -3
- data/app/services/forest_liana/resource_updater.rb +5 -2
- data/app/services/forest_liana/resources_getter.rb +6 -5
- data/app/services/forest_liana/scope_manager.rb +102 -0
- data/app/services/forest_liana/search_query_builder.rb +6 -3
- data/app/services/forest_liana/stat_getter.rb +2 -1
- data/app/services/forest_liana/value_stat_getter.rb +4 -2
- data/config/routes.rb +3 -0
- data/lib/forest_liana/version.rb +1 -1
- data/spec/dummy/app/controllers/forest/islands_controller.rb +5 -0
- data/spec/dummy/config/routes.rb +4 -0
- data/spec/dummy/lib/forest_liana/collections/island.rb +7 -0
- data/spec/requests/actions_controller_spec.rb +100 -12
- data/spec/requests/resources_spec.rb +2 -0
- data/spec/services/forest_liana/filters_parser_spec.rb +27 -1
- data/spec/services/forest_liana/has_many_getter_spec.rb +116 -0
- data/spec/services/forest_liana/line_stat_getter_spec.rb +14 -6
- data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +1 -3
- data/spec/services/forest_liana/pie_stat_getter_spec.rb +114 -0
- data/spec/services/forest_liana/resource_updater_spec.rb +116 -0
- data/spec/services/forest_liana/resources_getter_spec.rb +68 -1
- data/spec/services/forest_liana/scope_manager_spec.rb +232 -0
- data/spec/services/forest_liana/value_stat_getter_spec.rb +96 -0
- metadata +20 -15
- data/app/services/forest_liana/scope_validator.rb +0 -98
- data/test/services/forest_liana/has_many_getter_test.rb +0 -75
- data/test/services/forest_liana/pie_stat_getter_test.rb +0 -29
- data/test/services/forest_liana/resource_updater_test.rb +0 -86
- data/test/services/forest_liana/scope_validator_test.rb +0 -185
- data/test/services/forest_liana/value_stat_getter_test.rb +0 -71
@@ -2,16 +2,19 @@ module ForestLiana
|
|
2
2
|
class ResourceGetter < BaseGetter
|
3
3
|
attr_accessor :record
|
4
4
|
|
5
|
-
def initialize(resource, params)
|
5
|
+
def initialize(resource, params, forest_user)
|
6
6
|
@resource = resource
|
7
7
|
@params = params
|
8
|
-
@collection_name = ForestLiana.name_for(
|
8
|
+
@collection_name = ForestLiana.name_for(resource)
|
9
|
+
@user = forest_user
|
9
10
|
@collection = get_collection(@collection_name)
|
10
11
|
compute_includes()
|
11
12
|
end
|
12
13
|
|
13
14
|
def perform
|
14
|
-
|
15
|
+
records = get_resource().eager_load(@includes)
|
16
|
+
scoped_records = ForestLiana::ScopeManager.apply_scopes_on_records(records, @user, @collection_name, @params[:timezone])
|
17
|
+
@record = scoped_records.find(@params[:id])
|
15
18
|
end
|
16
19
|
end
|
17
20
|
end
|
@@ -3,15 +3,18 @@ module ForestLiana
|
|
3
3
|
attr_accessor :record
|
4
4
|
attr_accessor :errors
|
5
5
|
|
6
|
-
def initialize(resource, params)
|
6
|
+
def initialize(resource, params, forest_user)
|
7
7
|
@resource = resource
|
8
8
|
@params = params
|
9
9
|
@errors = nil
|
10
|
+
@user = forest_user
|
10
11
|
end
|
11
12
|
|
12
13
|
def perform
|
13
14
|
begin
|
14
|
-
|
15
|
+
collection_name = ForestLiana.name_for(@resource)
|
16
|
+
scoped_records = ForestLiana::ScopeManager.apply_scopes_on_records(@resource, @user, collection_name, @params[:timezone])
|
17
|
+
@record = scoped_records.find(@params[:id])
|
15
18
|
|
16
19
|
if has_strong_parameter
|
17
20
|
@record.update(resource_params)
|
@@ -4,7 +4,7 @@ module ForestLiana
|
|
4
4
|
attr_reader :includes
|
5
5
|
attr_reader :records_count
|
6
6
|
|
7
|
-
def initialize(resource, params)
|
7
|
+
def initialize(resource, params, forest_user)
|
8
8
|
@resource = resource
|
9
9
|
@params = params
|
10
10
|
@count_needs_includes = false
|
@@ -14,12 +14,13 @@ module ForestLiana
|
|
14
14
|
@field_names_requested = field_names_requested
|
15
15
|
get_segment
|
16
16
|
compute_includes
|
17
|
-
@
|
17
|
+
@user = forest_user
|
18
|
+
@search_query_builder = SearchQueryBuilder.new(@params, @includes, @collection, forest_user)
|
18
19
|
|
19
20
|
prepare_query
|
20
21
|
end
|
21
22
|
|
22
|
-
def self.get_ids_from_request(params)
|
23
|
+
def self.get_ids_from_request(params, user)
|
23
24
|
attributes = params.dig('data', 'attributes')
|
24
25
|
has_body_attributes = attributes != nil
|
25
26
|
is_select_all_records_query = has_body_attributes && attributes[:all_records] == true
|
@@ -45,11 +46,11 @@ module ForestLiana
|
|
45
46
|
collection: parent_collection_name,
|
46
47
|
id: attributes[:parent_collection_id],
|
47
48
|
association_name: attributes[:parent_association_name],
|
48
|
-
}))
|
49
|
+
}), user)
|
49
50
|
else
|
50
51
|
collection_name = attributes[:collection_name]
|
51
52
|
model = ForestLiana::SchemaUtils.find_model_from_collection_name(collection_name)
|
52
|
-
resources_getter = ForestLiana::ResourcesGetter.new(model, attributes)
|
53
|
+
resources_getter = ForestLiana::ResourcesGetter.new(model, attributes, user)
|
53
54
|
end
|
54
55
|
|
55
56
|
# NOTICE: build IDs list.
|
@@ -0,0 +1,102 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
class ScopeManager
|
3
|
+
@@scopes_cache = Hash.new
|
4
|
+
# 5 minutes exipration cache
|
5
|
+
@@scope_cache_expiration_delta = 300
|
6
|
+
|
7
|
+
def self.apply_scopes_on_records(records, forest_user, collection_name, timezone)
|
8
|
+
scope_filters = get_scope_for_user(forest_user, collection_name, as_string: true)
|
9
|
+
|
10
|
+
return records if scope_filters.blank?
|
11
|
+
|
12
|
+
FiltersParser.new(scope_filters, records, timezone).apply_filters
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.append_scope_for_user(existing_filter, user, collection_name)
|
16
|
+
scope_filter = get_scope_for_user(user, collection_name, as_string: true)
|
17
|
+
filters = [existing_filter, scope_filter].compact
|
18
|
+
|
19
|
+
case filters.length
|
20
|
+
when 0
|
21
|
+
nil
|
22
|
+
when 1
|
23
|
+
filters[0]
|
24
|
+
else
|
25
|
+
"{\"aggregator\":\"and\",\"conditions\":[#{existing_filter},#{scope_filter}]}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.get_scope_for_user(user, collection_name, as_string: false)
|
30
|
+
raise 'Missing required rendering_id' unless user['rendering_id']
|
31
|
+
raise 'Missing required collection_name' unless collection_name
|
32
|
+
|
33
|
+
collection_scope = get_collection_scope(user['rendering_id'], collection_name)
|
34
|
+
|
35
|
+
return nil unless collection_scope
|
36
|
+
|
37
|
+
filters = format_dynamic_values(user['id'], collection_scope)
|
38
|
+
|
39
|
+
as_string && filters ? JSON.generate(filters) : filters
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.get_collection_scope(rendering_id, collection_name)
|
43
|
+
if !@@scopes_cache[rendering_id]
|
44
|
+
# when scope cache is unset wait for the refresh
|
45
|
+
refresh_scopes_cache(rendering_id)
|
46
|
+
elsif has_cache_expired?(rendering_id)
|
47
|
+
# when cache expired refresh the scopes without waiting for it
|
48
|
+
Thread.new { refresh_scopes_cache(rendering_id) }
|
49
|
+
end
|
50
|
+
|
51
|
+
@@scopes_cache[rendering_id][:scopes][collection_name]
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.has_cache_expired?(rendering_id)
|
55
|
+
rendering_scopes = @@scopes_cache[rendering_id]
|
56
|
+
return true unless rendering_scopes
|
57
|
+
|
58
|
+
second_since_last_fetch = Time.now - rendering_scopes[:fetched_at]
|
59
|
+
second_since_last_fetch >= @@scope_cache_expiration_delta
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.refresh_scopes_cache(rendering_id)
|
63
|
+
scopes = fetch_scopes(rendering_id)
|
64
|
+
@@scopes_cache[rendering_id] = {
|
65
|
+
:fetched_at => Time.now,
|
66
|
+
:scopes => scopes
|
67
|
+
}
|
68
|
+
end
|
69
|
+
|
70
|
+
def self.fetch_scopes(rendering_id)
|
71
|
+
query_parameters = { 'renderingId' => rendering_id }
|
72
|
+
response = ForestLiana::ForestApiRequester.get('/liana/scopes', query: query_parameters)
|
73
|
+
|
74
|
+
if response.is_a?(Net::HTTPOK)
|
75
|
+
JSON.parse(response.body)
|
76
|
+
else
|
77
|
+
raise 'Unable to fetch scopes'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.format_dynamic_values(user_id, collection_scope)
|
82
|
+
filter = collection_scope.dig('scope', 'filter')
|
83
|
+
return nil unless filter
|
84
|
+
|
85
|
+
dynamic_scopes_values = collection_scope.dig('scope', 'dynamicScopesValues')
|
86
|
+
|
87
|
+
# Only goes one level deep as required for now
|
88
|
+
filter['conditions'].map do |condition|
|
89
|
+
value = condition['value']
|
90
|
+
if value.is_a?(String) && value.start_with?('$currentUser')
|
91
|
+
condition['value'] = dynamic_scopes_values.dig('users', user_id, value)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
filter
|
96
|
+
end
|
97
|
+
|
98
|
+
def self.invalidate_scope_cache(rendering_id)
|
99
|
+
@@scopes_cache.delete(rendering_id)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -4,12 +4,13 @@ module ForestLiana
|
|
4
4
|
|
5
5
|
attr_reader :fields_searched
|
6
6
|
|
7
|
-
def initialize(params, includes, collection)
|
7
|
+
def initialize(params, includes, collection, user)
|
8
8
|
@params = params
|
9
9
|
@includes = includes
|
10
10
|
@collection = collection
|
11
11
|
@fields_searched = []
|
12
12
|
@search = @params[:search]
|
13
|
+
@user = user
|
13
14
|
end
|
14
15
|
|
15
16
|
def perform(resource)
|
@@ -18,8 +19,10 @@ module ForestLiana
|
|
18
19
|
ForestLiana::QueryHelper.get_tables_associated_to_relations_name(@resource)
|
19
20
|
@records = search_param
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
filters = ForestLiana::ScopeManager.append_scope_for_user(@params[:filters], @user, @collection.name)
|
23
|
+
|
24
|
+
unless filters.blank?
|
25
|
+
@records = FiltersParser.new(filters, @records, @params[:timezone]).apply_filters
|
23
26
|
end
|
24
27
|
|
25
28
|
if @search
|
@@ -6,8 +6,10 @@ module ForestLiana
|
|
6
6
|
return if @params[:aggregate].blank?
|
7
7
|
resource = get_resource().eager_load(@includes)
|
8
8
|
|
9
|
-
|
10
|
-
|
9
|
+
filters = ForestLiana::ScopeManager.append_scope_for_user(@params[:filters], @user, @resource.name)
|
10
|
+
|
11
|
+
unless filters.blank?
|
12
|
+
filter_parser = FiltersParser.new(filters, resource, @params[:timezone])
|
11
13
|
resource = filter_parser.apply_filters
|
12
14
|
raw_previous_interval = filter_parser.get_previous_interval_condition
|
13
15
|
|
data/config/routes.rb
CHANGED
@@ -20,6 +20,9 @@ ForestLiana::Engine.routes.draw do
|
|
20
20
|
post '/stats/:collection' => 'stats#get'
|
21
21
|
post '/stats' => 'stats#get_with_live_query'
|
22
22
|
|
23
|
+
# Scopes
|
24
|
+
post '/scope-cache-invalidation' => 'scopes#invalidate_scope_cache'
|
25
|
+
|
23
26
|
# Stripe Integration
|
24
27
|
get '(*collection)_stripe_payments' => 'stripe#payments'
|
25
28
|
get ':collection/:id/stripe_payments' => 'stripe#payments'
|
data/lib/forest_liana/version.rb
CHANGED
data/spec/dummy/config/routes.rb
CHANGED
@@ -1,16 +1,42 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
3
|
describe 'Requesting Actions routes', :type => :request do
|
4
|
+
let(:rendering_id) { 13 }
|
5
|
+
let(:scope_filters) { nil }
|
6
|
+
|
4
7
|
before(:each) do
|
5
8
|
allow(ForestLiana::IpWhitelist).to receive(:is_ip_whitelist_retrieved) { true }
|
6
9
|
allow(ForestLiana::IpWhitelist).to receive(:is_ip_valid) { true }
|
7
|
-
Island.create(name: 'Corsica')
|
10
|
+
Island.create(id: 1, name: 'Corsica')
|
11
|
+
|
12
|
+
ForestLiana::ScopeManager.invalidate_scope_cache(rendering_id)
|
13
|
+
allow(ForestLiana::ScopeManager).to receive(:get_scope_for_user).and_return(scope_filters)
|
8
14
|
end
|
9
15
|
|
10
16
|
after(:each) do
|
11
17
|
Island.destroy_all
|
12
18
|
end
|
13
|
-
|
19
|
+
|
20
|
+
let(:token) {
|
21
|
+
JWT.encode({
|
22
|
+
id: 38,
|
23
|
+
email: 'michael.kelso@that70.show',
|
24
|
+
first_name: 'Michael',
|
25
|
+
last_name: 'Kelso',
|
26
|
+
team: 'Operations',
|
27
|
+
rendering_id: rendering_id,
|
28
|
+
exp: Time.now.to_i + 2.weeks.to_i
|
29
|
+
}, ForestLiana.auth_secret, 'HS256')
|
30
|
+
}
|
31
|
+
|
32
|
+
let(:headers) {
|
33
|
+
{
|
34
|
+
'Accept' => 'application/json',
|
35
|
+
'Content-Type' => 'application/json',
|
36
|
+
'Authorization' => "Bearer #{token}"
|
37
|
+
}
|
38
|
+
}
|
39
|
+
|
14
40
|
describe 'hooks' do
|
15
41
|
foo = {
|
16
42
|
field: 'foo',
|
@@ -126,25 +152,25 @@ describe 'Requesting Actions routes', :type => :request do
|
|
126
152
|
}
|
127
153
|
|
128
154
|
it 'should respond 200' do
|
129
|
-
post '/forest/actions/my_action/hooks/load', params: JSON.dump(params), headers:
|
155
|
+
post '/forest/actions/my_action/hooks/load', params: JSON.dump(params), headers: headers
|
130
156
|
expect(response.status).to eq(200)
|
131
157
|
expect(JSON.parse(response.body)).to eq({'fields' => [foo.merge({:value => nil}).stringify_keys]})
|
132
158
|
end
|
133
159
|
|
134
160
|
it 'should respond 500 with bad params' do
|
135
|
-
post '/forest/actions/my_action/hooks/load', params: {}
|
161
|
+
post '/forest/actions/my_action/hooks/load', params: {}, headers: headers
|
136
162
|
expect(response.status).to eq(500)
|
137
163
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: cannot retrieve action from collection'})
|
138
164
|
end
|
139
165
|
|
140
166
|
it 'should respond 500 with bad hook result type' do
|
141
|
-
post '/forest/actions/fail_action/hooks/load', params: JSON.dump(params), headers:
|
167
|
+
post '/forest/actions/fail_action/hooks/load', params: JSON.dump(params), headers: headers
|
142
168
|
expect(response.status).to eq(500)
|
143
169
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
144
170
|
end
|
145
171
|
|
146
172
|
it 'should respond 500 with bad hook result data structure' do
|
147
|
-
post '/forest/actions/cheat_action/hooks/load', params: JSON.dump(params), headers:
|
173
|
+
post '/forest/actions/cheat_action/hooks/load', params: JSON.dump(params), headers: headers
|
148
174
|
expect(response.status).to eq(500)
|
149
175
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
150
176
|
end
|
@@ -164,7 +190,7 @@ describe 'Requesting Actions routes', :type => :request do
|
|
164
190
|
}
|
165
191
|
|
166
192
|
it 'should respond 200' do
|
167
|
-
post '/forest/actions/my_action/hooks/change', params: JSON.dump(params), headers:
|
193
|
+
post '/forest/actions/my_action/hooks/change', params: JSON.dump(params), headers: headers
|
168
194
|
expect(response.status).to eq(200)
|
169
195
|
expected = updated_foo.clone.merge({:value => 'baz'})
|
170
196
|
expected[:widgetEdit] = nil
|
@@ -173,13 +199,13 @@ describe 'Requesting Actions routes', :type => :request do
|
|
173
199
|
end
|
174
200
|
|
175
201
|
it 'should respond 500 with bad params' do
|
176
|
-
post '/forest/actions/my_action/hooks/change', params: JSON.dump({ data: { attributes: { collection_name: 'Island' }}}), headers:
|
202
|
+
post '/forest/actions/my_action/hooks/change', params: JSON.dump({ data: { attributes: { collection_name: 'Island' }}}), headers: headers
|
177
203
|
expect(response.status).to eq(500)
|
178
204
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action change hook: fields params is mandatory'})
|
179
205
|
end
|
180
206
|
|
181
207
|
it 'should respond 500 with bad hook result type' do
|
182
|
-
post '/forest/actions/fail_action/hooks/change', params: JSON.dump(params), headers:
|
208
|
+
post '/forest/actions/fail_action/hooks/change', params: JSON.dump(params), headers: headers
|
183
209
|
expect(response.status).to eq(500)
|
184
210
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
185
211
|
end
|
@@ -196,7 +222,7 @@ describe 'Requesting Actions routes', :type => :request do
|
|
196
222
|
}
|
197
223
|
}
|
198
224
|
}
|
199
|
-
post '/forest/actions/enums_action/hooks/change', params: JSON.dump(p), headers:
|
225
|
+
post '/forest/actions/enums_action/hooks/change', params: JSON.dump(p), headers: headers
|
200
226
|
expect(response.status).to eq(200)
|
201
227
|
|
202
228
|
expected_enum = updated_enum.clone.merge({ :enums => %w[c d e], :value => nil, :widgetEdit => nil})
|
@@ -219,7 +245,7 @@ describe 'Requesting Actions routes', :type => :request do
|
|
219
245
|
}
|
220
246
|
}
|
221
247
|
}
|
222
|
-
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers:
|
248
|
+
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers: headers
|
223
249
|
expect(response.status).to eq(200)
|
224
250
|
|
225
251
|
expected_multiple_enum = updated_multiple_enum.clone.merge({ :enums => %w[c d z], :widgetEdit => nil, :value => %w[c]})
|
@@ -243,7 +269,7 @@ describe 'Requesting Actions routes', :type => :request do
|
|
243
269
|
}
|
244
270
|
}
|
245
271
|
|
246
|
-
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers:
|
272
|
+
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers: headers
|
247
273
|
expect(response.status).to eq(200)
|
248
274
|
|
249
275
|
expected_multiple_enum = wrongly_updated_multiple_enum.clone.merge({ :enums => %w[c d z], :widgetEdit => nil, :value => nil })
|
@@ -255,4 +281,66 @@ describe 'Requesting Actions routes', :type => :request do
|
|
255
281
|
end
|
256
282
|
end
|
257
283
|
end
|
284
|
+
|
285
|
+
describe 'calling the action' do
|
286
|
+
before(:each) do
|
287
|
+
allow_any_instance_of(ForestLiana::PermissionsChecker).to receive(:is_authorized?) { true }
|
288
|
+
end
|
289
|
+
|
290
|
+
let(:all_records) { false }
|
291
|
+
let(:params) {
|
292
|
+
{
|
293
|
+
data: {
|
294
|
+
attributes: {
|
295
|
+
collection_name: 'Island',
|
296
|
+
ids: ['1'],
|
297
|
+
all_records: all_records,
|
298
|
+
smart_action_id: 'Island-Test'
|
299
|
+
},
|
300
|
+
type: 'custom-action-requests'
|
301
|
+
},
|
302
|
+
timezone: 'Europe/Paris'
|
303
|
+
}
|
304
|
+
}
|
305
|
+
|
306
|
+
describe 'without scopes' do
|
307
|
+
it 'should respond 200 and perform the action' do
|
308
|
+
post '/forest/actions/test', params: JSON.dump(params), headers: headers
|
309
|
+
expect(response.status).to eq(200)
|
310
|
+
expect(JSON.parse(response.body)).to eq({'success' => 'You are OK.'})
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe 'with scopes' do
|
315
|
+
describe 'when record is in scope' do
|
316
|
+
let(:scope_filters) { JSON.generate({ field: 'name', operator: 'equal', value: 'Corsica' }) }
|
317
|
+
|
318
|
+
it 'should respond 200 and perform the action' do
|
319
|
+
post '/forest/actions/test', params: JSON.dump(params), headers: headers
|
320
|
+
expect(response.status).to eq(200)
|
321
|
+
expect(JSON.parse(response.body)).to eq({'success' => 'You are OK.'})
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
describe 'when record is out of scope' do
|
326
|
+
let(:scope_filters) { JSON.generate({ field: 'name', operator: 'equal', value: 'Ré' }) }
|
327
|
+
|
328
|
+
it 'should respond 400 and NOT perform the action' do
|
329
|
+
post '/forest/actions/test', params: JSON.dump(params), headers: headers
|
330
|
+
expect(response.status).to eq(400)
|
331
|
+
expect(JSON.parse(response.body)).to eq({ 'error' => 'Smart Action: target record not found' })
|
332
|
+
end
|
333
|
+
|
334
|
+
describe 'and all_records are targeted' do
|
335
|
+
let(:all_records) { true }
|
336
|
+
|
337
|
+
it 'should respond 200 and perform the action' do
|
338
|
+
post '/forest/actions/test', params: JSON.dump(params), headers: headers
|
339
|
+
expect(response.status).to eq(200)
|
340
|
+
expect(JSON.parse(response.body)).to eq({'success' => 'You are OK.'})
|
341
|
+
end
|
342
|
+
end
|
343
|
+
end
|
344
|
+
end
|
345
|
+
end
|
258
346
|
end
|