2021-01-25 14:32:26 +01:00
|
|
|
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
|
2021-01-26 13:26:55 +01:00
|
|
|
email_action = klass.new(action: action)
|
2021-01-25 14:32:26 +01:00
|
|
|
email = email_action.process(email)
|
|
|
|
rescue NameError => ex
|
|
|
|
Rails.logger.error "Skipped action##{action.id} '#{action.name}' - #{ex.inspect}"
|
|
|
|
raise InvalidRule, ex.message
|
|
|
|
end
|
|
|
|
|
|
|
|
email
|
|
|
|
end
|
|
|
|
|
|
|
|
def prepare_subjects(rule, email)
|
|
|
|
case rule.subject_type.downcase
|
|
|
|
when "header"
|
|
|
|
Array(email.header_values(rule.subject_value))
|
|
|
|
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?
|
|
|
|
}
|
|
|
|
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
|