Skip to content

Commit

Permalink
Microsoft Teams v4 integration (#124)
Browse files Browse the repository at this point in the history
  • Loading branch information
armiiller authored Sep 13, 2024
1 parent f6cc755 commit 536a3f7
Show file tree
Hide file tree
Showing 8 changed files with 546 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,10 @@ class Channel::MicrosoftTeams::V3 < Integration
self.option_time_zone ||= "UTC"
end

def converts_to
"PagerTree::Integrations::Channel::MicrosoftTeams::V4"
end

def adapter_supports_incoming?
false
end
Expand Down
218 changes: 218 additions & 0 deletions app/models/pager_tree/integrations/channel/microsoft_teams/v4.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
module PagerTree::Integrations
class Channel::MicrosoftTeams::V4 < Integration
OPTIONS = [
{key: :incoming_webhook_url, type: :string, default: nil},
{key: :alert_open, type: :boolean, default: false},
{key: :alert_acknowledged, type: :boolean, default: false},
{key: :alert_resolved, type: :boolean, default: false},
{key: :alert_dropped, type: :boolean, default: false},
{key: :outgoing_rules, type: :string, default: nil},
{key: :time_zone, type: :string, default: nil}
]
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"

validates :option_incoming_webhook_url, presence: true, url: {no_local: true}
validate :validate_time_zone_exists

after_initialize do
self.option_incoming_webhook_url ||= nil
self.option_alert_open ||= false
self.option_alert_acknowledged ||= false
self.option_alert_resolved ||= false
self.option_alert_dropped ||= false
self.option_outgoing_rules ||= ""
self.option_time_zone ||= "UTC"
end

def adapter_supports_incoming?
false
end

def adapter_supports_outgoing?
true
end

def adapter_show_outgoing_webhook_delivery?
true
end

def adapter_supports_title_template?
false
end

def adapter_supports_description_template?
false
end

def adapter_supports_auto_aggregate?
false
end

def adapter_supports_auto_resolve?
false
end

def adapter_outgoing_interest?(event_name)
try("option_#{event_name}") || false
end

def adapter_process_outgoing
url = adapter_outgoing_event.outgoing_rules_data.dig("webhook_url") || self.option_incoming_webhook_url
body = _blocks.merge(adapter_outgoing_event.outgoing_rules_data.except("webhook_url"))

outgoing_webhook_delivery = OutgoingWebhookDelivery.factory(
resource: self,
url: url,
body: body
)
outgoing_webhook_delivery.save!
outgoing_webhook_delivery.deliver_later

outgoing_webhook_delivery
end

private

def _alert
@_alert ||= adapter_outgoing_event.alert
end

def _blocks
{
type: "message",
attachments: [
{
contentType: "application/vnd.microsoft.card.adaptive",
contentUrl: nil,
content: {
type: "AdaptiveCard",
body: [
{
type: "Container",
backgroundImage: _color,
items: [
{
type: "TextBlock",
size: "Large",
weight: "Bolder",
text: _title
},
{
type: "ColumnSet",
columns: [
{
type: "Column",
items: [
{
type: "TextBlock",
weight: "Bolder",
text: _title,
wrap: true
},
{
type: "TextBlock",
spacing: "None",
text: "Created #{_alert.created_at.in_time_zone(option_time_zone).iso8601}",
wrap: true
}
],
width: "stretch"
}
]
}
]
},
{
type: "Container",
items: [
{
type: "FactSet",
facts: [
{
title: "Status:",
value: _alert.status&.upcase
}, {
title: "Urgency:",
value: _alert.urgency&.upcase
}, {
title: "Source:",
value: _alert.source&.name
}, {
title: "Destinations:",
value: _alert.alert_destinations&.map { |d| d.destination.name }&.join(", ")
}, {
title: "User:",
value: _alert.alert_responders&.where(role: :incident_commander)&.includes(account_user: :user)&.first&.account_user&.name
}
],
spacing: "None"
}
],
spacing: "Medium"
},
{
type: "Container",
items: [
{
type: "TextBlock",
text: _alert.description&.try(:to_plain_text),
wrap: true,
separator: true,
color: "Light"
},
{
type: "FactSet",
facts: _alert.additional_data&.map { |ad| {title: ad["label"], value: ad["value"]} } || [],
spacing: "Medium",
separator: true
}
],
spacing: "Medium",
separator: true
}
],
actions: [
{
type: "Action.OpenUrl",
title: "View",
url: Rails.application.routes.url_helpers.try(:alert_url, _alert, script_name: "/#{_alert.account_id}"),
style: "positive"
}
],
"$schema": "http://adaptivecards.io/schemas/adaptive-card.json",
version: "1.2"
}
}
]
}
end

def _title
return @_title if @_title.present?

@_title = if _alert.incident?
"Incident ##{_alert.tiny_id} [#{_alert.incident_severity.upcase.dasherize}] #{_alert.incident_message} - #{_alert.title}"
else
"Alert ##{_alert.tiny_id} #{_alert.title}"
end
end

def _color
case _alert.status
when "open", "dropped"
"https://pagertree.com/assets/img/icon/red-square.png"
when "acknowledged"
"https://pagertree.com/assets/img/icon/yellow-square.png"
when "resolved"
"https://pagertree.com/assets/img/icon/green-square.png"
else
"https://pagertree.com/assets/img/icon/grey-square.png"
end
end

def validate_time_zone_exists
return if option_time_zone.present? && ActiveSupport::TimeZone[option_time_zone].present?
errors.add(:option_time_zone, "does not exist")
end
end
end
3 changes: 3 additions & 0 deletions app/models/pager_tree/integrations/integration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class Integration < PagerTree::Integrations.integration_parent_class.constantize
# the outgoing event
attribute :adapter_outgoing_event

def converts_to
end

# START basic incoming functions
def adapter_supports_incoming?
false
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<div class="form-group group md:col-span-3">
<%= form.label :option_incoming_webhook_url %>
<%= form.text_field :option_incoming_webhook_url, class: "form-control" %>
<p class="form-hint"><%== t("pager_tree.integrations.common.option_incoming_webhook_url_hint_html") %></p>
</div>

<div class="form-group group md:col-span-3" data-controller="select">
<%= form.label :option_time_zone %>
<%= form.time_zone_select :option_time_zone, nil, {default: "UTC"}, { class: "form-control", data: { select_target: "select" }} %>
<p class="form-hint"><%== t(".option_time_zone_hint_html") %></p>
</div>

<%
opts = [
:alert_open,
:alert_acknowledged,
:alert_resolved,
:alert_dropped,
]
%>
<% opts.each do |opt| %>
<div class="form-group group">
<%= form.check_box "option_#{opt.to_s}".to_sym, class: "form-checkbox" %>
<%= form.label "option_#{opt.to_s}".to_sym, class: "inline-block" %>
<p class="form-hint md:inline-block"><%== t("pager_tree.integrations.common.option_#{opt.to_s}_hint_html") %></p>
</div>
<% end %>

</div>


<div class="grid grid-cols-1 gap-4">
<%= tag.div class: "form-group group", data: {controller: "code-editor", code_editor_language_value: "yaml", code_editor_read_only_value: false } do %>
<%= form.label :option_outgoing_rules, t("pager_tree.integrations.common.option_outgoing_rules") %>
<%= form.hidden_field :option_outgoing_rules, class: "form-control", data: {code_editor_target: "form"} %>
<%= tag.div class: "h-96", data: {code_editor_target: "editor"} do %><%= form.object.option_outgoing_rules %><% end %>
<p class="form-hint"><%== t("pager_tree.integrations.common.option_outgoing_rules_hint_html") %></p>
<% end %>
</div>
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<div class="sm:col-span-2">
<dt class="text-sm font-medium text-gray-500">
<%= t("activerecord.attributes.pager_tree/integrations/integration.option_incoming_webhook_url") %>
</dt>
<dd class="mt-1 text-sm text-gray-900">
<div class="flex items-center gap-2">
<p class="text-sm truncate">
<%= integration.option_incoming_webhook_url %>
</p>
</div>
</dd>
</div>

<div class="sm:col-span-2">
<dt class="text-sm font-medium text-gray-500">
<%= t("activerecord.attributes.pager_tree/integrations/channel/microsoft_teams/v3.option_time_zone") %>
</dt>
<dd class="mt-1 text-sm text-gray-900">
<div class="flex items-center gap-2">
<p class="text-sm truncate">
<%= integration.option_time_zone %>
</p>
</div>
</dd>
</div>

<%
opts = [
:alert_open,
:alert_acknowledged,
:alert_resolved,
:alert_dropped,
]
%>
<% opts.each do |opt| %>
<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500">
<%= t("activerecord.attributes.pager_tree/integrations/integration.option_#{opt.to_s}") %>
</dt>
<dd class="mt-1 text-sm text-gray-900">
<%= render partial: "shared/components/badge_enabled", locals: { enabled: integration.send("option_#{opt.to_s}") } %>
</dd>
</div>
<% end %>

<div class="sm:col-span-1">
<dt class="text-sm font-medium text-gray-500">
<%= t("pager_tree.integrations.common.option_outgoing_rules") %>
</dt>
<dd class="mt-1 text-sm text-gray-900">
<%= render partial: "shared/components/badge_enabled", locals: { enabled: integration.option_outgoing_rules.present? } %>
</dd>
</div>
3 changes: 3 additions & 0 deletions config/locales/en.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,9 @@ en:
v3:
form_options:
option_time_zone_hint_html: "The time zone to use when formatting dates and times"
v4:
form_options:
option_time_zone_hint_html: "The time zone to use when formatting dates and times"
cloudflare:
v3:
form_options:
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/pager_tree/integrations/integrations.yml
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,17 @@ channel_microsoft_teams_v3:
outgoing_rules: ""
time_zone: "Pacific Time (US & Canada)"

channel_microsoft_teams_v4:
type: "PagerTree::Integrations::Channel::MicrosoftTeams::V4"
options:
incoming_webhook_url: "https://statuscode.app/200"
alert_open: false
alert_acknowledged: false
alert_resolved: false
alert_dropped: false
outgoing_rules: ""
time_zone: "Pacific Time (US & Canada)"


channel_slack_v3:
type: "PagerTree::Integrations::Channel::Slack::V3"
Expand Down
Loading

0 comments on commit 536a3f7

Please sign in to comment.