Implement generic right checking for any View with the right parents

This commit is contained in:
Skia 2015-11-27 15:39:42 +01:00
parent b19ec084b6
commit 5c9e5a24ab
6 changed files with 143 additions and 13 deletions

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0007_auto_20151126_1613'),
]
operations = [
migrations.RemoveField(
model_name='page',
name='view_group',
),
migrations.AddField(
model_name='page',
name='view_group',
field=models.ManyToManyField(default=1, to='core.Group', related_name='viewable_pages'),
),
]

View File

@ -0,0 +1,23 @@
# -*- coding: utf-8 -*-
from __future__ import unicode_literals
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('core', '0008_auto_20151127_1007'),
]
operations = [
migrations.RemoveField(
model_name='page',
name='edit_group',
),
migrations.AddField(
model_name='page',
name='edit_group',
field=models.ManyToManyField(to='core.Group', related_name='editable_pages', default=1),
),
]

View File

@ -154,9 +154,11 @@ class Page(models.Model):
# playing with a Page object, use get_full_name() instead!
full_name = models.CharField(_('page name'), max_length=255, blank=True)
# TODO: Rightable abstract class from which every object with right needed will be able to be child of
# Put thoses 3 attributes there
owner_group = models.ForeignKey(Group, related_name="owned_pages", default=1)
edit_group = models.ForeignKey(Group, related_name="editable_pages", default=1)
view_group = models.ForeignKey(Group, related_name="viewable_pages", default=1)
edit_group = models.ManyToManyField(Group, related_name="editable_pages", default=1)
view_group = models.ManyToManyField(Group, related_name="viewable_pages", default=1)
class Meta:
unique_together = ('name', 'parent')

View File

@ -1,4 +1,65 @@
from django.http import HttpResponseForbidden
from django.core.exceptions import PermissionDenied
from django.views.generic.base import View
# TODO: see models.py's TODO!
class CanEditPropMixin(View):
"""
This view is made to protect any child view that would be showing some properties of an object that are restricted
to only the owner group of the given object.
In other word, you can make a view with this view as parent, and it would be retricted to the users that are in the
object's owner_group
"""
def dispatch(self, request, *arg, **kwargs):
res = super(CanEditPropMixin, self).dispatch(request, *arg, **kwargs)
obj = self.object
user = self.request.user
if obj is None:
return res
if user.is_superuser or user.groups.filter(name=obj.owner_group.name).exists():
return res
return HttpResponseForbidden("403, Forbidden")
class CanEditMixin(CanEditPropMixin):
"""
This view makes exactly the same this as its direct parent, but checks the group on the edit_group field of the
object
"""
def dispatch(self, request, *arg, **kwargs):
res = super(CanEditMixin, self).dispatch(request, *arg, **kwargs)
if res.status_code != 403:
return res
obj = self.object
user = self.request.user
if obj is None:
return res
for g in obj.edit_group.all():
if user.groups.filter(name=g.name).exists():
return super(CanEditPropMixin, self).dispatch(request, *arg, **kwargs)
return HttpResponseForbidden("403, Forbidden")
class CanViewMixin(CanEditMixin):
"""
This view still makes exactly the same this as its direct parent, but checks the group on the view_group field of
the object
"""
def dispatch(self, request, *arg, **kwargs):
res = super(CanViewMixin, self).dispatch(request, *arg, **kwargs)
if res.status_code != 403:
return res
obj = self.object
user = self.request.user
if obj is None:
return res
for g in obj.view_group.all():
if user.groups.filter(name=g.name).exists():
return super(CanEditPropMixin, self).dispatch(request, *arg, **kwargs)
raise PermissionDenied
return HttpResponseForbidden("403, Forbidden")
from .user import *
from .page import *
from .site import *
from .group import *

View File

@ -33,6 +33,17 @@ class UserGroupsForm(forms.ModelForm):
'user_permissions': CheckboxSelectMultiple,
}
class PagePropForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'
class Meta:
model = Page
fields = ['parent', 'name', 'owner_group', 'edit_group', 'view_group', ]
widgets = {
'edit_group': CheckboxSelectMultiple,
'view_group': CheckboxSelectMultiple,
}
class GroupEditForm(forms.ModelForm):
error_css_class = 'error'
required_css_class = 'required'

View File

@ -6,6 +6,8 @@ from django.contrib.auth.decorators import login_required, permission_required
from django.utils.decorators import method_decorator
from core.models import Page
from core.views.forms import PagePropForm
from core.views import CanViewMixin, CanEditMixin, CanEditPropMixin
class PageListView(ListView):
model = Page
@ -14,12 +16,23 @@ class PageListView(ListView):
context = super(PageListView, self).get_context_data(**kwargs)
return context
class PageView(DetailView):
model = Page
# Define some right management callable for user_passes_test
def user_can_view(as_view):
def guy(*arg, **kwargs):
res = self.as_view(*arg, **kwargs)
@method_decorator(permission_required('core.can_view'))
def dispatch(self, *args, **kwargs):
return super(PageView, self).dispatch(*args, **kwargs)
user = self.request.user
obj = self.page
for g in obj.view_group.all():
if g in user.groups.all():
print("Allowed")
return res
print("Not allowed")
return res
return guy
class PageView(CanViewMixin, DetailView):
model = Page
def get_object(self):
self.page = Page.get_page_by_full_name(self.kwargs['page_name'])
@ -34,14 +47,11 @@ class PageView(DetailView):
context['new_page'] = self.kwargs['page_name']
return context
class PagePropView(UpdateView):
class PagePropView(CanEditPropMixin, UpdateView):
model = Page
fields = ['parent', 'name', 'owner_group', 'edit_group', 'view_group', ]
form_class = PagePropForm
template_name_suffix = '_prop'
def __init__(self, *args, **kwargs):
super(PagePropView, self).__init__(*args, **kwargs)
def get_object(self):
page_name = self.kwargs['page_name']
p = Page.get_page_by_full_name(page_name)
@ -66,7 +76,7 @@ class PagePropView(UpdateView):
context['new_page'] = self.kwargs['page_name']
return context
class PageEditView(UpdateView):
class PageEditView(CanEditMixin, UpdateView):
model = Page
fields = ['title', 'content',]
template_name_suffix = '_edit'