2023-12-02 19:09:34 +01:00
|
|
|
from django.contrib.auth.models import User
|
2023-12-27 20:34:56 +01:00
|
|
|
from helpdesk.models import Queue, CustomField, TicketCustomFieldValue, Ticket
|
|
|
|
from helpdesk.serializers import TicketSerializer
|
2023-12-02 19:09:34 +01:00
|
|
|
from rest_framework.status import (
|
|
|
|
HTTP_201_CREATED
|
|
|
|
)
|
|
|
|
from rest_framework.test import APITestCase
|
|
|
|
import json
|
|
|
|
import os
|
|
|
|
import requests
|
|
|
|
import logging
|
|
|
|
|
|
|
|
# Set up a test weberver listeining on localhost:8123 for webhooks
|
|
|
|
import http.server
|
|
|
|
import threading
|
|
|
|
from http import HTTPStatus
|
|
|
|
|
|
|
|
class WebhookRequestHandler(http.server.BaseHTTPRequestHandler):
|
|
|
|
server: "WebhookServer"
|
|
|
|
|
|
|
|
def do_POST(self):
|
|
|
|
content_length = int(self.headers['Content-Length'])
|
|
|
|
body = self.rfile.read(content_length)
|
|
|
|
self.server.requests.append({
|
|
|
|
'path': self.path,
|
|
|
|
'headers': self.headers,
|
|
|
|
'body': body
|
|
|
|
})
|
|
|
|
if self.path == '/new-ticket':
|
|
|
|
self.server.handled_new_ticket_requests.append(json.loads(body.decode('utf-8')))
|
2023-12-05 00:36:20 +01:00
|
|
|
if self.path == '/new-ticket-1':
|
|
|
|
self.server.handled_new_ticket_requests_1.append(json.loads(body.decode('utf-8')))
|
2023-12-02 19:09:34 +01:00
|
|
|
elif self.path == '/followup':
|
|
|
|
self.server.handled_follow_up_requests.append(json.loads(body.decode('utf-8')))
|
2023-12-05 00:36:20 +01:00
|
|
|
elif self.path == '/followup-1':
|
|
|
|
self.server.handled_follow_up_requests_1.append(json.loads(body.decode('utf-8')))
|
2023-12-02 19:09:34 +01:00
|
|
|
self.send_response(HTTPStatus.OK)
|
|
|
|
self.end_headers()
|
|
|
|
|
|
|
|
def do_GET(self):
|
|
|
|
if not self.path == '/get-past-requests':
|
|
|
|
self.send_response(HTTPStatus.NOT_FOUND)
|
|
|
|
self.end_headers()
|
|
|
|
return
|
|
|
|
self.send_response(HTTPStatus.OK)
|
|
|
|
self.send_header('Content-type', 'application/json')
|
|
|
|
self.end_headers()
|
|
|
|
self.wfile.write(json.dumps({
|
|
|
|
'new_ticket_requests': self.server.handled_new_ticket_requests,
|
2023-12-05 00:36:20 +01:00
|
|
|
'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
|
2023-12-02 19:09:34 +01:00
|
|
|
}).encode('utf-8'))
|
|
|
|
|
|
|
|
|
|
|
|
class WebhookServer(http.server.HTTPServer):
|
|
|
|
def __init__(self, *args, **kwargs):
|
|
|
|
super().__init__(*args, **kwargs)
|
|
|
|
self.requests = []
|
|
|
|
self.handled_new_ticket_requests = []
|
2023-12-05 00:36:20 +01:00
|
|
|
self.handled_new_ticket_requests_1 = []
|
2023-12-02 19:09:34 +01:00
|
|
|
self.handled_follow_up_requests = []
|
2023-12-05 00:36:20 +01:00
|
|
|
self.handled_follow_up_requests_1 = []
|
2023-12-02 19:09:34 +01:00
|
|
|
|
|
|
|
def start(self):
|
|
|
|
self.thread = threading.Thread(target=self.serve_forever)
|
|
|
|
self.thread.daemon = True # Set as a daemon so it will be killed once the main thread is dead
|
|
|
|
self.thread.start()
|
|
|
|
|
|
|
|
def stop(self):
|
|
|
|
self.shutdown()
|
|
|
|
self.server_close()
|
|
|
|
self.thread.join()
|
|
|
|
|
|
|
|
|
|
|
|
class WebhookTest(APITestCase):
|
|
|
|
@classmethod
|
|
|
|
def setUpTestData(cls):
|
|
|
|
cls.queue = Queue.objects.create(
|
|
|
|
title='Test Queue',
|
|
|
|
slug='test-queue',
|
|
|
|
)
|
|
|
|
|
|
|
|
def setUp(self):
|
|
|
|
staff_user = User.objects.create_user(username='test', is_staff=True)
|
2023-12-27 20:34:56 +01:00
|
|
|
CustomField(
|
|
|
|
name="my_custom_field",
|
|
|
|
data_type="varchar",
|
|
|
|
required=False,
|
|
|
|
).save()
|
2023-12-02 19:09:34 +01:00
|
|
|
self.client.force_authenticate(staff_user)
|
|
|
|
|
|
|
|
def test_test_server(self):
|
|
|
|
server = WebhookServer(('localhost', 8123), WebhookRequestHandler)
|
|
|
|
server.start()
|
|
|
|
requests.post('http://localhost:8123/new-ticket', json={
|
|
|
|
"foo": "bar"})
|
|
|
|
handled_webhook_requests = requests.get('http://localhost:8123/get-past-requests').json()
|
|
|
|
self.assertEqual(handled_webhook_requests['new_ticket_requests'][-1]["foo"], "bar")
|
|
|
|
server.stop()
|
|
|
|
|
|
|
|
def test_create_ticket_and_followup_via_api(self):
|
|
|
|
server = WebhookServer(('localhost', 8124), WebhookRequestHandler)
|
2023-12-05 00:36:20 +01:00
|
|
|
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 , http://localhost:8124/followup-1'
|
2023-12-02 19:09:34 +01:00
|
|
|
server.start()
|
|
|
|
|
|
|
|
response = self.client.post('/api/tickets/', {
|
|
|
|
'queue': self.queue.id,
|
|
|
|
'title': 'Test title',
|
|
|
|
'description': 'Test description\nMulti lines',
|
|
|
|
'submitter_email': 'test@mail.com',
|
2023-12-27 20:34:56 +01:00
|
|
|
'priority': 4,
|
|
|
|
'custom_my_custom_field': 'custom value',
|
2023-12-02 19:09:34 +01:00
|
|
|
})
|
2023-12-27 20:34:56 +01:00
|
|
|
self.assertEqual(CustomField.objects.all().first().name, "my_custom_field")
|
|
|
|
self.assertEqual(TicketCustomFieldValue.objects.get(ticket=response.data['id']).value, 'custom value')
|
2023-12-02 19:09:34 +01:00
|
|
|
self.assertEqual(response.status_code, HTTP_201_CREATED)
|
|
|
|
handled_webhook_requests = requests.get('http://localhost:8124/get-past-requests')
|
|
|
|
handled_webhook_requests = handled_webhook_requests.json()
|
2023-12-05 00:36:20 +01:00
|
|
|
self.assertTrue(len(handled_webhook_requests['new_ticket_requests']) == 1)
|
|
|
|
self.assertTrue(len(handled_webhook_requests['new_ticket_requests_1']) == 1)
|
2023-12-02 19:09:34 +01:00
|
|
|
self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 0)
|
|
|
|
self.assertEqual(handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["title"], "Test title")
|
2023-12-05 00:36:20 +01:00
|
|
|
self.assertEqual(handled_webhook_requests['new_ticket_requests_1'][-1]["ticket"]["title"], "Test title")
|
2023-12-02 19:09:34 +01:00
|
|
|
self.assertEqual(handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["description"], "Test description\nMulti lines")
|
2023-12-27 20:34:56 +01:00
|
|
|
ticket = Ticket.objects.get(id=handled_webhook_requests["new_ticket_requests"][-1]["ticket"]["id"])
|
|
|
|
ticket.set_custom_field_values()
|
|
|
|
serializer = TicketSerializer(ticket)
|
|
|
|
self.assertEqual(
|
|
|
|
list(sorted(serializer.fields.keys())),
|
|
|
|
['assigned_to',
|
|
|
|
'attachment',
|
|
|
|
'custom_my_custom_field',
|
|
|
|
'description',
|
|
|
|
'due_date',
|
|
|
|
'followup_set',
|
|
|
|
'id',
|
|
|
|
'merged_to',
|
|
|
|
'on_hold',
|
|
|
|
'priority',
|
|
|
|
'queue',
|
|
|
|
'resolution',
|
|
|
|
'status',
|
|
|
|
'submitter_email',
|
|
|
|
'title']
|
|
|
|
)
|
|
|
|
self.assertEqual(serializer.data, handled_webhook_requests["new_ticket_requests"][-1]["ticket"])
|
2023-12-02 19:09:34 +01:00
|
|
|
response = self.client.post('/api/followups/', {
|
|
|
|
'ticket': handled_webhook_requests['new_ticket_requests'][-1]["ticket"]["id"],
|
|
|
|
"comment": "Test comment",
|
|
|
|
})
|
|
|
|
self.assertEqual(response.status_code, HTTP_201_CREATED)
|
|
|
|
handled_webhook_requests = requests.get('http://localhost:8124/get-past-requests')
|
|
|
|
handled_webhook_requests = handled_webhook_requests.json()
|
|
|
|
self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 1)
|
2023-12-05 00:36:20 +01:00
|
|
|
self.assertEqual(len(handled_webhook_requests['follow_up_requests_1']), 1)
|
2023-12-02 19:09:34 +01:00
|
|
|
self.assertEqual(handled_webhook_requests['follow_up_requests'][-1]["ticket"]["followup_set"][-1]["comment"], "Test comment")
|
2023-12-05 00:36:20 +01:00
|
|
|
self.assertEqual(handled_webhook_requests['follow_up_requests_1'][-1]["ticket"]["followup_set"][-1]["comment"], "Test comment")
|
2023-12-27 20:34:56 +01:00
|
|
|
|
2023-12-02 19:09:34 +01:00
|
|
|
server.stop()
|
|
|
|
|
|
|
|
def test_create_ticket_and_followup_via_email(self):
|
|
|
|
from .. import email
|
|
|
|
|
|
|
|
server = WebhookServer(('localhost', 8125), WebhookRequestHandler)
|
|
|
|
os.environ['HELPDESK_NEW_TICKET_WEBHOOK_URLS'] = 'http://localhost:8125/new-ticket'
|
|
|
|
os.environ["HELPDESK_FOLLOWUP_WEBHOOK_URLS"] = 'http://localhost:8125/followup'
|
|
|
|
server.start()
|
|
|
|
class MockMessage(dict):
|
|
|
|
def __init__(self, **kwargs):
|
|
|
|
self.__dict__.update(kwargs)
|
|
|
|
|
|
|
|
def get_all(self, key, default=None):
|
|
|
|
return self.__dict__.get(key, default)
|
|
|
|
|
|
|
|
payload = {
|
|
|
|
'body': "hello",
|
|
|
|
'full_body': "hello",
|
|
|
|
'subject': "Test subject",
|
|
|
|
'queue': self.queue,
|
|
|
|
'sender_email': "user@example.com",
|
|
|
|
'priority': "1",
|
|
|
|
'files': [],
|
|
|
|
}
|
|
|
|
|
|
|
|
message = {
|
|
|
|
"To": ["info@example.com"],
|
|
|
|
"Cc": [],
|
|
|
|
"Message-Id": "random1",
|
|
|
|
"In-Reply-To": "",
|
|
|
|
}
|
|
|
|
email.create_object_from_email_message(
|
|
|
|
message=MockMessage(**message),
|
|
|
|
ticket_id=None,
|
|
|
|
payload=payload,
|
|
|
|
files=[],
|
|
|
|
logger=logging.getLogger('helpdesk'),
|
|
|
|
)
|
|
|
|
|
|
|
|
handled_webhook_requests = requests.get('http://localhost:8125/get-past-requests')
|
|
|
|
handled_webhook_requests = handled_webhook_requests.json()
|
|
|
|
self.assertEqual(len(handled_webhook_requests['new_ticket_requests']), 1)
|
|
|
|
self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 0)
|
|
|
|
|
|
|
|
ticket_id = handled_webhook_requests['new_ticket_requests'][-1]["ticket"]['id']
|
|
|
|
from .. import models
|
|
|
|
ticket = models.Ticket.objects.get(id=ticket_id)
|
|
|
|
|
|
|
|
payload = {
|
|
|
|
'body': "hello",
|
|
|
|
'full_body': "hello",
|
|
|
|
'subject': f"[test-queue-{ticket_id}] Test subject",
|
|
|
|
'queue': self.queue,
|
|
|
|
'sender_email': "user@example.com",
|
|
|
|
'priority': "1",
|
|
|
|
'files': [],
|
|
|
|
}
|
|
|
|
|
|
|
|
message = {
|
|
|
|
"To": ["info@example.com"],
|
|
|
|
"Cc": [],
|
|
|
|
"Message-Id": "random",
|
|
|
|
"In-Reply-To": "123",
|
|
|
|
}
|
|
|
|
email.create_object_from_email_message(
|
|
|
|
message=MockMessage(**message),
|
|
|
|
ticket_id=ticket_id,
|
|
|
|
payload=payload,
|
|
|
|
files=[],
|
|
|
|
logger=logging.getLogger('helpdesk'),
|
|
|
|
)
|
|
|
|
handled_webhook_requests = requests.get('http://localhost:8125/get-past-requests')
|
|
|
|
handled_webhook_requests = handled_webhook_requests.json()
|
|
|
|
self.assertEqual(len(handled_webhook_requests['follow_up_requests']), 1)
|
|
|
|
self.assertEqual(handled_webhook_requests['follow_up_requests'][-1]["ticket"]["followup_set"][-1]["comment"], "hello")
|
|
|
|
self.assertEqual(handled_webhook_requests['follow_up_requests'][-1]["ticket"]["id"], ticket_id)
|
|
|
|
|
|
|
|
server.stop()
|