Browse Source

Remove the Zendesk integration (unfinished, could not get it to work acceptably)

pull/211/head
Pēteris Caune 6 years ago
parent
commit
b9a24a21e7
No known key found for this signature in database GPG Key ID: E28D7679E9A9EDE2
11 changed files with 0 additions and 318 deletions
  1. +0
    -14
      hc/api/models.py
  2. +0
    -64
      hc/api/tests/test_notify.py
  3. +0
    -45
      hc/api/transports.py
  4. +0
    -68
      hc/front/tests/test_add_zendesk.py
  5. +0
    -1
      hc/front/urls.py
  6. +0
    -59
      hc/front/views.py
  7. +0
    -4
      hc/settings.py
  8. +0
    -9
      static/css/channels.css
  9. BIN
      static/img/integrations/zendesk.png
  10. +0
    -11
      templates/front/channels.html
  11. +0
    -43
      templates/integrations/add_zendesk.html

+ 0
- 14
hc/api/models.py View File

@ -309,8 +309,6 @@ class Channel(models.Model):
return transports.Telegram(self) return transports.Telegram(self)
elif self.kind == "sms": elif self.kind == "sms":
return transports.Sms(self) return transports.Sms(self)
elif self.kind == "zendesk":
return transports.Zendesk(self)
elif self.kind == "trello": elif self.kind == "trello":
return transports.Trello(self) return transports.Trello(self)
else: else:
@ -488,18 +486,6 @@ class Channel(models.Model):
doc = json.loads(self.value) doc = json.loads(self.value)
return doc["account"] return doc["account"]
@property
def zendesk_token(self):
assert self.kind == "zendesk"
doc = json.loads(self.value)
return doc["access_token"]
@property
def zendesk_subdomain(self):
assert self.kind == "zendesk"
doc = json.loads(self.value)
return doc["subdomain"]
def latest_notification(self): def latest_notification(self):
return Notification.objects.filter(channel=self).latest() return Notification.objects.filter(channel=self).latest()


+ 0
- 64
hc/api/tests/test_notify.py View File

@ -534,67 +534,3 @@ class NotifyTestCase(BaseTestCase):
self.channel.notify(self.check) self.channel.notify(self.check)
self.assertTrue(mock_post.called) self.assertTrue(mock_post.called)
@patch("hc.api.transports.requests.request")
def test_zendesk_down(self, mock_post):
v = json.dumps({"access_token": "fake-token", "subdomain": "foo"})
self._setup_data("zendesk", v)
mock_post.return_value.status_code = 200
self.channel.notify(self.check)
assert Notification.objects.count() == 1
args, kwargs = mock_post.call_args
method, url = args
self.assertEqual(method, "post")
self.assertTrue("foo.zendesk.com" in url)
payload = kwargs["json"]
self.assertEqual(payload["request"]["type"], "incident")
self.assertTrue("down" in payload["request"]["subject"])
headers = kwargs["headers"]
self.assertEqual(headers["Authorization"], "Bearer fake-token")
@patch("hc.api.transports.requests.request")
@patch("hc.api.transports.requests.get")
def test_zendesk_up(self, mock_get, mock_post):
v = json.dumps({"access_token": "fake-token", "subdomain": "foo"})
self._setup_data("zendesk", v, status="up")
mock_post.return_value.status_code = 200
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {
"requests": [{
"url": "https://foo.example.org/comment",
"description": "code is %s" % self.check.code
}]
}
self.channel.notify(self.check)
assert Notification.objects.count() == 1
args, kwargs = mock_post.call_args
self.assertTrue("foo.example.org" in args[1])
payload = kwargs["json"]
self.assertEqual(payload["request"]["type"], "incident")
self.assertTrue("UP" in payload["request"]["subject"])
headers = kwargs["headers"]
self.assertEqual(headers["Authorization"], "Bearer fake-token")
@patch("hc.api.transports.requests.request")
@patch("hc.api.transports.requests.get")
def test_zendesk_up_with_no_existing_ticket(self, mock_get, mock_post):
v = json.dumps({"access_token": "fake-token", "subdomain": "foo"})
self._setup_data("zendesk", v, status="up")
mock_get.return_value.status_code = 200
mock_get.return_value.json.return_value = {"requests": []}
self.channel.notify(self.check)
n = Notification.objects.get()
self.assertEqual(n.error, "Could not find a ticket to update")
self.assertFalse(mock_post.called)

