Improve webhook env var handling & docs

This commit is contained in:
Timothy Hobbs 2023-12-04 23:36:20 +00:00
parent c959c24b96
commit 27f295098c
3 changed files with 21 additions and 8 deletions

View File

@ -3,8 +3,10 @@ Registering webhooks to be notified of helpesk events
You can register webhooks to allow third party apps to be notified of helpdesk events. Webhooks can be registered in one of two ways: You can register webhooks to allow third party apps to be notified of helpdesk events. Webhooks can be registered in one of two ways:
1. Setting comma separated environement variables; ``HELPDESK_NEW_TICKET_WEBHOOK_URLS``& ``HELPDESK_FOLLOWUP_WEBHOOK_URLS``. 1. Setting the following environement variables to a comma separated list of URLs; ``HELPDESK_NEW_TICKET_WEBHOOK_URLS``& ``HELPDESK_FOLLOWUP_WEBHOOK_URLS``.
2. Adding getter functions to your ``settings.py``. These should return a list of strings (urls); ``HELPDESK_GET_NEW_TICKET_WEBHOOK_URLS`` & ``HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS``. 2. Adding getter functions to your ``settings.py``. These should return a list of strings (urls); ``HELPDESK_GET_NEW_TICKET_WEBHOOK_URLS`` & ``HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS``.
3. You can optionally set ``HELPDESK_WEBHOOK_TIMEOUT`` which defaults to 3 seconds. Warning, however, webhook requests are sent out sychronously on ticket update. If your webhook handling server is too slow, you should fix this rather than causing helpdesk freezes by messing with this variable.
Once these URLs are configured, a serialized copy of the ticket object will be posted to each of these URLs each time a ticket is created or followed up on respectively. Once these URLs are configured, a serialized copy of the ticket object will be posted to each of these URLs each time a ticket is created or followed up on respectively.

View File

