0

I have an endpoint /api/v1/invoice/#id/

I want that only author of this invoice should be able to view invoice Or staff should be able to view this invoice And superuser should be able to view, update, delete invoice

I tried creating permissions.py file in my app:

permissions.py

from rest_framework.permissions import BasePermission


class AuthorGetStaffGetAdminAll(BasePermission):
    edit_methods = ("PUT", "PATCH", "DELETE")

    def has_permission(self, request, view):
        if request.user.is_authenticated:
            return True
        return False

    def has_object_permission(self, request, view, obj):
        if request.user.is_superuser:
            return True

        if obj.author == request.user and request.method not in self.edit_methods:
            return True

        if request.user.is_staff and request.method not in self.edit_methods:
            return True

        return False

serializer.py

class InvoiceSerializer(serializers.ModelSerializer):
    order = serializers.SlugRelatedField(slug_field='id', queryset=order.Order.objects.all())
    id = serializers.CharField(max_length=100, read_only=True)
    class Meta:
        model = invoice.Invoice
        fields = ['id', 'invoice_series', 'order', 'payment_id']

view.py

class InvoiceDisplayView(APIView):
    permission_classes = [AuthorGetStaffGetAdminAll]

    def get(self, request, invoice_id):
        invoice = Invoice.objects.get(id__iexact=invoice_id)
        serializer = InvoiceSerializer(invoice)
        return Response(serializer.data)

urls.py

from django.urls import path
from . import views

urlpatterns = [
    path('v1/invoices/<str:invoice_id>/', views.InvoiceDisplayView.as_view(), name="invoice_view"),
]
Rajesh
  • 9
  • 4
  • What issue are you facing here? – Uzzal H. Mohammad Nov 01 '21 at 06:25
  • Even if the user who has not created it, he can view the invoice details currently. I want that only owner of that invoice should be able to view it, or staff should be able to view it, and superuser should be able to view, update and delete invoice. – Rajesh Nov 01 '21 at 06:30
  • Did you add this created AuthorGetStaffGetAdminAll in the permission class in your APIView ? – Uzzal H. Mohammad Nov 01 '21 at 06:32
  • class InvoiceDisplayView(APIView): permission_classes = [AuthorGetStaffGetAdminAll] def get(self, request, invoice_id): invoice = Invoice.objects.get(id__iexact=invoice_id) serializer = InvoiceSerializer(invoice) return Response(serializer.data) – Rajesh Nov 01 '21 at 06:34
  • @UzzalH.Mohammad Yes I have added see code – Rajesh Nov 01 '21 at 06:35
  • I'm not sure your code looks okay here, can you check the users you are using are normal users and not a stuff or author(creator of that object) or super admin. – Uzzal H. Mohammad Nov 01 '21 at 06:45
  • Yes, I have created test cases, in that my user is normal user, not a staff and not admin. – Rajesh Nov 01 '21 at 06:46
  • I tried to change code in has_permission method of permissions.py file in that I tried using this code: def has_permission(self, request, view): if request.user.is_superuser: return True if request.user.is_staff: return True return False but it gives access to staff and admin only how can I check for is owner in this function – Rajesh Nov 01 '21 at 06:52
  • Try one more thing check if this has_object_permission is actually being called and figure out why it is returning true for normal user. – Uzzal H. Mohammad Nov 01 '21 at 06:56
  • In which case has_object_permission is called, while we try to get model data like Invoice.objects.get(id=id) at that time it should get called?? – Rajesh Nov 01 '21 at 07:43
  • Or can you give me idea how can I check that why control is not coming in this function?? – Rajesh Nov 01 '21 at 07:44
  • Do you have serializer class and queryset in the RetriveAPIView ? this permission is checked only for default queryset as far as I know. – Uzzal H. Mohammad Nov 01 '21 at 08:32
  • @UzzalH.Mohammad Yes I have serializer but its model serializer and I have updated my question and included all views.py, serializers.py, permission.py files please have a look and suggest me what can I do – Rajesh Nov 01 '21 at 09:14
  • I have added my answer to your problem. – Uzzal H. Mohammad Nov 01 '21 at 09:53

2 Answers2

1

APIView do not have object level permission check. You can update your APIView with RetrieveUpdateDestroyAPIView :

class InvoiceDisplayView(RetrieveUpdateDestroyAPIView):
    
    lookup_field = 'invoice_id'  # primary key
    permissions_classes = [IsAuthenticatedAndOwner]
    queryset = Invoice.objects.all()
    serializer_class = InvoiceSerializer

if your primary key is invoice_id you can do this and no get method is required, this alone serves put update delete and get all alone, usually primary_key is just id or pk , in that case lookup_field will be 'id' or 'pk' and you need to update your urls as well :

urlpatterns = [
    path('v1/invoices/<int:id>/', views.InvoiceDisplayView.as_view(), name="invoice_view"),
]
0

Since you are using APIView and not generic view, you have to call check_object_permissions explicitly, this answer explains everything.

Your get method should look like this:

    def get(self, request, invoice_id):
        invoice = Invoice.objects.get(id__iexact=invoice_id)
        self.check_object_permissions(request, invoice)   # This calls permissions
        serializer = InvoiceSerializer(invoice)
        return Response(serializer.data)
nenadp
  • 798
  • 1
  • 7
  • 15