Browse Source

Created an improved interface for arbitrary headers and simplified

header storage.
pull/140/head
someposer 7 years ago
parent
commit
5781ddfe4d
7 changed files with 79 additions and 22 deletions
  1. +2
    -2
      hc/api/tests/test_notify.py
  2. +1
    -1
      hc/api/transports.py
  3. +14
    -2
      hc/front/forms.py
  4. +6
    -6
      hc/front/tests/test_add_webhook.py
  5. +4
    -1
      hc/front/views.py
  6. +26
    -0
      static/js/webhook.js
  7. +26
    -10
      templates/integrations/add_webhook.html

+ 2
- 2
hc/api/tests/test_notify.py View File

@ -174,8 +174,8 @@ class NotifyTestCase(BaseTestCase):
@patch("hc.api.transports.requests.request") @patch("hc.api.transports.requests.request")
def test_webhooks_handle_headers(self, mock_request): def test_webhooks_handle_headers(self, mock_request):
self._setup_data("webhook", '{"url_down": "http://foo.com", ' self._setup_data("webhook", '{"url_down": "http://foo.com", '
'"url_up": "", "post_data": "data", "headers": '
'"{\\\"Content-Type\\\": \\\"application/json\\\"}"}')
'"url_up": "", "post_data": "data", '
'"headers": {"Content-Type": "application/json"}}')
self.channel.notify(self.check) self.channel.notify(self.check)
headers = { headers = {


+ 1
- 1
hc/api/transports.py View File

@ -167,7 +167,7 @@ class Webhook(HttpTransport):
payload = self.prepare(self.channel.post_data, check) payload = self.prepare(self.channel.post_data, check)
headers = {} headers = {}
if self.channel.headers: if self.channel.headers:
headers = json.loads(self.channel.headers)
headers = self.channel.headers
return self.post(url, data=payload.encode("utf-8"), headers=headers) return self.post(url, data=payload.encode("utf-8"), headers=headers)
else: else:
return self.get(url) return self.get(url)


+ 14
- 2
hc/front/forms.py View File

@ -66,10 +66,22 @@ class AddWebhookForm(forms.Form):
post_data = forms.CharField(max_length=1000, required=False) post_data = forms.CharField(max_length=1000, required=False)
headers = forms.CharField(max_length=1000, required=False)
def __init__(self, *args, **kwargs):
self.headers = {}
if all(k in kwargs for k in ("header_keys", "header_values")):
header_keys = kwargs.pop("header_keys")
header_values = kwargs.pop("header_values")
for i, (key, val) in enumerate(zip(header_keys, header_values)):
if key:
self.headers[key] = val
super(AddWebhookForm, self).__init__(*args, **kwargs)
def get_value(self): def get_value(self):
return json.dumps(self.cleaned_data, sort_keys=True)
val = dict(self.cleaned_data)
val["headers"] = self.headers
return json.dumps(val, sort_keys=True)
phone_validator = RegexValidator(regex='^\+\d{5,15}$', phone_validator = RegexValidator(regex='^\+\d{5,15}$',


+ 6
- 6
hc/front/tests/test_add_webhook.py View File

@ -18,7 +18,7 @@ class AddWebhookTestCase(BaseTestCase):
self.assertRedirects(r, "/integrations/") self.assertRedirects(r, "/integrations/")
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.value, '{"headers": "", "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}')
self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}')
def test_it_adds_webhook_using_team_access(self): def test_it_adds_webhook_using_team_access(self):
form = {"url_down": "http://foo.com", "url_up": "https://bar.com"} form = {"url_down": "http://foo.com", "url_up": "https://bar.com"}
@ -30,7 +30,7 @@ class AddWebhookTestCase(BaseTestCase):
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.user, self.alice) self.assertEqual(c.user, self.alice)
self.assertEqual(c.value, '{"headers": "", "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}')
self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "http://foo.com", "url_up": "https://bar.com"}')
def test_it_rejects_bad_urls(self): def test_it_rejects_bad_urls(self):
urls = [ urls = [
@ -59,7 +59,7 @@ class AddWebhookTestCase(BaseTestCase):
self.client.post(self.url, form) self.client.post(self.url, form)
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.value, '{"headers": "", "post_data": "", "url_down": "", "url_up": "http://foo.com"}')
self.assertEqual(c.value, '{"headers": {}, "post_data": "", "url_down": "", "url_up": "http://foo.com"}')
def test_it_adds_post_data(self): def test_it_adds_post_data(self):
form = {"url_down": "http://foo.com", "post_data": "hello"} form = {"url_down": "http://foo.com", "post_data": "hello"}
@ -69,15 +69,15 @@ class AddWebhookTestCase(BaseTestCase):
self.assertRedirects(r, "/integrations/") self.assertRedirects(r, "/integrations/")
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.value, '{"headers": "", "post_data": "hello", "url_down": "http://foo.com", "url_up": ""}')
self.assertEqual(c.value, '{"headers": {}, "post_data": "hello", "url_down": "http://foo.com", "url_up": ""}')
def test_it_adds_headers(self): def test_it_adds_headers(self):
form = {"url_down": "http://foo.com", "headers": '{"test": "123"}'}
form = {"url_down": "http://foo.com", "header_key[]": ["test", "test2"], "header_value[]": ["123", "abc"]}
self.client.login(username="[email protected]", password="password") self.client.login(username="[email protected]", password="password")
r = self.client.post(self.url, form) r = self.client.post(self.url, form)
self.assertRedirects(r, "/integrations/") self.assertRedirects(r, "/integrations/")
c = Channel.objects.get() c = Channel.objects.get()
self.assertEqual(c.value, '{"headers": "{\\\"test\\\": \\\"123\\\"}", "post_data": "", "url_down": "http://foo.com", "url_up": ""}')
self.assertEqual(c.value, '{"headers": {"test": "123", "test2": "abc"}, "post_data": "", "url_down": "http://foo.com", "url_up": ""}')