+ 0
- 45
hc/api/transports.py View File

@ -392,51 +392,6 @@ class Sms(HttpTransport):
return self.post(url, data=data, auth=auth) return self.post(url, data=data, auth=auth)
class Zendesk(HttpTransport):
TMPL = "https://%s.zendesk.com/api/v2/requests.json"
def get_payload(self, check):
return {
"request": {
"subject": tmpl("zendesk_title.html", check=check),
"type": "incident",
"comment": {
"body": tmpl("zendesk_description.html", check=check)
}
}
}
def notify_down(self, check):
headers = {"Authorization": "Bearer %s" % self.channel.zendesk_token}
url = self.TMPL % self.channel.zendesk_subdomain
return self.post(url, headers=headers, json=self.get_payload(check))
def notify_up(self, check):
# Get the list of requests made by us, in newest-to-oldest order
url = self.TMPL % self.channel.zendesk_subdomain
url += "?sort_by=created_at&sort_order=desc"
headers = {"Authorization": "Bearer %s" % self.channel.zendesk_token}
r = requests.get(url, headers=headers, timeout=10)
if r.status_code != 200:
return "Received status code %d" % r.status_code
# Update the first request that has check.code in its description
doc = r.json()
if "requests" in doc:
for obj in doc["requests"]:
if str(check.code) in obj["description"]:
payload = self.get_payload(check)
return self.put(obj["url"], headers=headers, json=payload)
return "Could not find a ticket to update"
def notify(self, check):
if check.status == "down":
return self.notify_down(check)
if check.status == "up":
return self.notify_up(check)
class Trello(HttpTransport): class Trello(HttpTransport):
URL = 'https://api.trello.com/1/cards' URL = 'https://api.trello.com/1/cards'


+ 0
- 68
hc/front/tests/test_add_zendesk.py View File

@ -1,68 +0,0 @@
import json
from django.test.utils import override_settings
from hc.api.models import Channel
from hc.test import BaseTestCase
from mock import patch
@override_settings(ZENDESK_CLIENT_ID="t1", ZENDESK_CLIENT_SECRET="s1")
class AddZendeskTestCase(BaseTestCase):
url = "/integrations/add_zendesk/"
def test_instructions_work(self):
self.client.login(username="[email protected]", password="password")
r = self.client.get(self.url)
self.assertContains(r, "Connect Zendesk Support", status_code=200)
def test_post_works(self):
self.client.login(username="[email protected]", password="password")
r = self.client.post(self.url, {"subdomain": "foo"})
self.assertEqual(r.status_code, 302)
self.assertTrue("foo.zendesk.com" in r["Location"])
# There should now be a key in session
self.assertTrue("zendesk" in self.client.session)
@override_settings(ZENDESK_CLIENT_ID=None)
def test_it_requires_client_id(self):
self.client.login(username="[email protected]", password="password")
r = self.client.get(self.url)
self.assertEqual(r.status_code, 404)
@patch("hc.front.views.requests.post")
def test_it_handles_oauth_response(self, mock_post):
session = self.client.session
session["zendesk"] = "foo"
session["subdomain"] = "foodomain"
session.save()
oauth_response = {"access_token": "test-token"}
mock_post.return_value.text = json.dumps(oauth_response)
mock_post.return_value.json.return_value = oauth_response
url = self.url + "?code=12345678&state=foo"
self.client.login(username="[email protected]", password="password")
r = self.client.get(url, follow=True)
self.assertRedirects(r, "/integrations/")
self.assertContains(r, "The Zendesk integration has been added!")
ch = Channel.objects.get()
self.assertEqual(ch.zendesk_token, "test-token")
self.assertEqual(ch.zendesk_subdomain, "foodomain")
# Session should now be clean
self.assertFalse("zendesk" in self.client.session)
self.assertFalse("subdomain" in self.client.session)
def test_it_avoids_csrf(self):
session = self.client.session
session["zendesk"] = "foo"
session.save()
url = self.url + "?code=12345678&state=bar"
self.client.login(username="[email protected]", password="password")
r = self.client.get(url)
self.assertEqual(r.status_code, 400)

