pager_tree-integrations 1.1.6 → 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.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/app/controllers/pager_tree/integrations/live_call_routing/twilio/v3_controller.rb +20 -0
  3. data/app/jobs/pager_tree/integrations/live_call_routing/twilio/v3/max_wait_time_job.rb +13 -0
  4. data/app/models/pager_tree/integrations/additional_datum.rb +2 -2
  5. data/app/models/pager_tree/integrations/alert.rb +2 -2
  6. data/app/models/pager_tree/integrations/aws_cloudwatch/v3.rb +15 -5
  7. data/app/models/pager_tree/integrations/boolean_store_accessor.rb +2 -2
  8. data/app/models/pager_tree/integrations/channel/hangouts/v3.rb +23 -2
  9. data/app/models/pager_tree/integrations/channel/mattermost/v3.rb +4 -0
  10. data/app/models/pager_tree/integrations/channel/microsoft_teams/v3.rb +74 -29
  11. data/app/models/pager_tree/integrations/channel/microsoft_teams/v4.rb +261 -0
  12. data/app/models/pager_tree/integrations/channel/slack/v3.rb +30 -3
  13. data/app/models/pager_tree/integrations/cloudflare/v3.rb +75 -0
  14. data/app/models/pager_tree/integrations/custom_webhook/v3.rb +206 -0
  15. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/datadog.json +12 -0
  16. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/datadog.yaml +30 -0
  17. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/generic_rules_definition.json +9 -0
  18. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/generic_rules_example.yaml +27 -0
  19. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/grafana.json +25 -0
  20. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/grafana.yaml +33 -0
  21. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/new_relic.json +40 -0
  22. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/new_relic.yaml +32 -0
  23. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/pingdom.json +30 -0
  24. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/pingdom.yaml +23 -0
  25. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_cloudwatch.json +12 -0
  26. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_cloudwatch.yaml +48 -0
  27. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_health_event.json +21 -0
  28. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_health_event.yaml +43 -0
  29. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_lambda_monitor.json +31 -0
  30. data/app/models/pager_tree/integrations/custom_webhook/v3_examples/sns_lambda_monitor.yaml +24 -0
  31. data/app/models/pager_tree/integrations/datadog/v3.rb +10 -3
  32. data/app/models/pager_tree/integrations/dynatrace/v3.rb +67 -0
  33. data/app/models/pager_tree/integrations/echoes_hq/v3.rb +138 -0
  34. data/app/models/pager_tree/integrations/elast_alert/v3.rb +24 -0
  35. data/app/models/pager_tree/integrations/email/v3.rb +272 -22
  36. data/app/models/pager_tree/integrations/email/v3_examples/example.yml +24 -0
  37. data/app/models/pager_tree/integrations/form/v3.rb +15 -3
  38. data/app/models/pager_tree/integrations/freshdesk/v3.rb +7 -5
  39. data/app/models/pager_tree/integrations/freshservice/v3.rb +7 -5
  40. data/app/models/pager_tree/integrations/grafana/v3.rb +2 -2
  41. data/app/models/pager_tree/integrations/hetrix_tools/v3.rb +160 -0
  42. data/app/models/pager_tree/integrations/honeybadger/v3.rb +1 -1
  43. data/app/models/pager_tree/integrations/hydrozen/v3.rb +6 -0
  44. data/app/models/pager_tree/integrations/integration.rb +52 -9
  45. data/app/models/pager_tree/integrations/jira_server/v3.rb +12 -2
  46. data/app/models/pager_tree/integrations/kapacitor/v3.rb +1 -1
  47. data/app/models/pager_tree/integrations/live_call_routing/twilio/v3.rb +257 -22
  48. data/app/models/pager_tree/integrations/logic_monitor/v3.rb +193 -3
  49. data/app/models/pager_tree/integrations/mattermost/outgoing_webhook/v3.rb +1 -1
  50. data/app/models/pager_tree/integrations/meta/workplace/v3.rb +230 -0
  51. data/app/models/pager_tree/integrations/new_relic/v3.rb +9 -5
  52. data/app/models/pager_tree/integrations/outgoing_event.rb +8 -0
  53. data/app/models/pager_tree/integrations/outgoing_webhook/v3.rb +108 -13
  54. data/app/models/pager_tree/integrations/outgoing_webhook_delivery/hook_relay.rb +43 -33
  55. data/app/models/pager_tree/integrations/outgoing_webhook_delivery.rb +6 -5
  56. data/app/models/pager_tree/integrations/prtg/v3.rb +2 -1
  57. data/app/models/pager_tree/integrations/pulsetic/v3.rb +70 -0
  58. data/app/models/pager_tree/integrations/scom/pagertree.ps1 +153 -0
  59. data/app/models/pager_tree/integrations/scom/v3.rb +58 -0
  60. data/app/models/pager_tree/integrations/sentry/v3.rb +477 -0
  61. data/app/models/pager_tree/integrations/server_guard24/v3.rb +1 -1
  62. data/app/models/pager_tree/integrations/sixty_six_uptime/v3.rb +118 -0
  63. data/app/models/pager_tree/integrations/slack/webhook/v3.rb +1 -1
  64. data/app/models/pager_tree/integrations/solar_winds/v3.rb +66 -2
  65. data/app/models/pager_tree/integrations/status_gator/v3.rb +69 -0
  66. data/app/models/pager_tree/integrations/uptime_kuma/v3.rb +76 -0
  67. data/app/models/pager_tree/integrations/uptime_robot/v3.rb +6 -0
  68. data/app/models/pager_tree/integrations/webhook/v3.rb +25 -7
  69. data/app/models/pager_tree/integrations/zabbix/v3.rb +95 -0
  70. data/app/models/pager_tree/integrations/zendesk/v3.rb +2 -0
  71. data/app/views/pager_tree/integrations/channel/hangouts/v3/_form_options.html.erb +7 -0
  72. data/app/views/pager_tree/integrations/channel/hangouts/v3/_show_options.html.erb +10 -0
  73. data/app/views/pager_tree/integrations/channel/microsoft_teams/v3/_form_options.html.erb +7 -0
  74. data/app/views/pager_tree/integrations/channel/microsoft_teams/v3/_show_options.html.erb +14 -0
  75. data/app/views/pager_tree/integrations/channel/microsoft_teams/v4/_form_options.html.erb +41 -0
  76. data/app/views/pager_tree/integrations/channel/microsoft_teams/v4/_show_options.html.erb +54 -0
  77. data/app/views/pager_tree/integrations/channel/slack/v3/_form_options.html.erb +6 -3
  78. data/app/views/pager_tree/integrations/channel/slack/v3/_show_options.html.erb +1 -1
  79. data/app/views/pager_tree/integrations/cloudflare/v3/_form_options.html.erb +7 -0
  80. data/app/views/pager_tree/integrations/cloudflare/v3/_show_options.html.erb +12 -0
  81. data/app/views/pager_tree/integrations/custom_webhook/v3/_form_options.html.erb +8 -0
  82. data/app/views/pager_tree/integrations/custom_webhook/v3/_show_options.html.erb +0 -0
  83. data/app/views/pager_tree/integrations/datadog/v3/_form_options.html.erb +7 -0
  84. data/app/views/pager_tree/integrations/datadog/v3/_show_options.html.erb +12 -0
  85. data/app/views/pager_tree/integrations/dynatrace/v3/_form_options.html.erb +0 -0
  86. data/app/views/pager_tree/integrations/dynatrace/v3/_show_options.html.erb +0 -0
  87. data/app/views/pager_tree/integrations/echoes_hq/v3/_form_options.html.erb +10 -0
  88. data/app/views/pager_tree/integrations/echoes_hq/v3/_show_options.html.erb +12 -0
  89. data/app/views/pager_tree/integrations/email/v3/_form_options.html.erb +41 -11
  90. data/app/views/pager_tree/integrations/email/v3/_show_options.html.erb +18 -0
  91. data/app/views/pager_tree/integrations/form/v3/_form_options.html.erb +1 -5
  92. data/app/views/pager_tree/integrations/hetrix_tools/v3/_form_options.html.erb +7 -0
  93. data/app/views/pager_tree/integrations/hetrix_tools/v3/_show_options.html.erb +12 -0
  94. data/app/views/pager_tree/integrations/hydrozen/v3/_form_options.html.erb +0 -0
  95. data/app/views/pager_tree/integrations/hydrozen/v3/_show_options.html.erb +0 -0
  96. data/app/views/pager_tree/integrations/live_call_routing/twilio/v3/_form_options.html.erb +44 -31
  97. data/app/views/pager_tree/integrations/live_call_routing/twilio/v3/_show_options.html.erb +93 -8
  98. data/app/views/pager_tree/integrations/logic_monitor/v3/_form_options.html.erb +31 -0
  99. data/app/views/pager_tree/integrations/logic_monitor/v3/_show_options.html.erb +60 -0
  100. data/app/views/pager_tree/integrations/meta/workplace/v3/_form_options.html.erb +44 -0
  101. data/app/views/pager_tree/integrations/meta/workplace/v3/_show_options.html.erb +68 -0
  102. data/app/views/pager_tree/integrations/outgoing_webhook/v3/_form_options.html.erb +17 -3
  103. data/app/views/pager_tree/integrations/outgoing_webhook/v3/_show_options.html.erb +20 -0
  104. data/app/views/pager_tree/integrations/pulsetic/v3/_form_options.html.erb +0 -0
  105. data/app/views/pager_tree/integrations/pulsetic/v3/_show_options.html.erb +0 -0
  106. data/app/views/pager_tree/integrations/scom/v3/_form_options.html.erb +0 -0
  107. data/app/views/pager_tree/integrations/scom/v3/_show_options.html.erb +0 -0
  108. data/app/views/pager_tree/integrations/sentry/v3/_form_options.html.erb +9 -0
  109. data/app/views/pager_tree/integrations/sentry/v3/_show_options.html.erb +15 -0
  110. data/app/views/pager_tree/integrations/sixty_six_uptime/v3/_form_options.html.erb +0 -0
  111. data/app/views/pager_tree/integrations/sixty_six_uptime/v3/_show_options.html.erb +0 -0
  112. data/app/views/pager_tree/integrations/solar_winds/v3/_form_options.html.erb +40 -0
  113. data/app/views/pager_tree/integrations/solar_winds/v3/_show_options.html.erb +66 -0
  114. data/app/views/pager_tree/integrations/status_gator/v3/_form_options.html.erb +13 -0
  115. data/app/views/pager_tree/integrations/status_gator/v3/_show_options.html.erb +24 -0
  116. data/app/views/pager_tree/integrations/uptime_kuma/v3/_form_options.html.erb +0 -0
  117. data/app/views/pager_tree/integrations/uptime_kuma/v3/_show_options.html.erb +0 -0
  118. data/app/views/pager_tree/integrations/webhook/v3/_form_options.html.erb +8 -0
  119. data/app/views/pager_tree/integrations/webhook/v3/_show_options.html.erb +15 -0
  120. data/app/views/pager_tree/integrations/zabbix/v3/_form_options.html.erb +7 -0
  121. data/app/views/pager_tree/integrations/zabbix/v3/_show_options.html.erb +12 -0
  122. data/config/locales/en.yml +158 -10
  123. data/config/routes.rb +1 -0
  124. data/lib/pager_tree/integrations/format_converters/yaml_json_converter.rb +67 -0
  125. data/lib/pager_tree/integrations/version.rb +1 -1
  126. data/lib/pager_tree/integrations.rb +11 -3
  127. metadata +84 -8
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 42e8ce6133c42b2f55fe684aa15e588e032ba1a36957a6b96e323775bc34bb16
4
- data.tar.gz: 6c0d6a23f3d4bc57c39e07e6eced049d8f7c54ff8fc6171d273abcc221438d17
3
+ metadata.gz: e60138a7eaeb7128332e9d7f95da9b65ad6dd06261ee1a2ee65a0ad31fe976d0
4
+ data.tar.gz: 3f53f3781b4b97087d229235d4daf839cbccb05be9b0ba39ea51aa95c7648494
5
5
  SHA512:
