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.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/forest_liana/actions_controller.rb +20 -18
  3. data/app/controllers/forest_liana/application_controller.rb +0 -9
  4. data/app/controllers/forest_liana/associations_controller.rb +2 -2
  5. data/app/controllers/forest_liana/resources_controller.rb +16 -6
  6. data/app/controllers/forest_liana/scopes_controller.rb +20 -0
  7. data/app/controllers/forest_liana/smart_actions_controller.rb +39 -6
  8. data/app/controllers/forest_liana/stats_controller.rb +5 -5
  9. data/app/services/forest_liana/apimap_sorter.rb +1 -0
  10. data/app/services/forest_liana/filters_parser.rb +8 -4
  11. data/app/services/forest_liana/has_many_dissociator.rb +2 -2
  12. data/app/services/forest_liana/has_many_getter.rb +2 -2
  13. data/app/services/forest_liana/leaderboard_stat_getter.rb +20 -14
  14. data/app/services/forest_liana/line_stat_getter.rb +5 -3
  15. data/app/services/forest_liana/permissions_checker.rb +42 -37
  16. data/app/services/forest_liana/permissions_formatter.rb +1 -1
  17. data/app/services/forest_liana/permissions_getter.rb +3 -6
  18. data/app/services/forest_liana/pie_stat_getter.rb +6 -3
  19. data/app/services/forest_liana/resource_getter.rb +6 -3
  20. data/app/services/forest_liana/resource_updater.rb +5 -2
  21. data/app/services/forest_liana/resources_getter.rb +6 -5
  22. data/app/services/forest_liana/scope_manager.rb +102 -0
  23. data/app/services/forest_liana/search_query_builder.rb +6 -3
  24. data/app/services/forest_liana/stat_getter.rb +2 -1
  25. data/app/services/forest_liana/token.rb +1 -0
  26. data/app/services/forest_liana/utils/beta_schema_utils.rb +1 -1
  27. data/app/services/forest_liana/value_stat_getter.rb +4 -2
  28. data/config/routes.rb +3 -1
  29. data/lib/forest_liana/bootstrapper.rb +4 -2
  30. data/lib/forest_liana/version.rb +1 -1
  31. data/spec/dummy/app/controllers/forest/islands_controller.rb +5 -0
  32. data/spec/dummy/config/routes.rb +4 -0
  33. data/spec/dummy/lib/forest_liana/collections/island.rb +7 -0
  34. data/spec/lib/forest_liana/bootstrapper_spec.rb +12 -0
  35. data/spec/requests/actions_controller_spec.rb +144 -23
  36. data/spec/requests/authentications_spec.rb +2 -1
  37. data/spec/requests/resources_spec.rb +2 -0
  38. data/spec/services/forest_liana/apimap_sorter_spec.rb +6 -4
  39. data/spec/services/forest_liana/filters_parser_spec.rb +1 -1
  40. data/spec/services/forest_liana/has_many_getter_spec.rb +116 -0
  41. data/spec/services/forest_liana/line_stat_getter_spec.rb +14 -6
  42. data/spec/services/forest_liana/permissions_checker_acl_disabled_spec.rb +45 -71
  43. data/spec/services/forest_liana/permissions_checker_acl_enabled_spec.rb +39 -63
  44. data/spec/services/forest_liana/permissions_checker_live_queries_spec.rb +3 -3
  45. data/spec/services/forest_liana/permissions_formatter_spec.rb +11 -11
  46. data/spec/services/forest_liana/pie_stat_getter_spec.rb +114 -0
  47. data/spec/services/forest_liana/resource_updater_spec.rb +116 -0
  48. data/spec/services/forest_liana/resources_getter_spec.rb +68 -1
  49. data/spec/services/forest_liana/scope_manager_spec.rb +232 -0
  50. data/spec/services/forest_liana/value_stat_getter_spec.rb +96 -0
  51. metadata +125 -118
  52. data/app/services/forest_liana/scope_validator.rb +0 -98
  53. data/test/services/forest_liana/has_many_getter_test.rb +0 -75
  54. data/test/services/forest_liana/pie_stat_getter_test.rb +0 -29
  55. data/test/services/forest_liana/resource_updater_test.rb +0 -86
  56. data/test/services/forest_liana/scope_validator_test.rb +0 -185
  57. data/test/services/forest_liana/value_stat_getter_test.rb +0 -71
