fix(src/tickets): wrap move ticket view in atomic transaction with select_for_update

Ensures data integrity and prevents race conditions when moving tickets.
This commit is contained in:
sankalp committed 2026-06-29 07:20:47 +05:45
1 parent 0497b7e68d
commit d30cfd61c3
1 file changed
+22 -19
+22 -19
View File
@@ -1,4 +1,4 @@
from django.db import models
from django.db import models, transaction
from rest_framework import generics, permissions
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
@@ -105,26 +105,29 @@ class TicketHistoryListView(generics.ListAPIView):
@api_view(["PATCH"])
@permission_classes([permissions.IsAuthenticated])
def move_ticket_view(request, pk):
ticket = generics.get_object_or_404(Ticket, pk=pk)
new_status_id = request.data.get("status_id")
if new_status_id:
new_status = generics.get_object_or_404(TicketStatus, pk=new_status_id)
with transaction.atomic():
ticket = generics.get_object_or_404(Ticket.objects.select_for_update(), pk=pk)
new_status_id = request.data.get("status_id")
if new_status_id:
new_status = generics.get_object_or_404(TicketStatus, pk=new_status_id)
if not ticket.project.user_can_move_to_status(request.user, new_status):
return Response(
{"error": "You don't have permission to move tickets to this status."},
status=403,
)
if not ticket.project.user_can_move_to_status(request.user, new_status):
return Response(
{
"error": "You don't have permission to move tickets to this status."
},
status=403,
)
old_status_id = ticket.status_id
ticket.status_id = new_status_id
ticket.save()
if old_status_id != int(new_status_id):
TicketHistory.objects.create(
ticket=ticket,
user=request.user,
status_id=new_status_id,
)
old_status_id = ticket.status_id
ticket.status_id = new_status_id
ticket.save()
if old_status_id != int(new_status_id):
TicketHistory.objects.create(
ticket=ticket,
user=request.user,
status_id=new_status_id,
)
return Response(TicketListSerializer(ticket).data)