EvoBal/app/services/rule_set_processor.rb

140 lines
3.4 KiB
Ruby

class RuleSetProcessor
class InvalidRule < ::ArgumentError
end
def process_all(rule_sets, email)
rule_sets.each { |rule_set|
email = process(rule_set, email)
}
email
end
def process(rule_set, email)
return email unless rule_set.enabled?
if evaluate_rules(rule_set, email)
email = execute_actions(rule_set.actions, email)
end
email
end
def evaluate_rules(rule_set, email)
rule_set_result = true
rule_set_result = catch(:done) {
rule_set.rules.each do |rule|
next unless rule.enabled?
subjects = prepare_subjects(rule, email)
rule_result = apply_rule(subjects, rule)
rule_result = !rule_result if rule.inverted?
rule_set_result = apply_operator(rule_set_result, rule_set.operator, rule_result)
rescue InvalidRule => ex
Rails.logger.error "Skipped rule##{rule.id} '#{rule.name}' - #{ex.inspect}"
next
end
}
rule_set_result
end
def execute_actions(actions, email)
actions.each do |action|
next unless action.enabled?
klass = action.class_name.constantize
email_action = klass.new(action: action)
email = email_action.process(email)
rescue NameError => ex
Rails.logger.error "Skipped action##{action.id} '#{action.name}' - #{ex.inspect}"
raise InvalidRule, ex.inspect
end
email
end
def prepare_subjects(rule, email)
case rule.subject_type.downcase
when "header"
Array(email.header_values(rule.subject_value))
when "subject"
Array(email.subject)
when "body"
Array(email.plain_body)
else
raise InvalidRule, "Unrecognized subject type '#{rule.subject_type}'"
end
end
private
def apply_rule(subjects, rule)
case rule.condition_type.downcase
when "match", "matches"
subjects.any? { |subject|
pattern = Regexp.new(rule.condition_value)
subject.match? pattern
}
when "equal", "equals"
subjects.any? { |subject|
subject == rule.condition_value
}
when "start", "starts"
subjects.any? { |subject|
subject.starts_with? rule.condition_value
}
when "end", "ends"
subjects.any? { |subject|
subject.ends_with? rule.condition_value
}
when "contain", "contains"
subjects.any? { |subject|
subject.include? rule.condition_value
}
when "exist", "exists"
subjects.any? { |subject|
subject.exists?
}
when "empty"
subjects.all? { |subject|
subject.empty?
}
when "date_before"
# subjects.all? { |subject|
# subject.empty?
# }
when "date_after"
# subjects.all? { |subject|
# subject.empty?
# }
else
raise InvalidRule, "Unrecognized condition type '#{rule. condition_type}'"
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 !(rules_state and result)
else
raise InvalidRule, "Unrecognized operator '#{operator}'"
end
end
end