@@ -20,7 +20,8 @@ module ForestLiana
20
20
  })
21
21
  ]
22
22
  }
23
- let(:scope_permissions) { nil }
23
+ let(:default_rendering_id) { 1 }
24
+ let(:segments_permissions) { { default_rendering_id => { 'segments' => nil } } }
24
25
  let(:default_api_permissions) {
25
26
  {
26
27
  "data" => {
@@ -41,7 +42,7 @@ module ForestLiana
41
42
  }
42
43
  },
43
44
  },
44
- 'renderings' => scope_permissions
45
+ 'renderings' => segments_permissions
45
46
  },
46
47
  "meta" => {
47
48
  "rolesACLActivated" => true
@@ -61,7 +62,6 @@ module ForestLiana
61
62
  },
62
63
  }
63
64
  }
64
- let(:default_rendering_id) { 1 }
65
65
 
66
66
  before do
67
67
  allow(ForestLiana).to receive(:apimap).and_return(schema)
@@ -14,7 +14,7 @@ module ForestLiana
14
14
  }
15
15
  }
16
16
  let(:old_format_action_permissions) { { 'allowed' => true, 'users' => nil } }
17
- let(:old_format_scope_permissions) { nil }
17
+ let(:old_format_segments_permissions) { nil }
18
18
  let(:old_format_permissions) {
19
19
  {
20
20
  'collection_1' => {
@@ -22,7 +22,7 @@ module ForestLiana
22
22
  'actions' => {
23
23
  'action_1' => old_format_action_permissions
24
24
  },
25
- 'scope' => old_format_scope_permissions
25
+ 'segments' => old_format_segments_permissions
26
26
  }
27
27
  }
28
28
  }
@@ -197,22 +197,22 @@ module ForestLiana
197
197
  end
198
198
  end
199
199
 
200
- describe 'scope permissions' do
201
- subject { converted_permission['renderings'][rendering_id]['collection_1']['scope'] }
202
- let(:expected_new_format_permissions) { old_format_scope_permissions }
200
+ describe 'segments permissions' do
201
+ subject { converted_permission['renderings'][rendering_id]['collection_1']['segments'] }
202
+ let(:expected_new_format_permissions) { old_format_segments_permissions }
203
203
 
204
- context 'when scope permissions are set' do
205
- let(:old_format_scope_permissions) { { 'dynamicScopesValues' => {}, 'filter' => { 'aggregator' => 'and', 'conditions' => [{ 'field' => 'field_1', 'operator' => 'equal', 'value' => true }] } } }
204
+ context 'when segments permissions are set' do
205
+ let(:old_format_segments_permissions) { ['segmentQuery1', 'segmentQuery2'] }
206
206
 
207
- it 'expected scope permissions should be set' do
207
+ it 'expected segments permissions should be set' do
208
208
  expect(subject).to eq expected_new_format_permissions
209
209
  end
210
210
  end
211
211
 
212
- context 'when scope permissions are nil' do
213
- let(:old_format_scope_permissions) { nil }
212
+ context 'when segments permissions are nil' do
213
+ let(:old_format_segments_permissions) { nil }
214
214
 
215
- it 'expected scope permissions should be nil' do
215
+ it 'expected segments permissions should be nil' do
216
216
  expect(subject).to eq expected_new_format_permissions
217
217
  end
218
218
  end
