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
@@ -1,98 +0,0 @@
1
- module ForestLiana
2
- class ScopeValidator
3
- def initialize(scope_permissions, users_variable_values)
4
- @scope_filters = scope_permissions
5
- @users_variable_values = users_variable_values
6
- end
7
-
8
- def is_scope_in_request?(scope_request)
9
- begin
10
- filters = JSON.parse(scope_request[:filters])
11
- rescue JSON::ParserError
12
- raise ForestLiana::Errors::HTTP422Error.new('Invalid filters JSON format')
13
- end
14
- @computed_scope = compute_condition_filters_from_scope(scope_request[:user_id])
15
-
16
- # NOTICE: Perfom a travel in the request condition filters tree to find the scope
17
- tagged_scope_filters = get_scope_found_in_request(filters)
18
-
19
- # NOTICE: Permission system always send an aggregator even if there is only one condition
20
- # In that case, if the condition is valid, then request was not edited
21
- return !tagged_scope_filters.nil? if @scope_filters['conditions'].length == 1
22
-
23
- # NOTICE: If there is more than one condition, do a final validation on the condition filters
24
- return tagged_scope_filters != nil &&
25
- tagged_scope_filters[:aggregator] == @scope_filters['aggregator'] &&
26
- tagged_scope_filters[:conditions] &&
27
- tagged_scope_filters[:conditions].length == @scope_filters['conditions'].length
28
- end
29
-
30
- private
31
-
32
- def compute_condition_filters_from_scope(user_id)
33
- computed_condition_filters = @scope_filters.clone
34
- computed_condition_filters['conditions'].each do |condition|
35
- if condition.include?('value') &&
36
- !condition['value'].nil? &&
37
- condition['value'].instance_of?(String) &&
38
- condition['value'].start_with?('$') &&
39
- @users_variable_values.include?(user_id)
40
- condition['value'] = @users_variable_values[user_id][condition['value']]
41
- end
42
- end
43
- return computed_condition_filters
44
- end
45
-
46
- def get_scope_found_in_request(filters)
47
- return nil unless filters
48
- return search_scope_aggregation(filters)
49
- end
50
-
51
- def search_scope_aggregation(node)
52
- ensure_valid_aggregation(node)
53
-
54
- return is_scope_condition?(node) unless node['aggregator']
55
-
56
- # NOTICE: Remove conditions that are not from the scope
57
- filtered_conditions = node['conditions'].map { |condition|
58
- search_scope_aggregation(condition)
59
- }.select { |condition|
60
- condition
61
- }
62
-
63
- # NOTICE: If there is only one condition filter left and its current aggregator is
64
- # an "and", this condition filter is the searched scope
65
- if (filtered_conditions.length == 1 &&
66
- filtered_conditions.first.is_a?(Hash) &&
67
- filtered_conditions.first.include?(:aggregator) &&
68
- node['aggregator'] == 'and')
69
- return filtered_conditions.first
70
- end
71
-
72
- # NOTICE: Otherwise, validate if the current node is the scope and return nil
73
- # if it's not
74
- return (filtered_conditions.length == @scope_filters['conditions'].length &&
75
- node['aggregator'] == @scope_filters['aggregator']) ?
76
- { aggregator: node['aggregator'], conditions: filtered_conditions } :
77
- nil
78
- end
79
-
80
- def is_scope_condition?(condition)
81
- ensure_valid_condition(condition)
82
- return @computed_scope['conditions'].include?(condition)
83
- end
84
-
85
- def ensure_valid_aggregation(node)
86
- raise ForestLiana::Errors::HTTP422Error.new('Filters cannot be a raw value') unless node.is_a?(Hash)
87
- raise_empty_condition_in_filter_error if node.empty?
88
- end
89
-
90
- def ensure_valid_condition(condition)
91
- raise_empty_condition_in_filter_error if condition.empty?
92
- raise ForestLiana::Errors::HTTP422Error.new('Condition cannot be a raw value') unless condition.is_a?(Hash)
93
- unless condition['field'].is_a?(String) and condition['operator'].is_a?(String)
94
- raise ForestLiana::Errors::HTTP422Error.new('Invalid condition format')
95
- end
96
- end
97
- end
98
- end
@@ -1,75 +0,0 @@
1
- module ForestLiana
2
- class HasManyGetterTest < ActiveSupport::TestCase
3
-
4
- collectionOwner = ForestLiana::Model::Collection.new({
5
- name: 'Owner',
6
- fields: []
7
- })
8
-
9
- collectionTree = ForestLiana::Model::Collection.new({
10
- name: 'Tree',
11
- fields: []
12
- })
13
-
14
- ForestLiana.apimap << collectionOwner
15
- ForestLiana.apimap << collectionTree
16
- ForestLiana.models << Owner
17
- ForestLiana.models << Tree
18
-
19
- test 'HasMany Getter page 1 size 15' do
20
- association = Owner.reflect_on_association(:trees)
21
-
22
- getter = HasManyGetter.new(Owner, association, {
23
- id: 1,
24
- association_name: 'trees',
25
- page: { size: 15, number: 1 },
26
- timezone: 'America/Nome'
27
- })
28
- getter.perform
29
- records = getter.records
30
- count = getter.count
31
-
32
- assert records.count == 3
33
- assert count = 3
34
- assert records.first.id == 7
35
- end
36
-
37
- test 'HasMany Getter with sort parameter' do
38
- association = Owner.reflect_on_association(:trees)
39
-
40
- getter = HasManyGetter.new(Owner, association, {
41
- id: 1,
42
- association_name: 'trees',
43
- sort: '-id',
44
- page: { size: 15, number: 1 },
45
- timezone: 'America/Nome'
46
- })
47
- getter.perform
48
- records = getter.records
49
- count = getter.count
50
-
51
- assert records.count == 3
52
- assert count = 3
53
- assert records.first.id == 8
54
- end
55
-
56
- test 'HasMany Getter with search parameter' do
57
- association = Owner.reflect_on_association(:trees)
58
-
59
- getter = HasManyGetter.new(Owner, association, {
60
- id: 1,
61
- association_name: 'trees',
62
- search: 'Fir',
63
- page: { size: 15, number: 1 },
64
- timezone: 'America/Nome'
65
- })
66
- getter.perform
67
- records = getter.records
68
- count = getter.count
69
-
70
- assert records.count == 1
71
- assert count = 1
72
- assert records.first.id == 8
73
- end
74
- end
75
- end
@@ -1,29 +0,0 @@
1
- module ForestLiana
2
- class PieStatGetterTest < ActiveSupport::TestCase
3
- test 'Pie stat getter with an aggregate on a boolean field' do
4
- stat = PieStatGetter.new(BooleanField, {
5
- type: "Pie",
6
- collection: "boolean_field",
7
- timezone: "Europe/Paris",
8
- aggregate: "Count",
9
- group_by_field: "field"
10
- })
11
-
12
- stat.perform
13
- assert stat.record.value.count == 0
14
- end
15
-
16
- test 'Pie stat getter with an aggregate on a foreign key' do
17
- stat = PieStatGetter.new(BelongsToField, {
18
- type: "Pie",
19
- collection: "belongs_to_field",
20
- timezone: "Europe/Paris",
21
- aggregate: "Count",
22
- group_by_field: "has_one_field_id"
23
- })
24
-
25
- stat.perform
26
- assert stat.record.value.count == 30
27
- end
28
- end
29
- end
@@ -1,86 +0,0 @@
1
- module ForestLiana
2
- class ResourceUpdaterTest < ActiveSupport::TestCase
3
-
4
- collection = ForestLiana::Model::Collection.new({
5
- name: 'SerializeField',
6
- fields: [{
7
- type: 'String',
8
- field: 'field'
9
- }]
10
- })
11
-
12
- ForestLiana.apimap << collection
13
- ForestLiana.models << SerializeField
14
-
15
- test 'Update a record on a "serialize" attribute with a missing value' do
16
- params = ActionController::Parameters.new(
17
- id: 1,
18
- data: {
19
- id: 1,
20
- type: "SerializeField",
21
- attributes: {}
22
- }
23
- )
24
- updater = ResourceUpdater.new(SerializeField, params)
25
- updater.perform
26
-
27
- assert updater.record.valid?
28
- assert updater.record.field == "value 1"
29
- end
30
-
31
- test 'Update a record on a "serialize" attribute with a null value' do
32
- params = ActionController::Parameters.new(
33
- id: 1,
34
- data: {
35
- id: 1,
36
- type: "SerializeField",
37
- attributes: {
38
- field: nil
39
- }
40
- }
41
- )
42
- updater = ResourceUpdater.new(SerializeField, params)
43
- updater.perform
44
-
45
- assert updater.record.valid?
46
- assert updater.record.field == []
47
- end
48
-
49
- test 'Update a record on a "serialize" attribute with a bad format value' do
50
- params = ActionController::Parameters.new(
51
- id: 1,
52
- data: {
53
- id: 1,
54
- type: "SerializeField",
55
- attributes: {
56
- field: "Lucas"
57
- }
58
- }
59
- )
60
- updater = ResourceUpdater.new(SerializeField, params)
61
- updater.perform
62
-
63
- assert updater.record.valid?
64
- assert updater.record.field == "value 1"
65
- assert updater.errors[0][:detail] == "Bad format for 'field' attribute value."
66
- end
67
-
68
- test 'Update a record on a "serialize" attribute with a well formated value' do
69
- params = ActionController::Parameters.new(
70
- id: 1,
71
- data: {
72
- id: 1,
73
- type: "SerializeField",
74
- attributes: {
75
- field: "[\"test\", \"test\"]"
76
- }
77
- }
78
- )
79
- updater = ResourceUpdater.new(SerializeField, params)
80
- updater.perform
81
-
82
- assert updater.record.valid?
83
- assert updater.record.field == ["test", "test"]
84
- end
85
- end
86
- end
@@ -1,185 +0,0 @@
1
- module ForestLiana
2
- class ScopeValidatorTest < ActiveSupport::TestCase
3
- test 'Request with aggregated condition filters should be allowed if it matches the scope exactly' do
4
- scope_validator = ForestLiana::ScopeValidator.new({
5
- 'aggregator' => 'and',
6
- 'conditions' => [
7
- { 'field' => 'name', 'value' => 'john', 'operator' => 'equal' },
8
- { 'field' => 'price', 'value' => '2500', 'operator' => 'equal' }
9
- ]
10
- }, [])
11
-
12
- allowed = scope_validator.is_scope_in_request?({
13
- user_id: '1',
14
- filters: JSON.generate({
15
- aggregator: 'and',
16
- conditions: [
17
- { field: 'name', value: 'john', operator: 'equal' },
18
- { field: 'price', value: '2500', operator: 'equal' }
19
- ]
20
- })
21
- })
22
- assert allowed == true
23
- end
24
-
25
- test 'Request with simple condition filter should be allowed if it matches the scope exactly' do
26
- scope_validator = ForestLiana::ScopeValidator.new({
27
- 'aggregator' => 'and',
28
- 'conditions' => [
29
- { 'field' => 'field', 'value' => 'value', 'operator' => 'equal' }
30
- ]
31
- }, [])
32
- allowed = scope_validator.is_scope_in_request?({
33
- user_id: '1',
34
- filters: JSON.generate({
35
- field: 'field', value: 'value', operator: 'equal'
36
- })
37
- })
38
- assert allowed == true
39
- end
40
-
41
- test 'Request with multiples condition filters should be allowed if it contains the scope ' do
42
- scope_validator = ForestLiana::ScopeValidator.new({
43
- 'aggregator' => 'and',
44
- 'conditions' => [
45
- { 'field' => 'name', 'value' => 'doe', 'operator' => 'equal' }
46
- ]
47
- }, []
48
- )
49
-
50
- allowed = scope_validator.is_scope_in_request?({
51
- user_id: '1',
52
- filters: JSON.generate({
53
- aggregator: 'and',
54
- conditions: [
55
- { field: 'name', value: 'doe', operator: 'equal' },
56
- { field: 'field2', value: 'value2', operator: 'equal' }
57
- ]
58
- })
59
- })
60
- assert allowed == true
61
- end
62
-
63
- test 'Request with dynamic user values should be allowed if it matches the scope exactly' do
64
- scope_validator = ForestLiana::ScopeValidator.new({
65
- 'aggregator' => 'and',
66
- 'conditions' => [
67
- { 'field' => 'name', 'value' => '$currentUser.lastname', 'operator' => 'equal' }
68
- ],
69
- }, {
70
- '1' => { '$currentUser.lastname' => 'john' }
71
- })
72
-
73
- allowed = scope_validator.is_scope_in_request?({
74
- user_id: '1',
75
- filters: JSON.generate({
76
- 'field' => 'name', 'value' => 'john', 'operator' => 'equal'
77
- })
78
- })
79
- assert allowed == true
80
- end
81
-
82
- test 'Request with multiples aggregation and dynamic values should be allowed if it contains the scope' do
83
- scope_validator = ForestLiana::ScopeValidator.new({
84
- 'aggregator' => 'or',
85
- 'conditions' => [
86
- { 'field' => 'price', 'value' => '2500', 'operator' => 'equal' },
87
- { 'field' => 'name', 'value' => '$currentUser.lastname', 'operator' => 'equal' }
88
- ]
89
- }, {
90
- '1' => { '$currentUser.lastname' => 'john' }
91
- })
92
-
93
- allowed = scope_validator.is_scope_in_request?({
94
- user_id: '1',
95
- filters: JSON.generate({
96
- aggregator: 'and',
97
- conditions: [
98
- { field: 'field', value: 'value', operator: 'equal' },
99
- {
100
- aggregator: 'or',
101
- conditions: [
102
- { field: 'price', value: '2500', operator: 'equal' },
103
- { field: 'name', value: 'john', operator: 'equal' }
104
- ]
105
- }
106
- ]
107
- })
108
- })
109
- assert allowed == true
110
- end
111
-
112
- test 'Request that does not match the expect scope should not be allowed' do
113
- scope_validator = ForestLiana::ScopeValidator.new({
114
- 'aggregator' => 'and',
115
- 'conditions' => [
116
- { 'field' => 'name', 'value' => 'john', 'operator' => 'equal' },
117
- { 'field' => 'price', 'value' => '2500', 'operator' => 'equal' }
118
- ]
119
- }, [])
120
-
121
- allowed = scope_validator.is_scope_in_request?({
122
- user_id: '1',
123
- filters: JSON.generate({
124
- aggregator: 'and',
125
- conditions: [
126
- { field: 'name', value: 'definitely_not_john', operator: 'equal' },
127
- { field: 'price', value: '0', operator: 'equal' }
128
- ]
129
- })
130
- })
131
- assert allowed == false
132
- end
133
-
134
- test 'Request that are missing part of the scope should not be allowed' do
135
- scope_validator = ForestLiana::ScopeValidator.new({
136
- 'aggregator' => 'and',
137
- 'conditions' => [
138
- { 'field' => 'name', 'value' => 'john', 'operator' => 'equal' },
139
- { 'field' => 'price', 'value' => '2500', 'operator' => 'equal' }
140
- ]
141
- }, [])
142
-
143
- allowed = scope_validator.is_scope_in_request?({
144
- user_id: '1',
145
- filters: JSON.generate({
146
- aggregator: 'and',
147
- conditions: [
148
- { field: 'name', value: 'john', operator: 'equal' },
149
- ]
150
- })
151
- })
152
- assert allowed == false
153
- end
154
-
155
- test 'Request that does not have a top aggregator being "and" should not be allowed' do
156
- scope_validator = ForestLiana::ScopeValidator.new({
157
- 'aggregator' => 'and',
158
- 'conditions' => [
159
- { 'field' => 'price', 'value' => '2500', 'operator' => 'equal' },
160
- { 'field' => 'name', 'value' => '$currentUser.lastname', 'operator' => 'equal' }
161
- ]
162
- }, {
163
- '1' => { '$currentUser.lastname' => 'john' }
164
- })
165
-
166
- allowed = scope_validator.is_scope_in_request?({
167
- user_id: '1',
168
- filters: JSON.generate({
169
- aggregator: 'or',
170
- conditions: [
171
- { field: 'field', value: 'value', operator: 'equal' },
172
- {
173
- aggregator: 'and',
174
- conditions: [
175
- { field: 'price', value: '2500', operator: 'equal' },
176
- { field: 'name', value: 'john', operator: 'equal' }
177
- ]
178
- }
179
- ]
180
- })
181
- })
182
- assert allowed == false
183
- end
184
- end
185
- end