forest_liana 7.0.0.beta.2 → 7.0.0.beta.6
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 +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
|