6
- metadata.gz: ff070b2a45a5d78a5542a91784e6e8411bd8670f213a669febcde1057e84c1fab92e48f335ff05a839b68f7a94133d27d967bd902c64cd308efc727608e118dd
7
- data.tar.gz: 3a02d1d7458a527c93c1095c0b4eb64697d1c24bcaf3563b2f0ed1bf4fa5fb3d92e5712a182d6d69072ec8587ed89cd2677053f3f7ab2a44c46cdff07f1faa0e
6
+ metadata.gz: 7c5f3e96aff985e486fd6375c6273ec7d433f011ab3164c0d611070cb1449c830c9c2a7a480e0ae1c4678e82440376c0a86cd26c93c54c76c42ca85634379325
7
+ data.tar.gz: 58ee61238c88f38785392782373f359c1af77b6173d28b45a8292dc13d406f63f31ea116e2682aa61711b33f16d2bc26cd3d5f0bb41f1c6338cef016b4093ea5
@@ -27,6 +27,12 @@ module PagerTree::Integrations
27
27
  head :ok
28
28
  end
29
29
 
30
+ def call_status
31
+ ::PagerTree::Integrations.deferred_request_class.constantize.perform_later_from_request!(request)
32
+
33
+ head :ok
34
+ end
35
+
30
36
  def queue_status_deferred(deferred_request)
