gitlab-org--gitlab-foss/lib/gitlab/email/receiver.rb
2016-01-07 13:37:14 +01:00

104 lines
2.9 KiB
Ruby

# Inspired in great part by Discourse's Email::Receiver
module Gitlab
module Email
class Receiver
class ProcessingError < StandardError; end
class EmailUnparsableError < ProcessingError; end
class SentNotificationNotFoundError < 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
def initialize(raw)
@raw = raw
end
def execute
raise EmptyEmailError if @raw.blank?
raise SentNotificationNotFoundError unless sent_notification
raise AutoGeneratedEmailError if message.header.to_s =~ /auto-(generated|replied)/
author = sent_notification.recipient
raise UserNotFoundError unless author
raise UserBlockedError if author.blocked?
project = sent_notification.project
raise UserNotAuthorizedError unless project && author.can?(:create_note, project)
raise NoteableNotFoundError unless sent_notification.noteable
reply = ReplyParser.new(message).execute.strip
raise EmptyEmailError if reply.blank?
reply = add_attachments(reply)
note = create_note(reply)
unless note.persisted?
message = "The comment could not be created for the following reasons:"
note.errors.full_messages.each do |error|
message << "\n\n- #{error}"
end
raise InvalidNoteError, message
end
end
private
def message
@message ||= Mail::Message.new(@raw)
rescue Encoding::UndefinedConversionError, Encoding::InvalidByteSequenceError => e
raise EmailUnparsableError, e
end
def reply_key
reply_key = nil
message.to.each do |address|
reply_key = Gitlab::IncomingEmail.key_from_address(address)
break if reply_key
end
reply_key
end
def sent_notification
return nil unless reply_key
SentNotification.for(reply_key)
end
def add_attachments(reply)
attachments = Email::AttachmentUploader.new(message).execute(sent_notification.project)
attachments.each do |link|
reply << "\n\n#{link[:markdown]}"
end
reply
end
def create_note(reply)
Notes::CreateService.new(
sent_notification.project,
sent_notification.recipient,
note: reply,
noteable_type: sent_notification.noteable_type,
noteable_id: sent_notification.noteable_id,
commit_id: sent_notification.commit_id,
line_code: sent_notification.line_code
).execute
end
end
end
end