mirror of https://gitlab.crans.org/bde/nk20
More optimisation
This commit is contained in:
parent
f80cb635d3
commit
6fc43e651e
|
@ -5,15 +5,19 @@ from django.contrib.contenttypes.models import ContentType
|
|||
from member.backends import PermissionBackend
|
||||
from rest_framework import viewsets
|
||||
|
||||
from note_kfet.middlewares import get_current_authenticated_user
|
||||
|
||||
|
||||
class ReadProtectedModelViewSet(viewsets.ModelViewSet):
|
||||
"""
|
||||
Protect a ModelViewSet by filtering the objects that the user cannot see.
|
||||
"""
|
||||
|
||||
def get_queryset(self):
|
||||
model = ContentType.objects.get_for_model(self.serializer_class.Meta.model)
|
||||
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, model, "view"))
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
|
||||
user = get_current_authenticated_user()
|
||||
self.queryset = model.objects.filter(PermissionBackend.filter_queryset(user, model, "view"))
|
||||
|
||||
|
||||
class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
|
||||
|
@ -21,6 +25,8 @@ class ReadOnlyProtectedModelViewSet(viewsets.ReadOnlyModelViewSet):
|
|||
Protect a ReadOnlyModelViewSet by filtering the objects that the user cannot see.
|
||||
"""
|
||||
|
||||
def get_queryset(self):
|
||||
model = ContentType.objects.get_for_model(self.serializer_class.Meta.model)
|
||||
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, model, "view"))
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
model = ContentType.objects.get_for_model(self.serializer_class.Meta.model).model_class()
|
||||
user = get_current_authenticated_user()
|
||||
self.queryset = model.objects.filter(PermissionBackend.filter_queryset(user, model, "view"))
|
||||
|
|
|
@ -19,30 +19,28 @@ class PermissionBackend(ModelBackend):
|
|||
|
||||
@staticmethod
|
||||
def permissions(user, model, type):
|
||||
for membership in Membership.objects.filter(user=user).all():
|
||||
if not membership.valid() or membership.roles is None:
|
||||
continue
|
||||
|
||||
for permission in Permission.objects.filter(
|
||||
rolepermissions__role=membership.roles,
|
||||
model__app_label=model.app_label, # For polymorphic models, we don't filter on model type
|
||||
type=type
|
||||
).all():
|
||||
permission = permission.about(
|
||||
user=user,
|
||||
club=membership.club,
|
||||
User=User,
|
||||
Club=Club,
|
||||
Membership=Membership,
|
||||
Note=Note,
|
||||
NoteUser=NoteUser,
|
||||
NoteClub=NoteClub,
|
||||
NoteSpecial=NoteSpecial,
|
||||
F=F,
|
||||
Q=Q
|
||||
)
|
||||
if permission.mask.rank <= get_current_session().get("permission_mask", 0):
|
||||
yield permission
|
||||
for permission in Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \
|
||||
.filter(
|
||||
rolepermissions__role__membership__user=user,
|
||||
model__app_label=model.app_label, # For polymorphic models, we don't filter on model type
|
||||
type=type,
|
||||
).all():
|
||||
club = Club.objects.get(pk=permission.club)
|
||||
permission = permission.about(
|
||||
user=user,
|
||||
club=club,
|
||||
User=User,
|
||||
Club=Club,
|
||||
Membership=Membership,
|
||||
Note=Note,
|
||||
NoteUser=NoteUser,
|
||||
NoteClub=NoteClub,
|
||||
NoteSpecial=NoteSpecial,
|
||||
F=F,
|
||||
Q=Q
|
||||
)
|
||||
if permission.mask.rank <= get_current_session().get("permission_mask", 0):
|
||||
yield permission
|
||||
|
||||
@staticmethod
|
||||
def filter_queryset(user, model, t, field=None):
|
||||
|
@ -55,6 +53,9 @@ class PermissionBackend(ModelBackend):
|
|||
:return: A query that corresponds to the filter to give to a queryset
|
||||
"""
|
||||
|
||||
from time import time
|
||||
ti = time()
|
||||
|
||||
if user.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
|
||||
# Superusers have all rights
|
||||
return Q()
|
||||
|
@ -64,11 +65,13 @@ class PermissionBackend(ModelBackend):
|
|||
|
||||
# Never satisfied
|
||||
query = Q(pk=-1)
|
||||
for perm in PermissionBackend.permissions(user, model, t):
|
||||
perms = PermissionBackend.permissions(user, model, t)
|
||||
for perm in perms:
|
||||
if perm.field and field != perm.field:
|
||||
continue
|
||||
if perm.type != t or perm.model != model:
|
||||
continue
|
||||
perm.update_query()
|
||||
query = query | perm.query
|
||||
return query
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@ from django_filters.rest_framework import DjangoFilterBackend
|
|||
from rest_framework.filters import OrderingFilter, SearchFilter
|
||||
|
||||
from api.viewsets import ReadProtectedModelViewSet, ReadOnlyProtectedModelViewSet
|
||||
from member.backends import PermissionBackend
|
||||
from .serializers import NotePolymorphicSerializer, AliasSerializer, TemplateCategorySerializer, \
|
||||
TransactionTemplateSerializer, TransactionPolymorphicSerializer
|
||||
from ..models.notes import Note, Alias
|
||||
|
@ -30,7 +29,7 @@ class NotePolymorphicViewSet(ReadOnlyProtectedModelViewSet):
|
|||
Parse query and apply filters.
|
||||
:return: The filtered set of requested notes
|
||||
"""
|
||||
queryset = super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Note, "view"))
|
||||
queryset = super().get_queryset()
|
||||
|
||||
alias = self.request.query_params.get("alias", ".*")
|
||||
queryset = queryset.filter(
|
||||
|
@ -57,7 +56,7 @@ class AliasViewSet(ReadProtectedModelViewSet):
|
|||
:return: The filtered set of requested aliases
|
||||
"""
|
||||
|
||||
queryset = super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Alias, "view"))
|
||||
queryset = super().get_queryset()
|
||||
|
||||
alias = self.request.query_params.get("alias", ".*")
|
||||
queryset = queryset.filter(
|
||||
|
|
|
@ -14,12 +14,14 @@ from django.utils.translation import gettext_lazy as _
|
|||
|
||||
class InstancedPermission:
|
||||
|
||||
def __init__(self, model, query, type, field, mask):
|
||||
def __init__(self, model, query, type, field, mask, **kwargs):
|
||||
self.model = model
|
||||
self.query = query
|
||||
self.raw_query = query
|
||||
self.query = None
|
||||
self.type = type
|
||||
self.field = field
|
||||
self.mask = mask
|
||||
self.kwargs = kwargs
|
||||
|
||||
def applies(self, obj, permission_type, field_name=None):
|
||||
"""
|
||||
|
@ -33,6 +35,8 @@ class InstancedPermission:
|
|||
|
||||
if self.type == 'add':
|
||||
if permission_type == self.type:
|
||||
self.update_query()
|
||||
|
||||
# Don't increase indexes
|
||||
obj.pk = 0
|
||||
# Force insertion, no data verification, no trigger
|
||||
|
@ -45,10 +49,16 @@ class InstancedPermission:
|
|||
if permission_type == self.type:
|
||||
if self.field and field_name != self.field:
|
||||
return False
|
||||
self.update_query()
|
||||
return obj in self.model.model_class().objects.filter(self.query).all()
|
||||
else:
|
||||
return False
|
||||
|
||||
def update_query(self):
|
||||
if not self.query:
|
||||
# noinspection PyProtectedMember
|
||||
self.query = Permission._about(self.raw_query, **self.kwargs)
|
||||
|
||||
def __repr__(self):
|
||||
if self.field:
|
||||
return _("Can {type} {model}.{field} in {query}").format(type=self.type, model=self.model, field=self.field, query=self.query)
|
||||
|
@ -178,7 +188,8 @@ class Permission(models.Model):
|
|||
field = getattr(field, value[i])
|
||||
return field
|
||||
|
||||
def _about(self, query, **kwargs):
|
||||
@staticmethod
|
||||
def _about(query, **kwargs):
|
||||
if len(query) == 0:
|
||||
# The query is either [] or {} and
|
||||
# applies to all objects of the model
|
||||
|
@ -186,11 +197,11 @@ class Permission(models.Model):
|
|||
return Q(pk=F("pk"))
|
||||
if isinstance(query, list):
|
||||
if query[0] == 'AND':
|
||||
return functools.reduce(operator.and_, [self._about(query, **kwargs) for query in query[1:]])
|
||||
return functools.reduce(operator.and_, [Permission._about(query, **kwargs) for query in query[1:]])
|
||||
elif query[0] == 'OR':
|
||||
return functools.reduce(operator.or_, [self._about(query, **kwargs) for query in query[1:]])
|
||||
return functools.reduce(operator.or_, [Permission._about(query, **kwargs) for query in query[1:]])
|
||||
elif query[0] == 'NOT':
|
||||
return ~self._about(query[1], **kwargs)
|
||||
return ~Permission._about(query[1], **kwargs)
|
||||
elif isinstance(query, dict):
|
||||
q_kwargs = {}
|
||||
for key in query:
|
||||
|
@ -206,7 +217,7 @@ class Permission(models.Model):
|
|||
return Q(**q_kwargs)
|
||||
else:
|
||||
# TODO: find a better way to crash here
|
||||
raise Exception("query {} is wrong".format(self.query))
|
||||
raise Exception("query {} is wrong".format(query))
|
||||
|
||||
def about(self, **kwargs):
|
||||
"""
|
||||
|
@ -214,8 +225,8 @@ class Permission(models.Model):
|
|||
replaced by their values and the query interpreted
|
||||
"""
|
||||
query = json.loads(self.query)
|
||||
query = self._about(query, **kwargs)
|
||||
return InstancedPermission(self.model, query, self.type, self.field, self.mask)
|
||||
# query = self._about(query, **kwargs)
|
||||
return InstancedPermission(self.model, query, self.type, self.field, self.mask, **kwargs)
|
||||
|
||||
def __str__(self):
|
||||
if self.field:
|
||||
|
|
|
@ -13,27 +13,35 @@ from member.backends import PermissionBackend
|
|||
@stringfilter
|
||||
def not_empty_model_list(model_name):
|
||||
user = get_current_authenticated_user()
|
||||
session = get_current_session()
|
||||
if user is None:
|
||||
return False
|
||||
elif user.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
|
||||
elif user.is_superuser and session.get("permission_mask", 0) >= 42:
|
||||
return True
|
||||
if session.get("not_empty_model_list_" + model_name, None):
|
||||
return session.get("not_empty_model_list_" + model_name, None) == 1
|
||||
spl = model_name.split(".")
|
||||
ct = ContentType.objects.get(app_label=spl[0], model=spl[1])
|
||||
qs = ct.model_class().objects.filter(PermissionBackend.filter_queryset(user, ct, "view"))
|
||||
return qs.exists()
|
||||
session["not_empty_model_list_" + model_name] = 1 if qs.exists() else 2
|
||||
return session.get("not_empty_model_list_" + model_name) == 1
|
||||
|
||||
|
||||
@stringfilter
|
||||
def not_empty_model_change_list(model_name):
|
||||
user = get_current_authenticated_user()
|
||||
session = get_current_session()
|
||||
if user is None:
|
||||
return False
|
||||
elif user.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
|
||||
elif user.is_superuser and session.get("permission_mask", 0) >= 42:
|
||||
return True
|
||||
if session.get("not_empty_model_change_list_" + model_name, None):
|
||||
return session.get("not_empty_model_change_list_" + model_name, None) == 1
|
||||
spl = model_name.split(".")
|
||||
ct = ContentType.objects.get(app_label=spl[0], model=spl[1])
|
||||
qs = ct.model_class().objects.filter(PermissionBackend.filter_queryset(user, ct, "change"))
|
||||
return qs.exists()
|
||||
session["not_empty_model_change_list_" + model_name] = 1 if qs.exists() else 2
|
||||
return session.get("not_empty_model_change_list_" + model_name) == 1
|
||||
|
||||
|
||||
register = template.Library()
|
||||
|
|
|
@ -199,6 +199,7 @@ function autoCompleteNote(field_id, alias_matched_id, note_list_id, notes, notes
|
|||
// When the user click on an alias, the associated note is added to the emitters
|
||||
alias_obj.click(function () {
|
||||
field.val("");
|
||||
old_pattern = "";
|
||||
// If the note is already an emitter, we increase the quantity
|
||||
var disp = null;
|
||||
notes_display.forEach(function (d) {
|
||||
|
|
Loading…
Reference in New Issue