summaryrefslogtreecommitdiff
path: root/app/services/projects/operations/update_service.rb
blob: b66435d013be0152f5ef377c97d04f65ffc57341 (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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# frozen_string_literal: true

module Projects
  module Operations
    class UpdateService < BaseService
      def execute
        Projects::UpdateService
          .new(project, current_user, project_update_params)
          .execute
      end

      private

      def project_update_params
        error_tracking_params
          .merge(alerting_setting_params)
          .merge(metrics_setting_params)
          .merge(grafana_integration_params)
          .merge(prometheus_integration_params)
          .merge(incident_management_setting_params)
          .merge(tracing_setting_params)
      end

      def alerting_setting_params
        return {} unless can?(current_user, :read_prometheus_alerts, project)

        attr = params[:alerting_setting_attributes]
        return {} unless attr

        regenerate_token = attr.delete(:regenerate_token)

        if regenerate_token
          attr[:token] = nil
        else
          attr = attr.except(:token)
        end

        { alerting_setting_attributes: attr }
      end

      def metrics_setting_params
        attribs = params[:metrics_setting_attributes]
        return {} unless attribs

        attribs[:external_dashboard_url] = attribs[:external_dashboard_url].presence

        { metrics_setting_attributes: attribs }
      end

      def error_tracking_params
        settings = params[:error_tracking_setting_attributes]
        return {} if settings.blank?

        if error_tracking_params_partial_updates?(settings)
          error_tracking_params_for_partial_update(settings)
        else
          error_tracking_params_for_update(settings)
        end
      end

      def error_tracking_params_partial_updates?(settings)
        # Help from @splattael :bow:
        # Make sure we're converting to symbols because
        # * ActionController::Parameters#keys returns a list of strings
        # * in specs we're using hashes with symbols as keys
        update_keys = settings.keys.map(&:to_sym)

        # Integrated error tracking works without Sentry integration,
        # so we don't need to update all those values from error_tracking_params_for_update method.
        # Instead we turn it on/off with partial update together with "enabled" attribute.
        # But since its optional, we exclude it from the condition below.
        update_keys.delete(:integrated)

        update_keys == %i[enabled]
      end

      def error_tracking_params_for_partial_update(settings)
        { error_tracking_setting_attributes: settings }
      end

      def error_tracking_params_for_update(settings)
        api_url = ::ErrorTracking::ProjectErrorTrackingSetting.build_api_url_from(
          api_host: settings[:api_host],
          project_slug: settings.dig(:project, :slug),
          organization_slug: settings.dig(:project, :organization_slug)
        )

        params = {
          error_tracking_setting_attributes: {
            api_url: api_url,
            enabled: settings[:enabled],
            project_name: settings.dig(:project, :name),
            organization_name: settings.dig(:project, :organization_name)
          }
        }
        params[:error_tracking_setting_attributes][:token] = settings[:token] unless /\A\*+\z/.match?(settings[:token]) # Don't update token if we receive masked value
        params[:error_tracking_setting_attributes][:integrated] = settings[:integrated] unless settings[:integrated].nil?

        params
      end

      def grafana_integration_params
        return {} unless attrs = params[:grafana_integration_attributes]

        destroy = attrs[:grafana_url].blank? && attrs[:token].blank?

        { grafana_integration_attributes: attrs.merge(_destroy: destroy) }
      end

      def prometheus_integration_params
        return {} unless attrs = params[:prometheus_integration_attributes]

        integration = project.find_or_initialize_integration(::Integrations::Prometheus.to_param)
        integration.assign_attributes(attrs)
        attrs = integration.to_integration_hash.except('created_at', 'updated_at')

        { prometheus_integration_attributes: attrs }
      end

      def incident_management_setting_params
        attrs = params[:incident_management_setting_attributes]
        return {} unless attrs

        regenerate_token = attrs.delete(:regenerate_token)

        if regenerate_token
          attrs[:pagerduty_token] = nil
        else
          attrs = attrs.except(:pagerduty_token)
        end

        { incident_management_setting_attributes: attrs }
      end

      def tracing_setting_params
        attr = params[:tracing_setting_attributes]
        return {} unless attr

        destroy = attr[:external_url].blank?

        { tracing_setting_attributes: attr.merge(_destroy: destroy) }
      end
    end
  end
end

Projects::Operations::UpdateService.prepend_mod_with('Projects::Operations::UpdateService')