Skip to content
Snippets Groups Projects
backends.py 3.56 KiB
Newer Older
ynerant's avatar
ynerant committed
# Copyright (C) 2018-2020 by BDE ENS Paris-Saclay
# SPDX-License-Identifier: GPL-3.0-or-later

from django.contrib.auth.models import User
from django.contrib.contenttypes.models import ContentType
from django.db.models import Q, F

from note.models import Note, NoteUser, NoteClub, NoteSpecial
ynerant's avatar
ynerant committed
from note_kfet.middlewares import get_current_session
from permission.models import Permission
from .models import Membership, Club
ynerant's avatar
ynerant committed
from django.contrib.auth.backends import ModelBackend
ynerant's avatar
ynerant committed
class PermissionBackend(ModelBackend):
Benjamin Graillot's avatar
Benjamin Graillot committed
    supports_object_permissions = True
    supports_anonymous_user = False
    supports_inactive_user = False

    def permissions(user, model, type):
ynerant's avatar
ynerant committed
        for membership in Membership.objects.filter(user=user).all():
            if not membership.valid() or membership.roles is None:
Benjamin Graillot's avatar
Benjamin Graillot committed
                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
    @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
        """

ynerant's avatar
ynerant committed
        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)
        for perm in PermissionBackend.permissions(user, model, t):
            if perm.field and field != perm.field:
            if perm.type != t or perm.model != model:
                continue
            query = query | perm.query
        return query

Benjamin Graillot's avatar
Benjamin Graillot committed
    def has_perm(self, user_obj, perm, obj=None):
ynerant's avatar
ynerant committed
        if user_obj.is_superuser and get_current_session().get("permission_mask", 0) >= 42:
ynerant's avatar
ynerant committed
            return True

Benjamin Graillot's avatar
Benjamin Graillot committed
        if obj is None:
            return True

        perm = perm.split('.')[-1].split('_', 2)
        perm_type = perm[0]
Benjamin Graillot's avatar
Benjamin Graillot committed
        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
ynerant's avatar
ynerant committed

    def has_module_perms(self, user_obj, app_label):
        return False
Benjamin Graillot's avatar
Benjamin Graillot committed

    def get_all_permissions(self, user_obj, obj=None):
        ct = ContentType.objects.get_for_model(obj)
        return list(self.permissions(user_obj, ct, "view"))