summaryrefslogtreecommitdiff
path: root/app/services/incident_management/issuable_escalation_statuses/prepare_update_service.rb
blob: 8f591b375ee4b02eb63d84d2b55735dfd3db2811 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
# frozen_string_literal: true

module IncidentManagement
  module IssuableEscalationStatuses
    class PrepareUpdateService < ::BaseProjectService
      include Gitlab::Utils::StrongMemoize

      SUPPORTED_PARAMS = %i[status status_change_reason].freeze

      def initialize(issuable, current_user, params)
        @issuable = issuable
        @param_errors = []

        super(project: issuable.project, current_user: current_user, params: Hash(params))
      end

      def execute
        return availability_error unless available?

        filter_unsupported_params
        filter_attributes
        filter_redundant_params

        return invalid_param_error if param_errors.any?

        ServiceResponse.success(payload: { escalation_status: params })
      end

      private

      attr_reader :issuable, :param_errors

      def available?
        issuable.supports_escalation? &&
          user_has_permissions? &&
          escalation_status.present?
      end

      def user_has_permissions?
        current_user&.can?(:update_escalation_status, issuable)
      end

      def escalation_status
        strong_memoize(:escalation_status) do
          issuable.escalation_status
        end
      end

      def filter_unsupported_params
        params.slice!(*supported_params)
      end

      def supported_params
        SUPPORTED_PARAMS
      end

      def filter_attributes
        filter_status
      end

      def filter_status
        status = params.delete(:status)
        return unless status

        status_event = escalation_status.status_event_for(status)
        add_param_error(:status) && return unless status_event

        params[:status_event] = status_event
      end

      def filter_redundant_params
        params.delete_if do |key, value|
          current_params.key?(key) && current_params[key] == value
        end
      end

      def current_params
        strong_memoize(:current_params) do
          {
            status_event: escalation_status.status_event_for(escalation_status.status_name)
          }
        end
      end

      def add_param_error(param)
        param_errors << param
      end

      def availability_error
        ServiceResponse.error(message: 'Escalation status updates are not available for this issue, user, or project.')
      end

      def invalid_param_error
        ServiceResponse.error(message: "Invalid value was provided for parameters: #{param_errors.join(', ')}")
      end
    end
  end
end

::IncidentManagement::IssuableEscalationStatuses::PrepareUpdateService.prepend_mod