jazzband/django-permission

Custom permission logic with @permission_required() decorator and {% if ... %} tag config issue

tabakov opened this issue · 1 comments

Hello!
I've read the docs, read #26 and #28 examples, tried to find out where I've mistaken using Kawaz sources, but still can't understand where I've made a mistake.

I'm using Djnago 1.11 with Python 3.6.1 and django-permission 1.4.0 (also tried under django 1.10.7, python 3.6.0)
I have 'console_test' project with 'console' app inside it. It has 1 model called Deal, so my models.py looks like this:

#models.py
from django.db import models

# Create your models here.
from django.contrib.auth.models import User

class Deal(models.Model):
    title = models.CharField(max_length=200)
    desc = models.CharField(max_length=200, blank=True)
    user = models.ForeignKey(User)

In settings.py of the project I've:
1)Added permission to INSTALLED_APPS:

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'console',
    'permission',
]

2)Added 'builtins': ['permission.templatetags.permissionif'], for using {% if user has ... %} in TEMPLATES:

TEMPLATES = [
    {
        'BACKEND': 'django.template.backends.django.DjangoTemplates',
        'DIRS': [os.path.join(BASE_DIR, 'templates')]
        ,
        'APP_DIRS': True,
        'OPTIONS': {
            'context_processors': [
                'django.template.context_processors.debug',
                'django.template.context_processors.request',
                'django.contrib.auth.context_processors.auth',
                'django.contrib.messages.context_processors.messages',
            ],
            'builtins': ['permission.templatetags.permissionif'],

        },
    },
]

3)Added to the bottom of the settings.py AUTHENTICATION_BACKENDS:

AUTHENTICATION_BACKENDS = (
    'django.contrib.auth.backends.ModelBackend', # default
    'permission.backends.PermissionBackend',
)

4)Then in project's urls.py (not app's) I've added Autodiscover

#urls.py
from django.conf.urls import url, include
from django.contrib import admin
from django.contrib.auth import views as auth_views

import permission; permission.autodiscover()

urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^console/', include('console.urls', namespace="console")),
    url(r'^accounts/login/$', auth_views.login, {'template_name': 'login.html'}, name='login'),
    url(r'^accounts/logout/$', auth_views.logout_then_login, name='logout'),
]

5)Then I've created perms.py file inside 'console' app dir (Is it right? Not in 'console_test' project root?) with AuthorPermissionLogic, StaffPermissionLogic and CustomPermissionLogic (for test purposes it always returns True):

#perms.py
from permission.logics import AuthorPermissionLogic, StaffPermissionLogic, PermissionLogic

class CustomPermissionLogic(PermissionLogic):
    def has_perm(self, user_obj, perm, obj=None):
        return True

PERMISSION_LOGICS = (
    ('console.Deal', AuthorPermissionLogic()),
    ('console.Deal', StaffPermissionLogic()),
    ('console.Deal', CustomPermissionLogic()),
)

In views I have 4 views (Index, Result, Detail and Change).

#views.py
from django.shortcuts import render

from django.shortcuts import get_object_or_404
from django.http import HttpResponse,HttpResponseRedirect
from django.core.urlresolvers import reverse

from .models import Deal
from django.views import generic
from permission.decorators import permission_required

class IndexView(generic.ListView):
    template_name = 'index.html'
    context_object_name = 'model_list'

    def get_queryset(self):
        return Deal.objects.all()

def change(request, model_id):
    model = get_object_or_404(Deal, pk=model_id)
    try:
        model.title = request.POST['title']
        model.desc = request.POST['desc']
        model.save()
        return HttpResponseRedirect(reverse('console:results', args=(model.id,)))
    except:
        return HttpResponse("Error changing model")

def detail(request, *args, **kwargs):
    model = get_object_or_404(Deal, pk=kwargs['model_id'])
    return render(request, 'detail.html', {'model': model})

def results(request, *args, **kwargs):
    model = get_object_or_404(Deal, pk=kwargs['model_id'])
    return render(request, 'results.html', {'model': model})

console app's urls.py are simple

#urls.py
from django.conf.urls import url
from . import views
urlpatterns = [
    url(r'^$', views.IndexView.as_view(), name='index'),
    url(r'^(?P<model_id>[0-9]+)/detail/$', views.detail, name='detail'),
    url(r'^(?P<model_id>[0-9]+)/results/$', views.results, name='results'),
    url(r'^(?P<model_id>[0-9]+)/change/$', views.change, name='change'),
]

I've tried a lot to make this module working for me but unfortunately unsuccessfully.

If I try to use, for example, 'deal.read' for permission name with @permission_required decorator I'm always getting error "Permission matching query does not exist.

If I try to use for example, 'read' for permission name @permission_required decorator I've always being redirected to login screen (no matter what CustomPermissionLogic has_perm function returns). Could you tell me where I've made a mistake?

So views under this decorator are unreachable for users. Super-user can reach these views (as I understand no permission checking is made for him) but {% if user has ... %} template tags inside view template also doesn't work.

So I have some questions:

  1. If I want to use @permission_required decorator to limit access to some views (for ex. With list of models and Detail page), how can I do that? What permission name I must use to limit access with that built-in Logic?

If I want to use AuthorPermissionLogic, StaffPermissionLogic, GroupInPermissionLogic what permission name must be? Must I use 'app_name.permission_name' or 'model_name.permission_name' or 'app_name.model_name.permission_name' or just 'permission_name'? Is it connected somehow with Logic?

Example

@permission_required('staff? or console.staff? or deal.staff?')
How to combine them (for ex. Author and Custom), with a list (['staff','author']?

  1. The same situation, if I want to use {% if user has ... %} template tags?

  2. I've created CustomPermissionLogic and want to create permissions for viewing, deleting, and modifying Deal model objects. How can I bind by permissions to be processed by CustomPermissionLogic. I've tried to check whether has_perm function is used during permission-checking process but it seems that it is unreachable, return True or return False or raise Exception inside it has no effect at alaa. I can't understand how to bind permissions to model or to CustomPermissionLogic. How does django-permission module bind them?

Example:

I want Deal model to have permissions: read, modify and delete
CustomPermissionLogic has has_perm function, that can process that permissions and return True or False.
CustomPermissionLogic binded to Deal model via perms.py file inside console app dir ('console.Deal', CustomPermissionLogic()),
How to bind my "new permissions" to Deal or to CustomPermissionLogic to use them with @permission_required() or {% if user has ... %}

assert user1.has_perm('permission.add_article') == True

As like the code in README, the name should be

{model_name}.{permission}_{app_name}

And if you would like to limit users to see the page. Add view permission by yourself (this is a Django part and not django-permission part) like

https://github.com/kawazrepos/Kawaz3rd/blob/develop/src/kawaz/apps/blogs/models.py#L72
https://github.com/kawazrepos/Kawaz3rd/blob/develop/src/kawaz/apps/blogs/views.py#L34