diff --git a/tracdb/tests.py b/tracdb/tests.py index f39de49fa7..85039f87ff 100644 --- a/tracdb/tests.py +++ b/tracdb/tests.py @@ -3,6 +3,7 @@ import time_machine from django.test import SimpleTestCase, TestCase +from django.urls import reverse from .models import ( Attachment, @@ -29,7 +30,7 @@ def test_router(self): class TicketTestCase(TracDBCreateDatabaseMixin, TestCase): - databases = {"trac"} + databases = {"default", "trac"} def _create_ticket(self, custom=None, **kwargs): """ @@ -224,6 +225,59 @@ def test_from_querystring_invalid_time(self): with self.assertRaises(ValueError): Ticket.objects.from_querystring("time=2024-10-24..") + def test_api_ticket_404(self): + no_ticket_url = reverse("api_ticket", args=[30000]) + response = self.client.get(no_ticket_url) + self.assertEqual(response.status_code, 404) + + def test_api_ticket_405(self): + ticket = self._create_ticket(summary="test") + ticket_url = reverse("api_ticket", args=[ticket.id]) + post_response = self.client.post(ticket_url, {}) + delete_response = self.client.delete(ticket_url) + self.assertEqual(post_response.status_code, 405) + self.assertEqual(delete_response.status_code, 405) + + def test_api_ticket_200(self): + ticket = self._create_ticket( + reporter="reporter@email.com", + type="Bug", + summary="test summary", + description="test description", + severity="Normal", + resolution="fixed", + status="assigned", + custom={ + "stage": "Accepted", + "has_patch": "1", + "needs_better_patch": "0", + "needs_tests": "0", + }, + ) + + with self.assertNumQueries(1, using="trac"): + response = self.client.get(reverse("api_ticket", args=[ticket.id])) + + self.assertEqual(response.status_code, 200) + self.assertJSONEqual( + response.content, + { + "id": ticket.id, + "type": "Bug", + "summary": "test summary", + "description": "test description", + "severity": "Normal", + "status": "assigned", + "resolution": "fixed", + "custom": { + "stage": "Accepted", + "has_patch": "1", + "needs_better_patch": "0", + "needs_tests": "0", + }, + }, + ) + class TracTimeTestCase(SimpleTestCase): def test_datetime_to_timestamp(self): diff --git a/tracdb/urls.py b/tracdb/urls.py index bf7aa4086b..65bdaa4153 100644 --- a/tracdb/urls.py +++ b/tracdb/urls.py @@ -4,4 +4,5 @@ urlpatterns = [ path("bouncing/", views.bouncing_tickets, name="bouncing_tickets"), + path("api/tickets/", views.api_ticket, name="api_ticket"), ] diff --git a/tracdb/views.py b/tracdb/views.py index 8240677a3d..d8c2969758 100644 --- a/tracdb/views.py +++ b/tracdb/views.py @@ -1,6 +1,9 @@ from django import db -from django.shortcuts import render +from django.http import JsonResponse +from django.shortcuts import get_object_or_404, render +from django.views.decorators.http import require_http_methods +from .models import Ticket from .tractime import timestamp_to_datetime @@ -29,3 +32,19 @@ def bouncing_tickets(request): def dictfetchall(cursor): desc = cursor.description return [dict(zip([col[0] for col in desc], row)) for row in cursor.fetchall()] + + +@require_http_methods(["GET"]) +def api_ticket(request, ticket_id): + ticket_qs = Ticket.objects.with_custom().values( + "id", + "type", + "summary", + "description", + "severity", + "status", + "resolution", + "custom", + ) + ticket = get_object_or_404(ticket_qs, id=ticket_id) + return JsonResponse(ticket)