Skip to content

Commit

Permalink
Merge pull request #309 from QutBioacoustics/fix-validate-filter-values
Browse files Browse the repository at this point in the history
validate filter values
  • Loading branch information
atruskie authored Dec 4, 2016
2 parents 47f8fc2 + 07cebfa commit 336df7c
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 2 deletions.
6 changes: 6 additions & 0 deletions lib/modules/filter/comparison.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ def compose_eq(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_eq_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
node.eq(value)
end

Expand All @@ -46,6 +47,7 @@ def compose_not_eq(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_not_eq_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
node.not_eq(value)
end

Expand All @@ -66,6 +68,7 @@ def compose_lt(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_lt_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
node.lt(value)
end

Expand Down Expand Up @@ -104,6 +107,7 @@ def compose_gt(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_gt_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
node.gt(value)
end

Expand Down Expand Up @@ -142,6 +146,7 @@ def compose_lteq(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_lteq_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
node.lteq(value)
end

Expand Down Expand Up @@ -180,6 +185,7 @@ def compose_gteq(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_gteq_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
node.gteq(value)
end

Expand Down
9 changes: 8 additions & 1 deletion lib/modules/filter/subset.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ module Subset
# @return [Arel::Nodes::Node] condition
def compose_contains(table, column_name, allowed, value)
validate_table_column(table, column_name, allowed)
compose_contains_node(table[column_name],value)
compose_contains_node(table[column_name], value)
end

# Create contains condition.
Expand All @@ -25,6 +25,7 @@ def compose_contains(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_contains_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
sanitized_value = sanitize_like_value(value)
contains_value = "%#{sanitized_value}%"
node.matches(contains_value)
Expand Down Expand Up @@ -65,6 +66,7 @@ def compose_starts_with(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_starts_with_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
sanitized_value = sanitize_like_value(value)
contains_value = "#{sanitized_value}%"
node.matches(contains_value)
Expand Down Expand Up @@ -105,6 +107,7 @@ def compose_ends_with(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_ends_with_node(node, value)
validate_node_or_attribute(node)
validate_basic_class(node, value)
sanitized_value = sanitize_like_value(value)
contains_value = "%#{sanitized_value}"
node.matches(contains_value)
Expand Down Expand Up @@ -307,6 +310,8 @@ def compose_range(table, column_name, allowed, from, to)
# @return [Arel::Nodes::Node] condition
def compose_range_node(node, from, to)
validate_node_or_attribute(node)
validate_basic_class(node, from)
validate_basic_class(node, to)
range = Range.new(from, to, true)
node.in(range)
end
Expand Down Expand Up @@ -348,6 +353,7 @@ def compose_regex(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_regex_node(node, value)
validate_node_or_attribute(node)
validate_string(value)
Arel::Nodes::Regexp.new(node, Arel::Nodes.build_quoted(value))
end

Expand All @@ -370,6 +376,7 @@ def compose_not_regex(table, column_name, allowed, value)
# @return [Arel::Nodes::Node] condition
def compose_not_regex_node(node, value)
validate_node_or_attribute(node)
validate_string(value)
Arel::Nodes::NotRegexp.new(node, Arel::Nodes.build_quoted(value))
end

Expand Down
26 changes: 26 additions & 0 deletions lib/modules/filter/validate.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ def validate_paging(offset, limit)
validate_integer(limit, 1)
end

# Check that value is an integer between min and max.
# @param [Integer] value
# @param [Integer] min
# @param [Integer] max
# @return [void]
def validate_integer(value, min = nil, max = nil)
fail CustomErrors::FilterArgumentError, 'Value must not be blank' if value.blank?
fail CustomErrors::FilterArgumentError, "Value must be an integer, got #{value}" if value.blank? || value != value.to_i
Expand All @@ -53,6 +58,12 @@ def validate_integer(value, min = nil, max = nil)
fail CustomErrors::FilterArgumentError, "Value must be #{max} or less, got #{value_i}" if !max.blank? && value_i > max
end

# Check that value is a string.
# @param [String] value
# @return [void]
def validate_string(value)
fail CustomErrors::FilterArgumentError, 'Value must be a string' unless value.is_a?(String)
end

# Validate query, table, and column values.
# @param [Arel::Query] query
Expand Down Expand Up @@ -254,7 +265,22 @@ def validate_float(value)

value_f = filtered.to_f
fail CustomErrors::FilterArgumentError, "Value must be greater than 0, got #{value_f}" if value_f <= 0
end

# Check that value is a 'basic class'.
# @param [Object] value
# @raise [FilterArgumentError] if value is not a 'basic class'
# @return [void]
def validate_basic_class(node, value)
return if value.is_a?(NilClass) || value.is_a?(Integer) || value.is_a?(String) || value.is_a?(Float) ||
value.is_a?(TrueClass) || value.is_a?(FalseClass)

node_descr = node.respond_to?(:name) ? node.name : '(custom item)'

fail CustomErrors::FilterArgumentError, "The value for #{node_descr} must not be a hash" if value.is_a?(Hash)
fail CustomErrors::FilterArgumentError, "The value for #{node_descr} must not be an array" if value.is_a?(Array)
fail CustomErrors::FilterArgumentError, "The value for #{node_descr} must not be a set" if value.is_a?(Set)
fail CustomErrors::FilterArgumentError, "The value for #{node_descr} must not be a range" if value.is_a?(Range)
end

# Check that a hash contains a key with expected type of value.
Expand Down
34 changes: 33 additions & 1 deletion spec/acceptance/audio_events_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -658,7 +658,39 @@ def get_modify_params
}
}
}.to_json }
standard_request_options(:post, 'FILTER (as anonymous user)', :ok, {remove_auth: true, response_body_content: '{"meta":{"status":200,"message":"OK","filter":{"audio_events_tags.tag_id":{"gt":0}},"sorting":{"order_by":"created_at","direction":"desc"},"paging":{"page":1,"items":25,"total":0,"max_page":0,"current":"http://localhost:3000/audio_events/filter?direction=desc\u0026items=25\u0026order_by=created_at\u0026page=0","previous":null,"next":null}},"data":[]}'})
standard_request_options(:post, 'FILTER (as anonymous user)', :ok, {
remove_auth: true,
response_body_content: '{"meta":{"status":200,"message":"OK","filter":{"audio_events_tags.tag_id":{"gt":0}},"sorting":{"order_by":"created_at","direction":"desc"},"paging":{"page":1,"items":25,"total":0,"max_page":0,"current":"http://localhost:3000/audio_events/filter?direction=desc\u0026items=25\u0026order_by=created_at\u0026page=0","previous":null,"next":null}},"data":[]}'})
end

post '/audio_events/filter' do
let(:authentication_token) { reader_token }
let(:raw_post) {
{
"filter" => {
"isReference" => {
"eq" => true
},
"durationSeconds" => {
"gteq" => {
"from" => 0,
"to" => nil
}
},
"lowFrequencyHertz" => {
"gteq" => 1100
}
},
"paging" => {
"items" => 10,
"page" => 1
}
}.to_json
}

standard_request_options(:post, 'FILTER (as reader, with invalid nil for gteq interval)', :bad_request,
{
response_body_content: '{"meta":{"status":400,"message":"Bad Request","error":{"details":"Filter parameters were not valid: The value for (custom item) must not be a hash","info":null}},"data":null}'
})
end
end

0 comments on commit 336df7c

Please sign in to comment.