mirror of
https://github.com/bugsink/bugsink.git
synced 2026-01-06 05:10:15 -06:00
API: adhere to Bugsink's DB-transactional model
as per https://www.bugsink.com/blog/database-transactions/
This commit is contained in:
@@ -1,5 +1,13 @@
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from bugsink.decorators import atomic_for_request_method
|
||||
|
||||
|
||||
class AtomicRequestMixin:
|
||||
def dispatch(self, request, *args, **kwargs):
|
||||
wrapped = atomic_for_request_method(super().dispatch, using=None)
|
||||
return wrapped(request, *args, **kwargs)
|
||||
|
||||
|
||||
class ExpandableSerializerMixin:
|
||||
expandable_fields = {}
|
||||
|
||||
@@ -4,6 +4,7 @@ from rest_framework.exceptions import ValidationError
|
||||
|
||||
from bugsink.utils import assert_
|
||||
from bugsink.api_pagination import AscDescCursorPagination
|
||||
from bugsink.api_mixins import AtomicRequestMixin
|
||||
|
||||
from .models import Event
|
||||
from .serializers import EventListSerializer, EventDetailSerializer
|
||||
@@ -18,7 +19,7 @@ class EventPagination(AscDescCursorPagination):
|
||||
default_direction = "desc" # newest first by default, aligned with UI
|
||||
|
||||
|
||||
class EventViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class EventViewSet(AtomicRequestMixin, viewsets.ReadOnlyModelViewSet):
|
||||
"""
|
||||
LIST requires: ?issue=<uuid>
|
||||
Optional: ?order=asc|desc (default: desc)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.test import TestCase as DjangoTestCase
|
||||
from bugsink.test_utils import TransactionTestCase25251 as TransactionTestCase
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
@@ -11,7 +11,7 @@ from issues.factories import get_or_create_issue
|
||||
from events.factories import create_event_data
|
||||
|
||||
|
||||
class EventApiTests(DjangoTestCase):
|
||||
class EventApiTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
token = AuthToken.objects.create()
|
||||
@@ -70,7 +70,7 @@ class EventApiTests(DjangoTestCase):
|
||||
self.assertEqual(ids[1], str(e1.id))
|
||||
|
||||
|
||||
class EventPaginationTests(DjangoTestCase):
|
||||
class EventPaginationTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
token = AuthToken.objects.create()
|
||||
|
||||
@@ -3,6 +3,8 @@ from rest_framework import viewsets
|
||||
from rest_framework.pagination import CursorPagination
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from bugsink.api_mixins import AtomicRequestMixin
|
||||
|
||||
from .models import Issue
|
||||
from .serializers import IssueSerializer
|
||||
|
||||
@@ -53,7 +55,7 @@ class IssuesCursorPagination(CursorPagination):
|
||||
return ["last_seen", "id"]
|
||||
|
||||
|
||||
class IssueViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
class IssueViewSet(AtomicRequestMixin, viewsets.ReadOnlyModelViewSet):
|
||||
"""
|
||||
LIST requires: ?project=<uuid>
|
||||
Optional: ?order=asc|desc (default: desc)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.test import TestCase as DjangoTestCase
|
||||
from bugsink.test_utils import TransactionTestCase25251 as TransactionTestCase
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
|
||||
@@ -13,7 +13,7 @@ from events.factories import create_event_data
|
||||
from issues.api_views import IssueViewSet
|
||||
|
||||
|
||||
class IssueApiTests(DjangoTestCase):
|
||||
class IssueApiTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
token = AuthToken.objects.create()
|
||||
@@ -86,7 +86,7 @@ class IssueApiTests(DjangoTestCase):
|
||||
self.assertEqual(r.json(), {"sort": ["Must be 'digest_order' or 'last_seen'."]})
|
||||
|
||||
|
||||
class IssuePaginationTests(DjangoTestCase):
|
||||
class IssuePaginationTests(TransactionTestCase):
|
||||
last_seen_deltas = [3, 1, 4, 0, 2]
|
||||
|
||||
def setUp(self):
|
||||
|
||||
@@ -2,7 +2,7 @@ from django.shortcuts import get_object_or_404
|
||||
from rest_framework import viewsets
|
||||
|
||||
from bugsink.api_pagination import AscDescCursorPagination
|
||||
from bugsink.api_mixins import ExpandViewSetMixin
|
||||
from bugsink.api_mixins import ExpandViewSetMixin, AtomicRequestMixin
|
||||
|
||||
from .models import Project
|
||||
from .serializers import (
|
||||
@@ -20,7 +20,7 @@ class ProjectPagination(AscDescCursorPagination):
|
||||
default_direction = "asc"
|
||||
|
||||
|
||||
class ProjectViewSet(ExpandViewSetMixin, viewsets.ModelViewSet):
|
||||
class ProjectViewSet(AtomicRequestMixin, ExpandViewSetMixin, viewsets.ModelViewSet):
|
||||
"""
|
||||
/api/canonical/0/projects/
|
||||
GET /projects/ → list ordered by name ASC, hides soft-deleted, optional ?team=<uuid> filter
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.test import TestCase as DjangoTestCase
|
||||
from bugsink.test_utils import TransactionTestCase25251 as TransactionTestCase
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
@@ -7,7 +7,7 @@ from teams.models import Team
|
||||
from projects.models import Project
|
||||
|
||||
|
||||
class ProjectApiTests(DjangoTestCase):
|
||||
class ProjectApiTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
token = AuthToken.objects.create()
|
||||
@@ -77,7 +77,7 @@ class ProjectApiTests(DjangoTestCase):
|
||||
self.assertEqual(r.status_code, 405)
|
||||
|
||||
|
||||
class ExpansionTests(DjangoTestCase):
|
||||
class ExpansionTests(TransactionTestCase):
|
||||
"""
|
||||
Expansion tests are exercised via ProjectViewSet, but the intent is to validate the
|
||||
generic ExpandableSerializerMixin infrastructure.
|
||||
|
||||
@@ -2,6 +2,7 @@ from rest_framework import viewsets
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from bugsink.api_pagination import AscDescCursorPagination
|
||||
from bugsink.api_mixins import AtomicRequestMixin
|
||||
|
||||
from .models import Release
|
||||
from .serializers import ReleaseListSerializer, ReleaseDetailSerializer, ReleaseCreateSerializer
|
||||
@@ -16,7 +17,7 @@ class ReleasePagination(AscDescCursorPagination):
|
||||
default_direction = "desc"
|
||||
|
||||
|
||||
class ReleaseViewSet(viewsets.ModelViewSet):
|
||||
class ReleaseViewSet(AtomicRequestMixin, viewsets.ModelViewSet):
|
||||
"""
|
||||
LIST requires: ?project=<id>
|
||||
Ordered by sort_epoch.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.test import TestCase as DjangoTestCase
|
||||
from bugsink.test_utils import TransactionTestCase25251 as TransactionTestCase
|
||||
from django.urls import reverse
|
||||
from django.utils import timezone
|
||||
from rest_framework.test import APIClient
|
||||
@@ -9,7 +9,7 @@ from releases.models import Release
|
||||
from releases.api_views import ReleaseViewSet
|
||||
|
||||
|
||||
class ReleaseApiTests(DjangoTestCase):
|
||||
class ReleaseApiTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
token = AuthToken.objects.create()
|
||||
@@ -81,7 +81,7 @@ class ReleaseApiTests(DjangoTestCase):
|
||||
self.assertEqual(delete_response.status_code, 405)
|
||||
|
||||
|
||||
class ReleasePaginationTests(DjangoTestCase):
|
||||
class ReleasePaginationTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
token = AuthToken.objects.create()
|
||||
|
||||
@@ -2,6 +2,7 @@ from django.shortcuts import get_object_or_404
|
||||
from rest_framework import viewsets
|
||||
|
||||
from bugsink.api_pagination import AscDescCursorPagination
|
||||
from bugsink.api_mixins import AtomicRequestMixin
|
||||
|
||||
from .models import Team
|
||||
from .serializers import (
|
||||
@@ -19,7 +20,7 @@ class TeamPagination(AscDescCursorPagination):
|
||||
default_direction = "asc"
|
||||
|
||||
|
||||
class TeamViewSet(viewsets.ModelViewSet):
|
||||
class TeamViewSet(AtomicRequestMixin, viewsets.ModelViewSet):
|
||||
"""
|
||||
/api/canonical/0/teams/
|
||||
GET /teams/ → list ordered by name ASC
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
from django.test import TestCase as DjangoTestCase
|
||||
from bugsink.test_utils import TransactionTestCase25251 as TransactionTestCase
|
||||
from django.urls import reverse
|
||||
from rest_framework.test import APIClient
|
||||
|
||||
@@ -6,7 +6,7 @@ from bsmain.models import AuthToken
|
||||
from teams.models import Team
|
||||
|
||||
|
||||
class TeamApiTests(DjangoTestCase):
|
||||
class TeamApiTests(TransactionTestCase):
|
||||
def setUp(self):
|
||||
self.client = APIClient()
|
||||
token = AuthToken.objects.create()
|
||||
|
||||
Reference in New Issue
Block a user