iachat/app/presenters/mail_presenter.rb
Sony Mathew f9b0427751
feat: email channel backend (#140) (#1255)
* feat: added support mailbox to handle email channel (#140)

Added a new mailbox called 'SupportMailbox' to handle all the
incoming emails other than reply emails.

An email channel will have a support email and forward email
associated with it. So we filter for the right email inbox based on
the support email of that inbox and route this to this mailbox.

This mailbox finds the account, inbox, contact (create a new one
if it does not exist) and creates a conversation and adds the
email content as the first message in the conversation.

Other minor things handled in this commit:

* renamed the procs for routing emails in application mailbox
* renamed ConversationMailbox to ReplyMailbox
* Added a fallback content in MailPresenter
* Added a record saving (bang) versions of enabling and disabling
features in Featurable module
* added new factory for the email channel

refs: #140
2020-09-21 22:44:22 +05:30

119 lines
3.4 KiB
Ruby

class MailPresenter < SimpleDelegator
attr_accessor :mail
def initialize(mail, account = nil)
super(mail)
@mail = mail
@account = account
end
def subject
encode_to_unicode(@mail.subject)
end
def text_content
@decoded_text_content ||= encode_to_unicode(text_part&.body&.decoded || fallback_content)
@text_content ||= {
full: @decoded_text_content,
reply: extract_reply(@decoded_text_content)[:reply],
quoted: extract_reply(@decoded_text_content)[:quoted_text]
}
end
def html_content
@decoded_html_content ||= encode_to_unicode(html_part&.body&.decoded || fallback_content)
@html_content ||= {
full: @decoded_html_content,
reply: extract_reply(@decoded_html_content)[:reply],
quoted: extract_reply(@decoded_html_content)[:quoted_text]
}
end
def fallback_content
body&.decoded || ''
end
def attachments
# ref : https://github.com/gorails-screencasts/action-mailbox-action-text/blob/master/app/mailboxes/posts_mailbox.rb
mail.attachments.map do |attachment|
blob = ActiveStorage::Blob.create_after_upload!(
io: StringIO.new(attachment.body.to_s),
filename: attachment.filename,
content_type: attachment.content_type
)
{ original: attachment, blob: blob }
end
end
def number_of_attachments
mail.attachments.count
end
def serialized_data
{
text_content: text_content,
html_content: html_content,
number_of_attachments: number_of_attachments,
subject: subject,
date: date,
to: to,
from: from,
in_reply_to: in_reply_to,
cc: cc,
bcc: bcc,
message_id: message_id
}
end
private
# forcing the encoding of the content to UTF-8 so as to be compatible with database and serializers
def encode_to_unicode(str)
current_encoding = str.encoding.name
str.encode(current_encoding, 'UTF-8', invalid: :replace, undef: :replace, replace: '?')
end
def extract_reply(content)
@regex_arr ||= quoted_text_regexes
content_length = content.length
# calculates the matching regex closest to top of page
index = @regex_arr.inject(content_length) do |min, regex|
[(content.index(regex) || content_length), min].min
end
{
reply: content[0..(index - 1)].strip,
quoted_text: content[index..].strip
}
end
def quoted_text_regexes
return sender_agnostic_regexes if @account.nil? || account_support_email.blank?
[
Regexp.new("From:\s* #{Regexp.escape(account_support_email)}", Regexp::IGNORECASE),
Regexp.new("<#{Regexp.escape(account_support_email)}>", Regexp::IGNORECASE),
Regexp.new("#{Regexp.escape(account_support_email)}\s+wrote:", Regexp::IGNORECASE),
Regexp.new("On(.*)#{Regexp.escape(account_support_email)}(.*)wrote:", Regexp::IGNORECASE)
] + sender_agnostic_regexes
end
def sender_agnostic_regexes
@sender_agnostic_regexes ||= [
Regexp.new("^.*On.*(\n)?wrote:$", Regexp::IGNORECASE),
Regexp.new('^.*On(.*)(.*)wrote:$', Regexp::IGNORECASE),
Regexp.new("-+original\s+message-+\s*$", Regexp::IGNORECASE),
Regexp.new("from:\s*$", Regexp::IGNORECASE)
]
end
def account_support_email
@account_support_email ||= begin
@account.support_email ||
GlobalConfig.get('MAILER_SUPPORT_EMAIL')['MAILER_SUPPORT_EMAIL'] ||
ENV.fetch('MAILER_SENDER_EMAIL', nil)
end
end
end