forest_liana 7.0.0.beta.2 → 7.0.0.beta.6
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/actions_controller.rb +20 -18
- data/app/controllers/forest_liana/application_controller.rb +0 -9
- data/app/controllers/forest_liana/associations_controller.rb +2 -2
- data/app/controllers/forest_liana/resources_controller.rb +16 -6
- data/app/controllers/forest_liana/scopes_controller.rb +20 -0
- data/app/controllers/forest_liana/smart_actions_controller.rb +39 -6
- data/app/controllers/forest_liana/stats_controller.rb +5 -5
- data/app/services/forest_liana/apimap_sorter.rb +1 -0
- data/app/services/forest_liana/filters_parser.rb +8 -4
- 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 +5 -3
- data/app/services/forest_liana/permissions_checker.rb +42 -37
- data/app/services/forest_liana/permissions_formatter.rb +1 -1
- data/app/services/forest_liana/permissions_getter.rb +3 -6
- 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/token.rb +1 -0
- data/app/services/forest_liana/utils/beta_schema_utils.rb +1 -1
- data/app/services/forest_liana/value_stat_getter.rb +4 -2
- data/config/routes.rb +3 -1
- data/lib/forest_liana/bootstrapper.rb +4 -2
- 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/lib/forest_liana/bootstrapper_spec.rb +12 -0
- data/spec/requests/actions_controller_spec.rb +144 -23
- data/spec/requests/authentications_spec.rb +2 -1
- data/spec/requests/resources_spec.rb +2 -0
- data/spec/services/forest_liana/apimap_sorter_spec.rb +6 -4
- data/spec/services/forest_liana/filters_parser_spec.rb +1 -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 +45 -71
- 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/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 +125 -118
- 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
@@ -6,7 +6,7 @@ module ForestLiana
|
|
6
6
|
|
7
7
|
return nil unless collection
|
8
8
|
|
9
|
-
collection.actions.find { |action| action.endpoint == endpoint && action.http_method == http_method }
|
9
|
+
collection.actions.find { |action| (action.endpoint == endpoint || "/#{action.endpoint}" == endpoint) && action.http_method == http_method }
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
@@ -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'
|
@@ -57,7 +60,6 @@ ForestLiana::Engine.routes.draw do
|
|
57
60
|
delete ':collection', to: router
|
58
61
|
|
59
62
|
# Smart Actions forms value
|
60
|
-
post 'actions/:action_name/values' => 'actions#values'
|
61
63
|
post 'actions/:action_name/hooks/load' => 'actions#load'
|
62
64
|
post 'actions/:action_name/hooks/change' => 'actions#change'
|
63
65
|
end
|
@@ -203,10 +203,12 @@ module ForestLiana
|
|
203
203
|
|
204
204
|
def setup_forest_liana_meta
|
205
205
|
ForestLiana.meta = {
|
206
|
-
database_type: database_type,
|
207
206
|
liana: 'forest-rails',
|
208
207
|
liana_version: ForestLiana::VERSION,
|
209
|
-
|
208
|
+
stack: {
|
209
|
+
database_type: database_type,
|
210
|
+
orm_version: Gem.loaded_specs["activerecord"].version.version,
|
211
|
+
}
|
210
212
|
}
|
211
213
|
end
|
212
214
|
|
data/lib/forest_liana/version.rb
CHANGED
data/spec/dummy/config/routes.rb
CHANGED
@@ -0,0 +1,12 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
describe Bootstrapper do
|
3
|
+
describe 'setup_forest_liana_meta' do
|
4
|
+
it "should put statistic data related to user stack on a dedicated object" do
|
5
|
+
expect(ForestLiana.meta[:stack])
|
6
|
+
.to include(:orm_version)
|
7
|
+
expect(ForestLiana.meta[:stack])
|
8
|
+
.to include(:database_type)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -1,23 +1,41 @@
|
|
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
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
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
|
+
}
|
21
39
|
|
22
40
|
describe 'hooks' do
|
23
41
|
foo = {
|
@@ -127,28 +145,32 @@ describe 'Requesting Actions routes', :type => :request do
|
|
127
145
|
island.actions = [action, fail_action, cheat_action, enums_action, multiple_enums_action]
|
128
146
|
|
129
147
|
describe 'call /load' do
|
130
|
-
params = {
|
148
|
+
params = {
|
149
|
+
data: {
|
150
|
+
attributes: { ids: [1], collection_name: 'Island' }
|
151
|
+
}
|
152
|
+
}
|
131
153
|
|
132
154
|
it 'should respond 200' do
|
133
|
-
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
|
134
156
|
expect(response.status).to eq(200)
|
135
157
|
expect(JSON.parse(response.body)).to eq({'fields' => [foo.merge({:value => nil}).stringify_keys]})
|
136
158
|
end
|
137
159
|
|
138
160
|
it 'should respond 500 with bad params' do
|
139
|
-
post '/forest/actions/my_action/hooks/load', params: {}
|
161
|
+
post '/forest/actions/my_action/hooks/load', params: {}, headers: headers
|
140
162
|
expect(response.status).to eq(500)
|
141
163
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: cannot retrieve action from collection'})
|
142
164
|
end
|
143
165
|
|
144
166
|
it 'should respond 500 with bad hook result type' do
|
145
|
-
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
|
146
168
|
expect(response.status).to eq(500)
|
147
169
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
148
170
|
end
|
149
171
|
|
150
172
|
it 'should respond 500 with bad hook result data structure' do
|
151
|
-
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
|
152
174
|
expect(response.status).to eq(500)
|
153
175
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
154
176
|
end
|
@@ -156,10 +178,19 @@ describe 'Requesting Actions routes', :type => :request do
|
|
156
178
|
|
157
179
|
describe 'call /change' do
|
158
180
|
updated_foo = foo.clone.merge({:previousValue => nil, :value => 'bar'})
|
159
|
-
params = {
|
181
|
+
params = {
|
182
|
+
data: {
|
183
|
+
attributes: {
|
184
|
+
ids: [1],
|
185
|
+
fields: [updated_foo],
|
186
|
+
collection_name: 'Island',
|
187
|
+
changed_field: 'foo'
|
188
|
+
}
|
189
|
+
}
|
190
|
+
}
|
160
191
|
|
161
192
|
it 'should respond 200' do
|
162
|
-
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
|
163
194
|
expect(response.status).to eq(200)
|
164
195
|
expected = updated_foo.clone.merge({:value => 'baz'})
|
165
196
|
expected[:widgetEdit] = nil
|
@@ -168,21 +199,30 @@ describe 'Requesting Actions routes', :type => :request do
|
|
168
199
|
end
|
169
200
|
|
170
201
|
it 'should respond 500 with bad params' do
|
171
|
-
post '/forest/actions/my_action/hooks/change', params: JSON.dump({
|
202
|
+
post '/forest/actions/my_action/hooks/change', params: JSON.dump({ data: { attributes: { collection_name: 'Island' }}}), headers: headers
|
172
203
|
expect(response.status).to eq(500)
|
173
204
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action change hook: fields params is mandatory'})
|
174
205
|
end
|
175
206
|
|
176
207
|
it 'should respond 500 with bad hook result type' do
|
177
|
-
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
|
178
209
|
expect(response.status).to eq(500)
|
179
210
|
expect(JSON.parse(response.body)).to eq({'error' => 'Error in smart action load hook: hook must return an array of fields'})
|
180
211
|
end
|
181
212
|
|
182
213
|
it 'should reset value when enums has changed' do
|
183
214
|
updated_enum = enum.clone.merge({:previousValue => nil, :value => 'a'}) # set value to a
|
184
|
-
p = {
|
185
|
-
|
215
|
+
p = {
|
216
|
+
data: {
|
217
|
+
attributes: {
|
218
|
+
ids: [1],
|
219
|
+
fields: [updated_foo, updated_enum],
|
220
|
+
collection_name: 'Island',
|
221
|
+
changed_field: 'foo'
|
222
|
+
}
|
223
|
+
}
|
224
|
+
}
|
225
|
+
post '/forest/actions/enums_action/hooks/change', params: JSON.dump(p), headers: headers
|
186
226
|
expect(response.status).to eq(200)
|
187
227
|
|
188
228
|
expected_enum = updated_enum.clone.merge({ :enums => %w[c d e], :value => nil, :widgetEdit => nil})
|
@@ -195,8 +235,17 @@ describe 'Requesting Actions routes', :type => :request do
|
|
195
235
|
|
196
236
|
it 'should not reset value when every enum values are in the enums definition' do
|
197
237
|
updated_multiple_enum = multiple_enum.clone.merge({:previousValue => nil, :value => %w[c]})
|
198
|
-
p = {
|
199
|
-
|
238
|
+
p = {
|
239
|
+
data: {
|
240
|
+
attributes: {
|
241
|
+
ids: [1],
|
242
|
+
fields: [foo, updated_multiple_enum],
|
243
|
+
collection_name: 'Island',
|
244
|
+
changed_field: 'foo'
|
245
|
+
}
|
246
|
+
}
|
247
|
+
}
|
248
|
+
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers: headers
|
200
249
|
expect(response.status).to eq(200)
|
201
250
|
|
202
251
|
expected_multiple_enum = updated_multiple_enum.clone.merge({ :enums => %w[c d z], :widgetEdit => nil, :value => %w[c]})
|
@@ -209,8 +258,18 @@ describe 'Requesting Actions routes', :type => :request do
|
|
209
258
|
|
210
259
|
it 'should reset value when one of the enum values is not in the enums definition' do
|
211
260
|
wrongly_updated_multiple_enum = multiple_enum.clone.merge({:previousValue => nil, :value => %w[a b]})
|
212
|
-
p = {
|
213
|
-
|
261
|
+
p = {
|
262
|
+
data: {
|
263
|
+
attributes: {
|
264
|
+
ids: [1],
|
265
|
+
fields: [foo, wrongly_updated_multiple_enum],
|
266
|
+
collection_name: 'Island',
|
267
|
+
changed_field: 'foo'
|
268
|
+
}
|
269
|
+
}
|
270
|
+
}
|
271
|
+
|
272
|
+
post '/forest/actions/multiple_enums_action/hooks/change', params: JSON.dump(p), headers: headers
|
214
273
|
expect(response.status).to eq(200)
|
215
274
|
|
216
275
|
expected_multiple_enum = wrongly_updated_multiple_enum.clone.merge({ :enums => %w[c d z], :widgetEdit => nil, :value => nil })
|
@@ -222,4 +281,66 @@ describe 'Requesting Actions routes', :type => :request do
|
|
222
281
|
end
|
223
282
|
end
|
224
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
|
225
346
|
end
|
@@ -45,7 +45,7 @@ describe "Authentications", type: :request do
|
|
45
45
|
|
46
46
|
describe "GET /authentication/callback" do
|
47
47
|
before() do
|
48
|
-
response = '{"data":{"id":666,"attributes":{"first_name":"Alice","last_name":"Doe","email":"alice@forestadmin.com","teams":[1,2,3]}}}'
|
48
|
+
response = '{"data":{"id":666,"attributes":{"first_name":"Alice","last_name":"Doe","email":"alice@forestadmin.com","teams":[1,2,3],"role":"Test"}}}'
|
49
49
|
allow(ForestLiana::ForestApiRequester).to receive(:get).with(
|
50
50
|
"/liana/v2/renderings/42/authorization", { :headers => { "forest-token" => "THE-ACCESS-TOKEN" }, :query=> {} }
|
51
51
|
).and_return(
|
@@ -72,6 +72,7 @@ describe "Authentications", type: :request do
|
|
72
72
|
"first_name" => 'Alice',
|
73
73
|
"last_name" => 'Doe',
|
74
74
|
"team" => 1,
|
75
|
+
"role" => "Test",
|
75
76
|
}
|
76
77
|
|
77
78
|
expect(decoded).to include(expected_token_data)
|
@@ -17,6 +17,8 @@ describe 'Requesting Tree resources', :type => :request do
|
|
17
17
|
allow(ForestLiana::IpWhitelist).to receive(:is_ip_valid) { true }
|
18
18
|
|
19
19
|
allow_any_instance_of(ForestLiana::PermissionsChecker).to receive(:is_authorized?) { true }
|
20
|
+
|
21
|
+
allow(ForestLiana::ScopeManager).to receive(:fetch_scopes).and_return({})
|
20
22
|
end
|
21
23
|
|
22
24
|
token = JWT.encode({
|
@@ -4,9 +4,11 @@ module ForestLiana
|
|
4
4
|
context 'on a disordered apimap' do
|
5
5
|
apimap = {
|
6
6
|
'meta': {
|
7
|
-
|
7
|
+
stack: {
|
8
|
+
'orm_version': '4.34.9',
|
9
|
+
'database_type': 'postgresql',
|
10
|
+
},
|
8
11
|
'liana_version': '1.5.24',
|
9
|
-
'database_type': 'postgresql',
|
10
12
|
liana: 'forest-rails',
|
11
13
|
},
|
12
14
|
'data': [{
|
@@ -165,8 +167,8 @@ module ForestLiana
|
|
165
167
|
end
|
166
168
|
|
167
169
|
it 'should sort the meta values' do
|
168
|
-
expect(apimap_sorted['meta'].keys).to eq(
|
169
|
-
|
170
|
+
expect(apimap_sorted['meta'].keys).to eq(['liana', 'liana_version', 'stack'])
|
171
|
+
expect(apimap_sorted['meta']['stack'].keys).to eq(['database_type', 'orm_version'])
|
170
172
|
end
|
171
173
|
end
|
172
174
|
end
|
@@ -281,7 +281,7 @@ module ForestLiana
|
|
281
281
|
let(:result) { filter_parser.parse_condition(condition) }
|
282
282
|
|
283
283
|
context 'on valid condition' do
|
284
|
-
it { expect(result).to eq "\"trees\".\"name\" LIKE '%3'" }
|
284
|
+
it { expect(result).to eq "\"trees\".\"name\" LIKE ('%3')" }
|
285
285
|
end
|
286
286
|
|
287
287
|
context 'on belongs_to condition' do
|
@@ -0,0 +1,116 @@
|
|
1
|
+
module ForestLiana
|
2
|
+
describe HasManyGetter do
|
3
|
+
describe 'when retrieving has many relationship related records' do
|
4
|
+
let(:rendering_id) { 13 }
|
5
|
+
let(:user) { { 'id' => '1', 'rendering_id' => rendering_id } }
|
6
|
+
let(:scopes) { { } }
|
7
|
+
let(:association) { Island.reflect_on_association(:trees) }
|
8
|
+
let(:params) {
|
9
|
+
{
|
10
|
+
id: Island.first.id,
|
11
|
+
association_name: 'trees',
|
12
|
+
page: { size: 15, number: 1 },
|
13
|
+
timezone: 'America/Nome'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
|
17
|
+
subject {
|
18
|
+
described_class.new(Island, association, params, user)
|
19
|
+
}
|
20
|
+
|
21
|
+
before(:each) do
|
22
|
+
madagascar = Island.create(name: 'madagascar')
|
23
|
+
re = Island.create(name: 'ré')
|
24
|
+
Tree.create(name: 'lemon tree', island: madagascar)
|
25
|
+
Tree.create(name: 'banana tree', island: madagascar)
|
26
|
+
Tree.create(name: 'papaya tree', island: madagascar)
|
27
|
+
Tree.create(name: 'apple tree', island: re)
|
28
|
+
Tree.create(name: 'banana tree', island: re)
|
29
|
+
ForestLiana::ScopeManager.invalidate_scope_cache(rendering_id)
|
30
|
+
allow(ForestLiana::ScopeManager).to receive(:fetch_scopes).and_return(scopes)
|
31
|
+
end
|
32
|
+
|
33
|
+
after(:each) do
|
34
|
+
Island.destroy_all
|
35
|
+
Tree.destroy_all
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'with empty scopes' do
|
39
|
+
describe 'with page 1 size 15' do
|
40
|
+
it 'should return the 3 trees matching madagascar' do
|
41
|
+
subject.perform
|
42
|
+
|
43
|
+
expect(subject.records.count).to eq 3
|
44
|
+
expect(subject.count).to eq 3
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe 'when sorting by decreasing id' do
|
49
|
+
let(:params) {
|
50
|
+
{
|
51
|
+
id: Island.first.id,
|
52
|
+
association_name: 'trees',
|
53
|
+
sort: '-id',
|
54
|
+
page: { size: 15, number: 1 },
|
55
|
+
timezone: 'America/Nome'
|
56
|
+
}
|
57
|
+
}
|
58
|
+
|
59
|
+
it 'should order records properly' do
|
60
|
+
subject.perform
|
61
|
+
|
62
|
+
expect(subject.records.count).to eq 3
|
63
|
+
expect(subject.count).to eq 3
|
64
|
+
expect(subject.records.first.id).to be > subject.records.last.id
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
describe 'when searching for banana tree' do
|
69
|
+
let(:params) {
|
70
|
+
{
|
71
|
+
id: Island.first.id,
|
72
|
+
association_name: 'trees',
|
73
|
+
search: 'banana',
|
74
|
+
page: { size: 15, number: 1 },
|
75
|
+
timezone: 'America/Nome'
|
76
|
+
}
|
77
|
+
}
|
78
|
+
|
79
|
+
it 'should return only the banana tree linked to madagascar' do
|
80
|
+
subject.perform
|
81
|
+
|
82
|
+
expect(subject.records.count).to eq 1
|
83
|
+
expect(subject.count).to eq 1
|
84
|
+
expect(subject.records.first.island.name).to eq 'madagascar'
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe 'with scopes' do
|
90
|
+
let(:scopes) { {
|
91
|
+
'Tree' => {
|
92
|
+
'scope'=> {
|
93
|
+
'filter'=> {
|
94
|
+
'aggregator' => 'and',
|
95
|
+
'conditions' => [
|
96
|
+
{ 'field' => 'name', 'operator' => 'contains', 'value' => 'a' }
|
97
|
+
]
|
98
|
+
},
|
99
|
+
'dynamicScopesValues' => { }
|
100
|
+
}
|
101
|
+
}
|
102
|
+
} }
|
103
|
+
|
104
|
+
describe 'when asking for all trees related to madagascar' do
|
105
|
+
it 'should return trees belonging to madagascar and matching the scopes' do
|
106
|
+
subject.perform
|
107
|
+
|
108
|
+
# Only `papaya` and `banana` contain an `a`
|
109
|
+
expect(subject.records.count).to eq 2
|
110
|
+
expect(subject.count).to eq 2
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|