forest_liana 7.0.0.beta.3 → 7.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/forest_liana/actions_controller.rb +20 -18
- data/app/controllers/forest_liana/application_controller.rb +0 -9
- data/app/controllers/forest_liana/associations_controller.rb +2 -2
- data/app/controllers/forest_liana/resources_controller.rb +15 -6
- data/app/controllers/forest_liana/scopes_controller.rb +20 -0
- data/app/controllers/forest_liana/smart_actions_controller.rb +39 -3
- data/app/controllers/forest_liana/stats_controller.rb +5 -5
- 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 +4 -2
- data/app/services/forest_liana/permissions_checker.rb +3 -4
- data/app/services/forest_liana/permissions_getter.rb +2 -2
- 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/value_stat_getter.rb +4 -2
- data/config/routes.rb +3 -1
- 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/requests/actions_controller_spec.rb +144 -23
- data/spec/requests/resources_spec.rb +2 -0
- 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 +1 -3
- 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 +20 -15
- 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
@@ -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
|