@@ -0,0 +1,114 @@
1
+ module ForestLiana
2
+ describe PieStatGetter do
3
+ let(:rendering_id) { 13 }
4
+ let(:user) { { 'id' => '1', 'rendering_id' => rendering_id } }
5
+ let(:records) { [
6
+ { name: 'Young Tree n1', age: 3 },
7
+ { name: 'Young Tree n2', age: 3 },
8
+ { name: 'Young Tree n3', age: 3 },
9
+ { name: 'Young Tree n4', age: 3 },
10
+ { name: 'Young Tree n5', age: 3 },
11
+ { name: 'Old Tree n1', age: 15 },
12
+ { name: 'Old Tree n2', age: 15 },
13
+ { name: 'Old Tree n3', age: 15 },
14
+ { name: 'Old Tree n4', age: 15 }
15
+ ] }
16
+
17
+ before(:each) do
18
+ ForestLiana::ScopeManager.invalidate_scope_cache(rendering_id)
19
+ allow(ForestLiana::ScopeManager).to receive(:fetch_scopes).and_return(scopes)
20
+
21
+ records.each { |record|
22
+ Tree.create!(name: record[:name], age: record[:age])
23
+ }
24
+ end
25
+
26
+ let(:model) { Tree }
27
+ let(:collection) { 'trees' }
28
+ let(:params) {
29
+ {
30
+ type: 'Pie',
31
+ collection: collection,
32
+ timezone: 'Europe/Paris',
33
+ aggregate: 'Count',
34
+ group_by_field: group_by_field
35
+ }
36
+ }
37
+
38
+ subject { PieStatGetter.new(model, params, user) }
39
+
40
+ describe 'with empty scopes' do
41
+ let(:scopes) { { } }
42
+
43
+ describe 'with an aggregate on the name field' do
44
+ let(:group_by_field) { 'name' }
45
+
46
+ it 'should be as many categories as records count' do
47
+ subject.perform
48
+ expect(subject.record.value).to eq [
49
+ {:key => "Old Tree n1", :value => 1},
50
+ {:key => "Old Tree n2", :value => 1},
51
+ {:key => "Old Tree n3", :value => 1},
52
+ {:key => "Old Tree n4", :value => 1},
53
+ {:key => "Young Tree n1", :value => 1},
54
+ {:key => "Young Tree n2", :value => 1},
55
+ {:key => "Young Tree n3", :value => 1},
56
+ {:key => "Young Tree n4", :value => 1},
57
+ {:key => "Young Tree n5", :value => 1}
58
+ ]
59
+ end
60
+ end
61
+
62
+ describe 'with an aggregate on the age field' do
63
+ let(:group_by_field) { 'age' }
64
+
65
+ it 'should be as many categories as different ages among records' do
66
+ subject.perform
67
+ expect(subject.record.value).to eq [{ :key => 3, :value => 5}, { :key => 15, :value => 4 }]
68
+ end
69
+ end
70
+ end
71
+
72
+ describe 'with scopes' do
73
+ let(:scopes) {
74
+ {
75
+ 'Tree' => {
76
+ 'scope'=> {
77
+ 'filter'=> {
78
+ 'aggregator' => 'and',
79
+ 'conditions' => [
80
+ { 'field' => 'age', 'operator' => 'less_than', 'value' => 10 }
81
+ ]
82
+ },
83
+ 'dynamicScopesValues' => { }
84
+ }
85
+ }
86
+ }
87
+ }
88
+
89
+ describe 'with an aggregate on the name field' do
90
+ let(:group_by_field) { 'name' }
91
+
92
+ it 'should be as many categories as records inside the scope' do
93
+ subject.perform
94
+ expect(subject.record.value).to eq [
95
+ {:key => "Young Tree n1", :value => 1},
96
+ {:key => "Young Tree n2", :value => 1},
97
+ {:key => "Young Tree n3", :value => 1},
98
+ {:key => "Young Tree n4", :value => 1},
99
+ {:key => "Young Tree n5", :value => 1}
100
+ ]
101
+ end
102
+ end
103
+
104
+ describe 'with an aggregate on the age field' do
105
+ let(:group_by_field) { 'age' }
106
+
107
+ it 'should be only one category' do
108
+ subject.perform
109
+ expect(subject.record.value).to eq [{ :key => 3, :value => 5}]
110
+ end
111
+ end
112
+ end
113
+ end
114
+ end
@@ -0,0 +1,116 @@
1
+ module ForestLiana
2
+ describe ResourceUpdater do
3
+ describe 'when updating a record' do
4
+ let(:params) {
5
+ ActionController::Parameters.new(
6
+ id: 1,
7
+ data: {
8
+ id: 1,
9
+ type: 'User',
10
+ attributes: attributes
11
+ }
12
+ )
13
+ }
14
+ let(:rendering_id) { 13 }
15
+ let(:user) { { 'id' => '1', 'rendering_id' => rendering_id } }
16
+ let(:scopes) { { } }
17
+
18
+ subject {
19
+ described_class.new(User, params, user)
20
+ }
21
+
22
+ before(:each) do
23
+ User.create(name: 'Merry')
24
+ ForestLiana::ScopeManager.invalidate_scope_cache(rendering_id)
25
+ allow(ForestLiana::ScopeManager).to receive(:fetch_scopes).and_return(scopes)
26
+ end
27
+
28
+ after(:each) do
29
+ User.destroy_all
30
+ end
31
+
32
+ describe 'with empty scopes' do
33
+ describe 'with a missing name in attributes' do
34
+ let(:attributes) { { } }
35
+
36
+ it 'should not update the record name' do
37
+ subject.perform
38
+
39
+ expect(subject.record.valid?).to be true
40
+ expect(subject.record.name).to eq 'Merry'
41
+ end
42
+ end
43
+
44
+ describe 'with a null name in attributes' do
45
+ let(:attributes) { { name: nil } }
46
+
47
+ it 'should set the record name to null' do
48
+ subject.perform
49
+
50
+ expect(subject.record.valid?).to be true
51
+ expect(subject.record.name).to eq nil
52
+ end
53
+ end
54
+
55
+ describe 'with a new value as name in attributes' do
56
+ let(:attributes) { { name: 'Pippin' } }
57
+
58
+ it 'should set the record name to null' do
59
+ subject.perform
60
+
61
+ expect(subject.record.valid?).to be true
62
+ expect(subject.record.name).to eq 'Pippin'
63
+ end
64
+ end
65
+ end
66
+
67
+ describe 'with scope excluding target record' do
68
+ let(:attributes) { { name: 'Gandalf' } }
69
+ let(:scopes) { {
70
+ 'User' => {
71
+ 'scope'=> {
72
+ 'filter'=> {
73
+ 'aggregator' => 'and',
74
+ 'conditions' => [
75
+ { 'field' => 'id', 'operator' => 'greater_than', 'value' => 2 }
76
+ ]
77
+ },
78
+ 'dynamicScopesValues' => { }
79
+ }
80
+ }
81
+ } }
82
+
83
+ it 'should not update the record name' do
84
+ subject.perform
85
+
86
+ expect(subject.record).to be nil
87
+ expect(subject.errors[0][:detail]).to eq 'Couldn\'t find User with \'id\'=1 [WHERE (("users"."id" > (2)))]'
88
+ end
89
+ end
90
+
91
+ describe 'with scope including target record' do
92
+ let(:attributes) { { name: 'Gandalf' } }
93
+ let(:scopes) { {
94
+ 'User' => {
95
+ 'scope'=> {
96
+ 'filter'=> {
97
+ 'aggregator' => 'and',
98
+ 'conditions' => [
99
+ { 'field' => 'id', 'operator' => 'less_than', 'value' => 2 }
100
+ ]
101
+ },
102
+ 'dynamicScopesValues' => { }
103
+ }
104
+ }
105
+ } }
106
+
107
+ it 'should not update the record name' do
108
+ subject.perform
109
+
110
+ expect(subject.record.valid?).to be true
111
+ expect(subject.record.name).to eq 'Gandalf'
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -6,13 +6,21 @@ module ForestLiana
6
6
  let(:sort) { 'id' }
