mirror of
https://github.com/django-helpdesk/django-helpdesk.git
synced 2025-06-03 00:15:46 +02:00
453 lines
18 KiB
Python
453 lines
18 KiB
Python
import base64
|
|
from collections import OrderedDict
|
|
from datetime import datetime
|
|
from django.contrib.auth.models import User
|
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
from freezegun import freeze_time
|
|
from helpdesk.models import CustomField, Queue, Ticket
|
|
from rest_framework import HTTP_HEADER_ENCODING
|
|
from rest_framework.exceptions import ErrorDetail
|
|
from rest_framework.status import (
|
|
HTTP_200_OK,
|
|
HTTP_201_CREATED,
|
|
HTTP_204_NO_CONTENT,
|
|
HTTP_400_BAD_REQUEST,
|
|
HTTP_403_FORBIDDEN,
|
|
)
|
|
from rest_framework.test import APITestCase
|
|
|
|
|
|
class TicketTest(APITestCase):
|
|
due_date = datetime(2022, 4, 10, 15, 6)
|
|
|
|
@classmethod
|
|
def setUpTestData(cls):
|
|
cls.queue = Queue.objects.create(
|
|
title="Test Queue",
|
|
slug="test-queue",
|
|
)
|
|
|
|
def test_create_api_ticket_not_authenticated_user(self):
|
|
response = self.client.post("/api/tickets/")
|
|
self.assertEqual(response.status_code, HTTP_403_FORBIDDEN)
|
|
|
|
def test_create_api_ticket_authenticated_non_staff_user(self):
|
|
non_staff_user = User.objects.create_user(username="test")
|
|
self.client.force_authenticate(non_staff_user)
|
|
response = self.client.post("/api/tickets/")
|
|
self.assertEqual(response.status_code, HTTP_403_FORBIDDEN)
|
|
|
|
def test_create_api_ticket_no_data(self):
|
|
staff_user = User.objects.create_user(username="test", is_staff=True)
|
|
self.client.force_authenticate(staff_user)
|
|
response = self.client.post("/api/tickets/")
|
|
self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(
|
|
response.data,
|
|
{
|
|
"queue": [
|
|
ErrorDetail(string="This field is required.", code="required")
|
|
],
|
|
"title": [
|
|
ErrorDetail(string="This field is required.", code="required")
|
|
],
|
|
},
|
|
)
|
|
self.assertFalse(Ticket.objects.exists())
|
|
|
|
def test_create_api_ticket_wrong_date_format(self):
|
|
staff_user = User.objects.create_user(username="test", is_staff=True)
|
|
self.client.force_authenticate(staff_user)
|
|
response = self.client.post(
|
|
"/api/tickets/",
|
|
{
|
|
"queue": self.queue.id,
|
|
"title": "Test title",
|
|
"due_date": "monday, 1st of may 2022",
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(
|
|
response.data,
|
|
{
|
|
"due_date": [
|
|
ErrorDetail(
|
|
string="Datetime has wrong format. Use one of these formats instead: YYYY-MM-DDThh:mm[:ss[.uuuuuu]][+HH:MM|-HH:MM|Z].",
|
|
code="invalid",
|
|
)
|
|
]
|
|
},
|
|
)
|
|
self.assertFalse(Ticket.objects.exists())
|
|
|
|
def test_create_api_ticket_authenticated_staff_user(self):
|
|
staff_user = User.objects.create_user(username="test", is_staff=True)
|
|
self.client.force_authenticate(staff_user)
|
|
response = self.client.post(
|
|
"/api/tickets/",
|
|
{
|
|
"queue": self.queue.id,
|
|
"title": "Test title",
|
|
"description": "Test description\nMulti lines",
|
|
"submitter_email": "test@mail.com",
|
|
"priority": 4,
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, HTTP_201_CREATED)
|
|
created_ticket = Ticket.objects.get()
|
|
self.assertEqual(created_ticket.title, "Test title")
|
|
self.assertEqual(created_ticket.description, "Test description\nMulti lines")
|
|
self.assertEqual(created_ticket.submitter_email, "test@mail.com")
|
|
self.assertEqual(created_ticket.priority, 4)
|
|
self.assertEqual(created_ticket.followup_set.count(), 1)
|
|
|
|
def test_create_api_ticket_with_basic_auth(self):
|
|
username = "admin"
|
|
password = "admin"
|
|
User.objects.create_user(username=username, password=password, is_staff=True)
|
|
|
|
test_user = User.objects.create_user(username="test")
|
|
merge_ticket = Ticket.objects.create(queue=self.queue, title="merge ticket")
|
|
|
|
# Generate base64 credentials string
|
|
credentials = f"{username}:{password}"
|
|
base64_credentials = base64.b64encode(
|
|
credentials.encode(HTTP_HEADER_ENCODING)
|
|
).decode(HTTP_HEADER_ENCODING)
|
|
|
|
self.client.credentials(HTTP_AUTHORIZATION=f"Basic {base64_credentials}")
|
|
response = self.client.post(
|
|
"/api/tickets/",
|
|
{
|
|
"queue": self.queue.id,
|
|
"title": "Title",
|
|
"description": "Description",
|
|
"resolution": "Resolution",
|
|
"assigned_to": test_user.id,
|
|
"submitter_email": "test@mail.com",
|
|
"status": Ticket.RESOLVED_STATUS,
|
|
"priority": 1,
|
|
"on_hold": True,
|
|
"due_date": self.due_date,
|
|
"merged_to": merge_ticket.id,
|
|
},
|
|
)
|
|
|
|
self.assertEqual(response.status_code, HTTP_201_CREATED)
|
|
created_ticket = Ticket.objects.last()
|
|
self.assertEqual(created_ticket.title, "Title")
|
|
self.assertEqual(created_ticket.description, "Description")
|
|
# resolution can not be set on creation
|
|
self.assertIsNone(created_ticket.resolution)
|
|
self.assertEqual(created_ticket.assigned_to, test_user)
|
|
self.assertEqual(created_ticket.submitter_email, "test@mail.com")
|
|
self.assertEqual(created_ticket.priority, 1)
|
|
# on_hold is False on creation
|
|
self.assertFalse(created_ticket.on_hold)
|
|
# status is always open on creation
|
|
self.assertEqual(created_ticket.status, Ticket.OPEN_STATUS)
|
|
self.assertEqual(created_ticket.due_date, self.due_date)
|
|
# merged_to can not be set on creation
|
|
self.assertIsNone(created_ticket.merged_to)
|
|
|
|
def test_edit_api_ticket(self):
|
|
staff_user = User.objects.create_user(username="admin", is_staff=True)
|
|
test_ticket = Ticket.objects.create(queue=self.queue, title="Test ticket")
|
|
|
|
test_user = User.objects.create_user(username="test")
|
|
merge_ticket = Ticket.objects.create(queue=self.queue, title="merge ticket")
|
|
|
|
self.client.force_authenticate(staff_user)
|
|
response = self.client.put(
|
|
"/api/tickets/%d/" % test_ticket.id,
|
|
{
|
|
"queue": self.queue.id,
|
|
"title": "Title",
|
|
"description": "Description",
|
|
"resolution": "Resolution",
|
|
"assigned_to": test_user.id,
|
|
"submitter_email": "test@mail.com",
|
|
"status": Ticket.RESOLVED_STATUS,
|
|
"priority": 1,
|
|
"on_hold": True,
|
|
"due_date": self.due_date,
|
|
"merged_to": merge_ticket.id,
|
|
},
|
|
)
|
|
|
|
self.assertEqual(response.status_code, HTTP_200_OK)
|
|
test_ticket.refresh_from_db()
|
|
self.assertEqual(test_ticket.title, "Title")
|
|
self.assertEqual(test_ticket.description, "Description")
|
|
self.assertEqual(test_ticket.resolution, "Resolution")
|
|
self.assertEqual(test_ticket.assigned_to, test_user)
|
|
self.assertEqual(test_ticket.submitter_email, "test@mail.com")
|
|
self.assertEqual(test_ticket.priority, 1)
|
|
self.assertTrue(test_ticket.on_hold)
|
|
self.assertEqual(test_ticket.status, Ticket.RESOLVED_STATUS)
|
|
self.assertEqual(test_ticket.due_date, self.due_date)
|
|
self.assertEqual(test_ticket.merged_to, merge_ticket)
|
|
|
|
def test_partial_edit_api_ticket(self):
|
|
staff_user = User.objects.create_user(username="admin", is_staff=True)
|
|
test_ticket = Ticket.objects.create(queue=self.queue, title="Test ticket")
|
|
|
|
self.client.force_authenticate(staff_user)
|
|
response = self.client.patch(
|
|
"/api/tickets/%d/" % test_ticket.id,
|
|
{
|
|
"description": "New description",
|
|
},
|
|
)
|
|
|
|
self.assertEqual(response.status_code, HTTP_200_OK)
|
|
test_ticket.refresh_from_db()
|
|
self.assertEqual(test_ticket.description, "New description")
|
|
|
|
def test_delete_api_ticket(self):
|
|
staff_user = User.objects.create_user(username="admin", is_staff=True)
|
|
test_ticket = Ticket.objects.create(queue=self.queue, title="Test ticket")
|
|
self.client.force_authenticate(staff_user)
|
|
response = self.client.delete("/api/tickets/%d/" % test_ticket.id)
|
|
self.assertEqual(response.status_code, HTTP_204_NO_CONTENT)
|
|
self.assertFalse(Ticket.objects.exists())
|
|
|
|
@freeze_time("2022-06-30 23:09:44")
|
|
def test_create_api_ticket_with_custom_fields(self):
|
|
# Create custom fields
|
|
for field_type, field_display in CustomField.DATA_TYPE_CHOICES:
|
|
extra_data = {}
|
|
if field_type in ("varchar", "text"):
|
|
extra_data["max_length"] = 10
|
|
if field_type == "integer":
|
|
# Set one field as required to test error if not provided
|
|
extra_data["required"] = True
|
|
if field_type == "decimal":
|
|
extra_data["max_length"] = 7
|
|
extra_data["decimal_places"] = 3
|
|
if field_type == "list":
|
|
extra_data["list_values"] = """Green
|
|
Blue
|
|
Red
|
|
Yellow"""
|
|
CustomField.objects.create(
|
|
name=field_type, label=field_display, data_type=field_type, **extra_data
|
|
)
|
|
|
|
staff_user = User.objects.create_user(username="test", is_staff=True)
|
|
self.client.force_authenticate(staff_user)
|
|
|
|
# Test creation without providing required field
|
|
response = self.client.post(
|
|
"/api/tickets/",
|
|
{
|
|
"queue": self.queue.id,
|
|
"title": "Test title",
|
|
"description": "Test description\nMulti lines",
|
|
"submitter_email": "test@mail.com",
|
|
"priority": 4,
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, HTTP_400_BAD_REQUEST)
|
|
self.assertEqual(
|
|
response.data,
|
|
{
|
|
"custom_integer": [
|
|
ErrorDetail(string="This field is required.", code="required")
|
|
]
|
|
},
|
|
)
|
|
|
|
# Test creation with custom field values
|
|
response = self.client.post(
|
|
"/api/tickets/",
|
|
{
|
|
"queue": self.queue.id,
|
|
"title": "Test title",
|
|
"description": "Test description\nMulti lines",
|
|
"submitter_email": "test@mail.com",
|
|
"priority": 4,
|
|
"custom_varchar": "test",
|
|
"custom_text": "multi\nline",
|
|
"custom_integer": "1",
|
|
"custom_decimal": "42.987",
|
|
"custom_list": "Red",
|
|
"custom_boolean": True,
|
|
"custom_date": "2022-4-11",
|
|
"custom_time": "23:59:59",
|
|
"custom_datetime": "2022-4-10 18:27",
|
|
"custom_email": "email@test.com",
|
|
"custom_url": "http://django-helpdesk.readthedocs.org/",
|
|
"custom_ipaddress": "127.0.0.1",
|
|
"custom_slug": "test-slug",
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, HTTP_201_CREATED)
|
|
# Check all fields with data returned from the response
|
|
self.assertEqual(
|
|
response.data,
|
|
{
|
|
"id": 1,
|
|
"queue": 1,
|
|
"title": "Test title",
|
|
"description": "Test description\nMulti lines",
|
|
"resolution": None,
|
|
"submitter_email": "test@mail.com",
|
|
"assigned_to": None,
|
|
"status": 1,
|
|
"on_hold": False,
|
|
"priority": 4,
|
|
"due_date": None,
|
|
"merged_to": None,
|
|
"followup_set": [
|
|
OrderedDict(
|
|
[
|
|
("id", 1),
|
|
("ticket", 1),
|
|
("user", 1),
|
|
("title", "Ticket Opened"),
|
|
("comment", "Test description\nMulti lines"),
|
|
("public", True),
|
|
("new_status", None),
|
|
("time_spent", None),
|
|
("followupattachment_set", []),
|
|
("date", "2022-06-30T23:09:44"),
|
|
("message_id", None),
|
|
]
|
|
)
|
|
],
|
|
"custom_varchar": "test",
|
|
"custom_text": "multi\nline",
|
|
"custom_integer": 1,
|
|
"custom_decimal": "42.987",
|
|
"custom_list": "Red",
|
|
"custom_boolean": True,
|
|
"custom_date": "2022-04-11",
|
|
"custom_time": "23:59:59",
|
|
"custom_datetime": "2022-04-10T18:27",
|
|
"custom_email": "email@test.com",
|
|
"custom_url": "http://django-helpdesk.readthedocs.org/",
|
|
"custom_ipaddress": "127.0.0.1",
|
|
"custom_slug": "test-slug",
|
|
},
|
|
)
|
|
|
|
def test_create_api_ticket_with_attachment(self):
|
|
staff_user = User.objects.create_user(username="test", is_staff=True)
|
|
self.client.force_authenticate(staff_user)
|
|
test_file = SimpleUploadedFile(
|
|
"file.jpg", b"file_content", content_type="image/jpg"
|
|
)
|
|
response = self.client.post(
|
|
"/api/tickets/",
|
|
{
|
|
"queue": self.queue.id,
|
|
"title": "Test title",
|
|
"description": "Test description\nMulti lines",
|
|
"submitter_email": "test@mail.com",
|
|
"priority": 4,
|
|
"attachment": test_file,
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, HTTP_201_CREATED)
|
|
created_ticket = Ticket.objects.get()
|
|
self.assertEqual(created_ticket.title, "Test title")
|
|
self.assertEqual(created_ticket.description, "Test description\nMulti lines")
|
|
self.assertEqual(created_ticket.submitter_email, "test@mail.com")
|
|
self.assertEqual(created_ticket.priority, 4)
|
|
self.assertEqual(created_ticket.followup_set.count(), 1)
|
|
self.assertEqual(
|
|
created_ticket.followup_set.get().followupattachment_set.count(), 1
|
|
)
|
|
attachment = created_ticket.followup_set.get().followupattachment_set.get()
|
|
self.assertEqual(
|
|
attachment.file.name,
|
|
f"helpdesk/attachments/test-queue-1-{created_ticket.secret_key}/1/file.jpg",
|
|
)
|
|
|
|
def test_create_follow_up_with_attachments(self):
|
|
staff_user = User.objects.create_user(username="test", is_staff=True)
|
|
self.client.force_authenticate(staff_user)
|
|
ticket = Ticket.objects.create(queue=self.queue, title="Test")
|
|
test_file_1 = SimpleUploadedFile(
|
|
"file.jpg", b"file_content", content_type="image/jpg"
|
|
)
|
|
test_file_2 = SimpleUploadedFile(
|
|
"doc.pdf", b"Doc content", content_type="application/pdf"
|
|
)
|
|
|
|
response = self.client.post(
|
|
"/api/followups/",
|
|
{
|
|
"ticket": ticket.id,
|
|
"title": "Test",
|
|
"comment": "Test answer\nMulti lines",
|
|
"attachments": [test_file_1, test_file_2],
|
|
},
|
|
)
|
|
self.assertEqual(response.status_code, HTTP_201_CREATED)
|
|
created_followup = ticket.followup_set.last()
|
|
self.assertEqual(created_followup.title, "Test")
|
|
self.assertEqual(created_followup.comment, "Test answer\nMulti lines")
|
|
self.assertEqual(created_followup.followupattachment_set.count(), 2)
|
|
self.assertEqual(
|
|
created_followup.followupattachment_set.first().filename, "doc.pdf"
|
|
)
|
|
self.assertEqual(
|
|
created_followup.followupattachment_set.first().mime_type, "application/pdf"
|
|
)
|
|
self.assertEqual(
|
|
created_followup.followupattachment_set.last().filename, "file.jpg"
|
|
)
|
|
self.assertEqual(
|
|
created_followup.followupattachment_set.last().mime_type, "image/jpg"
|
|
)
|
|
|
|
|
|
class UserTicketTest(APITestCase):
|
|
def setUp(self):
|
|
self.queue = Queue.objects.create(title="Test queue")
|
|
self.user = User.objects.create_user(username="test")
|
|
self.client.force_authenticate(self.user)
|
|
|
|
def test_get_user_tickets(self):
|
|
user = User.objects.create_user(username="test2", email="foo@example.com")
|
|
ticket_1 = Ticket.objects.create(
|
|
queue=self.queue, title="Test 1", submitter_email="foo@example.com"
|
|
)
|
|
Ticket.objects.create(
|
|
queue=self.queue, title="Test 2", submitter_email="bar@example.com"
|
|
)
|
|
ticket_3 = Ticket.objects.create(
|
|
queue=self.queue, title="Test 3", submitter_email="foo@example.com"
|
|
)
|
|
self.client.force_authenticate(user)
|
|
response = self.client.get("/api/user_tickets/")
|
|
self.assertEqual(response.status_code, HTTP_200_OK)
|
|
self.assertEqual(len(response.data["results"]), 2)
|
|
self.assertEqual(response.data["results"][0]["id"], ticket_3.id)
|
|
self.assertEqual(response.data["results"][1]["id"], ticket_1.id)
|
|
|
|
def test_staff_user(self):
|
|
staff_user = User.objects.create_user(
|
|
username="test2", is_staff=True, email="staff@example.com"
|
|
)
|
|
Ticket.objects.create(
|
|
queue=self.queue, title="Test 1", submitter_email="staff@example.com"
|
|
)
|
|
Ticket.objects.create(
|
|
queue=self.queue, title="Test 2", submitter_email="foo@example.com"
|
|
)
|
|
self.client.force_authenticate(staff_user)
|
|
response = self.client.get("/api/user_tickets/")
|
|
self.assertEqual(response.status_code, HTTP_200_OK)
|
|
self.assertEqual(len(response.data["results"]), 1)
|
|
|
|
def test_not_logged_in_user(self):
|
|
Ticket.objects.create(
|
|
queue=self.queue, title="Test 1", submitter_email="ex@example.com"
|
|
)
|
|
self.client.logout()
|
|
response = self.client.get("/api/user_tickets/")
|
|
self.assertEqual(response.status_code, HTTP_403_FORBIDDEN)
|