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-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
|
2020-03-19 01:26:06 +00:00
|
|
|
from django.contrib.contenttypes.models import ContentType
|
2020-03-18 13:42:35 +00:00
|
|
|
from django.db.models import Q, F
|
|
|
|
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
|
|
|
|
|
2020-03-19 01:26:06 +00:00
|
|
|
@staticmethod
|
2020-03-19 23:06:28 +00:00
|
|
|
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,
|
|
|
|
model__app_label=model.app_label, # For polymorphic models, we don't filter on model type
|
|
|
|
type=type,
|
|
|
|
).all():
|
2020-03-20 14:58:14 +00:00
|
|
|
if not isinstance(model, permission.model.__class__):
|
|
|
|
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
|
|
|
|
2020-03-19 01:26:06 +00:00
|
|
|
@staticmethod
|
|
|
|
def filter_queryset(user, model, t, field=None):
|
2020-03-18 13:42:35 +00:00
|
|
|
"""
|
|
|
|
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
|
2020-03-19 01:26:06 +00:00
|
|
|
:param t: The type of modification (view, add, change, delete)
|
2020-03-18 13:42:35 +00:00
|
|
|
: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:
|
2020-03-18 13:42:35 +00:00
|
|
|
# Superusers have all rights
|
|
|
|
return Q()
|
|
|
|
|
2020-03-19 01:26:06 +00:00
|
|
|
if not isinstance(model, ContentType):
|
|
|
|
model = ContentType.objects.get_for_model(model)
|
|
|
|
|
2020-03-18 13:42:35 +00:00
|
|
|
# Never satisfied
|
|
|
|
query = Q(pk=-1)
|
2020-03-20 00:46:59 +00:00
|
|
|
perms = PermissionBackend.permissions(user, model, t)
|
|
|
|
for perm in perms:
|
2020-03-19 01:26:06 +00:00
|
|
|
if perm.field and field != perm.field:
|
2020-03-18 13:42:35 +00:00
|
|
|
continue
|
2020-03-19 23:06:28 +00:00
|
|
|
if perm.type != t or perm.model != model:
|
2020-03-18 13:42:35 +00:00
|
|
|
continue
|
2020-03-20 00:46:59 +00:00
|
|
|
perm.update_query()
|
2020-03-18 13:42:35 +00:00
|
|
|
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:
|
2020-03-18 13:42:35 +00:00
|
|
|
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
|
2020-03-19 23:06:28 +00:00
|
|
|
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)):
|
2020-03-18 13:42:35 +00:00
|
|
|
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):
|
2020-03-19 23:06:28 +00:00
|
|
|
ct = ContentType.objects.get_for_model(obj)
|
|
|
|
return list(self.permissions(user_obj, ct, "view"))
|