7
7
  let(:fields) { }
8
8
  let(:filters) { }
9
+ let(:scopes) { { } }
10
+ let(:rendering_id) { 13 }
11
+ let(:user) { { 'id' => '1', 'rendering_id' => rendering_id } }
9
12
 
10
13
  let(:getter) { described_class.new(resource, {
11
14
  page: { size: pageSize, number: pageNumber },
12
15
  sort: sort,
13
16
  fields: fields,
14
17
  filters: filters,
15
- })}
18
+ }, user) }
19
+
20
+ def init_scopes
21
+ ForestLiana::ScopeManager.invalidate_scope_cache(rendering_id)
22
+ allow(ForestLiana::ScopeManager).to receive(:fetch_scopes).and_return(scopes)
23
+ end
16
24
 
17
25
  before(:each) do
18
26
  users = ['Michel', 'Robert', 'Vince', 'Sandro', 'Olesya', 'Romain', 'Valentin', 'Jason', 'Arnaud', 'Jeff', 'Steve', 'Marc', 'Xavier', 'Paul', 'Mickael', 'Mike', 'Maxime', 'Gertrude', 'Monique', 'Mia', 'Rachid', 'Edouard', 'Sacha', 'Caro', 'Amand', 'Nathan', 'Noémie', 'Robin', 'Gaelle', 'Isabelle']
