diff --git a/apps/api/viewsets.py b/apps/api/viewsets.py index f4dd56f6..01fc7998 100644 --- a/apps/api/viewsets.py +++ b/apps/api/viewsets.py @@ -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() diff --git a/apps/note/api/views.py b/apps/note/api/views.py index f806bbf2..be11aa7f 100644 --- a/apps/note/api/views.py +++ b/apps/note/api/views.py @@ -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") diff --git a/apps/note/models/transactions.py b/apps/note/models/transactions.py index c4f880f6..3d7aeb58 100644 --- a/apps/note/models/transactions.py +++ b/apps/note/models/transactions.py @@ -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,38 +196,51 @@ 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 """ - self.validate(False) + 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: - if 'force_insert' not in kwargs or not kwargs['force_insert']: - if 'force_update' not in kwargs or not kwargs['force_update']: - raise ValidationError(_("The transaction can't be saved since the source note " - "or the destination note is not active.")) + if not self.source.is_active or not self.destination.is_active: + if 'force_insert' not in kwargs or not kwargs['force_insert']: + if 'force_update' not in kwargs or not kwargs['force_update']: + raise ValidationError(_("The transaction can't be saved since the source note " + "or the destination note is not active.")) - # If the aliases are not entered, we assume that the used alias is the name of the note - if not self.source_alias: - self.source_alias = str(self.source) + # If the aliases are not entered, we assume that the used alias is the name of the note + if not self.source_alias: + self.source_alias = str(self.source) - if not self.destination_alias: - self.destination_alias = str(self.destination) + if not self.destination_alias: + self.destination_alias = str(self.destination) - if self.source.pk == self.destination.pk: - # When source == destination, no money is transferred + if self.source.pk == self.destination.pk: + # When source == destination, no money is transferred + 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) - return + self.log("Saved") - # We save first the transaction, in case of the user has no right to transfer money - super().save(*args, **kwargs) + # 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") - # Save notes - self.source._force_save = True - self.source.save() - self.destination._force_save = True - self.destination.save() + def log(self, msg): + with open("/tmp/log", "a") as f: + f.write(msg + "\n") def delete(self, **kwargs): """ diff --git a/apps/permission/models.py b/apps/permission/models.py index 235977bb..a7e178b3 100644 --- a/apps/permission/models.py +++ b/apps/permission/models.py @@ -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,35 +43,28 @@ 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 - for o in self.model.model_class().objects.filter(pk=0).all(): - o._force_delete = True - Model.delete(o) - # An object with pk 0 wouldn't deleted. That's not normal, we alert admins. - msg = "Lors de la vérification d'une permission d'ajout, un objet de clé primaire nulle était "\ - "encore présent.\n"\ - "Type de permission : " + self.type + "\n"\ - "Modèle : " + str(self.model) + "\n"\ - "Objet trouvé : " + str(model_to_dict(o)) + "\n\n"\ - "--\nLe BDE" - mail_admins("[Note Kfet] Un objet a été supprimé de force", msg) + with transaction.atomic(): + for o in self.model.model_class().objects.filter(pk=0).all(): + o._force_delete = True + Model.delete(o) + # An object with pk 0 wouldn't deleted. That's not normal, we alert admins. + msg = "Lors de la vérification d'une permission d'ajout, un objet de clé primaire nulle était "\ + "encore présent.\n"\ + "Type de permission : " + self.type + "\n"\ + "Modèle : " + str(self.model) + "\n"\ + "Objet trouvé : " + str(model_to_dict(o)) + "\n\n"\ + "--\nLe BDE" + mail_admins("[Note Kfet] Un objet a été supprimé de force", msg) - # Force insertion, no data verification, no trigger - obj._force_save = True - Model.save(obj, force_insert=True) - # We don't want log anything - obj._no_log = True - ret = self.model.model_class().objects.filter(self.query & Q(pk=0)).exists() - # Delete testing object - obj._force_delete = True - Model.delete(obj) + # Force insertion, no data verification, no trigger + obj._force_save = True + Model.save(obj, force_insert=True) + # We don't want log anything + obj._no_log = True + ret = self.model.model_class().objects.filter(self.query & Q(pk=0)).exists() + # Delete testing object + obj._force_delete = True + Model.delete(obj) with open("/tmp/log", "w") as f: f.write(str(obj) + ", " + str(obj.pk) + ", " + str(self.model.model_class().objects.filter(pk=0).exists()))