app/models/incoming_mail/handler.rb
module IncomingMail
class Handler
include MailAddressing
def initialize(params = {})
params.each do |key, value|
instance_variable_set("@#{key}", value)
end
end
def handle(payload)
if payload_is_raw?(payload)
create_response(payload[0])
elsif payload.is_a?(Mandrill::WebHook::EventDecorator)
create_response(payload)
else
fail "Invalid Mandrill event payload. Must be event==inbound or Mandrill::WebHook::EventDecorator instance"
end
end
private
def payload_is_raw?(payload)
payload.is_a?(Array) and payload[0]["event"] and payload[0]["event"] == "inbound"
end
def create_response(payload)
response = Response.new(type: identify_mail_type(payload))
if response.type == REQUEST && response.comment = transform_msg_to_comment(payload["msg"])
response.action = Response::COMMENT
send_comment_email(response.comment)
else
forward_message(response, payload)
end
response
end
def loop?(msg)
mail_msg = Mail.new(msg["raw_msg"])
from_raw = msg["headers"]["From"] || mail_msg.header["From"].value
from_raw == resend_to_email || resend_to_email.match("<#{from_raw}>")
end
def forward_message(response, payload)
if loop?(payload["msg"])
response.action = Response::DROPPED
else
Mailer.resend(payload["msg"]["raw_msg"]).deliver_later
response.action = Response::FORWARDED
end
end
def identify_mail_type(payload)
subject = payload["msg"]["subject"]
references = payload["msg"]["headers"]["References"]
if subject_line_matches(subject)
IncomingMail::REQUEST
elsif references && reference_header_matches(references)
IncomingMail::REQUEST
else
IncomingMail::UNKNOWN
end
end
def subject_line_matches(subject)
subject.match(/Request (#|FY)\d+/)
end
def reference_header_matches(header)
header.match(/<proposal-\d+/)
end
def transform_msg_to_comment(msg)
parsed_email = InboundMailParser.new(msg)
proposal = parsed_email.proposal
user = parsed_email.comment_user
# cannot create comment for non-existent user, or
# for user who is not already a subscriber
unless user && proposal.subscriber?(user)
return
end
create_comment(parsed_email.comment_text, proposal, user)
end
def create_comment(comment_text, proposal, user)
find_or_create_observation(proposal, user)
Comment.create(
comment_text: comment_text,
user: user,
proposal: proposal
)
end
def find_or_create_observation(proposal, user)
unless proposal.existing_observation_for(user)
reason = "Added comment via email reply"
ObservationCreator.new(
observer: user,
proposal_id: proposal.id,
reason: reason,
).run
end
end
def send_comment_email(comment)
DispatchFinder.run(comment.proposal).on_comment_created(comment)
end
end
end