nk20/apps/permission/backends.py

121 lines
4.4 KiB
Python
Raw Normal View History

2020-03-07 12:12:17 +00:00
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later
2020-04-01 01:42:19 +00:00
import datetime
2020-03-20 01:14:43 +00:00
from django.contrib.auth.backends import ModelBackend
2020-03-20 17:22:20 +00:00
from django.contrib.auth.models import User, AnonymousUser
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q, F
2020-03-31 12:57:44 +00:00
from note.models import Note, NoteUser, NoteClub, NoteSpecial
2020-03-19 15:12:52 +00:00
from note_kfet.middlewares import get_current_session
2020-03-20 13:43:35 +00:00
from member.models import Membership, Club
2019-09-18 12:26:42 +00:00
2020-03-20 17:22:20 +00:00
from .models import Permission
2019-09-18 12:26:42 +00:00
2020-03-07 12:12:17 +00:00
class PermissionBackend(ModelBackend):
2020-03-20 14:58:14 +00:00
"""
Manage permissions of users
"""
2019-09-18 12:26:42 +00:00
supports_object_permissions = True
supports_anonymous_user = False
supports_inactive_user = False
@staticmethod
def permissions(user, model, type):
2020-03-20 14:58:14 +00:00
"""
List all permissions of the given user that applies to a given model and a give type
:param user: The owner of the permissions
:param model: The model that the permissions shoud apply
:param type: The type of the permissions: view, change, add or delete
:return: A generator of the requested permissions
"""
2020-03-20 00:46:59 +00:00
for permission in Permission.objects.annotate(club=F("rolepermissions__role__membership__club")) \
.filter(
rolepermissions__role__membership__user=user,
2020-04-01 01:42:19 +00:00
rolepermissions__role__membership__date_start__lte=datetime.date.today(),
rolepermissions__role__membership__date_end__gte=datetime.date.today(),
2020-03-20 00:46:59 +00:00
model__app_label=model.app_label, # For polymorphic models, we don't filter on model type
type=type,
).all():
if not isinstance(model, permission.model.__class__) or not permission.club:
2020-03-20 14:58:14 +00:00
continue
2020-03-20 00:46:59 +00:00
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
2019-09-18 12:26:42 +00:00
@staticmethod
def filter_queryset(user, model, t, field=None):
"""
Filter a queryset by considering the permissions of a given user.
:param user: The owner of the permissions that are fetched
:param model: The concerned model of the queryset
:param t: The type of modification (view, add, change, delete)
:param field: The field of the model to test, if concerned
:return: A query that corresponds to the filter to give to a queryset
"""
2020-03-20 17:22:20 +00:00
if user is None or isinstance(user, AnonymousUser):
# Anonymous users can't do anything
return Q(pk=-1)
2020-03-19 15:12:52 +00:00
if user.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
# Superusers have all rights
return Q()
if not isinstance(model, ContentType):
model = ContentType.objects.get_for_model(model)
# Never satisfied
query = Q(pk=-1)
2020-03-20 00:46:59 +00:00
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
2020-03-20 00:46:59 +00:00
perm.update_query()
query = query | perm.query
return query
2019-09-18 12:26:42 +00:00
def has_perm(self, user_obj, perm, obj=None):
2020-03-20 17:22:20 +00:00
if user_obj is None or isinstance(user_obj, AnonymousUser):
return False
2020-03-19 15:12:52 +00:00
if user_obj.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
2020-03-07 12:12:17 +00:00
return True
2019-09-18 12:26:42 +00:00
if obj is None:
return True
perm = perm.split('.')[-1].split('_', 2)
perm_type = perm[0]
2019-09-18 12:26:42 +00:00
perm_field = perm[2] if len(perm) == 3 else None
ct = ContentType.objects.get_for_model(obj)
if any(permission.applies(obj, perm_type, perm_field)
for permission in self.permissions(user_obj, ct, perm_type)):
return True
return False
2020-03-07 12:12:17 +00:00
def has_module_perms(self, user_obj, app_label):
return False
2019-09-18 12:26:42 +00:00
def get_all_permissions(self, user_obj, obj=None):
ct = ContentType.objects.get_for_model(obj)
return list(self.permissions(user_obj, ct, "view"))