Skip to content

Commit 6e901e9

Browse files
authored
Freshservice (#40)
1 parent 9d87e2c commit 6e901e9

File tree

11 files changed

+208
-3
lines changed

11 files changed

+208
-3
lines changed

CREATING_AN_INTEGRATION.md

+5
Original file line numberDiff line numberDiff line change
@@ -167,3 +167,8 @@ Don't forget to add `English (en)` translations for your integration. You need t
167167

168168
### Tests
169169
Please make sure to add appropriate tests for your addition (model tests, and if applicable, controller tests). **These should be quality tests.**
170+
171+
You can test locally like so:
172+
`RAILS_ENV=test dotenv -f ".env.test.local" rails db:test:prepare test`
173+
174+
In the `.env.test.local` file, you will want to set your `DATABASE_URL` variable

Gemfile

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ gem "pg", "~> 1.3"
2020

2121
# integration dependencies
2222
gem "aws-sdk-sns", "~> 1.53"
23-
gem "deferred_request", "~> 1.0"
23+
gem "deferred_request", "~> 1.0.4"
2424
gem "httparty", "~> 0.20.0"
2525
gem "sanitize", "~> 6.0"
2626
gem "twilio-ruby", "~> 5.64"

Gemfile.lock

+2-2
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ GEM
9999
debug (1.4.0)
100100
irb (>= 1.3.6)
101101
reline (>= 0.2.7)
102-
deferred_request (1.0.2)
102+
deferred_request (1.0.4)
103103
rails (>= 6.0.0)
104104
digest (3.1.0)
105105
dotenv (2.7.6)
@@ -277,7 +277,7 @@ DEPENDENCIES
277277
appraisal (~> 2.4)
278278
aws-sdk-sns (~> 1.53)
279279
debug (>= 1.0.0)
280-
deferred_request (~> 1.0)
280+
deferred_request (~> 1.0.4)
281281
dotenv-rails (~> 2.7)
282282
httparty (~> 0.20.0)
283283
pager_tree-integrations!
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
module PagerTree::Integrations
2+
class Freshservice::V3 < Integration
3+
FS_TICKET_STATUS = {
4+
open: 2,
5+
pending: 3,
6+
resolved: 4,
7+
closed: 5
8+
}
9+
10+
FS_TICKET_PRIORITY = {
11+
low: 1,
12+
medium: 2,
13+
high: 3,
14+
urgent: 4
15+
}
16+
17+
OPTIONS = []
18+
store_accessor :options, *OPTIONS.map { |x| x[:key] }.map(&:to_s), prefix: "option"
19+
20+
after_initialize do
21+
end
22+
23+
def adapter_supports_incoming?
24+
true
25+
end
26+
27+
def adapter_supports_outgoing?
28+
false
29+
end
30+
31+
def adapter_incoming_can_defer?
32+
true
33+
end
34+
35+
def adapter_thirdparty_id
36+
_freshservice_webhook.dig("ticket_public_url")
37+
end
38+
39+
def adapter_action
40+
status = _freshservice_webhook.dig("ticket_status")
41+
status_i = status&.to_i
42+
43+
if status_i == FS_TICKET_STATUS[:open] || status == "Open" || status_i == FS_TICKET_STATUS[:pending] || status == "Pending"
44+
:create
45+
elsif status_i == FS_TICKET_STATUS[:resolved] || status == "Resolved" || status_i == FS_TICKET_STATUS[:closed] || status == "Closed"
46+
:resolve
47+
else
48+
:other
49+
end
50+
end
51+
52+
def adapter_process_create
53+
Alert.new(
54+
title: _title,
55+
description: _description,
56+
urgency: _urgency,
57+
thirdparty_id: adapter_thirdparty_id,
58+
dedup_keys: [adapter_thirdparty_id],
59+
additional_data: _additional_datums
60+
)
61+
end
62+
63+
private
64+
65+
def _freshservice_webhook
66+
# this is not a mistake, the webhook says fresh**desk**, not fresh**service**
67+
adapter_incoming_request_params.dig("freshdesk_webhook")
68+
end
69+
70+
def _title
71+
_freshservice_webhook.dig("ticket_subject")
72+
end
73+
74+
def _description
75+
_freshservice_webhook.dig("ticket_description")
76+
end
77+
78+
def _urgency
79+
priority = _freshservice_webhook.dig("ticket_priority")
80+
priority_i = priority&.to_i
81+
82+
if priority_i == FS_TICKET_PRIORITY[:low] || priority == "Low"
83+
:low
84+
elsif priority_i == FS_TICKET_PRIORITY[:medium] || priority == "Normal" || priority == "Medium"
85+
:medium
86+
elsif priority_i == FS_TICKET_PRIORITY[:high] || priority == "High"
87+
:high
88+
elsif priority_i == FS_TICKET_PRIORITY[:urgent] || priority == "Urgent"
89+
:critical
90+
end
91+
end
92+
93+
def _additional_datums
94+
[
95+
AdditionalDatum.new(format: "text", label: "Ticket ID", value: _freshservice_webhook.dig("ticket_id")),
96+
AdditionalDatum.new(format: "link", label: "Ticket URL", value: _freshservice_webhook.dig("ticket_url")),
97+
AdditionalDatum.new(format: "text", label: "Requester Email", value: _freshservice_webhook.dig("ticket_email")),
98+
AdditionalDatum.new(format: "text", label: "To Email", value: _freshservice_webhook.dig("ticket_to_email")),
99+
AdditionalDatum.new(format: "text", label: "CC Email", value: _freshservice_webhook.dig("ticket_cc_email"))
100+
]
101+
end
102+
end
103+
end

app/views/pager_tree/integrations/freshservice/v3/_form_options.html.erb

Whitespace-only changes.

app/views/pager_tree/integrations/freshservice/v3/_show_options.html.erb

Whitespace-only changes.

config/locales/en.yml

+3
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,9 @@ en:
3636
freshdesk:
3737
v3:
3838
form_options:
39+
freshservice:
40+
v3:
41+
form_options:
3942
live_call_routing:
4043
twilio:
4144
v3:

scripts/wsl-ip.sh

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
grep nameserver /etc/resolv.conf | awk '{print $2}' | xargs
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# See the following for details on why we need this for the deferred request library
2+
# https://stackoverflow.com/questions/71191685/visit-psych-nodes-alias-unknown-alias-default-psychbadalias
3+
# https://discuss.rubyonrails.org/t/cve-2022-32224-possible-rce-escalation-bug-with-serialized-columns-in-active-record/81017
4+
5+
if Gem::Version.new(Rails.version) >= Gem::Version.new("7.0.3.1")
6+
ActiveRecord.yaml_column_permitted_classes = [ActiveSupport::HashWithIndifferentAccess]
7+
end

test/fixtures/pager_tree/integrations/integrations.yml

+4
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,10 @@ freshdesk_v3:
4040
type: "PagerTree::Integrations::Freshdesk::V3"
4141
# options: no_options
4242

43+
freshservice_v3:
44+
type: "PagerTree::Integrations::Freshservice::V3"
45+
# options: no_options
46+
4347
live_call_routing_twilio_v3:
4448
type: "PagerTree::Integrations::LiveCallRouting::Twilio::V3"
4549
options:
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
require "test_helper"
2+
3+
module PagerTree::Integrations
4+
class Freshservice::V3Test < ActiveSupport::TestCase
5+
include Integrateable
6+
7+
setup do
8+
@integration = pager_tree_integrations_integrations(:freshservice_v3)
9+
10+
@create_request = {
11+
# not a mistake, freshservice uses the "freshdesk" key, not "freshservice"
12+
freshdesk_webhook: {
13+
ticket_id: "123",
14+
ticket_subject: "Ticket Subject",
15+
ticket_description: "Ticket Description",
16+
ticket_priority: 1,
17+
ticket_status: 2,
18+
ticket_url: "https://desk.freshservice.com/ticket/123",
19+
ticket_public_url: "https://public.freshservice.com/ticket/123",
20+
ticket_due_by_time: "2022-05-23T08:18:26-05:00",
21+
ticket_source: "Customer",
22+
ticket_requester_name: "Joe Bob",
23+
ticket_requester_email: "[email protected]",
24+
ticket_requester_phone: nil,
25+
ticket_company_name: "Acme Corp"
26+
}
27+
}.with_indifferent_access
28+
29+
@resolve_request = @create_request.deep_dup
30+
@resolve_request[:freshdesk_webhook][:ticket_status] = "Resolved"
31+
32+
@other_request = @create_request.deep_dup
33+
@other_request[:freshdesk_webhook][:ticket_status] = "baaad"
34+
end
35+
36+
test "sanity" do
37+
assert @integration.adapter_supports_incoming?
38+
assert @integration.adapter_incoming_can_defer?
39+
assert_not @integration.adapter_supports_outgoing?
40+
assert @integration.adapter_show_alerts?
41+
assert @integration.adapter_show_logs?
42+
assert_not @integration.adapter_show_outgoing_webhook_delivery?
43+
end
44+
45+
test "adapter_actions" do
46+
@integration.adapter_incoming_request_params = @create_request
47+
assert_equal :create, @integration.adapter_action
48+
49+
@integration.adapter_incoming_request_params = @resolve_request
50+
assert_equal :resolve, @integration.adapter_action
51+
52+
@integration.adapter_incoming_request_params = @other_request
53+
assert_equal :other, @integration.adapter_action
54+
end
55+
56+
test "adapter_thirdparty_id" do
57+
@integration.adapter_incoming_request_params = @create_request
58+
assert_equal @create_request[:freshdesk_webhook][:ticket_public_url], @integration.adapter_thirdparty_id
59+
end
60+
61+
test "adapter_process_create" do
62+
@integration.adapter_incoming_request_params = @create_request
63+
64+
true_alert = Alert.new(
65+
title: @create_request[:freshdesk_webhook][:ticket_subject],
66+
description: @create_request[:freshdesk_webhook][:ticket_description],
67+
urgency: :low,
68+
thirdparty_id: @create_request[:freshdesk_webhook][:ticket_public_url],
69+
dedup_keys: [@create_request[:freshdesk_webhook][:ticket_public_url]],
70+
additional_data: [
71+
AdditionalDatum.new(format: "text", label: "Ticket ID", value: @create_request[:freshdesk_webhook].dig("ticket_id")),
72+
AdditionalDatum.new(format: "link", label: "Ticket URL", value: @create_request[:freshdesk_webhook].dig("ticket_url")),
73+
AdditionalDatum.new(format: "text", label: "Requester Email", value: @create_request[:freshdesk_webhook].dig("ticket_email")),
74+
AdditionalDatum.new(format: "text", label: "To Email", value: @create_request[:freshdesk_webhook].dig("ticket_to_email")),
75+
AdditionalDatum.new(format: "text", label: "CC Email", value: @create_request[:freshdesk_webhook].dig("ticket_cc_email"))
76+
]
77+
)
78+
79+
assert_equal true_alert.to_json, @integration.adapter_process_create.to_json
80+
end
81+
end
82+
end

0 commit comments

Comments
 (0)