+ 0
- 1
hc/front/urls.py View File

@ -34,7 +34,6 @@ channel_urls = [
path('telegram/bot/', views.telegram_bot, name="hc-telegram-webhook"), path('telegram/bot/', views.telegram_bot, name="hc-telegram-webhook"),
path('add_telegram/', views.add_telegram, name="hc-add-telegram"), path('add_telegram/', views.add_telegram, name="hc-add-telegram"),
path('add_sms/', views.add_sms, name="hc-add-sms"), path('add_sms/', views.add_sms, name="hc-add-sms"),
path('add_zendesk/', views.add_zendesk, name="hc-add-zendesk"),
path('add_trello/', views.add_trello, name="hc-add-trello"), path('add_trello/', views.add_trello, name="hc-add-trello"),
path('add_trello/settings/', views.trello_settings, name="hc-trello-settings"), path('add_trello/settings/', views.trello_settings, name="hc-trello-settings"),
path('<uuid:code>/checks/', views.channel_checks, name="hc-channel-checks"), path('<uuid:code>/checks/', views.channel_checks, name="hc-channel-checks"),


+ 0
- 59
hc/front/views.py View File

@ -481,7 +481,6 @@ def channels(request):
"enable_telegram": settings.TELEGRAM_TOKEN is not None, "enable_telegram": settings.TELEGRAM_TOKEN is not None,
"enable_sms": settings.TWILIO_AUTH is not None, "enable_sms": settings.TWILIO_AUTH is not None,
"enable_pd": settings.PD_VENDOR_KEY is not None, "enable_pd": settings.PD_VENDOR_KEY is not None,
"enable_zendesk": settings.ZENDESK_CLIENT_ID is not None,
"enable_trello": settings.TRELLO_APP_KEY is not None, "enable_trello": settings.TRELLO_APP_KEY is not None,
"use_payments": settings.USE_PAYMENTS "use_payments": settings.USE_PAYMENTS
} }
@ -1049,64 +1048,6 @@ def add_sms(request):
return render(request, "integrations/add_sms.html", ctx) return render(request, "integrations/add_sms.html", ctx)
@login_required
def add_zendesk(request):
if settings.ZENDESK_CLIENT_ID is None:
raise Http404("zendesk integration is not available")
if request.method == "POST":
domain = request.POST.get("subdomain")
request.session["subdomain"] = domain
redirect_uri = settings.SITE_ROOT + reverse("hc-add-zendesk")
auth_url = "https://%s.zendesk.com/oauth/authorizations/new?" % domain
auth_url += urlencode({
"client_id": settings.ZENDESK_CLIENT_ID,
"redirect_uri": redirect_uri,
"response_type": "code",
"scope": "requests:read requests:write",
"state": _prepare_state(request, "zendesk")
})
return redirect(auth_url)
if "code" in request.GET:
code = _get_validated_code(request, "zendesk")
if code is None:
return HttpResponseBadRequest()
domain = request.session.pop("subdomain")
url = "https://%s.zendesk.com/oauth/tokens" % domain
redirect_uri = settings.SITE_ROOT + reverse("hc-add-zendesk")
result = requests.post(url, {
"client_id": settings.ZENDESK_CLIENT_ID,
"client_secret": settings.ZENDESK_CLIENT_SECRET,
"code": code,
"grant_type": "authorization_code",
"redirect_uri": redirect_uri,
"scope": "read"
})
doc = result.json()
if "access_token" in doc:
doc["subdomain"] = domain
channel = Channel(kind="zendesk")
channel.user = request.team.user
channel.value = json.dumps(doc)
channel.save()
channel.assign_all_checks()
messages.success(request,
"The Zendesk integration has been added!")
else:
messages.warning(request, "Something went wrong")
return redirect("hc-channels")
ctx = {"page": "channels"}
return render(request, "integrations/add_zendesk.html", ctx)
@login_required @login_required
def add_trello(request): def add_trello(request):
if settings.TRELLO_APP_KEY is None: if settings.TRELLO_APP_KEY is None:


