Django-rules setup issue: has_perm always False for custom user model

413 views Asked by At

I am new to Django. I have been trying to set up django-rules with a custom user model but keep getting a 404 when trying to access the page. Here is how the setup looks:

Custom user model

class User(AbstractBaseUser, PermissionsMixin):

    class Meta:
        verbose_name = _('user')
        verbose_name_plural = _('users')

    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False, unique=True)

    first_name = models.CharField(max_length=200)
    last_name = models.CharField(max_length=200)

    email = models.EmailField(
        verbose_name='email address',
        max_length=255,
        unique=True,
    )

    is_active = models.BooleanField(default=False)

    objects = UserManager()

    USERNAME_FIELD = 'email'
    REQUIRED_FIELDS = []

    def __str__(self):
        return self.email

settings.py

AUTHENTICATION_BACKENDS = (
    'rules.permissions.ObjectPermissionBackend',
    'django.contrib.auth.backends.ModelBackend',
)

installed apps

INSTALLED_APPS = [
    # ...
    'rules.apps.AutodiscoverRulesConfig',
]

rules.py

@rules.predicate
def is_organisation_member(user, organisation):
    """Check if user is an active organisation member"""
    m = get_if_exists(
        OrganisationMember,
        user=user,
        organisation=organisation,
        organisation__state=Organisation.LifecycleState.ACTIVE
    )
    if not m:
        return False
    if not m.is_active:
        return False
    return True

rules.add_perm('organisations.member',  (is_authenticated & is_active & is_organisation_member))

views.py

def get_organisation_by_slug(request, *args, **kwargs):
    return get_object_or_404(Organisation, workspace_name=kwargs['workspace'])

@permission_required('organisations.member', fn=get_organisation_by_slug)
def OrganisationView(request, workspace):
    # ...

urls.py

urlpatterns = [
    path('admin/', admin.site.urls),

    # ...

    # organisation
    path('<str:workspace>', v.OrganisationView, name="organisation-show"),
    # ...
]

According to the debug, is_organisation_member returns True, but the user still gets a 404 error when trying to view the page (without django-rules permission_required decorator the page works). Any ideas why am I getting a 404 response?

1

There are 1 answers

0
Alexey On

without django-rules's permission_required decorator the page works

That was only half true! It worked when the generator was removed and existing test data was present. But when the query returned nothing, the 404 error showed up.

I have incorrectly assumed the issue was in setting up rules but after removing the decorator the error still persisted. I didn't see that error before because I always had test data auto-generated (a list of projects) but not this time. So, after reviewing the view function, I realised I was raising a 404 error when the project query was returning an empty list:

@permission_required('organisations.member', fn=get_organisation_by_slug)
def OrganisationView(request, workspace):

    # Query strings:
    # Extract 'tab' value appended to url as
    # ?tab=projects
    tab = request.GET.get('tab', '')
    
    # Get organisation
    try:
        o = Organisation.objects.get(workspace_name=workspace)
    except Organisation.DoesNotExist:
        raise Http404("Not found.")

    if tab == 'projects':
        # Get project list 
        try:
            p = Project.objects.filter(organisation__workspace_name=workspace) \
                .order_by('-created_at')
        except Project.DoesNotExist:
            raise Http404("Not found")
    else:
        raise Http404("Not found...") # ERROR CAUSED BY THIS LINE
        # To fix the error, I have removed the above line and added the below query
        # p = Project.objects.filter(organisation__workspace_name=workspace) \
        #     .order_by('-created_at')

    # Set context 
    context = {
        'o': o,
        'projects': p
    }

    return render(request, 'bb/home.html', context)

As I was confident my view was okay, I didn't post the complete function making it hard for anyone else to pickup the error. I realised the error was in the view after adding has_perm(self, perm, obj=None): return True to the User model but still getting a 404 error.