Move core auth mixins to their own file

This commit is contained in:
imperosol
2025-01-10 21:37:12 +01:00
parent cba915c34d
commit 0c01ad1770
34 changed files with 274 additions and 235 deletions

View File

@ -22,23 +22,17 @@
#
#
import types
from typing import Any
from django.contrib.auth.mixins import AccessMixin
from django.core.exceptions import PermissionDenied
from django.http import (
HttpResponseForbidden,
HttpResponseNotFound,
HttpResponseServerError,
)
from django.shortcuts import render
from django.utils.functional import cached_property
from django.views.generic.base import View
from django.views.generic.detail import SingleObjectMixin
from django.views.generic.edit import FormView
from sentry_sdk import last_event_id
from core.models import User
from core.views.forms import LoginForm
@ -60,186 +54,6 @@ def internal_servor_error(request):
return HttpResponseServerError(render(request, "core/500.jinja"))
def can_edit_prop(obj: Any, user: User) -> bool:
"""Can the user edit the properties of the object.
Args:
obj: Object to test for permission
user: core.models.User to test permissions against
Returns:
True if user is authorized to edit object properties else False
Examples:
```python
if not can_edit_prop(self.object ,request.user):
raise PermissionDenied
```
"""
return obj is None or user.is_owner(obj)
def can_edit(obj: Any, user: User) -> bool:
"""Can the user edit the object.
Args:
obj: Object to test for permission
user: core.models.User to test permissions against
Returns:
True if user is authorized to edit object else False
Examples:
```python
if not can_edit(self.object, request.user):
raise PermissionDenied
```
"""
if obj is None or user.can_edit(obj):
return True
return can_edit_prop(obj, user)
def can_view(obj: Any, user: User) -> bool:
"""Can the user see the object.
Args:
obj: Object to test for permission
user: core.models.User to test permissions against
Returns:
True if user is authorized to see object else False
Examples:
```python
if not can_view(self.object ,request.user):
raise PermissionDenied
```
"""
if obj is None or user.can_view(obj):
return True
return can_edit(obj, user)
class GenericContentPermissionMixinBuilder(View):
"""Used to build permission mixins.
This view protect any child view that would be showing an object that is restricted based
on two properties.
Attributes:
raised_error: permission to be raised
"""
raised_error = PermissionDenied
@staticmethod
def permission_function(obj: Any, user: User) -> bool:
"""Function to test permission with."""
return False
@classmethod
def get_permission_function(cls, obj, user):
return cls.permission_function(obj, user)
def dispatch(self, request, *arg, **kwargs):
if hasattr(self, "get_object") and callable(self.get_object):
self.object = self.get_object()
if not self.get_permission_function(self.object, request.user):
raise self.raised_error
return super().dispatch(request, *arg, **kwargs)
# If we get here, it's a ListView
queryset = self.get_queryset()
l_id = [o.id for o in queryset if self.get_permission_function(o, request.user)]
if not l_id and queryset.count() != 0:
raise self.raised_error
self._get_queryset = self.get_queryset
def get_qs(self2):
return self2._get_queryset().filter(id__in=l_id)
self.get_queryset = types.MethodType(get_qs, self)
return super().dispatch(request, *arg, **kwargs)
class CanCreateMixin(View):
"""Protect any child view that would create an object.
Raises:
PermissionDenied:
If the user has not the necessary permission
to create the object of the view.
"""
def dispatch(self, request, *arg, **kwargs):
res = super().dispatch(request, *arg, **kwargs)
if not request.user.is_authenticated:
raise PermissionDenied
return res
def form_valid(self, form):
obj = form.instance
if can_edit_prop(obj, self.request.user):
return super().form_valid(form)
raise PermissionDenied
class CanEditPropMixin(GenericContentPermissionMixinBuilder):
"""Ensure the user has owner permissions on the child view object.
In other word, you can make a view with this view as parent,
and it will be retricted to the users that are in the
object's owner_group or that pass the `obj.can_be_viewed_by` test.
Raises:
PermissionDenied: If the user cannot see the object
"""
permission_function = can_edit_prop
class CanEditMixin(GenericContentPermissionMixinBuilder):
"""Ensure the user has permission to edit this view's object.
Raises:
PermissionDenied: if the user cannot edit this view's object.
"""
permission_function = can_edit
class CanViewMixin(GenericContentPermissionMixinBuilder):
"""Ensure the user has permission to view this view's object.
Raises:
PermissionDenied: if the user cannot edit this view's object.
"""
permission_function = can_view
class FormerSubscriberMixin(AccessMixin):
"""Check if the user was at least an old subscriber.
Raises:
PermissionDenied: if the user never subscribed.
"""
def dispatch(self, request, *args, **kwargs):
if not request.user.was_subscribed:
raise PermissionDenied
return super().dispatch(request, *args, **kwargs)
class SubscriberMixin(AccessMixin):
def dispatch(self, request, *args, **kwargs):
if not request.user.is_subscribed:
return self.handle_no_permission()
return super().dispatch(request, *args, **kwargs)
class DetailFormView(SingleObjectMixin, FormView):
"""Class that allow both a detail view and a form view."""