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
|
@@ -2,7 +2,7 @@ module PagerTree::Integrations
|
|
|
2
2
|
class Integration < PagerTree::Integrations.integration_parent_class.constantize
|
|
3
3
|
extend PagerTree::Integrations::BooleanStoreAccessor
|
|
4
4
|
|
|
5
|
-
serialize :options, JSON
|
|
5
|
+
serialize :options, coder: JSON
|
|
6
6
|
encrypts :options
|
|
7
7
|
|
|
8
8
|
GENERIC_OPTIONS = [
|
|
@@ -29,6 +29,9 @@ module PagerTree::Integrations
|
|
|
29
29
|
# the outgoing event
|
|
30
30
|
attribute :adapter_outgoing_event
|
|
31
31
|
|
|
32
|
+
def converts_to
|
|
33
|
+
end
|
|
34
|
+
|
|
32
35
|
# START basic incoming functions
|
|
33
36
|
def adapter_supports_incoming?
|
|
34
37
|
false
|
|
@@ -91,6 +94,14 @@ module PagerTree::Integrations
|
|
|
91
94
|
false
|
|
92
95
|
end
|
|
93
96
|
|
|
97
|
+
def adapter_supports_auto_aggregate?
|
|
98
|
+
true
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def adapter_supports_auto_resolve?
|
|
102
|
+
true
|
|
103
|
+
end
|
|
104
|
+
|
|
94
105
|
# START basic show functions
|
|
95
106
|
def adapter_show_alerts?
|
|
96
107
|
adapter_supports_incoming?
|
|
@@ -106,35 +117,67 @@ module PagerTree::Integrations
|
|
|
106
117
|
# END basic show functions
|
|
107
118
|
|
|
108
119
|
def adapter_response_rate_limit
|
|
109
|
-
adapter_controller&.head(
|
|
120
|
+
adapter_controller&.head(adapter_response_rate_limit_code)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def adapter_response_rate_limit_code
|
|
124
|
+
:too_many_requests
|
|
110
125
|
end
|
|
111
126
|
|
|
112
127
|
def adapter_response_disabled
|
|
113
|
-
adapter_controller&.head(
|
|
128
|
+
adapter_controller&.head(adapter_response_disabled_code)
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def adapter_response_disabled_code
|
|
132
|
+
:method_not_allowed
|
|
114
133
|
end
|
|
115
134
|
|
|
116
135
|
def adapter_response_inactive_subscription
|
|
117
|
-
adapter_controller&.head(
|
|
136
|
+
adapter_controller&.head(adapter_response_inactive_subscription_code)
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
def adapter_response_inactive_subscription_code
|
|
140
|
+
:payment_required
|
|
118
141
|
end
|
|
119
142
|
|
|
120
143
|
def adapter_response_upgrade
|
|
121
|
-
adapter_controller&.head(
|
|
144
|
+
adapter_controller&.head(adapter_response_upgrade_code)
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def adapter_response_upgrade_code
|
|
148
|
+
:payment_required
|
|
122
149
|
end
|
|
123
150
|
|
|
124
151
|
def adapter_response_maintenance_mode
|
|
125
|
-
adapter_controller&.head(
|
|
152
|
+
adapter_controller&.head(adapter_response_maintenance_mode_code)
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
def adapter_response_maintenance_mode_code
|
|
156
|
+
:ok
|
|
126
157
|
end
|
|
127
158
|
|
|
128
159
|
def adapter_response_blocked
|
|
129
|
-
adapter_controller&.head(
|
|
160
|
+
adapter_controller&.head(adapter_response_blocked_code)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
def adapter_response_blocked_code
|
|
164
|
+
:forbidden
|
|
130
165
|
end
|
|
131
166
|
|
|
132
167
|
def adapter_response_deferred
|
|
133
|
-
adapter_controller&.head(
|
|
168
|
+
adapter_controller&.head(adapter_response_deferred_code)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def adapter_response_deferred_code
|
|
172
|
+
:ok
|
|
134
173
|
end
|
|
135
174
|
|
|
136
175
|
def adapter_response_incoming
|
|
137
|
-
adapter_controller&.head(
|
|
176
|
+
adapter_controller&.head(adapter_response_incoming_code)
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def adapter_response_incoming_code
|
|
180
|
+
:ok
|
|
138
181
|
end
|
|
139
182
|
|
|
140
183
|
def cast_types
|
|
@@ -29,7 +29,7 @@ module PagerTree::Integrations
|
|
|
29
29
|
|
|
30
30
|
def adapter_action
|
|
31
31
|
event = adapter_incoming_request_params.dig("webhookEvent")
|
|
32
|
-
event == "jira:issue_created" || (
|
|
32
|
+
(event == "jira:issue_created" || (option_issue_updated == true && event == "jira:issue_updated")) ? :create : :other
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
def adapter_process_create
|
|
@@ -53,8 +53,18 @@ module PagerTree::Integrations
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def _additional_datums
|
|
56
|
+
# links look like this: "https://jira.atlassian.com/rest/api/2/issue/99291"
|
|
57
|
+
# we want them to look like thish https://jira.atlassian.com/browse/CS-6157
|
|
58
|
+
jira_id = adapter_incoming_request_params.dig("issue", "id")
|
|
59
|
+
jira_link = adapter_incoming_request_params.dig("issue", "self")
|
|
60
|
+
jira_key = adapter_incoming_request_params.dig("issue", "key")
|
|
61
|
+
|
|
62
|
+
if jira_link.present? && jira_key.present? && jira_id.present?
|
|
63
|
+
jira_link = jira_link.gsub("/rest/api/2/issue/#{jira_id}", "/browse/#{jira_key}")
|
|
64
|
+
end
|
|
65
|
+
|
|
56
66
|
[
|
|
57
|
-
AdditionalDatum.new(format: "link", label: "Issue URL", value:
|
|
67
|
+
AdditionalDatum.new(format: "link", label: "Issue URL", value: jira_link)
|
|
58
68
|
]
|
|
59
69
|
end
|
|
60
70
|
end
|
|
@@ -4,33 +4,50 @@ module PagerTree::Integrations
|
|
|
4
4
|
{key: :account_sid, type: :string, default: nil},
|
|
5
5
|
{key: :api_key, type: :string, default: nil},
|
|
6
6
|
{key: :api_secret, type: :string, default: nil},
|
|
7
|
+
{key: :api_region, type: :string, default: "ashburn.us1"},
|
|
7
8
|
{key: :force_input, type: :boolean, default: false},
|
|
8
9
|
{key: :record, type: :boolean, default: false},
|
|
9
|
-
{key: :
|
|
10
|
+
{key: :send_straight_to_voicemail, type: :boolean, default: false},
|
|
11
|
+
{key: :record_email, type: :string, default: ""},
|
|
12
|
+
{key: :banned_phone, type: :string, default: ""},
|
|
13
|
+
{key: :dial_pause, type: :integer},
|
|
14
|
+
{key: :max_wait_time, type: :integer, default: nil},
|
|
15
|
+
{key: :skip_resolve_on_hangup, type: :boolean, default: false}
|
|
10
16
|
]
|
|
11
17
|
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
|
|
12
18
|
|
|
19
|
+
API_REGIONS = ["ashburn.us1", "dublin.ie1", "sydney.au1"]
|
|
20
|
+
|
|
13
21
|
has_one_attached :option_connect_now_media
|
|
14
22
|
has_one_attached :option_music_media
|
|
15
23
|
has_one_attached :option_no_answer_media
|
|
16
24
|
has_one_attached :option_no_answer_thank_you_media
|
|
25
|
+
has_one_attached :option_no_answer_no_record_media
|
|
17
26
|
has_one_attached :option_please_wait_media
|
|
18
27
|
has_one_attached :option_welcome_media
|
|
19
28
|
|
|
20
29
|
validates :option_account_sid, presence: true
|
|
21
30
|
validates :option_api_key, presence: true
|
|
22
31
|
validates :option_api_secret, presence: true
|
|
32
|
+
validates :option_api_region, inclusion: {in: API_REGIONS}
|
|
23
33
|
validates :option_force_input, inclusion: {in: [true, false]}
|
|
24
34
|
validates :option_record, inclusion: {in: [true, false]}
|
|
35
|
+
validates :option_send_straight_to_voicemail, inclusion: {in: [true, false]}
|
|
36
|
+
validates :option_skip_resolve_on_hangup, inclusion: {in: [true, false]}
|
|
37
|
+
validates :option_max_wait_time, numericality: {greater_than_or_equal_to: 30, less_than_or_equal_to: 3600}, allow_nil: true
|
|
25
38
|
validate :validate_record_emails
|
|
26
39
|
|
|
27
40
|
after_initialize do
|
|
28
41
|
self.option_account_sid ||= nil
|
|
29
42
|
self.option_api_key ||= nil
|
|
30
43
|
self.option_api_secret ||= nil
|
|
44
|
+
self.option_api_region ||= "ashburn.us1"
|
|
31
45
|
self.option_force_input ||= false
|
|
32
46
|
self.option_record ||= false
|
|
47
|
+
self.option_send_straight_to_voicemail ||= false
|
|
33
48
|
self.option_record_email ||= ""
|
|
49
|
+
self.option_banned_phone ||= ""
|
|
50
|
+
self.option_skip_resolve_on_hangup ||= false
|
|
34
51
|
end
|
|
35
52
|
|
|
36
53
|
SPEAK_OPTIONS = {
|
|
@@ -58,12 +75,24 @@ module PagerTree::Integrations
|
|
|
58
75
|
option_no_answer_thank_you_media.present? ? option_no_answer_thank_you_media.url : URI.join(Rails.application.routes.url_helpers.root_url, "audios/thanks-for-message.mp3").to_s
|
|
59
76
|
end
|
|
60
77
|
|
|
78
|
+
def option_no_answer_no_record_media_url
|
|
79
|
+
option_no_answer_no_record_media.present? ? option_no_answer_no_record_media.url : nil
|
|
80
|
+
end
|
|
81
|
+
|
|
61
82
|
def option_record_emails=(x)
|
|
62
83
|
self.option_record_email = Array(x).join(",")
|
|
63
84
|
end
|
|
64
85
|
|
|
65
86
|
def option_record_emails
|
|
66
|
-
|
|
87
|
+
option_record_email.split(",")
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
def option_banned_phones=(x)
|
|
91
|
+
self.option_banned_phone = Array(x).join(",")
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def option_banned_phones
|
|
95
|
+
option_banned_phone.split(",")
|
|
67
96
|
end
|
|
68
97
|
|
|
69
98
|
def option_record_emails_list=(x)
|
|
@@ -82,8 +111,24 @@ module PagerTree::Integrations
|
|
|
82
111
|
option_record_emails
|
|
83
112
|
end
|
|
84
113
|
|
|
114
|
+
def option_banned_phones_list=(x)
|
|
115
|
+
# what comes in as json, via tagify
|
|
116
|
+
uniq_array = []
|
|
117
|
+
begin
|
|
118
|
+
uniq_array = JSON.parse(x).map { |y| y["value"] }.uniq
|
|
119
|
+
rescue JSON::ParserError => exception
|
|
120
|
+
Rails.logger.debug(exception)
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
self.option_banned_phones = uniq_array
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def option_banned_phones_list
|
|
127
|
+
option_banned_phones
|
|
128
|
+
end
|
|
129
|
+
|
|
85
130
|
def validate_record_emails
|
|
86
|
-
errors.add(:record_emails, "must be a valid email") if option_record_emails.any? { |x| !x.match(URI::MailTo::EMAIL_REGEXP) }
|
|
131
|
+
errors.add(:record_emails, "must be a valid email") if option_record_emails.any? { |x| !(x.match(URI::MailTo::EMAIL_REGEXP) || ["team", "team-admin", "on-call"].include?(x)) }
|
|
87
132
|
end
|
|
88
133
|
|
|
89
134
|
def adapter_supports_incoming?
|
|
@@ -94,8 +139,12 @@ module PagerTree::Integrations
|
|
|
94
139
|
true
|
|
95
140
|
end
|
|
96
141
|
|
|
142
|
+
def adapter_supports_auto_aggregate?
|
|
143
|
+
false
|
|
144
|
+
end
|
|
145
|
+
|
|
97
146
|
def adapter_outgoing_interest?(event_name)
|
|
98
|
-
["alert_acknowledged", "alert_dropped"].include?(event_name)
|
|
147
|
+
["alert_acknowledged", "alert_dropped"].include?(event_name)
|
|
99
148
|
end
|
|
100
149
|
|
|
101
150
|
def adapter_incoming_can_defer?
|
|
@@ -106,8 +155,20 @@ module PagerTree::Integrations
|
|
|
106
155
|
true
|
|
107
156
|
end
|
|
108
157
|
|
|
158
|
+
def is_banned?
|
|
159
|
+
from_number = adapter_incoming_request_params.dig("From")
|
|
160
|
+
return false unless from_number.present?
|
|
161
|
+
option_banned_phones.any? { |x| from_number.include?(x) }
|
|
162
|
+
rescue
|
|
163
|
+
false
|
|
164
|
+
end
|
|
165
|
+
|
|
109
166
|
def adapter_action
|
|
110
|
-
|
|
167
|
+
if is_banned?
|
|
168
|
+
:other
|
|
169
|
+
else
|
|
170
|
+
:create
|
|
171
|
+
end
|
|
111
172
|
end
|
|
112
173
|
|
|
113
174
|
def adapter_thirdparty_id
|
|
@@ -126,12 +187,93 @@ module PagerTree::Integrations
|
|
|
126
187
|
end
|
|
127
188
|
|
|
128
189
|
def adapter_response_incoming
|
|
190
|
+
if is_banned?
|
|
191
|
+
_twiml.reject
|
|
192
|
+
|
|
193
|
+
adapter_source_log&.sublog("Caller #{adapter_incoming_request_params.dig("From")} on blocked list. Rejected call.")
|
|
194
|
+
adapter_source_log&.save
|
|
195
|
+
|
|
196
|
+
return adapter_controller&.render(xml: _twiml.to_xml)
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if adapter_alert.meta["live_call_status_callback_set"] != true
|
|
200
|
+
begin
|
|
201
|
+
# give us status updates on the call, so we can clean up if they hang up before leaving a message
|
|
202
|
+
_call.update(
|
|
203
|
+
status_callback: PagerTree::Integrations::Engine.routes.url_helpers.call_status_live_call_routing_twilio_v3_url(id, thirdparty_id: _thirdparty_id),
|
|
204
|
+
status_callback_method: "POST",
|
|
205
|
+
url: adapter_controller&.url_for || endpoint
|
|
206
|
+
)
|
|
207
|
+
|
|
208
|
+
adapter_alert.meta["live_call_status_callback_set"] = true
|
|
209
|
+
adapter_alert.save!
|
|
210
|
+
rescue ::Twilio::REST::RestError => e
|
|
211
|
+
if e.code == 21220
|
|
212
|
+
# 21220 - Unable to update record. Call is not in-progress. Cannot redirect.
|
|
213
|
+
adapter_alert.logs.create!(message: "Updating the call for status callbacks failed. The caller has already hung up.")
|
|
214
|
+
else
|
|
215
|
+
adapter_alert.logs.create!(message: "Updating the call for status callbacks failed. #{e.message}")
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
adapter_alert.logs.create!(message: "Marking alert as resolved due to call update failure.")
|
|
219
|
+
adapter_alert.resolve!(self, force: true)
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
return adapter_controller&.render(xml: _twiml.to_xml)
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
# if this was attached to a router
|
|
226
|
+
if !adapter_alert.meta["live_call_router_team_prefix_ids"].present? && routers.size > 0 && account.subscription_feature_routers?
|
|
227
|
+
adapter_alert.logs.create!(message: "Routed to router. Attempting to get a list of teams...")
|
|
228
|
+
team_ids = []
|
|
229
|
+
default_receiver_team_ids = []
|
|
230
|
+
v3 = adapter_alert.v3_format
|
|
231
|
+
routers.each do |router|
|
|
232
|
+
if router.enabled? && router.kept?
|
|
233
|
+
actions = router.rules_eval({
|
|
234
|
+
always: true,
|
|
235
|
+
alert: v3
|
|
236
|
+
})
|
|
237
|
+
|
|
238
|
+
actions.flatten!
|
|
239
|
+
|
|
240
|
+
actions.each do |action|
|
|
241
|
+
team_ids << Array(action["receiver"]) if action["type"] == "assign"
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
# hold on to the default destination team ids in case we need them later
|
|
245
|
+
default_receiver_team_ids |= [router.default_receiver.prefix_id] if router.default_receiver.present?
|
|
246
|
+
end
|
|
247
|
+
end # end routers.each
|
|
248
|
+
|
|
249
|
+
team_ids.flatten!
|
|
250
|
+
team_ids.uniq!
|
|
251
|
+
|
|
252
|
+
# if the router didn't return any teams, use the default receiver teams
|
|
253
|
+
team_ids = default_receiver_team_ids if team_ids.size == 0
|
|
254
|
+
|
|
255
|
+
if team_ids.size > 0
|
|
256
|
+
adapter_alert.logs.create!(message: "Router provided #{team_ids.size} teams: #{team_ids}")
|
|
257
|
+
adapter_alert.meta["live_call_router_team_prefix_ids"] = team_ids
|
|
258
|
+
adapter_alert.save!
|
|
259
|
+
else
|
|
260
|
+
adapter_alert.logs.create!(message: "Router provided no teams.")
|
|
261
|
+
end
|
|
262
|
+
end # end if routers
|
|
263
|
+
|
|
129
264
|
if _teams_size == 0
|
|
265
|
+
adapter_alert.logs.create!(message: "This integration is not configured to route to any teams. Hang up.")
|
|
130
266
|
_twiml.say(message: "This integration is not configured to route to any teams. Goodbye", **SPEAK_OPTIONS)
|
|
131
267
|
_twiml.hangup
|
|
132
268
|
return adapter_controller&.render(xml: _twiml.to_xml)
|
|
133
269
|
end
|
|
134
270
|
|
|
271
|
+
if option_record && option_send_straight_to_voicemail && adapter_alert.meta["live_call_send_straight_to_voicemail"].nil?
|
|
272
|
+
# flag this call to send straight to voicemail
|
|
273
|
+
adapter_alert.meta["live_call_send_straight_to_voicemail"] = true
|
|
274
|
+
adapter_alert.save!
|
|
275
|
+
end
|
|
276
|
+
|
|
135
277
|
if !adapter_alert.meta["live_call_welcome"] && option_welcome_media.present?
|
|
136
278
|
adapter_alert.logs.create!(message: "Play welcome media to caller.")
|
|
137
279
|
_twiml.play(url: option_welcome_media.url)
|
|
@@ -142,6 +284,17 @@ module PagerTree::Integrations
|
|
|
142
284
|
if selected_team
|
|
143
285
|
adapter_alert.logs.create!(message: "Caller selected team '#{selected_team.name}'.") if _teams_size > 1 || option_force_input
|
|
144
286
|
|
|
287
|
+
if adapter_alert.meta["live_call_send_straight_to_voicemail"] == true
|
|
288
|
+
adapter_alert.destination_teams = [selected_team]
|
|
289
|
+
adapter_alert.save!
|
|
290
|
+
|
|
291
|
+
adapter_alert.logs.create!(message: "Send caller straight to voicemail (integration option).")
|
|
292
|
+
|
|
293
|
+
_twiml.redirect(PagerTree::Integrations::Engine.routes.url_helpers.dropped_live_call_routing_twilio_v3_url(id, thirdparty_id: _thirdparty_id), method: "POST")
|
|
294
|
+
|
|
295
|
+
return adapter_controller&.render(xml: _twiml.to_xml)
|
|
296
|
+
end
|
|
297
|
+
|
|
145
298
|
adapter_alert.logs.create!(message: "Play please wait media to caller.")
|
|
146
299
|
_twiml.play(url: option_please_wait_media_url)
|
|
147
300
|
friendly_name = adapter_alert.id
|
|
@@ -167,6 +320,12 @@ module PagerTree::Integrations
|
|
|
167
320
|
# kick off the alert workflow
|
|
168
321
|
adapter_alert.route_later
|
|
169
322
|
adapter_alert.logs.create!(message: "Successfully enqueued alert team workflow.")
|
|
323
|
+
|
|
324
|
+
if option_max_wait_time.present?
|
|
325
|
+
# set the max wait time for the queue
|
|
326
|
+
PagerTree::Integrations::LiveCallRouting::Twilio::V3::MaxWaitTimeJob.set(wait: option_max_wait_time.seconds).perform_later(id, adapter_alert.id)
|
|
327
|
+
adapter_alert.logs.create!(message: "Max wait time set to #{option_max_wait_time} seconds.")
|
|
328
|
+
end
|
|
170
329
|
else
|
|
171
330
|
adapter_alert.meta["live_call_repeat_count"] ||= 0
|
|
172
331
|
adapter_alert.meta["live_call_repeat_count"] += 1
|
|
@@ -181,7 +340,7 @@ module PagerTree::Integrations
|
|
|
181
340
|
end
|
|
182
341
|
end
|
|
183
342
|
else
|
|
184
|
-
adapter_alert.logs.create!(message: "Caller input bad input (too many times). Hangup.")
|
|
343
|
+
adapter_alert.logs.create!(message: "Caller input: bad input (too many times). Hangup.")
|
|
185
344
|
adapter_alert.resolve!(self)
|
|
186
345
|
_twiml.say(message: "Too much invalid input. Goodbye.", **SPEAK_OPTIONS)
|
|
187
346
|
_twiml.hangup
|
|
@@ -227,16 +386,49 @@ module PagerTree::Integrations
|
|
|
227
386
|
adapter_alert.additional_data.push(AdditionalDatum.new(format: "link", label: "Voicemail", value: recording_url).to_h)
|
|
228
387
|
adapter_alert.save!
|
|
229
388
|
|
|
230
|
-
adapter_alert.logs.create!(message: "Caller left a
|
|
389
|
+
adapter_alert.logs.create!(message: "Caller left a voicemail.")
|
|
390
|
+
|
|
391
|
+
if option_record_emails.any?
|
|
392
|
+
emails = option_record_emails.map do |x|
|
|
393
|
+
if x == "team"
|
|
394
|
+
Array(adapter_alert.destination_teams.map(&:admin_users).flatten&.map(&:email)) + Array(adapter_alert.destination_teams.map(&:member_users).flatten&.map(&:email))
|
|
395
|
+
elsif x == "team-admin"
|
|
396
|
+
Array(adapter_alert.destination_teams.map(&:admin_users).flatten&.map(&:email))
|
|
397
|
+
elsif x == "on-call"
|
|
398
|
+
adapter_alert.destination_teams.map do |t|
|
|
399
|
+
Array(t.schedule.current_oncall_event_occurrences.map(&:attendees).flatten.map(&:attendee).uniq.map(&:email))
|
|
400
|
+
end
|
|
401
|
+
else
|
|
402
|
+
x
|
|
403
|
+
end
|
|
404
|
+
end.flatten.compact_blank.uniq
|
|
231
405
|
|
|
232
|
-
|
|
233
|
-
|
|
406
|
+
adapter_alert.logs.create!(message: "Sending voicemail recording to #{emails.size} emails.")
|
|
407
|
+
emails.each do |email|
|
|
408
|
+
LiveCallRouting::Twilio::V3Mailer.with(email: email, alert: adapter_alert, from: adapter_incoming_request_params.dig("From"), recording_url: recording_url).call_recording.deliver_later
|
|
409
|
+
end
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
if adapter_alert.meta["live_call_send_straight_to_voicemail"] == true
|
|
413
|
+
adapter_alert.logs.create!(message: "Call was sent straight to voicemail and caller left a message. Routing the alert.")
|
|
414
|
+
|
|
415
|
+
# kick off the alert workflow
|
|
416
|
+
adapter_alert.route_later
|
|
417
|
+
adapter_alert.logs.create!(message: "Successfully enqueued alert team workflow.")
|
|
234
418
|
end
|
|
235
419
|
elsif option_record
|
|
420
|
+
adapter_alert.logs.create!(message: "No one is available to answer this call. Requesting voicemail recording.")
|
|
236
421
|
_twiml.play(url: option_no_answer_media_url)
|
|
237
422
|
_twiml.record(max_length: 60)
|
|
238
423
|
else
|
|
239
|
-
|
|
424
|
+
# A friendly goodbye (when the integration has been configured to not record)
|
|
425
|
+
if option_no_answer_no_record_media_url.present?
|
|
426
|
+
adapter_alert.logs.create!(message: "No one is available to answer this call. Play media. Hangup on caller.")
|
|
427
|
+
_twiml.play(url: option_no_answer_no_record_media_url)
|
|
428
|
+
else
|
|
429
|
+
adapter_alert.logs.create!(message: "No one is available to answer this call. Say message. Hangup on caller.")
|
|
430
|
+
_twiml.say(message: "No one is available to answer this call. Goodbye.", **SPEAK_OPTIONS)
|
|
431
|
+
end
|
|
240
432
|
_twiml.hangup
|
|
241
433
|
end
|
|
242
434
|
|
|
@@ -245,19 +437,43 @@ module PagerTree::Integrations
|
|
|
245
437
|
|
|
246
438
|
def adapter_process_queue_status_deferred
|
|
247
439
|
queue_result = adapter_incoming_request_params.dig("QueueResult")
|
|
248
|
-
adapter_source_log&.sublog("Processing
|
|
440
|
+
adapter_source_log&.sublog("Processing queue status #{queue_result}")
|
|
249
441
|
|
|
250
442
|
if queue_result == "hangup"
|
|
251
443
|
self.adapter_alert = alerts.find_by(thirdparty_id: _thirdparty_id)
|
|
252
444
|
adapter_alert.logs.create!(message: "Caller hungup while waiting in queue.")
|
|
253
|
-
adapter_alert.resolve!(self)
|
|
445
|
+
adapter_alert.resolve!(self, force: true) unless option_skip_resolve_on_hangup
|
|
254
446
|
queue_destroy
|
|
255
447
|
end
|
|
256
448
|
|
|
257
449
|
adapter_source_log&.save!
|
|
258
450
|
end
|
|
259
451
|
|
|
452
|
+
def adapter_process_call_status_deferred
|
|
453
|
+
call_status = adapter_incoming_request_params.dig("CallStatus")
|
|
454
|
+
adapter_source_log&.sublog("Processing call status #{call_status}")
|
|
455
|
+
|
|
456
|
+
if ["completed"].include?(call_status)
|
|
457
|
+
self.adapter_alert = alerts.find_by(thirdparty_id: _thirdparty_id)
|
|
458
|
+
|
|
459
|
+
if adapter_alert.present? && adapter_alert.meta["live_call_send_straight_to_voicemail"] == true && !adapter_alert.additional_data.any? { |x| x["label"] == "Voicemail" }
|
|
460
|
+
if option_skip_resolve_on_hangup
|
|
461
|
+
adapter_alert.logs.create!(message: "Caller hung up without leaving a message.")
|
|
462
|
+
else
|
|
463
|
+
adapter_alert.logs.create!(message: "Caller hung up without leaving a message. Marking alert as resolved.")
|
|
464
|
+
adapter_alert.resolve!(self, force: true)
|
|
465
|
+
end
|
|
466
|
+
elsif adapter_alert.present? && adapter_alert.meta["live_call_send_straight_to_voicemail"] != true && !adapter_alert.meta["live_call_queue_sid"].present?
|
|
467
|
+
adapter_alert.logs.create!(message: "Caller hungup before being put in a queue. Marking alert as resolved.")
|
|
468
|
+
adapter_alert.resolve!(self, force: true)
|
|
469
|
+
end
|
|
470
|
+
end
|
|
471
|
+
end
|
|
472
|
+
|
|
260
473
|
def adapter_process_outgoing
|
|
474
|
+
return unless adapter_alert.source_id == id
|
|
475
|
+
return if adapter_alert.meta["live_call_send_straight_to_voicemail"] == true
|
|
476
|
+
|
|
261
477
|
event = adapter_outgoing_event.event_name.to_s
|
|
262
478
|
if event == "alert_acknowledged"
|
|
263
479
|
_on_acknowledge
|
|
@@ -266,6 +482,14 @@ module PagerTree::Integrations
|
|
|
266
482
|
end
|
|
267
483
|
end
|
|
268
484
|
|
|
485
|
+
def max_wait_time_reached!(alert_id)
|
|
486
|
+
# Handle max wait time reached logic
|
|
487
|
+
self.adapter_alert = alerts.find(alert_id)
|
|
488
|
+
return unless adapter_alert&.status_open?
|
|
489
|
+
|
|
490
|
+
_on_max_wait_time_reached
|
|
491
|
+
end
|
|
492
|
+
|
|
269
493
|
private
|
|
270
494
|
|
|
271
495
|
def _thirdparty_id
|
|
@@ -273,7 +497,7 @@ module PagerTree::Integrations
|
|
|
273
497
|
end
|
|
274
498
|
|
|
275
499
|
def _title
|
|
276
|
-
"Incoming call from #{adapter_incoming_request_params.dig("From")}"
|
|
500
|
+
"Incoming call from #{adapter_incoming_request_params.dig("From")&.chars&.join(" ")}"
|
|
277
501
|
end
|
|
278
502
|
|
|
279
503
|
def _additional_datums
|
|
@@ -286,8 +510,12 @@ module PagerTree::Integrations
|
|
|
286
510
|
]
|
|
287
511
|
end
|
|
288
512
|
|
|
513
|
+
def _api_region
|
|
514
|
+
API_REGIONS.include?(option_api_region) ? option_api_region : "ashburn.us1"
|
|
515
|
+
end
|
|
516
|
+
|
|
289
517
|
def _client
|
|
290
|
-
@_client ||= ::Twilio::REST::Client.new(
|
|
518
|
+
@_client ||= ::Twilio::REST::Client.new(option_api_key, option_api_secret, option_account_sid, _api_region)
|
|
291
519
|
end
|
|
292
520
|
|
|
293
521
|
def _call
|
|
@@ -298,12 +526,20 @@ module PagerTree::Integrations
|
|
|
298
526
|
@_twiml ||= ::Twilio::TwiML::VoiceResponse.new
|
|
299
527
|
end
|
|
300
528
|
|
|
529
|
+
def _teams
|
|
530
|
+
@_teams ||= adapter_alert.meta["live_call_router_team_prefix_ids"].present? ? Team.where(account_id: account_id, prefix_id: adapter_alert.meta["live_call_router_team_prefix_ids"]) : teams
|
|
531
|
+
end
|
|
532
|
+
|
|
301
533
|
def _teams_size
|
|
302
|
-
@_teams_size ||=
|
|
534
|
+
@_teams_size ||= _teams.size
|
|
303
535
|
end
|
|
304
536
|
|
|
305
537
|
def _teams_sorted
|
|
306
|
-
@_teams_sorted ||=
|
|
538
|
+
@_teams_sorted ||= adapter_alert.meta["live_call_router_team_prefix_ids"].present? ?
|
|
539
|
+
# sorts by the order the user gave us in the router
|
|
540
|
+
_teams.sort_by { |t| adapter_alert.meta["live_call_router_team_prefix_ids"].index(t.prefix_id) } :
|
|
541
|
+
# sorts in alpha order (not ascii, but dictionary style order)
|
|
542
|
+
_teams.order(name: :asc)
|
|
307
543
|
end
|
|
308
544
|
|
|
309
545
|
def _teams_message
|
|
@@ -333,21 +569,23 @@ module PagerTree::Integrations
|
|
|
333
569
|
|
|
334
570
|
if number.present?
|
|
335
571
|
_twiml.play(url: option_connect_now_media_url)
|
|
336
|
-
_twiml.pause(length: 1)
|
|
572
|
+
_twiml.pause(length: option_dial_pause.to_i.clamp(1, 15))
|
|
337
573
|
_twiml.dial(number: number, caller_id: _call.to, answer_on_bridge: true)
|
|
338
574
|
_call.update(twiml: _twiml.to_xml)
|
|
339
575
|
# log if we successfully transfered or failed
|
|
340
|
-
adapter_alert.logs.create!(message: "
|
|
576
|
+
adapter_alert.logs.create!(message: "Transferring the call succeeded.")
|
|
341
577
|
else
|
|
342
578
|
_twiml.say(message: "Someone has acknowledged this call, but they do not have a phone number on file. Goodbye.")
|
|
343
579
|
_twiml.hangup
|
|
344
580
|
_call.update(twiml: _twiml.to_xml)
|
|
345
|
-
adapter_alert.logs.create!(message: "
|
|
581
|
+
adapter_alert.logs.create!(message: "Transferring the call failed. #{account_user.user.name} has no phone number on file.")
|
|
346
582
|
end
|
|
347
583
|
rescue ::Twilio::REST::RestError => e
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
adapter_alert.logs.create!(message: "
|
|
584
|
+
if e.code == 21220
|
|
585
|
+
# 21220 - Unable to update record. Call is not in-progress. Cannot redirect.
|
|
586
|
+
adapter_alert.logs.create!(message: "[on_acknowledge] Transferring the call failed. The caller has already hung up.")
|
|
587
|
+
else
|
|
588
|
+
adapter_alert.logs.create!(message: "[on_acknowledge] Transferring the call failed. #{e.message}")
|
|
351
589
|
end
|
|
352
590
|
end
|
|
353
591
|
|
|
@@ -355,10 +593,23 @@ module PagerTree::Integrations
|
|
|
355
593
|
# log that we are going to transer
|
|
356
594
|
adapter_alert.logs.create!(message: "The alert was dropped. Attempting to transfer the call...")
|
|
357
595
|
_call.update(url: PagerTree::Integrations::Engine.routes.url_helpers.dropped_live_call_routing_twilio_v3_url(id, thirdparty_id: adapter_alert.thirdparty_id))
|
|
358
|
-
|
|
359
|
-
|
|
596
|
+
adapter_alert.logs.create!(message: "Transferring the call succeeded.")
|
|
597
|
+
rescue ::Twilio::REST::RestError => e
|
|
598
|
+
if e.code == 21220
|
|
599
|
+
# 21220 - Unable to update record. Call is not in-progress. Cannot redirect
|
|
600
|
+
adapter_alert.logs.create!(message: "[on_drop] Transferring the call failed. The caller has already hung up.")
|
|
601
|
+
else
|
|
602
|
+
adapter_alert.logs.create!(message: "[on_drop] Transferring the call failed. #{e.message}")
|
|
603
|
+
end
|
|
604
|
+
end
|
|
605
|
+
|
|
606
|
+
def _on_max_wait_time_reached
|
|
607
|
+
# log that we are going to transfer
|
|
608
|
+
adapter_alert.logs.create!(message: "The max wait time was reached. Attempting to transfer the caller (via max wait time, to voicemail or hangup)...")
|
|
609
|
+
_call.update(url: PagerTree::Integrations::Engine.routes.url_helpers.dropped_live_call_routing_twilio_v3_url(id, thirdparty_id: adapter_alert.thirdparty_id))
|
|
610
|
+
adapter_alert.logs.create!(message: "Transferring the caller (via max wait time, to voicemail or hangup) succeeded.")
|
|
360
611
|
rescue ::Twilio::REST::RestError => e
|
|
361
|
-
adapter_alert.logs.create!(message: "
|
|
612
|
+
adapter_alert.logs.create!(message: "Transferring the caller (via max wait time, to voicemail or hangup) failed. #{e.message}")
|
|
362
613
|
end
|
|
363
614
|
|
|
364
615
|
def queue_destroy
|