31
37
  params = deferred_request.params
32
38
 
@@ -42,6 +48,20 @@ module PagerTree::Integrations
42
48
  @integration.adapter_process_queue_status_deferred
43
49
  end
44
50
 
51
+ def call_status_deferred(deferred_request)
52
+ params = deferred_request.params
53
+
54
+ id = params.dig("id")
55
+ @integration = find_integration(id)
56
+
57
+ deferred_request.account_id = @integration.account_id
58
+ @integration.adapter_source_log = @integration.logs.create!(level: :info, format: :json, message: deferred_request.request) if @integration.log_incoming_requests?
59
+ @integration.adapter_incoming_request_params = params
60
+ @integration.adapter_incoming_deferred_request = deferred_request
61
+
62
+ @integration.adapter_process_call_status_deferred
63
+ end
64
+
45
65
  private
46
66
 
47
67
  def set_integration
@@ -0,0 +1,13 @@
1
+ class PagerTree::Integrations::LiveCallRouting::Twilio::V3::MaxWaitTimeJob < ApplicationJob
2
+ queue_as :default
3
+
4
+ def perform(*args)
5
+ integration_id = args[0]
6
+ alert_id = args[1]
7
+
8
+ integration = Integration.find(integration_id)
9
+ integration.max_wait_time_reached!(alert_id)
10
+ rescue => e
11
+ Rails.logger.error("MaxWaitTimeJob failed: #{e.message}")
12
+ end
13
+ end
@@ -33,8 +33,8 @@ module PagerTree::Integrations
33
33
  def to_h
