require 'gitlab/email/handler/create_note' require 'gitlab/email/handler/create_issue' # Inspired in great part by Discourse's Email::Receiver module Gitlab module Email class ProcessingError < StandardError; end class EmailUnparsableError < ProcessingError; end class SentNotificationNotFoundError < ProcessingError; end class ProjectNotFound < ProcessingError; end class EmptyEmailError < ProcessingError; end class AutoGeneratedEmailError < ProcessingError; end class UserNotFoundError < ProcessingError; end class UserBlockedError < ProcessingError; end class UserNotAuthorizedError < ProcessingError; end class NoteableNotFoundError < ProcessingError; end class InvalidNoteError < ProcessingError; end class InvalidIssueError < ProcessingError; end class Receiver def initialize(raw) @raw = raw end def execute raise EmptyEmailError if @raw.blank? mail = build_mail mail_key = extract_mail_key(mail) raise SentNotificationNotFoundError unless mail_key if handler = find_handler(mail, mail_key) handler.execute elsif mail_key =~ %r{/|\+} # Sent Notification mail_key would not have / or + raise ProjectNotFound else raise SentNotificationNotFoundError end end def build_mail Mail::Message.new(@raw) rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError => e raise EmailUnparsableError, e end def extract_mail_key(mail) key_from_to_header(mail) || key_from_additional_headers(mail) end def key_from_to_header(mail) mail.to.find do |address| key = Gitlab::IncomingEmail.key_from_address(address) break key if key end end def key_from_additional_headers(mail) Array(mail.references).find do |mail_id| key = Gitlab::IncomingEmail.key_from_fallback_message_id(mail_id) break key if key end end def find_handler(mail, mail_key) [Handler::CreateNote, Handler::CreateIssue].find do |klass| handler = klass.new(mail, mail_key) break handler if handler.can_handle? end end end end end