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:
1 file changed
+22
-19
+22
-19
@@ -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)
|
||||
|
||||
|
||||
Reference in new issue
Block a user