@@ -43,6 +51,7 @@ module ForestLiana
43
51
  ].map { |location| Location.create(coordinates: location[:coordinates], island: location[:island]) }
44
52
 
45
53
  reference = Reference.create()
54
+ init_scopes
46
55
  end
47
56
 
48
57
  after(:each) do
@@ -355,5 +364,63 @@ module ForestLiana
355
364
  )
356
365
  end
357
366
  end
367
+
368
+ describe 'when scopes are defined' do
369
+ let(:resource) { Island }
370
+ let(:pageSize) { 15 }
371
+ let(:fields) { }
372
+ let(:filters) { }
373
+ let(:scopes) {
374
+ {
375
+ 'Island' => {
376
+ 'scope'=> {
377
+ 'filter'=> {
378
+ 'aggregator' => 'and',
379
+ 'conditions' => [
380
+ { 'field' => 'name', 'operator' => 'contains', 'value' => 'u' }
381
+ ]
382
+ },
383
+ 'dynamicScopesValues' => { }
384
+ }
385
+ }
386
+ }
387
+ }
388
+
389
+ describe 'when there are NO filters already defined' do
390
+ it 'should get only the records matching the scope' do
391
+ getter.perform
392
+ records = getter.records
393
+ count = getter.count
394
+
395
+ expect(records.count).to eq 3
396
+ expect(count).to eq 3
397
+ expect(records.first.name).to eq 'Skull'
398
+ expect(records.second.name).to eq 'Muerta'
399
+ expect(records.third.name).to eq 'Treasure'
400
+ end
401
+ end
402
+
403
+ describe 'when there are filters already defined' do
404
+ let(:filters) { {
405
+ aggregator: 'and',
406
+ conditions: [{
407
+ field: 'name',
408
+ operator: 'contains',
409
+ value: 'a',
410
+ }]
411
+ }.to_json }
412
+
413
+ it 'should get only the records matching the scope' do
414
+ getter.perform
415
+ records = getter.records
416
+ count = getter.count
417
+
418
+ expect(records.count).to eq 2
419
+ expect(count).to eq 2
420
+ expect(records.first.name).to eq 'Muerta'
421
+ expect(records.second.name).to eq 'Treasure'
422
+ end
423
+ end
424
+ end
358
425
  end
359
426
  end
