summaryrefslogtreecommitdiff
path: root/lib/gitlab/email/handler/service_desk_handler.rb
diff options
context:
space:
mode:
Diffstat (limited to 'lib/gitlab/email/handler/service_desk_handler.rb')
-rw-r--r--lib/gitlab/email/handler/service_desk_handler.rb152
1 files changed, 152 insertions, 0 deletions
diff --git a/lib/gitlab/email/handler/service_desk_handler.rb b/lib/gitlab/email/handler/service_desk_handler.rb
new file mode 100644
index 00000000000..bcd8b98a06f
--- /dev/null
+++ b/lib/gitlab/email/handler/service_desk_handler.rb
@@ -0,0 +1,152 @@
+# frozen_string_literal: true
+
+# handles service desk issue creation emails with these formats:
+# incoming+gitlab-org-gitlab-ce-20-issue-@incoming.gitlab.com
+# incoming+gitlab-org/gitlab-ce@incoming.gitlab.com (legacy)
+module Gitlab
+ module Email
+ module Handler
+ class ServiceDeskHandler < BaseHandler
+ include ReplyProcessing
+ include Gitlab::Utils::StrongMemoize
+
+ HANDLER_REGEX = /\A#{HANDLER_ACTION_BASE_REGEX}-issue-\z/.freeze
+ HANDLER_REGEX_LEGACY = /\A(?<project_path>[^\+]*)\z/.freeze
+ PROJECT_KEY_PATTERN = /\A(?<slug>.+)-(?<key>[a-z0-9_]+)\z/.freeze
+
+ def initialize(mail, mail_key, service_desk_key: nil)
+ super(mail, mail_key)
+
+ if service_desk_key.present?
+ @service_desk_key = service_desk_key
+ elsif !mail_key&.include?('/') && (matched = HANDLER_REGEX.match(mail_key.to_s))
+ @project_slug = matched[:project_slug]
+ @project_id = matched[:project_id]&.to_i
+ elsif matched = HANDLER_REGEX_LEGACY.match(mail_key.to_s)
+ @project_path = matched[:project_path]
+ end
+ end
+
+ def can_handle?
+ Gitlab::ServiceDesk.supported? && (project_id || can_handle_legacy_format? || service_desk_key)
+ end
+
+ def execute
+ raise ProjectNotFound if project.nil?
+
+ create_issue!
+ send_thank_you_email! if from_address
+ end
+
+ def metrics_params
+ super.merge(project: project&.full_path)
+ end
+
+ def metrics_event
+ :receive_email_service_desk
+ end
+
+ private
+
+ attr_reader :project_id, :project_path, :service_desk_key
+
+ def project
+ strong_memoize(:project) do
+ @project = service_desk_key ? project_from_key : super
+ @project = nil unless @project&.service_desk_enabled?
+ @project
+ end
+ end
+
+ def project_from_key
+ return unless match = service_desk_key.match(PROJECT_KEY_PATTERN)
+
+ project = Project.find_by_service_desk_project_key(match[:key])
+ return unless valid_project_key?(project, match[:slug])
+
+ project
+ end
+
+ def valid_project_key?(project, slug)
+ project.present? && slug == project.full_path_slug && Feature.enabled?(:service_desk_custom_address, project)
+ end
+
+ def create_issue!
+ @issue = Issues::CreateService.new(
+ project,
+ User.support_bot,
+ title: issue_title,
+ description: message_including_template,
+ confidential: true,
+ service_desk_reply_to: from_address
+ ).execute
+
+ raise InvalidIssueError unless @issue.persisted?
+
+ if service_desk_setting&.issue_template_missing?
+ create_template_not_found_note(@issue)
+ end
+ end
+
+ def send_thank_you_email!
+ Notify.service_desk_thank_you_email(@issue.id).deliver_later!
+ end
+
+ def message_including_template
+ description = message_including_reply
+ template_content = service_desk_setting&.issue_template_content
+
+ if template_content.present?
+ description += " \n" + template_content
+ end
+
+ description
+ end
+
+ def service_desk_setting
+ strong_memoize(:service_desk_setting) do
+ project.service_desk_setting
+ end
+ end
+
+ def create_template_not_found_note(issue)
+ issue_template_key = service_desk_setting&.issue_template_key
+
+ warning_note = <<-MD.strip_heredoc
+ WARNING: The template file #{issue_template_key}.md used for service desk issues is empty or could not be found.
+ Please check service desk settings and update the file to be used.
+ MD
+
+ note_params = {
+ noteable: issue,
+ note: warning_note
+ }
+
+ ::Notes::CreateService.new(
+ project,
+ User.support_bot,
+ note_params
+ ).execute
+ end
+
+ def from_address
+ (mail.reply_to || []).first || mail.from.first || mail.sender
+ end
+
+ def issue_title
+ from = "(from #{from_address})" if from_address
+
+ "Service Desk #{from}: #{mail.subject}"
+ end
+
+ def can_handle_legacy_format?
+ project_path && project_path.include?('/') && !mail_key.include?('+')
+ end
+
+ def author
+ User.support_bot
+ end
+ end
+ end
+ end
+end