34
34
  {
35
35
  format: self.format,
36
- label: self.label,
37
- value: self.value
36
+ label: label,
37
+ value: value
38
38
  }
39
39
  end
40
40
  end
@@ -47,12 +47,12 @@ module PagerTree::Integrations
47
47
  end
48
48
 
49
49
  def incident?
50
- ActiveModel::Type::Boolean.new.cast(self.incident)
50
+ ActiveModel::Type::Boolean.new.cast(incident)
51
51
  end
52
52
 
53
53
  def push_additional_data(additional_datum)
54
54
  if additional_datum.valid?
55
- self.additional_data.push(additional_data.to_json)
55
+ additional_data.push(additional_datum.to_h)
56
56
  true
57
57
  else
58
58
  false
@@ -12,7 +12,7 @@ module PagerTree::Integrations
12
12
  end
13
13
 
14
14
  def adapter_should_block_incoming?(request)
15
- !Aws::SNS::MessageVerifier.new.authentic?(request.params)
15
+ false
16
16
  end
17
17
 
18
18
  def adapter_thirdparty_id
@@ -41,19 +41,29 @@ module PagerTree::Integrations
41
41
 
42
42
  def adapter_process_other
43
43
  if _type == "SubscriptionConfirmation" || _type == "UnsubscribeConfirmation"
44
- url = adapter_incoming_request_params.dig("SubscribeURL")
44
+ url = _sns_notification.dig("SubscribeURL")
45
45
  HTTParty.get(url) if url
46
46
  end
47
47
  end
48
48
 
49
49
  private
50
50
 
51
+ # the sns notification is sent with a text/plain but the text is formatted as json
52
+ # need parse the text into json
53
+ def _sns_notification
54
+ @_sns_notification ||= begin
55
+ JSON.parse(adapter_incoming_deferred_request.body).with_indifferent_access
56
+ rescue
57
+ {}
58
+ end
59
+ end
60
+
51
61
  def _type
52
- @_type ||= adapter_incoming_request_params.dig("Type")
62
+ @_type ||= _sns_notification.dig("Type")
53
63
  end
54
64
 
55
65
  def _message
56
- @_message ||= adapter_incoming_request_params.dig("Message")
66
+ @_message ||= _sns_notification.dig("Message")
57
67
  end
58
68
 
59
69
  def _json
@@ -67,7 +77,7 @@ module PagerTree::Integrations
67
77
 
68
78
  def _thirdparty_id
69
79
  [
70
- adapter_incoming_request_params.dig("TopicArn"),
80
+ _sns_notification.dig("TopicArn"),
71
81
  _json.dig("AlarmName")
72
82
  ].join(":")
73
83
  end
@@ -25,7 +25,7 @@
25
25
  #
26
26
  module PagerTree::Integrations::BooleanStoreAccessor
27
27
  def boolean_store_accessor(attr_name)