@@ -0,0 +1,232 @@
1
+ module ForestLiana
2
+ describe ScopeManager do
3
+ let(:rendering_id) { 13 }
4
+ let(:user) { { 'id' => '1', 'rendering_id' => rendering_id } }
5
+ let(:collection_name) { 'Users' }
6
+ let(:first_collection_scope) {
7
+ {
8
+ 'scope'=> {
9
+ 'filter'=> {
10
+ 'aggregator' => 'and',
11
+ 'conditions' => [
12
+ { 'field' => 'description', 'operator' => 'contains', 'value' => 'check' }
13
+ ]
14
+ },
15
+ 'dynamicScopesValues' => { }
16
+ }
17
+ }
18
+ }
19
+ let(:second_collection_scope) {
20
+ {
21
+ 'scope'=> {
22
+ 'filter'=> {
23
+ 'aggregator' => 'and',
24
+ 'conditions' => [
25
+ { 'field' => 'description', 'operator' => 'contains', 'value' => 'toto' }
26
+ ]
27
+ },
28
+ 'dynamicScopesValues' => { }
29
+ }
30
+ }
31
+ }
32
+ let(:first_json_scopes) { JSON.generate({ collection_name => first_collection_scope }) }
33
+ let(:second_json_scopes) { JSON.generate({ collection_name => second_collection_scope }) }
34
+ let(:first_scopes_api_call_response) { Net::HTTPOK.new({}, 200, first_json_scopes) }
35
+ let(:second_scopes_api_call_response) { Net::HTTPOK.new({}, 200, second_json_scopes) }
36
+
37
+ before do
38
+ described_class.invalidate_scope_cache(rendering_id)
39
+ allow(ForestLiana::ForestApiRequester).to receive(:get).and_return(first_scopes_api_call_response, second_scopes_api_call_response)
40
+ allow(first_scopes_api_call_response).to receive(:body).and_return(first_json_scopes)
41
+ allow(second_scopes_api_call_response).to receive(:body).and_return(second_json_scopes)
42
+ end
43
+
44
+ describe '#get_scope_for_user' do
45
+ describe 'with invalid inputs' do
46
+ it 'should raise an error on missing rendering_id' do
47
+ expect {
48
+ described_class.get_scope_for_user({}, collection_name)
49
+ }.to raise_error 'Missing required rendering_id'
50
+ end
51
+
52
+ it 'should raise an error on missing collection_name' do
53
+ expect {
54
+ described_class.get_scope_for_user(user, nil)
55
+ }.to raise_error 'Missing required collection_name'
56
+ end
57
+ end
58
+
59
+ describe 'when the backend return an errored response' do
60
+ let(:first_scopes_api_call_response) { Net::HTTPNotFound.new({}, 404, nil) }
61
+
62
+ it 'should raise an error' do
63
+ expect {
64
+ described_class.get_scope_for_user(user, collection_name)
65
+ }.to raise_error 'Unable to fetch scopes'
66
+ end
67
+ end
68
+
69
+ describe 'when retrieving scopes once with no cached value' do
70
+ let(:scope) { described_class.get_scope_for_user(user, collection_name) }
71
+
72
+ it 'should fetch the relevant scope and return it' do
73
+ expect(scope).to eq first_collection_scope['scope']['filter']
74
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).once
75
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).with('/liana/scopes', query: { 'renderingId' => rendering_id })
76
+ end
77
+ end
78
+
79
+ describe 'when retrieving scopes twice before the refresh cache delta' do
80
+ let(:scope_first_fetch) { described_class.get_scope_for_user(user, collection_name) }
81
+ let(:scope_second_fetch) { described_class.get_scope_for_user(user, collection_name) }
82
+
83
+ it 'should return the same value twice and have fetch the scopes from the backend only once' do
84
+ expect(scope_first_fetch).to eq first_collection_scope['scope']['filter']
85
+ expect(scope_second_fetch).to eq first_collection_scope['scope']['filter']
86
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).once.with('/liana/scopes', query: { 'renderingId' => rendering_id })
87
+ end
88
+ end
89
+
90
+ describe 'when retrieving scopes twice after the refresh cache delta' do
91
+ let(:scope_first_fetch) { described_class.get_scope_for_user(user, collection_name) }
92
+ let(:scope_second_fetch) { described_class.get_scope_for_user(user, collection_name) }
93
+
94
+ it 'should return same value but trigger a fetch twice' do
95
+ expect(scope_first_fetch).to eq first_collection_scope['scope']['filter']
96
+ allow(Time).to receive(:now).and_return(Time.now + 20.minutes)
97
+ expect(scope_second_fetch).to eq first_collection_scope['scope']['filter']
98
+ # sleep to wait for the Thread to trigger the call to the `ForestApiRequester`
99
+ sleep(0.001)
100
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).twice.with('/liana/scopes', query: { 'renderingId' => rendering_id })
101
+ end
102
+ end
103
+
104
+ describe 'when retrieving scopes three times after the refresh cache delta' do
105
+ let(:scope_first_fetch) { described_class.get_scope_for_user(user, collection_name) }
106
+ let(:scope_second_fetch) { described_class.get_scope_for_user(user, collection_name) }
107
+ let(:scope_third_fetch) { described_class.get_scope_for_user(user, collection_name) }
108
+
109
+ it 'should return a new value on third call and have fetch the scopes from the backend only twice' do
110
+ expect(scope_first_fetch).to eq first_collection_scope['scope']['filter']
111
+ allow(Time).to receive(:now).and_return(Time.now + 20.minutes)
112
+ expect(scope_second_fetch).to eq first_collection_scope['scope']['filter']
113
+ # sleep to wait for the Thread to update the cache
114
+ sleep(0.001)
115
+ expect(scope_third_fetch).to eq second_collection_scope['scope']['filter']
116
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).twice.with('/liana/scopes', query: { 'renderingId' => rendering_id })
117
+ end
118
+ end
119
+
120
+ describe 'when scope contains dynamic values' do
121
+ let(:first_collection_scope) {
122
+ {
123
+ 'scope' => {
124
+ 'filter'=> {
125
+ 'aggregator' => 'and',
126
+ 'conditions' => [
127
+ { 'field' => 'description', 'operator' => 'contains', 'value' => '$currentUser.firstName' }
128
+ ]
129
+ },
130
+ 'dynamicScopesValues' => {
131
+ 'users' => { '1' => { '$currentUser.firstName' => 'Valentin' } }
132
+ }
133
+ }
134
+ }
135
+ }
136
+ let(:scope_filter) { described_class.get_scope_for_user(user, collection_name) }
137
+ let(:expected_filter) {
138
+ {
139
+ 'aggregator' => 'and',
140
+ 'conditions' => [
141
+ { 'field' => 'description', 'operator' => 'contains', 'value' => 'Valentin' }
142
+ ]
143
+ }
144
+ }
145
+
146
+ it 'should replace the dynamic values properly' do
147
+ expect(scope_filter).to eq expected_filter
148
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).once
149
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).with('/liana/scopes', query: { 'renderingId' => rendering_id })
150
+ end
151
+ end
152
+
153
+ describe 'when target collection has no scopes' do
154
+ let(:first_collection_scope) { { } }
155
+ let(:scope_filter) { described_class.get_scope_for_user(user, collection_name) }
156
+
157
+ it 'should return nil' do
158
+ expect(scope_filter).to eq nil
159
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).once
160
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).with('/liana/scopes', query: { 'renderingId' => rendering_id })
161
+ end
162
+ end
163
+
164
+ describe 'when target collection has no scopes' do
165
+ let(:first_collection_scope) { { } }
166
+ let(:scope_filter) { described_class.get_scope_for_user(user, collection_name) }
167
+
168
+ it 'should return nil' do
169
+ expect(scope_filter).to eq nil
170
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).once
171
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).with('/liana/scopes', query: { 'renderingId' => rendering_id })
172
+ end
173
+ end
174
+
175
+ describe 'when asking for filters as string' do
176
+ let(:scope) { described_class.get_scope_for_user(user, collection_name, as_string: true) }
177
+ let(:expected_filters) { "{\"aggregator\":\"and\",\"conditions\":[{\"field\":\"description\",\"operator\":\"contains\",\"value\":\"check\"}]}" }
178
+
179
+ it 'should fetch the relevant scope and return it as a string' do
180
+ expect(scope).to eq expected_filters
181
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).once
182
+ expect(ForestLiana::ForestApiRequester).to have_received(:get).with('/liana/scopes', query: { 'renderingId' => rendering_id })
183
+ end
184
+ end
185
+ end
186
+
187
+ describe '#append_scope_for_user' do
188
+ let(:existing_filter) { "{\"aggregator\":\"and\",\"conditions\":[{\"field\":\"shipping_status\",\"operator\":\"equal\",\"value\":\"Shipped\"}]}" }
189
+ let(:first_collection_scope_filter_as_string) { "{\"aggregator\":\"and\",\"conditions\":[{\"field\":\"description\",\"operator\":\"contains\",\"value\":\"check\"}]}" }
190
+
191
+ describe 'when the target collection has NO scopes defined' do
192
+ let(:first_collection_scope) { { } }
193
+
194
+ describe 'when providing NO existing filters' do
195
+ let(:existing_filter) { nil }
196
+ let(:filters) { described_class.append_scope_for_user(existing_filter, user, collection_name) }
197
+
198
+ it 'should return nil' do
199
+ expect(filters).to eq nil
200
+ end
201
+ end
202
+
203
+ describe 'when providing existing filters' do
204
+ let(:filters) { described_class.append_scope_for_user(existing_filter, user, collection_name) }
205
+
206
+ it 'should return only the exisitng filters' do
207
+ expect(filters).to eq existing_filter
208
+ end
209
+ end
210
+ end
211
+
212
+ describe 'when the target collection has scopes defined' do
213
+ describe 'when providing NO existing filters' do
214
+ let(:existing_filter) { nil }
215
+ let(:filters) { described_class.append_scope_for_user(existing_filter, user, collection_name) }
216
+
217
+ it 'should return only the scope filters' do
218
+ expect(filters).to eq first_collection_scope_filter_as_string
219
+ end
220
+ end
221
+
222
+ describe 'when providing existing filters' do
223
+ let(:filters) { described_class.append_scope_for_user(existing_filter, user, collection_name) }
224
+
225
+ it 'should return the aggregation between the exisitng filters and the scope filters' do
226
+ expect(filters).to eq "{\"aggregator\":\"and\",\"conditions\":[#{existing_filter},#{first_collection_scope_filter_as_string}]}"
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
232
+ end