pager_tree-integrations 1.1.5 → 1.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/app/controllers/pager_tree/integrations/live_call_routing/twilio/v3_controller.rb +20 -0
- data/app/jobs/pager_tree/integrations/live_call_routing/twilio/v3/max_wait_time_job.rb +13 -0
- data/app/models/pager_tree/integrations/additional_datum.rb +2 -2
- data/app/models/pager_tree/integrations/alert.rb +2 -2
- data/app/models/pager_tree/integrations/aws_cloudwatch/v3.rb +15 -5
- data/app/models/pager_tree/integrations/boolean_store_accessor.rb +2 -2
- data/app/models/pager_tree/integrations/channel/hangouts/v3.rb +23 -2
- data/app/models/pager_tree/integrations/channel/mattermost/v3.rb +4 -0
- data/app/models/pager_tree/integrations/channel/microsoft_teams/v3.rb +74 -29
- data/app/models/pager_tree/integrations/channel/microsoft_teams/v4.rb +261 -0
- data/app/models/pager_tree/integrations/channel/slack/v3.rb +30 -3
- data/app/models/pager_tree/integrations/cloudflare/v3.rb +75 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3.rb +206 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/datadog.json +12 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/datadog.yaml +30 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/generic_rules_definition.json +9 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/generic_rules_example.yaml +27 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/grafana.json +25 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/grafana.yaml +33 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/new_relic.json +40 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/new_relic.yaml +32 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/pingdom.json +30 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/pingdom.yaml +23 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_cloudwatch.json +12 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_cloudwatch.yaml +48 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_health_event.json +21 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_health_event.yaml +43 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_lambda_monitor.json +31 -0
- data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_lambda_monitor.yaml +24 -0
- data/app/models/pager_tree/integrations/datadog/v3.rb +10 -3
- data/app/models/pager_tree/integrations/dynatrace/v3.rb +67 -0
- data/app/models/pager_tree/integrations/echoes_hq/v3.rb +138 -0
- data/app/models/pager_tree/integrations/elast_alert/v3.rb +24 -0
- data/app/models/pager_tree/integrations/email/v3.rb +272 -22
- data/app/models/pager_tree/integrations/email/v3_examples/example.yml +24 -0
- data/app/models/pager_tree/integrations/form/v3.rb +15 -3
- data/app/models/pager_tree/integrations/freshdesk/v3.rb +7 -5
- data/app/models/pager_tree/integrations/freshservice/v3.rb +7 -5
- data/app/models/pager_tree/integrations/grafana/v3.rb +2 -2
- data/app/models/pager_tree/integrations/hetrix_tools/v3.rb +160 -0
- data/app/models/pager_tree/integrations/honeybadger/v3.rb +1 -1
- data/app/models/pager_tree/integrations/hydrozen/v3.rb +6 -0
- data/app/models/pager_tree/integrations/integration.rb +52 -9
- data/app/models/pager_tree/integrations/jira_server/v3.rb +12 -2
- data/app/models/pager_tree/integrations/kapacitor/v3.rb +1 -1
- data/app/models/pager_tree/integrations/live_call_routing/twilio/v3.rb +276 -25
- data/app/models/pager_tree/integrations/logic_monitor/v3.rb +193 -3
- data/app/models/pager_tree/integrations/mattermost/outgoing_webhook/v3.rb +1 -1
- data/app/models/pager_tree/integrations/meta/workplace/v3.rb +230 -0
- data/app/models/pager_tree/integrations/new_relic/v3.rb +9 -5
- data/app/models/pager_tree/integrations/outgoing_event.rb +8 -0
- data/app/models/pager_tree/integrations/outgoing_webhook/v3.rb +108 -13
- data/app/models/pager_tree/integrations/outgoing_webhook_delivery/hook_relay.rb +43 -33
- data/app/models/pager_tree/integrations/outgoing_webhook_delivery.rb +6 -5
- data/app/models/pager_tree/integrations/prtg/v3.rb +2 -1
- data/app/models/pager_tree/integrations/pulsetic/v3.rb +70 -0
- data/app/models/pager_tree/integrations/scom/pagertree.ps1 +153 -0
- data/app/models/pager_tree/integrations/scom/v3.rb +58 -0
- data/app/models/pager_tree/integrations/sentry/v3.rb +477 -0
- data/app/models/pager_tree/integrations/server_guard24/v3.rb +1 -1
- data/app/models/pager_tree/integrations/sixty_six_uptime/v3.rb +118 -0
- data/app/models/pager_tree/integrations/slack/webhook/v3.rb +1 -1
- data/app/models/pager_tree/integrations/solar_winds/v3.rb +66 -2
- data/app/models/pager_tree/integrations/status_gator/v3.rb +69 -0
- data/app/models/pager_tree/integrations/uptime_kuma/v3.rb +76 -0
- data/app/models/pager_tree/integrations/uptime_robot/v3.rb +6 -0
- data/app/models/pager_tree/integrations/webhook/v3.rb +25 -7
- data/app/models/pager_tree/integrations/zabbix/v3.rb +95 -0
- data/app/models/pager_tree/integrations/zendesk/v3.rb +2 -0
- data/app/views/pager_tree/integrations/channel/hangouts/v3/_form_options.html.erb +7 -0
- data/app/views/pager_tree/integrations/channel/hangouts/v3/_show_options.html.erb +10 -0
- data/app/views/pager_tree/integrations/channel/microsoft_teams/v3/_form_options.html.erb +7 -0
- data/app/views/pager_tree/integrations/channel/microsoft_teams/v3/_show_options.html.erb +14 -0
- data/app/views/pager_tree/integrations/channel/microsoft_teams/v4/_form_options.html.erb +41 -0
- data/app/views/pager_tree/integrations/channel/microsoft_teams/v4/_show_options.html.erb +54 -0
- data/app/views/pager_tree/integrations/channel/slack/v3/_form_options.html.erb +6 -3
- data/app/views/pager_tree/integrations/channel/slack/v3/_show_options.html.erb +1 -1
- data/app/views/pager_tree/integrations/cloudflare/v3/_form_options.html.erb +7 -0
- data/app/views/pager_tree/integrations/cloudflare/v3/_show_options.html.erb +12 -0
- data/app/views/pager_tree/integrations/custom_webhook/v3/_form_options.html.erb +8 -0
- data/app/views/pager_tree/integrations/custom_webhook/v3/_show_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/datadog/v3/_form_options.html.erb +7 -0
- data/app/views/pager_tree/integrations/datadog/v3/_show_options.html.erb +12 -0
- data/app/views/pager_tree/integrations/dynatrace/v3/_form_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/dynatrace/v3/_show_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/echoes_hq/v3/_form_options.html.erb +10 -0
- data/app/views/pager_tree/integrations/echoes_hq/v3/_show_options.html.erb +12 -0
- data/app/views/pager_tree/integrations/email/v3/_form_options.html.erb +41 -11
- data/app/views/pager_tree/integrations/email/v3/_show_options.html.erb +18 -0
- data/app/views/pager_tree/integrations/form/v3/_form_options.html.erb +1 -5
- data/app/views/pager_tree/integrations/hetrix_tools/v3/_form_options.html.erb +7 -0
- data/app/views/pager_tree/integrations/hetrix_tools/v3/_show_options.html.erb +12 -0
- data/app/views/pager_tree/integrations/hydrozen/v3/_form_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/hydrozen/v3/_show_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/live_call_routing/twilio/v3/_form_options.html.erb +44 -31
- data/app/views/pager_tree/integrations/live_call_routing/twilio/v3/_show_options.html.erb +93 -8
- data/app/views/pager_tree/integrations/logic_monitor/v3/_form_options.html.erb +31 -0
- data/app/views/pager_tree/integrations/logic_monitor/v3/_show_options.html.erb +60 -0
- data/app/views/pager_tree/integrations/meta/workplace/v3/_form_options.html.erb +44 -0
- data/app/views/pager_tree/integrations/meta/workplace/v3/_show_options.html.erb +68 -0
- data/app/views/pager_tree/integrations/outgoing_webhook/v3/_form_options.html.erb +17 -3
- data/app/views/pager_tree/integrations/outgoing_webhook/v3/_show_options.html.erb +20 -0
- data/app/views/pager_tree/integrations/pulsetic/v3/_form_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/pulsetic/v3/_show_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/scom/v3/_form_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/scom/v3/_show_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/sentry/v3/_form_options.html.erb +9 -0
- data/app/views/pager_tree/integrations/sentry/v3/_show_options.html.erb +15 -0
- data/app/views/pager_tree/integrations/sixty_six_uptime/v3/_form_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/sixty_six_uptime/v3/_show_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/solar_winds/v3/_form_options.html.erb +40 -0
- data/app/views/pager_tree/integrations/solar_winds/v3/_show_options.html.erb +66 -0
- data/app/views/pager_tree/integrations/status_gator/v3/_form_options.html.erb +13 -0
- data/app/views/pager_tree/integrations/status_gator/v3/_show_options.html.erb +24 -0
- data/app/views/pager_tree/integrations/uptime_kuma/v3/_form_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/uptime_kuma/v3/_show_options.html.erb +0 -0
- data/app/views/pager_tree/integrations/webhook/v3/_form_options.html.erb +8 -0
- data/app/views/pager_tree/integrations/webhook/v3/_show_options.html.erb +15 -0
- data/app/views/pager_tree/integrations/zabbix/v3/_form_options.html.erb +7 -0
- data/app/views/pager_tree/integrations/zabbix/v3/_show_options.html.erb +12 -0
- data/config/locales/en.yml +158 -10
- data/config/routes.rb +1 -0
- data/lib/pager_tree/integrations/format_converters/yaml_json_converter.rb +67 -0
- data/lib/pager_tree/integrations/version.rb +1 -1
- data/lib/pager_tree/integrations.rb +11 -3
- metadata +84 -8
|
@@ -1,17 +1,37 @@
|
|
|
1
1
|
module PagerTree::Integrations
|
|
2
2
|
class Email::V3 < Integration
|
|
3
|
+
extend ::PagerTree::Integrations::Env
|
|
4
|
+
|
|
5
|
+
# the source log (if created) - Its what shows on the integration page (different from deferred request)
|
|
6
|
+
attribute :adapter_source_log
|
|
7
|
+
|
|
3
8
|
OPTIONS = [
|
|
4
9
|
{key: :allow_spam, type: :boolean, default: false},
|
|
5
|
-
{key: :dedup_threads, type: :boolean, default: true}
|
|
10
|
+
{key: :dedup_threads, type: :boolean, default: true},
|
|
11
|
+
{key: :sanitize_level, type: :string, default: "relaxed"},
|
|
12
|
+
{key: :custom_definition, type: :string, default: nil},
|
|
13
|
+
{key: :custom_definition_enabled, type: :boolean, default: false}
|
|
6
14
|
]
|
|
15
|
+
|
|
7
16
|
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
|
|
8
17
|
|
|
18
|
+
SANITIZE_LEVELS = ["basic", "default", "relaxed", "relaxed_2", "restricted"]
|
|
19
|
+
|
|
9
20
|
validates :option_allow_spam, inclusion: {in: [true, false]}
|
|
10
21
|
validates :option_dedup_threads, inclusion: {in: [true, false]}
|
|
22
|
+
validates :option_sanitize_level, inclusion: {in: SANITIZE_LEVELS}
|
|
23
|
+
validates :option_custom_definition, presence: true, if: ->(record) { record.option_custom_definition_enabled == true }
|
|
24
|
+
|
|
25
|
+
def self.custom_webhook_v3_service_url
|
|
26
|
+
::PagerTree::Integrations.integration_custom_webhook_v3_service_url.presence ||
|
|
27
|
+
find_value_by_name("integration_custom_webhook_v3", "service_url")
|
|
28
|
+
end
|
|
11
29
|
|
|
12
30
|
after_initialize do
|
|
13
31
|
self.option_allow_spam = false if option_allow_spam.nil?
|
|
14
32
|
self.option_dedup_threads = true if option_dedup_threads.nil?
|
|
33
|
+
self.option_sanitize_level = "relaxed" if option_sanitize_level.nil?
|
|
34
|
+
self.option_custom_definition_enabled = false if option_custom_definition_enabled.nil?
|
|
15
35
|
end
|
|
16
36
|
|
|
17
37
|
# SPECIAL: override integration endpoint
|
|
@@ -23,7 +43,24 @@ module PagerTree::Integrations
|
|
|
23
43
|
postfix = "_tst" if Rails.env.test?
|
|
24
44
|
postfix = "_dev" if Rails.env.development?
|
|
25
45
|
|
|
26
|
-
|
|
46
|
+
if Rails.env.production?
|
|
47
|
+
if created_at&.after?(DateTime.parse("2023-09-01"))
|
|
48
|
+
# new emails
|
|
49
|
+
# int_abc123@domain.com
|
|
50
|
+
"#{(v == 3) ? prefix_id : id}@#{domain}"
|
|
51
|
+
else
|
|
52
|
+
# legacy emails
|
|
53
|
+
# a+int_abc123@domain.com
|
|
54
|
+
"#{inbox}#{postfix}+#{(v == 3) ? prefix_id : id}@#{domain}"
|
|
55
|
+
end
|
|
56
|
+
else
|
|
57
|
+
# staging, test, development
|
|
58
|
+
"#{inbox}#{postfix}+#{(v == 3) ? prefix_id : id}@#{domain}"
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def custom_definition?
|
|
63
|
+
option_custom_definition_enabled && option_custom_definition.present?
|
|
27
64
|
end
|
|
28
65
|
|
|
29
66
|
def adapter_should_block?
|
|
@@ -47,23 +84,120 @@ module PagerTree::Integrations
|
|
|
47
84
|
end
|
|
48
85
|
|
|
49
86
|
def adapter_action
|
|
50
|
-
|
|
87
|
+
if custom_definition?
|
|
88
|
+
case custom_response_result.dig("type")&.downcase
|
|
89
|
+
when "create"
|
|
90
|
+
:create
|
|
91
|
+
when "acknowledge"
|
|
92
|
+
:acknowledge
|
|
93
|
+
when "resolve"
|
|
94
|
+
:resolve
|
|
95
|
+
else
|
|
96
|
+
:other
|
|
97
|
+
end
|
|
98
|
+
else
|
|
99
|
+
:create
|
|
100
|
+
end
|
|
51
101
|
end
|
|
52
102
|
|
|
53
103
|
def adapter_process_create
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
104
|
+
if custom_definition?
|
|
105
|
+
Alert.new(
|
|
106
|
+
title: _title,
|
|
107
|
+
description: _description,
|
|
108
|
+
urgency: _urgency,
|
|
109
|
+
thirdparty_id: _thirdparty_id,
|
|
110
|
+
dedup_keys: _dedup_keys,
|
|
111
|
+
incident: _incident,
|
|
112
|
+
incident_severity: _incident_severity,
|
|
113
|
+
incident_message: _incident_message,
|
|
114
|
+
tags: _tags,
|
|
115
|
+
meta: _meta,
|
|
116
|
+
additional_data: _additional_datums,
|
|
117
|
+
attachments: _attachments
|
|
118
|
+
)
|
|
119
|
+
else
|
|
120
|
+
Alert.new(
|
|
121
|
+
title: _title,
|
|
122
|
+
description: _description,
|
|
123
|
+
urgency: urgency,
|
|
124
|
+
thirdparty_id: _thirdparty_id,
|
|
125
|
+
dedup_keys: _dedup_keys,
|
|
126
|
+
additional_data: _additional_datums,
|
|
127
|
+
attachments: _attachments
|
|
128
|
+
)
|
|
129
|
+
end
|
|
63
130
|
end
|
|
64
131
|
|
|
65
132
|
private
|
|
66
133
|
|
|
134
|
+
def _custom_response
|
|
135
|
+
return @_custom_response ||= {} unless custom_definition?
|
|
136
|
+
|
|
137
|
+
@_custom_response ||= begin
|
|
138
|
+
log_hash = {
|
|
139
|
+
subject: _mail.subject,
|
|
140
|
+
body: _body,
|
|
141
|
+
from: _mail.from,
|
|
142
|
+
to: _mail.to
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
body_hash = {
|
|
146
|
+
log: log_hash,
|
|
147
|
+
config: JSON.parse(PagerTree::Integrations::FormatConverters::YamlJsonConverter.convert_to_json(option_custom_definition))
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
response = HTTParty.post(
|
|
151
|
+
self.class.custom_webhook_v3_service_url,
|
|
152
|
+
body: body_hash.to_json,
|
|
153
|
+
headers: {"Content-Type" => "application/json"},
|
|
154
|
+
timeout: 2
|
|
155
|
+
)
|
|
156
|
+
|
|
157
|
+
unless response.success?
|
|
158
|
+
if response.parsed_response.dig("error").present?
|
|
159
|
+
adapter_source_log&.sublog({
|
|
160
|
+
message: "Custom Webhook Service Error:",
|
|
161
|
+
parsed_response: response.parsed_response
|
|
162
|
+
})
|
|
163
|
+
adapter_source_log&.save
|
|
164
|
+
end
|
|
165
|
+
raise "Custom Webhook Service HTTP error: #{response.code} - #{response.message} - #{response.body}"
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
adapter_source_log&.sublog({
|
|
169
|
+
message: "Custom Webhook Service Response:",
|
|
170
|
+
parsed_response: response.parsed_response
|
|
171
|
+
})
|
|
172
|
+
adapter_source_log&.save
|
|
173
|
+
|
|
174
|
+
response.parsed_response
|
|
175
|
+
rescue JSON::ParserError => e
|
|
176
|
+
Rails.logger.error("Custom Webhook YAML to JSON conversion error: #{e.message}")
|
|
177
|
+
adapter_source_log&.sublog("Custom Webhook YAML to JSON conversion error: #{e.message}")
|
|
178
|
+
adapter_source_log&.save
|
|
179
|
+
raise "Invalid YAML configuration: #{e.message}"
|
|
180
|
+
rescue HTTParty::Error, SocketError, Net::OpenTimeout, Net::ReadTimeout => e
|
|
181
|
+
Rails.logger.error("Custom Webhook Service error: #{e.message}")
|
|
182
|
+
adapter_source_log&.sublog("Custom Webhook Service error: #{e.message}")
|
|
183
|
+
adapter_source_log&.save
|
|
184
|
+
raise "Custom Webhook Service error: #{e.message}"
|
|
185
|
+
rescue => e
|
|
186
|
+
Rails.logger.error("Unexpected error in Custom Webhook: #{e.message}")
|
|
187
|
+
adapter_source_log&.sublog("Unexpected error in Custom Webhook: #{e.message}")
|
|
188
|
+
adapter_source_log&.save
|
|
189
|
+
raise e
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def _custom_response_status
|
|
194
|
+
@_custom_response_status ||= _custom_response.dig("status")
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def custom_response_result
|
|
198
|
+
@_custom_response_result ||= _custom_response.dig("results")&.first || {}
|
|
199
|
+
end
|
|
200
|
+
|
|
67
201
|
def _mail
|
|
68
202
|
@_mail ||= adapter_incoming_request_params.dig("mail")
|
|
69
203
|
end
|
|
@@ -73,28 +207,83 @@ module PagerTree::Integrations
|
|
|
73
207
|
end
|
|
74
208
|
|
|
75
209
|
def _thirdparty_id
|
|
76
|
-
|
|
210
|
+
if custom_definition?
|
|
211
|
+
@_thirdparty_id ||= custom_response_result.dig("thirdparty_id").to_s.presence
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
@_thirdparty_id ||= _mail.message_id || SecureRandom.uuid
|
|
77
215
|
end
|
|
78
216
|
|
|
79
217
|
def _dedup_keys
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
218
|
+
return @_dedup_keys if @_dedup_keys
|
|
219
|
+
|
|
220
|
+
@_dedup_keys ||= []
|
|
221
|
+
|
|
222
|
+
if option_dedup_threads
|
|
223
|
+
@_dedup_keys.concat(Array(_thirdparty_id))
|
|
224
|
+
@_dedup_keys.concat(Array(_mail.references))
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
if custom_definition?
|
|
228
|
+
@_dedup_keys.concat(Array(custom_response_result.dig("dedup_keys")))
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
# only dedup the references per integration. Customer like sending one email to multiple integration inboxes
|
|
232
|
+
@_dedup_keys = @_dedup_keys.compact_blank.uniq.map { |x| "#{prefix_id}_#{x}" }
|
|
83
233
|
end
|
|
84
234
|
|
|
85
235
|
def _title
|
|
86
|
-
|
|
236
|
+
if custom_definition?
|
|
237
|
+
@_title ||= custom_response_result.dig("title")&.to_s&.presence
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
@_title ||= _mail.subject.to_s.presence || "Incoming Email - Untitled Alert"
|
|
87
241
|
end
|
|
88
242
|
|
|
89
243
|
def _description
|
|
90
|
-
|
|
244
|
+
if custom_definition?
|
|
245
|
+
@_description ||= custom_response_result.dig("description")&.to_s&.presence
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
@_description ||= _body.to_s
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
def _urgency
|
|
252
|
+
if custom_definition?
|
|
253
|
+
@_urgency ||= custom_response_result.dig("urgency")&.to_s&.presence
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
@_urgency ||= urgency
|
|
257
|
+
end
|
|
258
|
+
|
|
259
|
+
def _incident
|
|
260
|
+
@_incident ||= ActiveModel::Type::Boolean.new.cast(custom_response_result.dig("incident"))
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
def _incident_severity
|
|
264
|
+
custom_response_result.dig("incident_severity")&.to_s&.presence
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
def _incident_message
|
|
268
|
+
custom_response_result.dig("incident_message")&.to_s&.presence
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def _tags
|
|
272
|
+
tags = custom_response_result.dig("tags")
|
|
273
|
+
tags = tags.split(",") if tags.is_a?(String)
|
|
274
|
+
Array(tags).compact_blank.map(&:to_s).uniq
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
def _meta
|
|
278
|
+
meta = custom_response_result.dig("meta")
|
|
279
|
+
meta.is_a?(Hash) ? meta : {}
|
|
91
280
|
end
|
|
92
281
|
|
|
93
282
|
def _body
|
|
94
283
|
return @_body if @_body
|
|
95
284
|
|
|
96
285
|
if _mail.multipart? && _mail.html_part
|
|
97
|
-
document = Nokogiri::HTML(_mail.html_part
|
|
286
|
+
document = Nokogiri::HTML(_mail_body_part_to_utf8(_mail.html_part))
|
|
98
287
|
|
|
99
288
|
_attachments_hash.map do |attachment_hash|
|
|
100
289
|
attachment = attachment_hash[:original]
|
|
@@ -109,9 +298,11 @@ module PagerTree::Integrations
|
|
|
109
298
|
end
|
|
110
299
|
end
|
|
111
300
|
|
|
112
|
-
@_body =
|
|
301
|
+
@_body = custom_definition? ?
|
|
302
|
+
(document.at_css("body")&.inner_html || document.to_html) :
|
|
303
|
+
::Sanitize.fragment(document, _sanitize_config)
|
|
113
304
|
elsif _mail.multipart? && _mail.text_part
|
|
114
|
-
@_body = _mail.text_part
|
|
305
|
+
@_body = _mail_body_part_to_utf8(_mail.text_part)
|
|
115
306
|
else
|
|
116
307
|
@_body = _mail.decoded
|
|
117
308
|
end
|
|
@@ -119,6 +310,43 @@ module PagerTree::Integrations
|
|
|
119
310
|
@_body
|
|
120
311
|
end
|
|
121
312
|
|
|
313
|
+
def _sanitize_config
|
|
314
|
+
case option_sanitize_level
|
|
315
|
+
when "basic" then Sanitize::Config::BASIC
|
|
316
|
+
when "default" then Sanitize::Config::DEFAULT
|
|
317
|
+
when "relaxed" then Sanitize::Config::RELAXED
|
|
318
|
+
when "restricted" then Sanitize::Config::RESTRICTED
|
|
319
|
+
when "relaxed_2"
|
|
320
|
+
Sanitize::Config.merge(Sanitize::Config::RELAXED, elements: Sanitize::Config::RELAXED[:elements].excluding("style"))
|
|
321
|
+
end
|
|
322
|
+
end
|
|
323
|
+
|
|
324
|
+
# Encodings can cause lots of issues, so we try to convert to UTF-8
|
|
325
|
+
# https://github.com/mikel/mail#encodings
|
|
326
|
+
# https://stackoverflow.com/a/15818886/2903189
|
|
327
|
+
def _mail_body_part_to_utf8(part_to_use)
|
|
328
|
+
# get the message body without the header information
|
|
329
|
+
body = part_to_use.body.decoded
|
|
330
|
+
|
|
331
|
+
if body.encoding.name != "UTF-8"
|
|
332
|
+
# readout the encoding (charset) of the part
|
|
333
|
+
encoding = part_to_use.content_type_parameters["charset"] if part_to_use.content_type_parameters
|
|
334
|
+
|
|
335
|
+
# and convert it to UTF-8
|
|
336
|
+
if encoding
|
|
337
|
+
body = body.force_encoding(encoding).encode("UTF-8")
|
|
338
|
+
else
|
|
339
|
+
raise StandardError.new "Unknown encoding for mail body part"
|
|
340
|
+
end
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
# return the body
|
|
344
|
+
body
|
|
345
|
+
rescue
|
|
346
|
+
# if something goes wrong, just return the original body with characters replaced
|
|
347
|
+
body.encode("UTF-8", "binary", invalid: :replace, undef: :replace, replace: "?")
|
|
348
|
+
end
|
|
349
|
+
|
|
122
350
|
def _attachments_hash
|
|
123
351
|
@_attachments_hash ||= _mail.attachments.map do |attachment|
|
|
124
352
|
blob = ActiveStorage::Blob.create_and_upload!(
|
|
@@ -136,7 +364,29 @@ module PagerTree::Integrations
|
|
|
136
364
|
|
|
137
365
|
# TODO: Implement any additional data that should be shown in the alert with high priority (be picky as to 'very important' information)
|
|
138
366
|
def _additional_datums
|
|
139
|
-
|
|
367
|
+
return @_additional_datums if @_additional_datums
|
|
368
|
+
|
|
369
|
+
if custom_definition?
|
|
370
|
+
@_additional_datums ||= begin
|
|
371
|
+
items = custom_response_result.dig("additional_data") || []
|
|
372
|
+
items = [items] unless items.is_a?(Array)
|
|
373
|
+
|
|
374
|
+
items.each_with_object([]) do |ad, result|
|
|
375
|
+
next unless ad.is_a?(Hash)
|
|
376
|
+
|
|
377
|
+
format = ad["format"].to_s
|
|
378
|
+
next unless PagerTree::Integrations::AdditionalDatum::FORMATS.include?(format)
|
|
379
|
+
|
|
380
|
+
result << AdditionalDatum.new(
|
|
381
|
+
format: format,
|
|
382
|
+
label: ad["label"].to_s.presence || "Untitled",
|
|
383
|
+
value: ad["value"]
|
|
384
|
+
)
|
|
385
|
+
end
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
|
|
389
|
+
@_additional_datums ||= [
|
|
140
390
|
AdditionalDatum.new(format: "email", label: "From", value: _mail.from),
|
|
141
391
|
AdditionalDatum.new(format: "email", label: "To", value: _mail.to),
|
|
142
392
|
AdditionalDatum.new(format: "email", label: "CCs", value: _mail.cc)
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
rules:
|
|
3
|
+
- match:
|
|
4
|
+
log.body:
|
|
5
|
+
"$regex": "event_type=Automatic"
|
|
6
|
+
"$options": "i"
|
|
7
|
+
actions:
|
|
8
|
+
- type: "create"
|
|
9
|
+
title: "{{log.subject}}"
|
|
10
|
+
description: "{{{log.body}}}"
|
|
11
|
+
# Works for:
|
|
12
|
+
# event_url=https://...
|
|
13
|
+
# event_url=<a href="https://...">
|
|
14
|
+
thirdparty_id: >-
|
|
15
|
+
{{{itemAt (regexMatch log.body 'event_url=(?:<a\s+href=")?(https?://[^"\r\n>]+)') 1}}}
|
|
16
|
+
|
|
17
|
+
- match:
|
|
18
|
+
log.body:
|
|
19
|
+
"$regex": "event_type=Manual"
|
|
20
|
+
"$options": "i"
|
|
21
|
+
actions:
|
|
22
|
+
- type: "resolve"
|
|
23
|
+
thirdparty_id: >-
|
|
24
|
+
{{{itemAt (regexMatch log.body 'event_url=(?:<a\s+href=")?(https?://[^"\r\n>]+)') 1}}}
|
|
@@ -50,15 +50,27 @@ module PagerTree::Integrations
|
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def adapter_response_inactive_subscription
|
|
53
|
-
adapter_controller&.render(status:
|
|
53
|
+
adapter_controller&.render(status: adapter_response_inactive_subscription_code, json: {code: Rack::Utils.status_code(adapter_response_inactive_subscription_code), errors: ["Customer must subscribe service plan to use this integration"]})
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def adapter_response_inactive_subscription_code
|
|
57
|
+
:payment_required
|
|
54
58
|
end
|
|
55
59
|
|
|
56
60
|
def adapter_response_upgrade
|
|
57
|
-
adapter_controller&.render(status:
|
|
61
|
+
adapter_controller&.render(status: adapter_response_upgrade_code, json: {code: Rack::Utils.status_code(adapter_response_upgrade_code), errors: ["Customer must upgrade service plan to use this integration"]})
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def adapter_response_upgrade_code
|
|
65
|
+
:payment_required
|
|
58
66
|
end
|
|
59
67
|
|
|
60
68
|
def adapter_response_maintenance_mode
|
|
61
|
-
adapter_controller&.render(status:
|
|
69
|
+
adapter_controller&.render(status: adapter_response_maintenance_mode_code, json: {code: Rack::Utils.status_code(adapter_response_maintenance_mode_code), errors: ["Integration currently in maintenance mode"]})
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def adapter_response_maintenance_mode_code
|
|
73
|
+
:service_unavailable
|
|
62
74
|
end
|
|
63
75
|
|
|
64
76
|
def adapter_thirdparty_id
|
|
@@ -39,8 +39,10 @@ module PagerTree::Integrations
|
|
|
39
39
|
def adapter_action
|
|
40
40
|
status = _freshdesk_webhook.dig("ticket_status")
|
|
41
41
|
status_i = status&.to_i
|
|
42
|
-
if
|
|
42
|
+
if !adapter_alert.present? || status_i == FD_TICKET_STATUS[:open] || status == "Open"
|
|
43
43
|
:create
|
|
44
|
+
elsif status_i == FD_TICKET_STATUS[:pending] || status == "Pending"
|
|
45
|
+
:acknowledge
|
|
44
46
|
elsif status_i == FD_TICKET_STATUS[:resolved] || status == "Resolved" || status_i == FD_TICKET_STATUS[:closed] || status == "Closed"
|
|
45
47
|
:resolve
|
|
46
48
|
else
|
|
@@ -78,13 +80,13 @@ module PagerTree::Integrations
|
|
|
78
80
|
priority_i = priority&.to_i
|
|
79
81
|
|
|
80
82
|
if priority_i == FD_TICKET_PRIORITY[:low] || priority == "Low"
|
|
81
|
-
|
|
83
|
+
"low"
|
|
82
84
|
elsif priority_i == FD_TICKET_PRIORITY[:medium] || priority == "Normal"
|
|
83
|
-
|
|
85
|
+
"medium"
|
|
84
86
|
elsif priority_i == FD_TICKET_PRIORITY[:high] || priority == "High"
|
|
85
|
-
|
|
87
|
+
"high"
|
|
86
88
|
elsif priority_i == FD_TICKET_PRIORITY[:urgent] || priority == "Urgent"
|
|
87
|
-
|
|
89
|
+
"critical"
|
|
88
90
|
end
|
|
89
91
|
end
|
|
90
92
|
|
|
@@ -40,8 +40,10 @@ module PagerTree::Integrations
|
|
|
40
40
|
status = _freshservice_webhook.dig("ticket_status")
|
|
41
41
|
status_i = status&.to_i
|
|
42
42
|
|
|
43
|
-
if status_i == FS_TICKET_STATUS[:open] || status == "Open" || status_i == FS_TICKET_STATUS[:pending]
|
|
43
|
+
if status_i == FS_TICKET_STATUS[:open] || status == "Open" || status_i == FS_TICKET_STATUS[:pending]
|
|
44
44
|
:create
|
|
45
|
+
elsif status_i == FS_TICKET_STATUS[:pending] || status == "Pending"
|
|
46
|
+
:acknowledge
|
|
45
47
|
elsif status_i == FS_TICKET_STATUS[:resolved] || status == "Resolved" || status_i == FS_TICKET_STATUS[:closed] || status == "Closed"
|
|
46
48
|
:resolve
|
|
47
49
|
else
|
|
@@ -80,13 +82,13 @@ module PagerTree::Integrations
|
|
|
80
82
|
priority_i = priority&.to_i
|
|
81
83
|
|
|
82
84
|
if priority_i == FS_TICKET_PRIORITY[:low] || priority == "Low"
|
|
83
|
-
|
|
85
|
+
"low"
|
|
84
86
|
elsif priority_i == FS_TICKET_PRIORITY[:medium] || priority == "Normal" || priority == "Medium"
|
|
85
|
-
|
|
87
|
+
"medium"
|
|
86
88
|
elsif priority_i == FS_TICKET_PRIORITY[:high] || priority == "High"
|
|
87
|
-
|
|
89
|
+
"high"
|
|
88
90
|
elsif priority_i == FS_TICKET_PRIORITY[:urgent] || priority == "Urgent"
|
|
89
|
-
|
|
91
|
+
"critical"
|
|
90
92
|
end
|
|
91
93
|
end
|
|
92
94
|
|
|
@@ -19,7 +19,7 @@ module PagerTree::Integrations
|
|
|
19
19
|
end
|
|
20
20
|
|
|
21
21
|
def adapter_thirdparty_id
|
|
22
|
-
adapter_incoming_request_params.dig("ruleId")
|
|
22
|
+
adapter_incoming_request_params.dig("ruleId") || adapter_incoming_request_params.dig("groupKey") || SecureRandom.uuid
|
|
23
23
|
end
|
|
24
24
|
|
|
25
25
|
def adapter_action
|
|
@@ -46,7 +46,7 @@ module PagerTree::Integrations
|
|
|
46
46
|
private
|
|
47
47
|
|
|
48
48
|
def _title
|
|
49
|
-
adapter_incoming_request_params.dig("ruleName")
|
|
49
|
+
adapter_incoming_request_params.dig("ruleName") || adapter_incoming_request_params.dig("title")
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
def _description
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
module PagerTree::Integrations
|
|
2
|
+
class HetrixTools::V3 < Integration
|
|
3
|
+
OPTIONS = [
|
|
4
|
+
{key: :authentication_token, type: :string, default: nil}
|
|
5
|
+
]
|
|
6
|
+
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
|
|
7
|
+
|
|
8
|
+
after_initialize do
|
|
9
|
+
self.option_authentication_token ||= nil
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def adapter_should_block_incoming?(request)
|
|
13
|
+
option_authentication_token.present? && (request.headers["Authorization"] != "Bearer #{option_authentication_token}")
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def adapter_supports_incoming?
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def adapter_supports_outgoing?
|
|
21
|
+
false
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def adapter_incoming_can_defer?
|
|
25
|
+
true
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def adapter_thirdparty_id
|
|
29
|
+
try("_adapter_thirdparty_id_#{_webhook_type}") || SecureRandom.hex(16)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def adapter_action
|
|
33
|
+
try("_adapter_action_#{_webhook_type}") || :other
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def _adapter_action_uptime
|
|
37
|
+
case adapter_incoming_request_params.dig("monitor_status")
|
|
38
|
+
when "online" then :resolve
|
|
39
|
+
when "offline" then :create
|
|
40
|
+
else
|
|
41
|
+
:other
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
def _adapter_action_blacklist
|
|
46
|
+
:create
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def _adapter_action_resource_usage
|
|
50
|
+
:create
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def adapter_process_create
|
|
54
|
+
Alert.new(
|
|
55
|
+
title: _title,
|
|
56
|
+
description: _description,
|
|
57
|
+
thirdparty_id: adapter_thirdparty_id,
|
|
58
|
+
dedup_keys: [],
|
|
59
|
+
additional_data: _additional_datums
|
|
60
|
+
)
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def _adapter_thirdparty_id_uptime
|
|
64
|
+
adapter_incoming_request_params.dig("monitor_id")
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
def _adapter_thirdparty_id_blacklist
|
|
68
|
+
SecureRandom.hex(16)
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def _adapter_thirdparty_id_resource_usage
|
|
72
|
+
adapter_incoming_request_params.dig("monitor_id")
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def _webhook_type
|
|
76
|
+
@_webhook_type ||= if _webhook_type_uptime?
|
|
77
|
+
:uptime
|
|
78
|
+
elsif _webhook_type_resource_usage?
|
|
79
|
+
:resource_usage
|
|
80
|
+
elsif _webhook_type_blacklist?
|
|
81
|
+
:blacklist
|
|
82
|
+
else
|
|
83
|
+
:unknown
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def _webhook_type_uptime?
|
|
88
|
+
adapter_incoming_request_params.dig("monitor_errors").present?
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def _webhook_type_blacklist?
|
|
92
|
+
json = adapter_incoming_request_params.dig("_json")
|
|
93
|
+
json.present? && json.is_a?(Array)
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def _webhook_type_resource_usage?
|
|
97
|
+
adapter_incoming_request_params.dig("resource_usage").present?
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
def _title
|
|
101
|
+
try("_title_#{_webhook_type}") || "HetrixTools Alert"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def _title_uptime
|
|
105
|
+
"#{adapter_incoming_request_params.dig("monitor_name")} is #{adapter_incoming_request_params.dig("monitor_status")}"
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def _title_blacklist
|
|
109
|
+
"Blacklist Alert"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def _title_resource_usage
|
|
113
|
+
"#{adapter_incoming_request_params.dig("monitor_name")} usage alert"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
def _description
|
|
117
|
+
try("_description_#{_webhook_type}") || "No description provided"
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def _description_uptime
|
|
121
|
+
"<p>#{adapter_incoming_request_params.dig("monitor_target")} is #{adapter_incoming_request_params.dig("monitor_status")}</p>" +
|
|
122
|
+
adapter_incoming_request_params.dig("monitor_errors").map { |k, v| "<p>#{k}: #{v}</p>" }.join("")
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def _description_blacklist
|
|
126
|
+
adapter_incoming_request_params.dig("_json").map { |x| "#{x["monitor"]} (#{x["blacklisted_now"]})" }.join("<br/>")
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def _description_resource_usage
|
|
130
|
+
[
|
|
131
|
+
"<p>Resource Type: #{adapter_incoming_request_params.dig("resource_usage", "resource_type")}</p>",
|
|
132
|
+
"<p>Current Usage: #{adapter_incoming_request_params.dig("resource_usage", "current_usage")}</p>",
|
|
133
|
+
"<p>Average Usage: #{adapter_incoming_request_params.dig("resource_usage", "average_usage")} / #{adapter_incoming_request_params.dig("resource_usage", "average_minutes")}m</p>"
|
|
134
|
+
].join("")
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
def _additional_datums
|
|
138
|
+
try("_additional_datums_#{_webhook_type}") || []
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def _additional_datums_uptime
|
|
142
|
+
[
|
|
143
|
+
AdditionalDatum.new(format: "datetime", label: "Timestamp", value: Time.at(adapter_incoming_request_params.dig("timestamp"))),
|
|
144
|
+
AdditionalDatum.new(format: "text", label: "Monitor Type", value: adapter_incoming_request_params.dig("monitor_type")),
|
|
145
|
+
AdditionalDatum.new(format: "link", label: "Monitor Target", value: adapter_incoming_request_params.dig("monitor_target"))
|
|
146
|
+
]
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def _additional_datums_blacklist
|
|
150
|
+
[]
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def _additional_datums_resource_usage
|
|
154
|
+
[
|
|
155
|
+
AdditionalDatum.new(format: "text", label: "Resource Type", value: adapter_incoming_request_params.dig("resource_usage", "resource_type")),
|
|
156
|
+
AdditionalDatum.new(format: "text", label: "Current Usage", value: adapter_incoming_request_params.dig("resource_usage", "current_usage"))
|
|
157
|
+
]
|
|
158
|
+
end
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -11,7 +11,7 @@ module PagerTree::Integrations
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def adapter_should_block_incoming?(request)
|
|
14
|
-
|
|
14
|
+
option_token.present? && (request.headers["honeybadger-token"] != option_token)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def adapter_supports_incoming?
|