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