@ -7,6 +7,7 @@ from django import forms
from django.conf import settings from django.conf import settings
from django.core.exceptions import ImproperlyConfigured from django.core.exceptions import ImproperlyConfigured
import os import os
import re
import warnings import warnings
@ -281,7 +282,7 @@ HELPDESK_ATTACHMENT_DIR_PERMS = int(getattr(settings, 'HELPDESK_ATTACHMENT_DIR_P
def get_followup_webhook_urls(): def get_followup_webhook_urls():
urls = os.environ.get('HELPDESK_FOLLOWUP_WEBHOOK_URLS', None) urls = os.environ.get('HELPDESK_FOLLOWUP_WEBHOOK_URLS', None)
if urls: if urls:
return urls.split(',') return re.split(r'[\s],[\s]', urls)
HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS = getattr(settings, 'HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS', get_followup_webhook_urls) HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS = getattr(settings, 'HELPDESK_GET_FOLLOWUP_WEBHOOK_URLS', get_followup_webhook_urls)

View File

@ -27,8 +27,12 @@ class WebhookRequestHandler(http.server.BaseHTTPRequestHandler):
}) })
if self.path == '/new-ticket': if self.path == '/new-ticket':
self.server.handled_new_ticket_requests.append(json.loads(body.decode('utf-8'))) self.server.handled_new_ticket_requests.append(json.loads(body.decode('utf-8')))
if self.path == '/new-ticket-1':
self.server.handled_new_ticket_requests_1.append(json.loads(body.decode('utf-8')))
elif self.path == '/followup': elif self.path == '/followup':
self.server.handled_follow_up_requests.append(json.loads(body.decode('utf-8'))) self.server.handled_follow_up_requests.append(json.loads(body.decode('utf-8')))
elif self.path == '/followup-1':
self.server.handled_follow_up_requests_1.append(json.loads(body.decode('utf-8')))
self.send_response(HTTPStatus.OK) self.send_response(HTTPStatus.OK)
self.end_headers() self.end_headers()
@ -42,7 +46,9 @@ class WebhookRequestHandler(http.server.BaseHTTPRequestHandler):
self.end_headers() self.end_headers()
self.wfile.write(json.dumps({ self.wfile.write(json.dumps({
'new_ticket_requests': self.server.handled_new_ticket_requests, 'new_ticket_requests': self.server.handled_new_ticket_requests,
'follow_up_requests': self.server.handled_follow_up_requests 'new_ticket_requests_1': self.server.handled_new_ticket_requests_1,
'follow_up_requests': self.server.handled_follow_up_requests,
'follow_up_requests_1': self.server.handled_follow_up_requests_1
}).encode('utf-8')) }).encode('utf-8'))
@ -51,7 +57,9 @@ class WebhookServer(http.server.HTTPServer):
super().__init__(*args, **kwargs) super().__init__(*args, **kwargs)
self.requests = [] self.requests = []
self.handled_new_ticket_requests = [] self.handled_new_ticket_requests = []
self.handled_new_ticket_requests_1 = []
self.handled_follow_up_requests = [] self.handled_follow_up_requests = []
self.handled_follow_up_requests_1 = []
def start(self): def start(self):
self.thread = threading.Thread(target=self.serve_forever) self.thread = threading.Thread(target=self.serve_forever)
@ -78,8 +86,6 @@ class WebhookTest(APITestCase):
def test_test_server(self): def test_test_server(self):
server = WebhookServer(('localhost', 8123), WebhookRequestHandler) server = WebhookServer(('localhost', 8123), WebhookRequestHandler)
os.environ['HELPDESK_NEW_TICKET_WEBHOOK_URLS'] = 'http://localhost:8123/new-ticket'
os.environ["HELPDESK_FOLLOWUP_WEBHOOK_URLS"] = 'http://localhost:8123/followup'
server.start() server.start()
requests.post('http://localhost:8123/new-ticket', json={ requests.post('http://localhost:8123/new-ticket', json={
@ -90,8 +96,8 @@ class WebhookTest(APITestCase):
def test_create_ticket_and_followup_via_api(self): def test_create_ticket_and_followup_via_api(self):
server = WebhookServer(('localhost', 8124), WebhookRequestHandler) server = WebhookServer(('localhost', 8124), WebhookRequestHandler)
os.environ['HELPDESK_NEW_TICKET_WEBHOOK_URLS'] = 'http://localhost:8124/new-ticket' os.environ['HELPDESK_NEW_TICKET_WEBHOOK_URLS'] = 'http://localhost:8124/new-ticket, http://localhost:8124/new-ticket-1'
os.environ["HELPDESK_FOLLOWUP_WEBHOOK_URLS"] = 'http://localhost:8124/followup' os.environ["HELPDESK_FOLLOWUP_WEBHOOK_URLS"] = 'http://localhost:8124/followup , http://localhost:8124/followup-1'
server.start() server.start()
response = self.client.post('/api/tickets/', { response = self.client.post('/api/tickets/', {
@ -104,9 +110,11 @@ class WebhookTest(APITestCase):
self.assertEqual(response.status_code, HTTP_201_CREATED) self.assertEqual(response.status_code, HTTP_201_CREATED)
handled_webhook_requests = requests.get('http://localhost:8124/get-past-requests') handled_webhook_requests = requests.get('http://localhost:8124/get-past-requests')
handled_webhook_requests = handled_webhook_requests.json() handled_webhook_requests = handled_webhook_requests.json()
self.assertTrue(len(handled_webhook_requests['new_ticket_requests']) >= 1) self.assertTrue(len(handled_webhook_requests['new_ticket_requests']) == 1)
self.assertTrue(len(handled_webhook_requests['new_ticket_requests_1']) == 1)
self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 0) self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 0)
self.assertEqual(handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["title"], "Test title") self.assertEqual(handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["title"], "Test title")
self.assertEqual(handled_webhook_requests['new_ticket_requests_1'][-1]["ticket"]["title"], "Test title")
self.assertEqual(handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["description"], "Test description\nMulti lines") self.assertEqual(handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["description"], "Test description\nMulti lines")
response = self.client.post('/api/followups/', { response = self.client.post('/api/followups/', {
'ticket': handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["id"], 'ticket': handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["id"],
@ -116,7 +124,9 @@ class WebhookTest(APITestCase):
handled_webhook_requests = requests.get('http://localhost:8124/get-past-requests') handled_webhook_requests = requests.get('http://localhost:8124/get-past-requests')
handled_webhook_requests = handled_webhook_requests.json() handled_webhook_requests = handled_webhook_requests.json()
self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 1) self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 1)
self.assertEqual(len(handled_webhook_requests['follow_up_requests_1']), 1)
self.assertEqual(handled_webhook_requests['follow_up_requests'][-1]["ticket"]["followup_set"][-1]["comment"], "Test comment") self.assertEqual(handled_webhook_requests['follow_up_requests'][-1]["ticket"]["followup_set"][-1]["comment"], "Test comment")
self.assertEqual(handled_webhook_requests['follow_up_requests_1'][-1]["ticket"]["followup_set"][-1]["comment"], "Test comment")
server.stop() server.stop()
def test_create_ticket_and_followup_via_email(self): def test_create_ticket_and_followup_via_email(self):