EvoBal/app/services/filter_processor.rb

140 lines
3.5 KiB
Ruby

class FilterProcessor
class InvalidFilter < ::ArgumentError
end
def process_all(filters, email)
filters.each { |filter|
email = process(filter, email)
}
email
end
def process(filter, email)
return email unless filter.enabled?
if evaluate_conditions(filter, email)
email = execute_operations(filter.operations, email)
end
email
end
def evaluate_conditions(filter, email)
filter_result = true
filter_result = catch(:done) {
filter.conditions.each do |condition|
next unless condition.enabled?
properties = prepare_properties(condition, email)
condition_result = apply_condition(properties, condition)
condition_result = !condition_result if filter.inverted?
filter_result = apply_operator(filter_result, filter.operator, condition_result)
rescue InvalidFilter => ex
Rails.logger.error "Skipped filter##{filter.id} '#{filter.description}' - #{ex.inspect}"
next
end
}
filter_result
end
def execute_operations(operations, email)
operations.each do |operation|
next unless operation.enabled?
klass = operation.class_name.constantize
email_operation = klass.new(operation: operation)
email = email_operation.process(email)
rescue NameError => ex
Rails.logger.error "Skipped operation##{operation.id} '#{operation.class_name}' - #{ex.inspect}"
raise InvalidFilter, ex.inspect
end
email
end
def prepare_properties(filter, email)
case filter.property_type.downcase
when "header"
Array(email.header_values(filter.property_value))
when "subject"
Array(email.subject)
when "body"
Array(email.plain_body)
else
raise InvalidFilter, "Unrecognized property type '#{filter.property_type}'"
end
end
private
def apply_condition(properties, condition)
case condition.test_method.downcase
when "match", "matches"
properties.any? { |property|
pattern = Regexp.new(condition.test_value)
property.match? pattern
}
when "equal", "equals"
properties.any? { |property|
property == condition.test_value
}
when "start", "starts"
properties.any? { |property|
property.starts_with? condition.test_value
}
when "end", "ends"
properties.any? { |property|
property.ends_with? condition.test_value
}
when "contain", "contains"
properties.any? { |property|
property.include? condition.test_value
}
when "exist", "exists"
properties.any? { |property|
property.exists?
}
when "empty"
properties.all? { |property|
property.empty?
}
when "date_before"
# properties.all? { |property|
# property.empty?
# }
when "date_after"
# properties.all? { |property|
# property.empty?
# }
else
raise InvalidFilter, "Unrecognized test method '#{condition.test_method}'"
end
end
def apply_operator(state, operator, result)
case operator.upcase
when "AND"
if result
(state and result)
else
throw :done, false
end
when "OR"
if result
throw :done, true
else
(state or result)
end
# when "XOR"
# (state or result) and !(conditions_state and result)
else
raise InvalidFilter, "Unrecognized operator '#{operator}'"
end
end
end