Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Microsoft Teams v4 integration #124

Merged
merged 3 commits into from
Sep 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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