+ 4
- 1
hc/front/views.py View File

@ -437,7 +437,10 @@ def add_email(request):
@login_required @login_required
def add_webhook(request): def add_webhook(request):
if request.method == "POST": if request.method == "POST":
form = AddWebhookForm(request.POST)
header_keys = request.POST.getlist('header_key[]')
header_values = request.POST.getlist('header_value[]')
form = AddWebhookForm(request.POST or None,
header_keys=header_keys, header_values=header_values)
if form.is_valid(): if form.is_valid():
channel = Channel(user=request.team.user, kind="webhook") channel = Channel(user=request.team.user, kind="webhook")
channel.value = form.get_value() channel.value = form.get_value()


+ 26
- 0
static/js/webhook.js View File

@ -0,0 +1,26 @@
$(function() {
$("#webhook_headers").on("click", ".webhook_header_btn.btn-danger", function(e) {
e.preventDefault();
$(this).closest("div.row").remove();
});
$("#webhook_headers").on("click", ".webhook_header_btn.btn-info", function(e) {
e.preventDefault();
// Add new header form
$("#webhook_headers").append(
'<div class="row">\
<div class="col-xs-6 col-sm-6" style="padding-right: 0px;">\
<input type="text" class="form-control" name="header_key[]" placeholder="Key">\
</div>\
<div class="col-xs-6 col-sm-6" style="padding-left: 0px;">\
<div class="input-group">\
<input type="text" class="form-control" name="header_value[]" placeholder="Value">\
<span class="input-group-btn">\
<button class="webhook_header_btn btn btn-danger" type="button" class="btn">X</button>\
</span>\
</div>\
</div>\
</div>');
});
});

+ 26
- 10
templates/integrations/add_webhook.html View File

@ -106,20 +106,28 @@
</div> </div>
</div> </div>
<div class="form-group {{ form.headers.css_classes }}"> <div class="form-group {{ form.headers.css_classes }}">
<label class="col-sm-2 control-label">Custom Headers</label>
<div class="col-sm-10">
<input
<label class="col-sm-2 control-label">Headers</label>
<div id="webhook_headers" class="col-xs-12 col-sm-10">
<div class="row">
<div class="col-xs-6 col-sm-6" style="padding-right: 0px;">
<input type="text" class="form-control" name="header_key[]" placeholder="Key">
</div>
<div class="col-xs-6 col-sm-6" style="padding-left: 0px;">
<div class="input-group">
<input type="text" class="form-control" name="header_value[]" placeholder="Value">
<span class="input-group-btn">
<button class="webhook_header_btn btn btn-info" type="button" class="btn">+</button>
</span>
</div>
</div>
</div>
</div>
<input type="hidden"
type="text" type="text"
class="form-control" class="form-control"
name="headers" name="headers"
placeholder='{"Content-Type": "application/json"}'
value="{{ form.headers.value|default:"" }}"> value="{{ form.headers.value|default:"" }}">
{% if form.headers.errors %}
<div class="help-block">
{{ form.headers.errors|join:"" }}
</div>
{% endif %}
</div>
</div> </div>
<div class="form-group"> <div class="form-group">
<div class="col-sm-offset-2 col-sm-10"> <div class="col-sm-offset-2 col-sm-10">
@ -130,3 +138,11 @@
</div> </div>
</div> </div>
{% endblock %} {% endblock %}
{% block scripts %}
{% compress js %}
<script src="{% static 'js/jquery-2.1.4.min.js' %}"></script>
<script src="{% static 'js/bootstrap.min.js' %}"></script>
<script src="{% static 'js/webhook.js' %}"></script>
{% endcompress %}
{% endblock %}

Loading…
Cancel
Save