fix admin user persm
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 5s
Build and Push Docker Images / Build and Push Docker Images (push) Failing after 5s
This commit is contained in:
@@ -1,6 +1,44 @@
|
||||
from rest_framework import permissions
|
||||
|
||||
|
||||
def user_is_admin(user) -> bool:
|
||||
"""Single source of truth for "is this user an administrator?".
|
||||
|
||||
Any of the three flags grants admin access: the app-specific ``is_admin``
|
||||
flag, Django's ``is_staff``, or ``is_superuser``. Both the permission
|
||||
classes and the per-view authorization checks use this so the three flags
|
||||
behave identically everywhere.
|
||||
"""
|
||||
return bool(
|
||||
user
|
||||
and user.is_authenticated
|
||||
and (
|
||||
getattr(user, "is_admin", False)
|
||||
or getattr(user, "is_staff", False)
|
||||
or getattr(user, "is_superuser", False)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
class IsAdminOrStaffPermission(permissions.BasePermission):
|
||||
"""Admin gate for admin-only endpoints and for views that have no
|
||||
model/queryset of their own (e.g. proxy endpoints).
|
||||
|
||||
``IsStaffEditorPermission`` can't be used on model-less views because it
|
||||
derives the required permission from ``view.queryset.model`` (``None``
|
||||
there); it also requires granular Django model permissions that admin
|
||||
accounts are not necessarily granted. This gate keys off admin status
|
||||
instead.
|
||||
"""
|
||||
|
||||
message = {
|
||||
"message": "You do not have permission to perform this action.",
|
||||
}
|
||||
|
||||
def has_permission(self, request, view):
|
||||
return user_is_admin(request.user)
|
||||
|
||||
|
||||
class IsStaffEditorPermission(permissions.DjangoModelPermissions):
|
||||
perms_map = {
|
||||
"GET": ["%(app_label)s.view_%(model_name)s"],
|
||||
|
||||
@@ -94,6 +94,7 @@ class CustomUserSerializer(serializers.ModelSerializer):
|
||||
"email",
|
||||
"last_login",
|
||||
"date_joined",
|
||||
"is_staff",
|
||||
"is_superuser",
|
||||
)
|
||||
|
||||
|
||||
+23
-27
@@ -7,6 +7,7 @@ from rest_framework import generics, permissions
|
||||
from rest_framework.authtoken.serializers import AuthTokenSerializer
|
||||
from api.filters import UserFilter
|
||||
from api.mixins import StaffEditorPermissionMixin
|
||||
from api.permissions import IsAdminOrStaffPermission, user_is_admin
|
||||
from api.models import User, Atoll, Island, TemporaryUser
|
||||
from api.notifications import send_sms
|
||||
from rest_framework.response import Response
|
||||
@@ -256,7 +257,8 @@ class UserprofileAPIView(generics.RetrieveUpdateAPIView):
|
||||
return self.request.user
|
||||
|
||||
|
||||
class UserUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
class UserUpdateAPIView(generics.UpdateAPIView):
|
||||
permission_classes = [IsAdminOrStaffPermission]
|
||||
serializer_class = UserUpdateSerializer
|
||||
queryset = User.objects.all()
|
||||
lookup_field = "pk"
|
||||
@@ -269,10 +271,7 @@ class UserUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
{"message": "You cannot update a superuser."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
if request.user != user and (
|
||||
not request.user.is_authenticated
|
||||
or not getattr(request.user, "is_admin", False)
|
||||
):
|
||||
if request.user != user and not user_is_admin(request.user):
|
||||
return Response(
|
||||
{"message": "You are not authorized to update this user."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
@@ -287,7 +286,8 @@ class UserUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
return super().update(request, *args, **kwargs)
|
||||
|
||||
|
||||
class AgreementUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
class AgreementUpdateAPIView(generics.UpdateAPIView):
|
||||
permission_classes = [IsAdminOrStaffPermission]
|
||||
serializer_class = UserAgreementSerializer
|
||||
queryset = User.objects.all()
|
||||
lookup_field = "pk"
|
||||
@@ -300,10 +300,7 @@ class AgreementUpdateAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView)
|
||||
{"message": "You cannot update a superuser."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
if request.user != user and (
|
||||
not request.user.is_authenticated
|
||||
or not getattr(request.user, "is_admin", False)
|
||||
):
|
||||
if request.user != user and not user_is_admin(request.user):
|
||||
return Response(
|
||||
{"message": "You are not authorized to update this user."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
@@ -372,7 +369,8 @@ class ListUserView(StaffEditorPermissionMixin, generics.ListAPIView):
|
||||
return User.objects.none()
|
||||
|
||||
|
||||
class UserVerifyAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
class UserVerifyAPIView(generics.UpdateAPIView):
|
||||
permission_classes = [IsAdminOrStaffPermission]
|
||||
serializer_class = CustomUserSerializer
|
||||
queryset = User.objects.all()
|
||||
lookup_field = "pk"
|
||||
@@ -380,10 +378,7 @@ class UserVerifyAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
def update(self, request, *args, **kwargs):
|
||||
user_id = kwargs.get("pk")
|
||||
user = get_object_or_404(User, pk=user_id)
|
||||
if request.user != user and (
|
||||
not request.user.is_authenticated
|
||||
or not getattr(request.user, "is_admin", False)
|
||||
):
|
||||
if request.user != user and not user_is_admin(request.user):
|
||||
return Response(
|
||||
{"message": "You are not authorized to update this user."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
@@ -421,7 +416,8 @@ class UserVerifyAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
|
||||
return Response({"message": "User successfully verified."})
|
||||
|
||||
|
||||
class UserRejectAPIView(StaffEditorPermissionMixin, generics.DestroyAPIView):
|
||||
class UserRejectAPIView(generics.DestroyAPIView):
|
||||
permission_classes = [IsAdminOrStaffPermission]
|
||||
serializer_class = CustomUserSerializer
|
||||
queryset = User.objects.all()
|
||||
lookup_field = "pk"
|
||||
@@ -446,10 +442,7 @@ class UserRejectAPIView(StaffEditorPermissionMixin, generics.DestroyAPIView):
|
||||
{"message": "You cannot remove a superuser."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
if request.user != user and (
|
||||
not request.user.is_authenticated
|
||||
or not getattr(request.user, "is_admin", False)
|
||||
):
|
||||
if request.user != user and not user_is_admin(request.user):
|
||||
return Response(
|
||||
{"message": "You are not authorized to reject this user."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
@@ -524,7 +517,8 @@ def filter_temporary_user(request):
|
||||
)
|
||||
|
||||
|
||||
class UserDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView):
|
||||
class UserDetailAPIView(generics.RetrieveAPIView):
|
||||
permission_classes = [IsAdminOrStaffPermission]
|
||||
queryset = User.objects.all()
|
||||
serializer_class = CustomReadOnlyUserSerializer
|
||||
lookup_field = "pk"
|
||||
@@ -532,11 +526,7 @@ class UserDetailAPIView(StaffEditorPermissionMixin, generics.RetrieveAPIView):
|
||||
def retrieve(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
user = request.user
|
||||
if (
|
||||
user != instance
|
||||
and not getattr(user, "is_admin", False)
|
||||
and not user.is_superuser #type: ignore
|
||||
):
|
||||
if user != instance and not user_is_admin(user):
|
||||
return Response(
|
||||
{"message": "You are not authorized to view this user's details."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
@@ -617,7 +607,7 @@ class RetrieveUpdateDestroyIslandView(
|
||||
return super().update(request, *args, **kwargs)
|
||||
|
||||
|
||||
class PersonVerifyAPIView(StaffEditorPermissionMixin, generics.GenericAPIView):
|
||||
class PersonVerifyAPIView(generics.GenericAPIView):
|
||||
"""
|
||||
Admin-gated proxy to the external Person verification API.
|
||||
|
||||
@@ -625,9 +615,15 @@ class PersonVerifyAPIView(StaffEditorPermissionMixin, generics.GenericAPIView):
|
||||
directly (it would leak an internal infra host to the browser), so the
|
||||
backend owns the integration. Returns the upstream JSON as-is.
|
||||
|
||||
This view has no model of its own, so it uses ``IsAdminOrStaffPermission``
|
||||
rather than the model-based ``StaffEditorPermissionMixin`` (which would
|
||||
crash dereferencing ``view.queryset.model``).
|
||||
|
||||
GET /api/auth/person/<id_card>/
|
||||
"""
|
||||
|
||||
permission_classes = [IsAdminOrStaffPermission]
|
||||
|
||||
def get(self, request, id_card: str, *args, **kwargs):
|
||||
import requests
|
||||
from decouple import config
|
||||
|
||||
Reference in New Issue
Block a user