+ 0
- 4
hc/settings.py View File

@ -184,10 +184,6 @@ TWILIO_FROM = os.getenv("TWILIO_FROM")
# PagerDuty # PagerDuty
PD_VENDOR_KEY = os.getenv("PD_VENDOR_KEY") PD_VENDOR_KEY = os.getenv("PD_VENDOR_KEY")
# Zendesk
ZENDESK_CLIENT_ID = os.getenv("ZENDESK_CLIENT_ID")
ZENDESK_CLIENT_SECRET = os.getenv("ZENDESK_CLIENT_ID")
# Trello # Trello
TRELLO_APP_KEY = os.getenv("TRELLO_APP_KEY") TRELLO_APP_KEY = os.getenv("TRELLO_APP_KEY")


+ 0
- 9
static/css/channels.css View File

@ -247,12 +247,3 @@ table.channels-table > tbody > tr > th {
.webhook-header { .webhook-header {
margin-bottom: 4px; margin-bottom: 4px;
} }
/* Add Zendesk */
.zendesk-subdomain {
margin-bottom: 8px;
}
.zendesk-subdomain input {
border-right: 0;
}

BIN
static/img/integrations/zendesk.png View File

Before After
Width: 200  |  Height: 200  |  Size: 2.9 KiB

+ 0
- 11
templates/front/channels.html View File

@ -270,17 +270,6 @@
<a href="{% url 'hc-add-opsgenie' %}" class="btn btn-primary">Add Integration</a> <a href="{% url 'hc-add-opsgenie' %}" class="btn btn-primary">Add Integration</a>
</li> </li>
{% if enable_zendesk %}
<li>
<img src="{% static 'img/integrations/zendesk.png' %}"
class="icon" alt="Zendesk icon" />
<h2>Zendesk Support</h2>
<p>Create a Zendesk support ticket when a check goes down.</p>
<a href="{% url 'hc-add-zendesk' %}" class="btn btn-primary">Add Integration</a>
</li>
{% endif %}
{% if enable_trello %} {% if enable_trello %}
<li> <li>
<img src="{% static 'img/integrations/trello.png' %}" <img src="{% static 'img/integrations/trello.png' %}"


+ 0
- 43
templates/integrations/add_zendesk.html View File

@ -1,43 +0,0 @@
{% extends "base.html" %}
{% load humanize static hc_extras %}
{% block title %}Add Zendesk - {% site_name %}{% endblock %}
{% block content %}
<div class="row">
<div class="col-sm-12">
<h1>Zendesk Support</h1>
<div class="jumbotron">
<p>
If your team uses <a href="http://zendesk.com/">Zendesk</a>,
you can set up {% site_name %} to create Zendesk support tickets
when checks go <strong>down</strong>, and comment on them when
checks go back <strong>up</strong>.
</p>
<form method="post">
{% csrf_token %}
<div class="row">
<div class="col-sm-offset-3 col-sm-6">
<div class="input-group input-group-lg zendesk-subdomain">
<input
name="subdomain"
placeholder="Subdomain"
type="text"
class="form-control">
<span class="input-group-addon">.zendesk.com</span>
</div>
<button type="submit" class="btn btn-lg btn-default btn-block">
<img class="ai-icon" src="{% static 'img/integrations/zendesk.png' %}" alt="Zendesk" />
Connect Zendesk Support
</button>
</div>
</div>
</form>
</div>
</div>
</div>
{% endblock %}

Loading…
Cancel
Save