28
- define_method "#{attr_name}=".to_sym do |value|
28
+ define_method :"#{attr_name}=" do |value|
29
29
  values = ["1", true]
30
30
  super(values.include?(value))
31
31
  end
@@ -35,7 +35,7 @@ module PagerTree::Integrations::BooleanStoreAccessor
35
35
  !values.include?(super())
36
36
  end
37
37
 
38
- define_method "#{attr_name}?".to_sym do
38
+ define_method :"#{attr_name}?" do
39
39
  send(attr_name)
40
40
  end
41
41
  end
@@ -3,9 +3,11 @@ module PagerTree::Integrations
3
3
  OPTIONS = [
4
4
  {key: :incoming_webhook_url, type: :string, default: nil},
5
5
  {key: :alert_open, type: :boolean, default: false},
6
+ {key: :alert_assigned, type: :boolean, default: false},
6
7
  {key: :alert_acknowledged, type: :boolean, default: false},
7
8
  {key: :alert_resolved, type: :boolean, default: false},
8
9
  {key: :alert_dropped, type: :boolean, default: false},
10
+ {key: :thread_same_alert, type: :boolean, default: false},
9
11
  {key: :outgoing_rules, type: :string, default: nil}
10
12
  ]
11
13
  store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
@@ -15,9 +17,11 @@ module PagerTree::Integrations
15
17
  after_initialize do
16
18
  self.option_incoming_webhook_url ||= nil
17
19
  self.option_alert_open ||= false
20
+ self.option_alert_assigned ||= false
18
21
  self.option_alert_acknowledged ||= false
19
22
  self.option_alert_resolved ||= false
20
23
  self.option_alert_dropped ||= false
24
+ self.option_thread_same_alert ||= false
21
25
  self.option_outgoing_rules ||= ""
22
26
  end
23
27
 
@@ -41,14 +45,31 @@ module PagerTree::Integrations
41
45
  false
42
46
  end
43
47
 
48
+ def adapter_supports_auto_aggregate?
49
+ false
50
+ end
51
+
52
+ def adapter_supports_auto_resolve?
53
+ false
54
+ end
55
+
44
56
  def adapter_outgoing_interest?(event_name)
45
57
  try("option_#{event_name}") || false
46
58
  end
47
59
 
48
60
  def adapter_process_outgoing
49
- url = adapter_outgoing_event.outgoing_rules_data.dig("webhook_url") || self.option_incoming_webhook_url
61
+ url = adapter_outgoing_event.outgoing_rules_data.dig("webhook_url") || option_incoming_webhook_url
50
62
  body = _blocks.merge(adapter_outgoing_event.outgoing_rules_data.except("webhook_url"))
51
63
 
64
+ if option_thread_same_alert == true
65
+ body[:thread] = {threadKey: _alert.id}
66
+
67
+ uri = URI(url)
68
+ uri_params = URI.decode_www_form(uri.query || "").to_h.merge({messageReplyOption: "REPLY_MESSAGE_FALLBACK_TO_NEW_THREAD"})
69
+ uri.query = URI.encode_www_form(uri_params)
70
+ url = uri.to_s
71
+ end
72
+
52
73
  outgoing_webhook_delivery = OutgoingWebhookDelivery.factory(
53
74
  resource: self,
54
75
  url: url,
@@ -131,7 +152,7 @@ module PagerTree::Integrations
131
152
  text: "VIEW IN PAGERTREE",
132
153
  onClick: {
133
154
  openLink: {
134
- url: nil
155
+ url: Rails.application.routes.url_helpers.try(:alert_url, _alert, script_name: "/#{_alert.account_id}")
135
156
  }
136
157
  }
137
158
  }
@@ -2,5 +2,9 @@ module PagerTree::Integrations
2
2
  class Channel::Mattermost::V3 < Channel::Slack::V3
3
3
  # we can just piggy back the Channel::Slack::V3 since Mattermost is a clone of Slack
4
4
  # both integrations have the same exact functionality
5
+
6
+ def _alert_created_at_timestamp_formatted
7
+ _alert.created_at.utc.iso8601.to_s
8
+ end
5
9
  end
6
10
  end
@@ -6,11 +6,14 @@ module PagerTree::Integrations
6
6
  {key: :alert_acknowledged, type: :boolean, default: false},
7
7
  {key: :alert_resolved, type: :boolean, default: false},
8
8
  {key: :alert_dropped, type: :boolean, default: false},
