1# frozen_string_literal: true
2
3require 'gitlab/email/handler/base_handler'
4
5# handles issue creation emails with these formats:
6#   incoming+gitlab-org-gitlab-ce-20-Author_Token12345678-issue@incoming.gitlab.com
7#   incoming+gitlab-org/gitlab-ce+Author_Token12345678@incoming.gitlab.com (legacy)
8module Gitlab
9  module Email
10    module Handler
11      class CreateIssueHandler < BaseHandler
12        include ReplyProcessing
13
14        HANDLER_REGEX        = /\A#{HANDLER_ACTION_BASE_REGEX}-(?<incoming_email_token>.+)-issue\z/.freeze
15        HANDLER_REGEX_LEGACY = /\A(?<project_path>[^\+]*)\+(?<incoming_email_token>.*)\z/.freeze
16
17        def initialize(mail, mail_key)
18          super(mail, mail_key)
19
20          if !mail_key&.include?('/') && (matched = HANDLER_REGEX.match(mail_key.to_s))
21            @project_slug         = matched[:project_slug]
22            @project_id           = matched[:project_id]&.to_i
23            @incoming_email_token = matched[:incoming_email_token]
24          elsif matched = HANDLER_REGEX_LEGACY.match(mail_key.to_s)
25            @project_path         = matched[:project_path]
26            @incoming_email_token = matched[:incoming_email_token]
27          end
28        end
29
30        def can_handle?
31          incoming_email_token && (project_id || can_handle_legacy_format?)
32        end
33
34        def execute
35          raise ProjectNotFound unless project
36
37          validate_permission!(:create_issue)
38
39          verify_record!(
40            record: create_issue,
41            invalid_exception: InvalidIssueError,
42            record_name: 'issue')
43        end
44
45        # rubocop: disable CodeReuse/ActiveRecord
46        def author
47          @author ||= User.find_by(incoming_email_token: incoming_email_token)
48        end
49        # rubocop: enable CodeReuse/ActiveRecord
50
51        def metrics_event
52          :receive_email_create_issue
53        end
54
55        private
56
57        def create_issue
58          ::Issues::CreateService.new(
59            project: project,
60            current_user: author,
61            params: {
62              title: mail.subject,
63              description: message_including_reply_or_only_quotes
64            },
65            spam_params: nil
66          ).execute
67        end
68
69        def can_handle_legacy_format?
70          project_path && !incoming_email_token.include?('+') && !mail_key.include?(Gitlab::IncomingEmail::UNSUBSCRIBE_SUFFIX_LEGACY)
71        end
72      end
73    end
74  end
75end
76