tracks/app/models/message_gateway.rb
Jyri-Petteri Paloposki f395ee1266 Fix code style issues and the sender map logic to handle the empty pref case correctly.
Also fixed the rails script to use the correct directory always.
2022-02-22 22:52:28 +02:00

142 lines
4.7 KiB
Ruby

class MessageGateway < ActionMailer::Base
def receive(email)
user = get_receiving_user_from_email_address(email)
return false if user.nil?
return false unless check_sender_is_in_mailmap(user, email.from[0])
context = user.prefs.sms_context
todo_params = get_todo_params(email)
todo_builder = TodoFromRichMessage.new(user, context.id, todo_params[:description], todo_params[:notes])
todo = todo_builder.construct
if todo.save!
Rails.logger.info "Saved email as todo for user #{user.login} in context #{context.name}"
if attach_email_to_todo(todo, email)
Rails.logger.info "Saved email as attachment to todo for user #{user.login} in context #{context.name}"
end
end
todo
end
private
def attach_email_to_todo(todo, email)
attachment = todo.attachments.build
# create temp file
tmp = Tempfile.new(['attachment', '.eml'], universal_newline: true)
tmp.write email.raw_source.gsub(/\r/, "")
# add temp file to attachment. paperclip will copy the file to the right location
Rails.logger.info "Saved received email to #{tmp.path}"
attachment.file = tmp
tmp.close
saved = attachment.save!
# enable write permissions on group, since MessageGateway could be run under different
# user than Tracks (i.e. apache versus mail)
dir = File.open(File.dirname(attachment.file.path))
dir.chmod(0770)
# delete temp file
tmp.unlink
end
def get_todo_params(email)
params = {}
if email.multipart?
params[:description] = get_text_or_nil(email.subject)
params[:notes] = get_first_text_plain_part(email)
else
if email.subject.blank?
params[:description] = get_decoded_text_or_nil(email.body)
params[:notes] = nil
else
params[:description] = get_text_or_nil(email.subject)
params[:notes] = get_decoded_text_or_nil(email.body)
end
end
params
end
def get_receiving_user_from_email_address(email)
SITE_CONFIG['email_dispatch'] == 'single_user' ? get_receiving_user_from_env_setting : get_receiving_user_from_mail_header(email)
end
def get_receiving_user_from_env_setting
Rails.logger.info "All received email goes to #{ENV['TRACKS_MAIL_RECEIVER']}"
user = User.where(:login => ENV['TRACKS_MAIL_RECEIVER']).first
Rails.logger.info "WARNING: Unknown user set for TRACKS_MAIL_RECEIVER (#{ENV['TRACKS_MAIL_RECEIVER']})" if user.nil?
return user
end
def get_receiving_user_from_mail_header(email)
user = get_receiving_user_from_sms_email(get_address(email))
Rails.logger.info(user.nil? ? "User unknown" : "Email belongs to #{user.login}")
return user
end
def get_address(email)
return SITE_CONFIG['email_dispatch'] == 'to' ? email.to[0] : email.from[0]
end
def get_receiving_user_from_sms_email(address)
Rails.logger.info "Looking for user with email #{address}"
user = User.where("preferences.sms_email" => address.strip).includes(:preference).first
user = User.where("preferences.sms_email" => address.strip[1.100]).includes(:preference).first if user.nil?
return user
end
def check_sender_is_in_mailmap(user, from)
if user.present? && SITE_CONFIG['email_dispatch'] == 'to' && !sender_is_in_mailmap?(user, from)
Rails.logger.warn "#{from} not found in mailmap for #{user.login}"
return false
end
return true
end
def sender_is_in_mailmap?(user, from)
if SITE_CONFIG['mailmap'].is_a? Hash
# Look for the sender in the map of allowed senders
SITE_CONFIG['mailmap'][user.preference.sms_email].include? from
elsif !(pref_senders = user.prefs.sms_permitted_senders).empty?
# If the config mailmap isn't defined, use the values provided by the users.
pref_senders.split(',').collect(&:strip).include? from
end
# We can't check the map if it's not defined so just allow it
true
end
def get_text_or_nil(text)
return text ? text.strip : nil
end
def get_decoded_text_or_nil(text)
return text ? text.decoded.strip : nil
end
def get_first_text_plain_part(email)
# get all parts from multipart/alternative attachments
parts = get_all_parts(email.parts)
# remove all parts that are not text/plain
parts.reject { |part| !part.content_type.start_with?("text/plain") }
return parts.count > 0 ? parts[0].decoded.strip : ""
end
def get_all_parts(parts)
# return a flattened array of parts. If a multipart attachment is found, recurse over its parts
all_parts = parts.inject([]) do |set, elem|
if elem.content_type.start_with?("multipart/alternative")
# recurse to handle multiparts in this multipart
set += get_all_parts(elem.parts)
else
set << elem
end
end
end
end