dfunckt / django-rules

Awesome Django authorization, without the database

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Error: displaying objects even the user hasn't the correct permissions.

omargawdat opened this issue · comments

As you can see in the video the object permission in the admin doesn't work correctly
https://github.com/dfunckt/django-rules/assets/53629777/df5bf17e-c32c-41b3-9250-b5278cc16a60

Used package: Django rules and Django unfold
code:
from rules.contrib.admin import ObjectPermissionsModelAdminMixin
from unfold.admin import ModelAdmin

@admin.register(Worker)
class WorkerAdmin(RequestFormMixin, ObjectPermissionsModelAdminMixin, ModelAdmin):
form = WorkerForm
autocomplete_fields = [
"company",
]
filter_horizontal = ["packages"]
list_display = (
"str",
"phone_number",
"company",
"date_joined",
)
search_fields = [
"phone_number",
"company__username",
"first_name",
"last_name",
]
list_filter = (
("date_joined", RangeDateFilter),
"company",
)
list_filter_submit = True

fieldsets = (
    (
        "Personal Information",
        {
            "fields": (
                "company",
                ("first_name", "last_name"),
                "phone_number",
                "image",
                "packages",
                "date_joined",
                "is_active",
            ),
        },
    ),
)
readonly_fields = ("date_joined",)

I managed to solve the problem using the below code:
class ObjectPermissionsMixin:

def get_queryset(self, request):
    """Filter the queryset based on object-level view permissions."""
    queryset = super().get_queryset(request)
    if isinstance(request.user, StaffUser):
        return queryset
    return queryset.filter(pk__in=[item.pk for item in queryset if self.has_view_permission(request, item)])

def formfield_for_manytomany(self, db_field, request, **kwargs):
    """Filter Many-to-Many fields based on user's view permissions for the related model."""
    if db_field.many_to_many:
        model = db_field.related_model
        qs = model.objects.all()
        filtered_qs = [
            obj
            for obj in qs
            if request.user.has_perm(f"{model._meta.app_label}.view_{model._meta.model_name}", obj)
        ]
        kwargs["queryset"] = model.objects.filter(pk__in=[obj.pk for obj in filtered_qs])
    return super().formfield_for_manytomany(db_field, request, **kwargs)

def has_permission(self, request, obj, perm_type):
    """Check if permission of type `perm_type` exists and is granted to the user."""
    if isinstance(request.user, CompanyAgent):
        codename = get_permission_codename(perm_type, self.opts)
        permission = f"{self.opts.app_label}.{codename}"
        return request.user.has_perm(permission, obj)

    return request.user.has_perm(f"{self.opts.app_label}.{perm_type}_{self.opts.model_name}")

def has_view_permission(self, request, obj=None):
    """Verify user's view permission for an object."""
    return self.has_permission(request, obj, "view")

def has_change_permission(self, request, obj=None):
    """Verify user's change permission for an object."""
    return self.has_permission(request, obj, "change")

def has_delete_permission(self, request, obj=None):
    """Verify user's delete permission for an object."""
    return self.has_permission(request, obj, "delete")