mirror of
https://gitlab.crans.org/bde/nk20
synced 2025-06-21 01:48:21 +02:00
Protect views from viewing if the user has no right to view an object
This commit is contained in:
@ -2,6 +2,7 @@
|
||||
# SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
from django.contrib.auth.models import User
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import PermissionDenied
|
||||
from django.db.models import Q, F
|
||||
|
||||
@ -15,7 +16,8 @@ class PermissionBackend(ModelBackend):
|
||||
supports_anonymous_user = False
|
||||
supports_inactive_user = False
|
||||
|
||||
def permissions(self, user):
|
||||
@staticmethod
|
||||
def permissions(user):
|
||||
for membership in Membership.objects.filter(user=user).all():
|
||||
if not membership.valid() or membership.roles is None:
|
||||
continue
|
||||
@ -37,12 +39,13 @@ class PermissionBackend(ModelBackend):
|
||||
)
|
||||
yield permission
|
||||
|
||||
def filter_queryset(self, user, model, type, field=None):
|
||||
@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 type: The type of modification (view, add, change, delete)
|
||||
: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
|
||||
"""
|
||||
@ -51,12 +54,15 @@ class PermissionBackend(ModelBackend):
|
||||
# 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 self.permissions(user):
|
||||
if field and field != perm.field:
|
||||
for perm in PermissionBackend.permissions(user):
|
||||
if perm.field and field != perm.field:
|
||||
continue
|
||||
if perm.model != model or perm.type != type:
|
||||
if perm.model != model or perm.type != t:
|
||||
continue
|
||||
query = query | perm.query
|
||||
return query
|
||||
|
@ -23,6 +23,7 @@ from note.forms import AliasForm, ImageForm
|
||||
from note.models import Alias, NoteUser
|
||||
from note.models.transactions import Transaction
|
||||
from note.tables import HistoryTable, AliasTable
|
||||
from .backends import PermissionBackend
|
||||
|
||||
from .filters import UserFilter, UserFilterFormHelper
|
||||
from .forms import SignUpForm, ProfileForm, ClubForm, MembershipForm, MemberFormSet, FormSetHelper
|
||||
@ -120,6 +121,9 @@ class UserDetailView(LoginRequiredMixin, DetailView):
|
||||
context_object_name = "user_object"
|
||||
template_name = "member/profile_detail.html"
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, User, "view"))
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
user = context['user_object']
|
||||
@ -147,7 +151,7 @@ class UserListView(LoginRequiredMixin, SingleTableView):
|
||||
formhelper_class = UserFilterFormHelper
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
qs = super().get_queryset()
|
||||
qs = super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, User, "view"))
|
||||
self.filter = self.filter_class(self.request.GET, queryset=qs)
|
||||
self.filter.form.helper = self.formhelper_class()
|
||||
return self.filter.qs
|
||||
@ -296,7 +300,7 @@ class UserAutocomplete(autocomplete.Select2QuerySetView):
|
||||
if not self.request.user.is_authenticated:
|
||||
return User.objects.none()
|
||||
|
||||
qs = User.objects.all()
|
||||
qs = User.objects.filter(PermissionBackend.filter_queryset(self.request.user, User, "view")).all()
|
||||
|
||||
if self.q:
|
||||
qs = qs.filter(username__regex="^" + self.q)
|
||||
@ -327,11 +331,17 @@ class ClubListView(LoginRequiredMixin, SingleTableView):
|
||||
model = Club
|
||||
table_class = ClubTable
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))
|
||||
|
||||
|
||||
class ClubDetailView(LoginRequiredMixin, DetailView):
|
||||
model = Club
|
||||
context_object_name = "club"
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Club, "view"))
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
club = context["club"]
|
||||
@ -350,6 +360,11 @@ class ClubAddMemberView(LoginRequiredMixin, CreateView):
|
||||
form_class = MembershipForm
|
||||
template_name = 'member/add_members.html'
|
||||
|
||||
def get_queryset(self, **kwargs):
|
||||
return super().get_queryset().filter(PermissionBackend.filter_queryset(self.request.user, Membership, "view")
|
||||
| PermissionBackend.filter_queryset(self.request.user, Membership,
|
||||
"change"))
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['formset'] = MemberFormSet()
|
||||
|
Reference in New Issue
Block a user