9
- {key: :outgoing_rules, type: :string, default: nil}
9
+ {key: :outgoing_rules, type: :string, default: nil},
10
+ {key: :time_zone, type: :string, default: nil},
11
+ {key: :compact_message, type: :boolean, default: false}
10
12
  ]
11
13
  store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
12
14
 
13
15
  validates :option_incoming_webhook_url, presence: true, url: {no_local: true}
16
+ validate :validate_time_zone_exists
14
17
 
15
18
  after_initialize do
16
19
  self.option_incoming_webhook_url ||= nil
@@ -19,6 +22,12 @@ module PagerTree::Integrations
19
22
  self.option_alert_resolved ||= false
20
23
  self.option_alert_dropped ||= false
21
24
  self.option_outgoing_rules ||= ""
25
+ self.option_time_zone ||= "UTC"
26
+ self.option_compact_message ||= false
27
+ end
28
+
29
+ def converts_to
30
+ "PagerTree::Integrations::Channel::MicrosoftTeams::V4"
22
31
  end
23
32
 
24
33
  def adapter_supports_incoming?
@@ -41,12 +50,20 @@ module PagerTree::Integrations
41
50
  false
42
51
  end
43
52
 
53
+ def adapter_supports_auto_aggregate?
54
+ false
55
+ end
56
+
57
+ def adapter_supports_auto_resolve?
58
+ false
59
+ end
60
+
44
61
  def adapter_outgoing_interest?(event_name)
45
62
  try("option_#{event_name}") || false
46
63
  end
47
64
 
48
65
  def adapter_process_outgoing
49
- url = adapter_outgoing_event.outgoing_rules_data.dig("webhook_url") || self.option_incoming_webhook_url
66
+ url = adapter_outgoing_event.outgoing_rules_data.dig("webhook_url") || option_incoming_webhook_url
50
67
  body = _blocks.merge(adapter_outgoing_event.outgoing_rules_data.except("webhook_url"))
51
68
 
