diff --git a/tracdb/tests.py b/tracdb/tests.py index e7b7f9c24..3cda3ff6a 100644 --- a/tracdb/tests.py +++ b/tracdb/tests.py @@ -157,3 +157,63 @@ def test_from_querystring_model_and_custom_field_together(self): Ticket.objects.from_querystring("severity=high&stage=unreviewed"), ["test1"], ) + + +class TicketAPITestCase(TracDBCreateDatabaseMixin, TestCase): + databases = {"default", "trac"} + + def test_empty_results(self): + response = self.client.get("/trac/api/?ids=1") + self.assertJSONEqual(response.content, {"tickets": []}) + + def test_single_result(self): + t = Ticket.objects.create(reporter="test", description="test") + + response = self.client.get(f"/trac/api/?ids={t.id}") + + self.assertJSONEqual( + response.content, + { + "tickets": [ + { + "id": t.id, + "reporter": "test", + "description": "test", + "resolution": "", + "status": "", + "changes": [], + } + ] + }, + ) + + def test_single_result_with_comment(self): + t = Ticket.objects.create() + t.changes.create(author="test", field="test", _time=1) + + response = self.client.get(f"/trac/api/?ids={t.id}") + + self.assertJSONEqual( + response.content, + { + "tickets": [ + { + "id": t.id, + "reporter": "", + "description": "", + "resolution": "", + "status": "", + "changes": [ + { + "author": "test", + "field": "test", + "time": "1970-01-01T00:00:00.000001+00:00", + } + ], + } + ] + }, + ) + + def test_querycount(self): + pass # TODO (make sure there's no N+1 issue) diff --git a/tracdb/urls.py b/tracdb/urls.py index bf7aa4086..bbe868be8 100644 --- a/tracdb/urls.py +++ b/tracdb/urls.py @@ -4,4 +4,5 @@ urlpatterns = [ path("bouncing/", views.bouncing_tickets, name="bouncing_tickets"), + path("api/", views.miniapi, name="miniapi"), ] diff --git a/tracdb/views.py b/tracdb/views.py index 9e725f593..e0a5f9da4 100644 --- a/tracdb/views.py +++ b/tracdb/views.py @@ -1,9 +1,10 @@ import datetime from django import db +from django.http import JsonResponse from django.shortcuts import render -from .models import _epoc +from .models import Ticket, _epoc def bouncing_tickets(request): @@ -35,3 +36,41 @@ def ts2dt(ts): def dictfetchall(cursor): desc = cursor.description return [dict(zip([col[0] for col in desc], row)) for row in cursor.fetchall()] + + +def miniapi(request): + """ + Return information about the requestest tickets (JSON) + """ + # TODO: max size + # TODO: paginate? + # TODO: error handling + pks = request.GET.get("ids") + tickets = ( + Ticket.objects.filter(pk__in=pks) + .only("status", "reporter", "resolution", "description") + .prefetch_related("changes") + ) + + return JsonResponse( + { + "tickets": [ + { + "id": ticket.pk, + "status": ticket.status, + "reporter": ticket.reporter, # TODO: sanitize (emails, ...) + "resolution": ticket.resolution, + "description": ticket.description, + "changes": [ + { + "time": change.time.isoformat(), + "author": change.author, # TODO: sanitize (emails, ...) + "field": change.field, + } + for change in ticket.changes.all() + ], + } + for ticket in tickets + ] + } + )