mirror of
				https://gitlab.crans.org/bde/nk20
				synced 2025-11-04 01:12:08 +01:00 
			
		
		
		
	🐛 Fix transaction update concurency
This commit is contained in:
		@@ -4,7 +4,7 @@
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
from rest_framework import viewsets
 | 
			
		||||
from note_kfet.middlewares import get_current_authenticated_user
 | 
			
		||||
from note_kfet.middlewares import get_current_session
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class ReadProtectedModelViewSet(viewsets.ModelViewSet):
 | 
			
		||||
@@ -17,7 +17,8 @@ class ReadProtectedModelViewSet(viewsets.ModelViewSet):
 | 
			
		||||
        self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        user = get_current_authenticated_user()
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        get_current_session().setdefault("permission_mask", 42)
 | 
			
		||||
        return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@@ -31,5 +32,6 @@ class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
 | 
			
		||||
        self.model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        user = get_current_authenticated_user()
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        get_current_session().setdefault("permission_mask", 42)
 | 
			
		||||
        return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view")).distinct()
 | 
			
		||||
 
 | 
			
		||||
@@ -9,7 +9,7 @@ from rest_framework import viewsets
 | 
			
		||||
from rest_framework.response import Response
 | 
			
		||||
from rest_framework import status
 | 
			
		||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
 | 
			
		||||
from note_kfet.middlewares import get_current_authenticated_user
 | 
			
		||||
from note_kfet.middlewares import  get_current_session
 | 
			
		||||
from permission.backends import PermissionBackend
 | 
			
		||||
 | 
			
		||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, ConsumerSerializer,\
 | 
			
		||||
@@ -154,5 +154,7 @@ class TransactionViewSet(ReadProtectedModelViewSet):
 | 
			
		||||
    search_fields = ['$reason', ]
 | 
			
		||||
 | 
			
		||||
    def get_queryset(self):
 | 
			
		||||
        user = get_current_authenticated_user()
 | 
			
		||||
        return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view"))
 | 
			
		||||
        user = self.request.user
 | 
			
		||||
        get_current_session().setdefault("permission_mask", 42)
 | 
			
		||||
        return self.model.objects.filter(PermissionBackend.filter_queryset(user, self.model, "view"))\
 | 
			
		||||
            .order_by("created_at", "id")
 | 
			
		||||
 
 | 
			
		||||
@@ -1,7 +1,7 @@
 | 
			
		||||
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
 | 
			
		||||
# SPDX-License-Identifier: GPL-3.0-or-later
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.db import models, transaction
 | 
			
		||||
from django.urls import reverse
 | 
			
		||||
from django.utils import timezone
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
@@ -196,10 +196,15 @@ class Transaction(PolymorphicModel):
 | 
			
		||||
                or dest_balance > 2147483647 or dest_balance < -2147483648:
 | 
			
		||||
            raise ValidationError(_("The note balances must be between - 21 474 836.47 € and 21 474 836.47 €."))
 | 
			
		||||
 | 
			
		||||
    @transaction.atomic
 | 
			
		||||
    def save(self, *args, **kwargs):
 | 
			
		||||
        """
 | 
			
		||||
        When saving, also transfer money between two notes
 | 
			
		||||
        """
 | 
			
		||||
        with transaction.atomic():
 | 
			
		||||
            self.refresh_from_db()
 | 
			
		||||
            self.source.refresh_from_db()
 | 
			
		||||
            self.destination.refresh_from_db()
 | 
			
		||||
            self.validate(False)
 | 
			
		||||
 | 
			
		||||
            if not self.source.is_active or not self.destination.is_active:
 | 
			
		||||
@@ -220,14 +225,22 @@ class Transaction(PolymorphicModel):
 | 
			
		||||
                super().save(*args, **kwargs)
 | 
			
		||||
                return
 | 
			
		||||
 | 
			
		||||
            self.log("Saving")
 | 
			
		||||
            # We save first the transaction, in case of the user has no right to transfer money
 | 
			
		||||
            super().save(*args, **kwargs)
 | 
			
		||||
            self.log("Saved")
 | 
			
		||||
 | 
			
		||||
            # Save notes
 | 
			
		||||
            self.source._force_save = True
 | 
			
		||||
            self.source.save()
 | 
			
		||||
            self.log("Source saved")
 | 
			
		||||
            self.destination._force_save = True
 | 
			
		||||
            self.destination.save()
 | 
			
		||||
            self.log("Destination saved")
 | 
			
		||||
 | 
			
		||||
    def log(self, msg):
 | 
			
		||||
        with open("/tmp/log", "a") as f:
 | 
			
		||||
            f.write(msg + "\n")
 | 
			
		||||
 | 
			
		||||
    def delete(self, **kwargs):
 | 
			
		||||
        """
 | 
			
		||||
 
 | 
			
		||||
@@ -10,7 +10,7 @@ from time import sleep
 | 
			
		||||
from django.contrib.contenttypes.models import ContentType
 | 
			
		||||
from django.core.exceptions import ValidationError
 | 
			
		||||
from django.core.mail import mail_admins
 | 
			
		||||
from django.db import models
 | 
			
		||||
from django.db import models, transaction
 | 
			
		||||
from django.db.models import F, Q, Model
 | 
			
		||||
from django.forms import model_to_dict
 | 
			
		||||
from django.utils.translation import gettext_lazy as _
 | 
			
		||||
@@ -43,14 +43,7 @@ class InstancedPermission:
 | 
			
		||||
 | 
			
		||||
                obj = copy(obj)
 | 
			
		||||
                obj.pk = 0
 | 
			
		||||
                # Ensure previous models are deleted
 | 
			
		||||
                for ignored in range(1000):
 | 
			
		||||
                    if self.model.model_class().objects.filter(pk=0).exists():
 | 
			
		||||
                        # If the object exists, that means that one permission is currently checked.
 | 
			
		||||
                        # We wait before the other permission, at most 1 second.
 | 
			
		||||
                        sleep(0.001)
 | 
			
		||||
                        continue
 | 
			
		||||
                    break
 | 
			
		||||
                with transaction.atomic():
 | 
			
		||||
                    for o in self.model.model_class().objects.filter(pk=0).all():
 | 
			
		||||
                        o._force_delete = True
 | 
			
		||||
                        Model.delete(o)
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user