52
69
  outgoing_webhook_delivery = OutgoingWebhookDelivery.factory(
@@ -67,6 +84,12 @@ module PagerTree::Integrations
67
84
  end
68
85
 
69
86
  def _blocks
87
+ facts = if option_compact_message
88
+ _compact_facts
89
+ else
90
+ _full_facts
91
+ end
92
+
70
93
  {
71
94
  "@type": "MessageCard",
72
95
  "@context": "http://schema.org/extensions",
@@ -74,33 +97,8 @@ module PagerTree::Integrations
74
97
  summary: _title,
75
98
  sections: [{
76
99
  activityTitle: _title,
77
- activitySubtitle: _alert.description&.try(:to_plain_text),
78
- facts: [
79
- {
80
- name: "Status",
81
- value: _alert.status.upcase
82
- },
83
- {
84
- name: "Urgency",
85
- value: _alert.urgency.upcase
86
- },
87
- {
88
- name: "Created",
89
- value: _alert.created_at.utc
90
- },
91
- {
92
- name: "Source",
93
- value: _alert.source&.name
94
- },
95
- {
96
- name: "Destinations",
97
- value: _alert.alert_destinations&.map { |d| d.destination.name }&.join(", ")
98
- },
99
- {
100
- name: "User",
101
- value: _alert.alert_responders&.where(role: :incident_commander)&.includes(account_user: :user)&.first&.account_user&.name
102
- }
103
- ],
100
+ activitySubtitle: option_compact_message ? nil : _alert.description&.try(:to_plain_text),
101
+ facts: facts,
104
102
  markdown: true
105
103
  }],
106
104
  potentialAction: [
@@ -116,6 +114,48 @@ module PagerTree::Integrations
116
114
  }
117
115
  end
118
116
 
117
+ def _compact_facts
118
+ [
119
+ {
120
+ name: "Status",
121
+ value: _alert.status.upcase
122
+ },
123
+ {
124
+ name: "User",
125
+ value: _alert.alert_responders&.where(role: :incident_commander)&.includes(account_user: :user)&.first&.account_user&.name
126
+ }
127
+ ]
128
+ end
129
+
130
+ def _full_facts
131
+ [
132
+ {
133
+ name: "Status",
134
+ value: _alert.status.upcase
135
+ },
136
+ {
137
+ name: "Urgency",
138
+ value: _alert.urgency.upcase
139
+ },
140
+ {
141
+ name: "Created",
142
+ value: _alert.created_at.in_time_zone(option_time_zone).iso8601
143
+ },
144
+ {
145
+ name: "Source",
146
+ value: _alert.source&.name
147
+ },
148
+ {
149
+ name: "Destinations",
150
+ value: _alert.alert_destinations&.map { |d| d.destination.name }&.join(", ")
151
+ },
152
+ {
153
+ name: "User",
154
+ value: _alert.alert_responders&.where(role: :incident_commander)&.includes(account_user: :user)&.first&.account_user&.name
155
+ }
156
+ ]
157
+ end
158
+
119
159
  def _title
120
160
  return @_title if @_title.present?
121
161
 
@@ -138,5 +178,10 @@ module PagerTree::Integrations
138
178
  "#555555"
139
179
  end
140
180
  end
181
+
182
+ def validate_time_zone_exists
183
+ return if option_time_zone.present? && ActiveSupport::TimeZone[option_time_zone].present?
184
+ errors.add(:option_time_zone, "does not exist")
185
+ end
141
186
  end
142
187
  end
@@ -0,0 +1,261 @@
1
+ module PagerTree::Integrations
2
+ class Channel::MicrosoftTeams::V4 < Integration
3
+ OPTIONS = [
4
+ {key: :incoming_webhook_url, type: :string, default: nil},
5
+ {key: :alert_open, type: :boolean, default: false},
6
+ {key: :alert_acknowledged, type: :boolean, default: false},
7
+ {key: :alert_resolved, type: :boolean, default: false},
8
+ {key: :alert_dropped, type: :boolean, default: false},
9
+ {key: :outgoing_rules, type: :string, default: nil},
10
+ {key: :time_zone, type: :string, default: nil},
11
+ {key: :compact_message, type: :boolean, default: false}
12
+ ]
13
+ store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
14
+
15
+ validates :option_incoming_webhook_url, presence: true, url: {no_local: true}
16
+ validate :validate_time_zone_exists
17
+
18
+ after_initialize do
19
+ self.option_incoming_webhook_url ||= nil
20
+ self.option_alert_open ||= false
21
+ self.option_alert_acknowledged ||= false
22
+ self.option_alert_resolved ||= false
23
+ self.option_alert_dropped ||= false
24
+ self.option_outgoing_rules ||= ""
25
+ self.option_time_zone ||= "UTC"
26
+ self.option_compact_message ||= false
27
+ end
28
+
29
+ def adapter_supports_incoming?
30
+ false
31
+ end
32
+
33
+ def adapter_supports_outgoing?
34
+ true
35
+ end
36
+
37
+ def adapter_show_outgoing_webhook_delivery?
38
+ true
39
+ end
40
+
41
+ def adapter_supports_title_template?
42
+ false
43
+ end
44
+
45
+ def adapter_supports_description_template?
46
+ false
47
+ end
48
+
49
+ def adapter_supports_auto_aggregate?
50
+ false
51
+ end
52
+
53
+ def adapter_supports_auto_resolve?
54
+ false
55
+ end
56
+
57
+ def adapter_outgoing_interest?(event_name)
58
+ try("option_#{event_name}") || false
59
+ end
60
+
61
+ def adapter_process_outgoing
62
+ url = adapter_outgoing_event.outgoing_rules_data.dig("webhook_url") || option_incoming_webhook_url
63
+ body = _blocks.merge(adapter_outgoing_event.outgoing_rules_data.except("webhook_url"))
64
+
65
+ outgoing_webhook_delivery = OutgoingWebhookDelivery.factory(
66
+ resource: self,
67
+ url: url,
68
+ body: body
69
+ )
70
+ outgoing_webhook_delivery.save!
71
+ outgoing_webhook_delivery.deliver_later
72
+
73
+ outgoing_webhook_delivery
74
+ end
75
+
76
+ private
77
+
78
+ def _alert
79
+ @_alert ||= adapter_outgoing_event.alert
80
+ end
81
+
82
+ def _blocks
83
+ body = if option_compact_message
84
+ _compact_body
85
+ else
86
+ _full_body
87
+ end
88
+
89
+ {
90
+ type: "message",
91
+ attachments: [
92
+ {
93
+ contentType: "application/vnd.microsoft.card.adaptive",
94
+ contentUrl: nil,
95
+ content: {
96
+ type: "AdaptiveCard",
97
+ body: body,
98
+ actions: [
99
+ {
100
+ type: "Action.OpenUrl",
101
+ title: "View",
102
+ url: Rails.application.routes.url_helpers.try(:alert_url, _alert, script_name: "/#{_alert.account_id}"),
103
+ style: "positive"
104
+ }
105
+ ],
106
+ "$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
107
+ version: "1.2"
108
+ }
109
+ }
110
+ ]
111
+ }
112
+ end
113
+
114
+ def _compact_body
115
+ [
116
+ {
117
+ type: "Container",
118
+ backgroundImage: _color,
119
+ items: [
120
+ {
121
+ type: "TextBlock",
122
+ size: "Large",
123
+ weight: "Bolder",
124
+ text: _title
125
+ },
126
+ {
127
+ type: "FactSet",
128
+ facts: [
129
+ {
130
+ title: "Status:",
131
+ value: _alert.status&.upcase
132
+ },
133
+ {
134
+ title: "User:",
135
+ value: _alert.alert_responders&.where(role: :incident_commander)&.includes(account_user: :user)&.first&.account_user&.name
136
+ }
137
+ ],
138
+ spacing: "ExtraSmall"
139
+ }
140
+ ]
141
+ }
142
+ ]
143
+ end
144
+
145
+ def _full_body
146
+ [
147
+ {
148
+ type: "Container",
149
+ backgroundImage: _color,
150
+ items: [
151
+ {
152
+ type: "TextBlock",
153
+ size: "Large",
154
+ weight: "Bolder",
155
+ text: _title
156
+ },
157
+ {
158
+ type: "ColumnSet",
159
+ columns: [
160
+ {
161
+ type: "Column",
162
+ items: [
163
+ {
164
+ type: "TextBlock",
165
+ weight: "Bolder",
166
+ text: _title,
167
+ wrap: true
168
+ },
169
+ {
170
+ type: "TextBlock",
171
+ spacing: "None",
172
+ text: "Created #{_alert.created_at.in_time_zone(option_time_zone).iso8601}",
173
+ wrap: true
174
+ }
175
+ ],
176
+ width: "stretch"
177
+ }
178
+ ]
179
+ }
180
+ ]
181
+ },
182
+ {
183
+ type: "Container",
184
+ items: [
185
+ {
186
+ type: "FactSet",
187
+ facts: [
188
+ {
189
+ title: "Status:",
190
+ value: _alert.status&.upcase
191
+ }, {
192
+ title: "Urgency:",
193
+ value: _alert.urgency&.upcase
194
+ }, {
195
+ title: "Source:",
196
+ value: _alert.source&.name
197
+ }, {
198
+ title: "Destinations:",
199
+ value: _alert.alert_destinations&.map { |d| d.destination.name }&.join(", ")
200
+ }, {
201
+ title: "User:",
202
+ value: _alert.alert_responders&.where(role: :incident_commander)&.includes(account_user: :user)&.first&.account_user&.name
203
+ }
204
+ ],
205
+ spacing: "None"
206
+ }
207
+ ],
208
+ spacing: "Medium"
209
+ },
210
+ {
211
+ type: "Container",
212
+ items: [
213
+ {
214
+ type: "TextBlock",
215
+ text: _alert.description&.try(:to_plain_text),
216
+ wrap: true,
217
+ separator: true,
218
+ maxLines: 24
219
+ },
220
+ {
221
+ type: "FactSet",
222
+ facts: _alert.additional_data&.map { |ad| {title: ad["label"], value: Array(ad["value"]).join(", ")} } || [],
223
+ spacing: "Medium",
224
+ separator: true
225
+ }
226
+ ],
227
+ spacing: "Medium",
228
+ separator: true
229
+ }
230
+ ]
231
+ end
232
+
233
+ def _title
234
+ return @_title if @_title.present?
235
+
236
+ @_title = if _alert.incident?
237
+ "Incident ##{_alert.tiny_id} [#{_alert.incident_severity.upcase.dasherize}] #{_alert.incident_message} - #{_alert.title}"
238
+ else
239
+ "Alert ##{_alert.tiny_id} #{_alert.title}"
240
+ end
241
+ end
242
+
243
+ def _color
244
+ case _alert.status
245
+ when "open", "dropped"
246
+ "https://pagertree.com/assets/img/icon/red-square.png"
247
+ when "acknowledged"
248
+ "https://pagertree.com/assets/img/icon/yellow-square.png"
249
+ when "resolved"
250
+ "https://pagertree.com/assets/img/icon/green-square.png"
251
+ else
252
+ "https://pagertree.com/assets/img/icon/grey-square.png"
253
+ end
254
+ end
255
+
256
+ def validate_time_zone_exists
257
+ return if option_time_zone.present? && ActiveSupport::TimeZone[option_time_zone].present?
258
+ errors.add(:option_time_zone, "does not exist")
259
+ end
260
+ end
261
+ end