0

I've had a table in which different expenses are displaying which are bills, rents, salaries, etc, and I want to hide salaries from my staff, so I'm adding new filter to my queryset which needs to restrict that to them, but when I test it with different users, it is still there.

I'm not entirely sure why is this happening, so can someone please explain me what am I doing wrong here. Thanks!

This is my custom permission:

@staticmethod
def can_view_salaries(user):
    return user.is_staff and user.has_perm('cms_expenses.can_view_salaries')

You can see my restapi views in which I'm doing the filtering.

class ExpenseViewSet(viewsets.ModelViewSet):
    def get_queryset(self):
        only_recurrent = self.request.query_params.get('recurrent', False)
        queryset = models.Expense.objects.get_expenses_list(self.request.user)
        if only_recurrent:
            queryset = queryset.exclude(scheduled_recurrence__isnull=True)
        if self.check_object_permissions(self.request.user, queryset):
            queryset = ExpenseAccessService.can_view_salaries(self.request.user)
        return queryset

    serializer_class = ExpenseSerializer
    filter_backends = (
        filters.DjangoFilterBackend,
        filters.SearchFilter,
        filters.OrderingFilter
    )

    filter_fields = ('paid', 'generated',)
    ordering_fields = (
        'value', 'currency', 'category', 'attachment', 'created', 'scheduled_recurrence', 'paid',
        'scheduled_recurrence__interval', 'scheduled_recurrence__next_occurrence', 'payment_proof',
        'description')
    search_fields = (
        'value', 'currency', 'category', 'attachment', 'created', 'paid',
        'scheduled_recurrence__interval', 'scheduled_recurrence__next_occurrence', 'payment_proof',
        'description')

    pagination_class = StandardResultsOffsetPagination

    permission_classes = [
        permissions.IsAuthenticated,
        expenses_permissions.ExpensesPermissions
    ]
copser
  • 2,523
  • 5
  • 38
  • 73
  • 1
    `can_view_salaries` function returns a boolean value. Why are you assigning it to a queryset? – AKS Apr 12 '17 at 06:51
  • @AKS I only want to filter the list properly based on permissions in the rest api view, that is why I'm using it in the queryset, but I'm open to suggestions, so I can understand this properly – copser Apr 12 '17 at 06:54
  • 1
    The logic in `get_queryset` is completely broken. If the user doesn't have object permissions, it doesn't change the queryset at all and just returns it. And if the user *does* have permissions, then it returns a boolean, which makes no sense at all. – Daniel Roseman Apr 12 '17 at 08:19
  • @DanielRoseman ok, so how can I fix this so I can not show salaries, can you show me? – copser Apr 12 '17 at 08:38

2 Answers2

0

Actually, check_object_permissions() doesn't check multi objects permissions

def check_object_permissions(self, request, obj):
    """
    Check if the request should be permitted for a given object.
    Raises an appropriate exception if the request is not permitted.
    """
    for permission in self.get_permissions():
        if not permission.has_object_permission(request, self, obj):
            self.permission_denied(
                request, message=getattr(permission, 'message', None)
            )

And, if you want to custom response.data , you'd better to override get_serializer_class like this:

def get_serializer_class(self):
    if self.request.user.is_staff:
        return StaffExpenseSerializer
    if self.request.user.is_superuser:
        return AdminExpenseSerializer
Lingbing
  • 30
  • 5
0

I'm a bit late posting the answer to this question, but someone may find it useful so, after talking to my friend and reading Daniela Roseman hint on the custom permissions that I wanted so setup for stuff, I've come up with this solutions:

class ExpenseViewSet(viewsets.ModelViewSet):
    def get_queryset(self):
        only_recurrent = self.request.query_params.get('recurrent', False)
        queryset = models.Expense.objects.get_expenses_list(self.request.user)
        if only_recurrent:
            queryset = queryset.exclude(scheduled_recurrence__isnull=True)
        if not ExpenseAccessService.can_view_salaries_and_commissions(self.request.user):
            queryset = queryset.exclude(category__in=["salary", "commissions"])
        return queryset

With django exclude I've restricted my stuff in future viewing of salaries and commissions, I've also come up with a solution using complex lookups with Q objects, but exclude is easier to read.

copser
  • 2,523
  • 5
  • 38
  • 73