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.
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