CMS permissions can be managed from group views.
These permissions concern pages, images, documents and access to the wagtail admin site. Only appropriate elements can be selected: only the kfet root page and its descendants, same for the kfet root collection (for images and documents), and kfet snippets (MemberTeam). Add django-formset-js as dependency to help manipulate formsets. K-Fêt groups created from "devdata" commands get suitable permissions for the CMS.
This commit is contained in:
parent
82582866b4
commit
07f1a53532
19 changed files with 687 additions and 8 deletions
|
@ -68,6 +68,7 @@ INSTALLED_APPS = [
|
|||
'autocomplete_light',
|
||||
'captcha',
|
||||
'django_cas_ng',
|
||||
'djangoformsetjs',
|
||||
'bootstrapform',
|
||||
'kfet',
|
||||
'kfet.open',
|
||||
|
|
|
@ -5,6 +5,8 @@ from django.db import models
|
|||
from django.utils.crypto import get_random_string
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from kfet.cms.models import CmsPermissionManager
|
||||
|
||||
|
||||
class GenericTeamTokenManager(models.Manager):
|
||||
|
||||
|
@ -52,6 +54,7 @@ class CorePermissionManager(models.Manager):
|
|||
|
||||
class Permission(DjangoPermission):
|
||||
kfetcore = CorePermissionManager()
|
||||
kfetcms = CmsPermissionManager()
|
||||
|
||||
class Meta:
|
||||
proxy = True
|
||||
|
|
|
@ -11,6 +11,8 @@ from django.utils.translation import ugettext_lazy as _
|
|||
from django.views.generic import View
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from kfet.cms.views import get_kfetcms_group_formview_extra
|
||||
|
||||
from .forms import GroupForm
|
||||
from .models import GenericTeamToken, Group
|
||||
|
||||
|
@ -125,6 +127,8 @@ def get_group_formview_extras():
|
|||
_group_formview_extras = []
|
||||
|
||||
# Register additional group forms below.
|
||||
_group_formview_extras.append(
|
||||
get_kfetcms_group_formview_extra())
|
||||
|
||||
return [extra.copy() for extra in _group_formview_extras]
|
||||
|
||||
|
|
194
kfet/cms/forms.py
Normal file
194
kfet/cms/forms.py
Normal file
|
@ -0,0 +1,194 @@
|
|||
from django import forms
|
||||
from django.contrib.auth.models import Group
|
||||
from django.template.loader import render_to_string
|
||||
from django.utils.functional import cached_property
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailusers.forms import GroupPagePermissionFormSet
|
||||
|
||||
from utils.forms import KeepUnselectableModelFormMixin
|
||||
|
||||
from kfet.auth.fields import BasePermissionsField
|
||||
from kfet.auth.models import Permission
|
||||
|
||||
|
||||
class CmsGroupForm(KeepUnselectableModelFormMixin, forms.ModelForm):
|
||||
"""
|
||||
Allow to change permissions related to the cms of a `Group` object.
|
||||
"""
|
||||
access_admin = forms.BooleanField(
|
||||
label=_("Accès à l'administration"),
|
||||
required=False,
|
||||
help_text=_(
|
||||
"<b>Attention :</b> Aucun paramétrage effectué dans cette section "
|
||||
"n'aura d'effet si cette case est décochée."
|
||||
),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = ()
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
group = self.instance
|
||||
|
||||
if group.pk is not None:
|
||||
self.fields['access_admin'].initial = (
|
||||
group.permissions.filter(pk=self.access_admin_perm.pk).exists()
|
||||
)
|
||||
|
||||
def save(self):
|
||||
group = super().save()
|
||||
|
||||
if self.cleaned_data['access_admin']:
|
||||
group.permissions.add(self.access_admin_perm)
|
||||
else:
|
||||
group.permissions.remove(self.access_admin_perm)
|
||||
|
||||
return group
|
||||
|
||||
@cached_property
|
||||
def access_admin_perm(self):
|
||||
return Permission.objects.get(
|
||||
content_type__app_label='wagtailadmin',
|
||||
codename='access_admin',
|
||||
)
|
||||
|
||||
|
||||
class SnippetsCmsGroupForm(KeepUnselectableModelFormMixin, forms.ModelForm):
|
||||
permissions = BasePermissionsField(
|
||||
label='',
|
||||
queryset=Permission.kfetcms.all(),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Group
|
||||
fields = ('permissions',)
|
||||
|
||||
|
||||
def prepare_page_permissions_formset(pages):
|
||||
"""
|
||||
Create a new formset from base `GroupPagePermissionFormSet` Wagtail
|
||||
formset.
|
||||
|
||||
- The choices of `pages` field of forms are limited to `pages`.
|
||||
- If there is no initial data, add an initial with the first collection
|
||||
selected.
|
||||
- Make 'as_admin_panel' use a custom template.
|
||||
|
||||
Arguments
|
||||
pages (iterable of `Page`)
|
||||
|
||||
Returns
|
||||
A formset to select group permissions of pages.
|
||||
|
||||
"""
|
||||
class RestrictedFormSet(GroupPagePermissionFormSet):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Remove forms cache, as theirs options are changed.
|
||||
del self.forms
|
||||
|
||||
# 'initial' must be setup before accessing 'forms'.
|
||||
|
||||
self.initial = list(
|
||||
filter(lambda i: i['page'] in pages, self.initial))
|
||||
|
||||
# This is just little kindness.
|
||||
if not self.initial and pages:
|
||||
self.initial = [{'page': pages[0]}]
|
||||
|
||||
for form in self.forms:
|
||||
self.customize_form(form)
|
||||
|
||||
@property
|
||||
def empty_form(self):
|
||||
form = super().empty_form
|
||||
self.customize_form(form)
|
||||
return form
|
||||
|
||||
def customize_form(self, form):
|
||||
# Widget must be setup before queryset.
|
||||
form.fields['page'].widget = forms.Select()
|
||||
form.fields['page'].queryset = pages
|
||||
# Force use of `CheckboxInput` for `DELETE` field, as `HiddenInput`
|
||||
# is not compatible with `django-formset-js`.
|
||||
form.fields['DELETE'].widget = forms.CheckboxInput()
|
||||
|
||||
def as_admin_panel(self):
|
||||
# http://docs.wagtail.io/en/latest/reference/hooks.html#register-group-permission-panel
|
||||
template = 'kfet/permissions/page_permissions_formset.html'
|
||||
return render_to_string(template, {'formset': self})
|
||||
|
||||
return RestrictedFormSet
|
||||
|
||||
|
||||
def prepare_collection_member_permissions_formset(formset_cls, collections):
|
||||
"""
|
||||
Create a new formset from base `formset_cls`.
|
||||
|
||||
- The choices of `collections` field of forms produced by `formset_cls` are
|
||||
limited to `collections`.
|
||||
- If there is no initial data, add an initial with the first collection
|
||||
selected.
|
||||
- Make 'as_admin_panel' use a custom template.
|
||||
|
||||
Arguments
|
||||
formset_cls (subclass of
|
||||
`wagtail.wagtailcore.forms`
|
||||
`.BaseGroupCollectionMemberPermissionFormSet`
|
||||
):
|
||||
Formset to select group permissions of a collection member model.
|
||||
It should be rerieved from the `group_permission_panel` Wagtail
|
||||
hook. This includes the `Document` and `Image` models of Wagtail.
|
||||
collections (iterable of `wagtail.wagtailcore.models.Collection`)
|
||||
|
||||
Returns
|
||||
A formset to select group permissions of collection-related models.
|
||||
|
||||
"""
|
||||
class RestrictedFormSet(formset_cls):
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
# Remove forms cache, as theirs options are changed.
|
||||
del self.forms
|
||||
|
||||
# 'initial' must be setup before accessing 'forms'.
|
||||
|
||||
self.initial = list(
|
||||
filter(lambda i: i['collection'] in collections, self.initial))
|
||||
|
||||
# This is just little kindness.
|
||||
if not self.initial and collections:
|
||||
self.initial = [{'collection': collections[0]}]
|
||||
|
||||
for form in self.forms:
|
||||
self.customize_form(form)
|
||||
|
||||
@property
|
||||
def empty_form(self):
|
||||
form = super().empty_form
|
||||
self.customize_form(form)
|
||||
return form
|
||||
|
||||
def customize_form(self, form):
|
||||
form.fields['collection'].queryset = collections
|
||||
# Force use of `CheckboxInput` for `DELETE` field, as `HiddenInput`
|
||||
# is not compatible with `django-formset-js`.
|
||||
form.fields['DELETE'].widget = forms.CheckboxInput()
|
||||
|
||||
def as_admin_panel(self):
|
||||
template = (
|
||||
'kfet/permissions/collection_member_permissions_formset.html')
|
||||
model = self.permission_queryset[0].content_type.model_class()
|
||||
return render_to_string(template, {
|
||||
'formset': self,
|
||||
'model_name': model._meta.verbose_name_plural,
|
||||
})
|
||||
|
||||
return RestrictedFormSet
|
|
@ -1,8 +1,14 @@
|
|||
from django.contrib.auth.models import Group
|
||||
from django.core.management import call_command
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.db.models import Q
|
||||
|
||||
from wagtail.wagtailcore.models import Page, Site
|
||||
from wagtail.wagtailcore.models import (
|
||||
GroupCollectionPermission, GroupPagePermission, Page, Site,
|
||||
)
|
||||
|
||||
from kfet.models import Group, Permission
|
||||
|
||||
from ...utils import get_kfet_root_collection, get_kfet_root_page
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
|
@ -33,3 +39,169 @@ class Command(BaseCommand):
|
|||
# Par défaut, il s'agit d'une copie du site K-Fêt (17-05)
|
||||
|
||||
call_command('loaddata', options['file'])
|
||||
|
||||
# Si les groupes K-Fêt existent, certaines permissions du CMS leur sont
|
||||
# données.
|
||||
|
||||
try:
|
||||
group_chef = Group.objects.get(name='K-Fêt César')
|
||||
except Group.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
self.add_admin_access(group_chef)
|
||||
|
||||
try:
|
||||
group_boy = Group.objects.get(name='K-Fêt Légionnaire')
|
||||
except Group.DoesNotExist:
|
||||
pass
|
||||
else:
|
||||
self.add_staff_access(group_boy)
|
||||
|
||||
def add_admin_access(self, group):
|
||||
"""
|
||||
Add all cms-related permissions to `group`.
|
||||
|
||||
Explicitly, permissions added are:
|
||||
- access admin of Wagtail,
|
||||
- all permissions for the kfet root page (by inheritance, this applies
|
||||
to all its descendants),
|
||||
- all permissions on the MemberTeam snippet,
|
||||
- add/change documents,
|
||||
- add/change images.
|
||||
|
||||
To avoid bugs related to permissions not added by this method, it is
|
||||
guaranteed the group has more or the same permissions than at the
|
||||
beginning.
|
||||
"""
|
||||
group.permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type__app_label='wagtailadmin',
|
||||
codename='access_admin',
|
||||
),
|
||||
# Snippets permissions
|
||||
*Permission.kfetcms.all(),
|
||||
)
|
||||
|
||||
# Page permissions: set all for the kfet root page.
|
||||
|
||||
root_page = get_kfet_root_page()
|
||||
|
||||
p_types = ('add', 'edit', 'publish', 'bulk_delete', 'lock')
|
||||
|
||||
GroupPagePermission.objects.filter(
|
||||
group=group, page=root_page,
|
||||
permission_type__in=p_types,
|
||||
).delete()
|
||||
|
||||
GroupPagePermission.objects.bulk_create([
|
||||
GroupPagePermission(
|
||||
group=group, page=root_page,
|
||||
permission_type=p_type,
|
||||
)
|
||||
for p_type in p_types
|
||||
])
|
||||
|
||||
# Collection-based permissions: set all for the kfet root collection
|
||||
# for each known collection-based model (docs, images).
|
||||
|
||||
root_collection = get_kfet_root_collection()
|
||||
|
||||
collection_perms = Permission.objects.filter(
|
||||
Q(
|
||||
content_type__app_label='wagtaildocs',
|
||||
codename__in=['add_document', 'change_document'],
|
||||
) |
|
||||
Q(
|
||||
content_type__app_label='wagtailimages',
|
||||
codename__in=['add_image', 'change_image'],
|
||||
)
|
||||
)
|
||||
|
||||
GroupCollectionPermission.objects.filter(
|
||||
group=group, collection=root_collection,
|
||||
permission__in=collection_perms,
|
||||
).delete()
|
||||
|
||||
GroupCollectionPermission.objects.bulk_create([
|
||||
GroupCollectionPermission(
|
||||
group=group, collection=root_collection,
|
||||
permission=perm,
|
||||
)
|
||||
for perm in collection_perms
|
||||
])
|
||||
|
||||
def add_staff_access(self, group):
|
||||
"""
|
||||
Add a subset of cms-related permissions to `group`.
|
||||
|
||||
Permissions added are:
|
||||
- access admin of Wagtail,
|
||||
- add/edit permissions for the kfet root page (by inheritance, this
|
||||
applies to all its descendants),
|
||||
- all permissions on the MemberTeam snippet,
|
||||
- add/change own documents,
|
||||
- add/change own images.
|
||||
|
||||
Because 'publish' page permission type is not given, group members can
|
||||
only create or change pages as drafts.
|
||||
|
||||
To avoid bugs related to permissions not added by this method, it is
|
||||
guaranteed the group has more or the same permissions than at the
|
||||
beginning.
|
||||
"""
|
||||
group.permissions.add(
|
||||
Permission.objects.get(
|
||||
content_type__app_label='wagtailadmin',
|
||||
codename='access_admin',
|
||||
),
|
||||
*Permission.kfetcms.filter(codename__in=[
|
||||
'add_memberteam',
|
||||
]),
|
||||
)
|
||||
|
||||
# Give 'safe' operations permissions for the kfet root page.
|
||||
|
||||
root_page = get_kfet_root_page()
|
||||
|
||||
p_types = ('add', 'edit')
|
||||
|
||||
GroupPagePermission.objects.filter(
|
||||
group=group, page=root_page,
|
||||
permission_type__in=p_types,
|
||||
).delete()
|
||||
|
||||
GroupPagePermission.objects.bulk_create([
|
||||
GroupPagePermission(
|
||||
group=group, page=root_page,
|
||||
permission_type=p_type,
|
||||
)
|
||||
for p_type in p_types
|
||||
])
|
||||
|
||||
# Give 'safe' operations permissions for the collection-based models.
|
||||
|
||||
root_collection = get_kfet_root_collection()
|
||||
|
||||
collection_perms = Permission.objects.filter(
|
||||
Q(
|
||||
content_type__app_label='wagtaildocs',
|
||||
codename__in=['add_document'],
|
||||
) |
|
||||
Q(
|
||||
content_type__app_label='wagtailimages',
|
||||
codename__in=['add_image'],
|
||||
)
|
||||
)
|
||||
|
||||
GroupCollectionPermission.objects.filter(
|
||||
group=group, collection=root_collection,
|
||||
permission__in=collection_perms,
|
||||
).delete()
|
||||
|
||||
GroupCollectionPermission.objects.bulk_create([
|
||||
GroupCollectionPermission(
|
||||
group=group, collection=root_collection,
|
||||
permission=perm,
|
||||
)
|
||||
for perm in collection_perms
|
||||
])
|
||||
|
|
|
@ -11,7 +11,7 @@ from wagtail.wagtailimages.edit_handlers import ImageChooserPanel
|
|||
from wagtail.wagtailsnippets.blocks import SnippetChooserBlock
|
||||
from wagtail.wagtailsnippets.models import register_snippet
|
||||
|
||||
from kfet.cms.context_processors import get_articles
|
||||
from .utils import get_page_model_names
|
||||
|
||||
|
||||
@register_snippet
|
||||
|
@ -60,6 +60,7 @@ class MenuBlock(blocks.StaticBlock):
|
|||
template = 'kfetcms/block_menu.html'
|
||||
|
||||
def get_context(self, *args, **kwargs):
|
||||
from .context_processors import get_articles
|
||||
context = super().get_context(*args, **kwargs)
|
||||
context.update(get_articles())
|
||||
return context
|
||||
|
@ -172,3 +173,18 @@ class KFetPage(Page):
|
|||
page.seo_title = page.title
|
||||
|
||||
return context
|
||||
|
||||
|
||||
##
|
||||
# Helpers for kfetauth app
|
||||
##
|
||||
|
||||
|
||||
class CmsPermissionManager(models.Manager):
|
||||
def get_queryset(self):
|
||||
return (
|
||||
super().get_queryset()
|
||||
.filter(content_type__app_label='kfetcms')
|
||||
# Permissions of Page-based models are unused.
|
||||
.exclude(content_type__model__in=get_page_model_names())
|
||||
)
|
||||
|
|
|
@ -0,0 +1,20 @@
|
|||
{% load widget_tweaks %}
|
||||
{% load kfet_extras %}
|
||||
|
||||
<div class="form-inline" data-formset-form>
|
||||
{{ form.non_field_errors }}
|
||||
{% if form.DELETE %}{% include "kfet/formset_form_actions.html" %}{% endif %}
|
||||
<div class="form-group">
|
||||
{{ form.collection|add_class:"form-control input-sm" }}
|
||||
</div>
|
||||
{% for option in form.permissions %}
|
||||
<div class="checkbox">
|
||||
{% with p_type=formset.permission_types|get:forloop.counter0 %}
|
||||
{# p_type format: (identifier, short_label, long_label) #}
|
||||
<label title="{{ p_type.2 }}">
|
||||
{{ option.tag }} {{ p_type.1}}
|
||||
</label>
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
|
@ -0,0 +1,42 @@
|
|||
{% load i18n %}
|
||||
{% load formset_tags %}
|
||||
|
||||
<div data-formset-prefix="{{ formset.prefix }}">
|
||||
|
||||
<div class="h5">
|
||||
<button type="button" class="pull-right btn btn-default btn-sm" data-formset-add>
|
||||
{% trans "Ajouter pour une autre collection" %}
|
||||
</button>
|
||||
<b>{{ model_name|title }}</b>
|
||||
</div>
|
||||
|
||||
{{ formset.management_form }}
|
||||
|
||||
{% if formset.non_form_errors %}
|
||||
<span class="help-block">{{ formset.non_form_errors }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% with form_tpl="kfet/permissions/collection_member_permissions_form.html" %}
|
||||
|
||||
<div data-formset-body>
|
||||
{% for form in formset %}
|
||||
{% include form_tpl with form=form formset=formset only %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
{% include form_tpl with form=formset.empty_form formset=formset only %}
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
|
||||
{% endwith %}
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$( function() {
|
||||
let $formset_container = $('[data-formset-prefix={{ formset.prefix }}]');
|
||||
$formset_container.formset();
|
||||
});
|
||||
</script>
|
|
@ -0,0 +1,20 @@
|
|||
{% load widget_tweaks %}
|
||||
{% load kfet_extras %}
|
||||
|
||||
<div class="form-inline" data-formset-form>
|
||||
{{ form.non_field_errors }}
|
||||
{% if form.DELETE %}{% include "kfet/formset_form_actions.html" %}{% endif %}
|
||||
<div class="form-group">
|
||||
{{ form.page|add_class:"form-control input-sm" }}
|
||||
</div>
|
||||
{% for option in form.permission_types %}
|
||||
<div class="checkbox">
|
||||
{% with p_type=formset.permission_types|get:forloop.counter0 %}
|
||||
{# p_type format: (identifier, short_label, long_label) #}
|
||||
<label title="{{ p_type.2 }}">
|
||||
{{ option.tag }} {{ p_type.1 }}
|
||||
</label>
|
||||
{% endwith %}
|
||||
</div>
|
||||
{% endfor %}
|
||||
</div>
|
|
@ -0,0 +1,42 @@
|
|||
{% load i18n %}
|
||||
{% load formset_tags %}
|
||||
|
||||
<div data-formset-prefix="{{ formset.prefix }}">
|
||||
|
||||
<div class="h5">
|
||||
<button type="button" class="pull-right btn btn-default btn-sm" data-formset-add>
|
||||
{% trans "Ajouter pour une autre page" %}
|
||||
</button>
|
||||
<b>{% trans "Pages" %}</b>
|
||||
</div>
|
||||
|
||||
{{ formset.management_form }}
|
||||
|
||||
{% if formset.non_form_errors %}
|
||||
<span class="help-block">{{ formset.non_form_errors }}</span>
|
||||
{% endif %}
|
||||
|
||||
{% with form_tpl="kfet/permissions/page_permissions_form.html" %}
|
||||
|
||||
<div data-formset-body>
|
||||
{% for form in formset %}
|
||||
{% include form_tpl with form=form formset=formset only %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
<script type="form-template" data-formset-empty-form>
|
||||
{% escapescript %}
|
||||
{% include form_tpl with form=formset.empty_form formset=formset only %}
|
||||
{% endescapescript %}
|
||||
</script>
|
||||
|
||||
{% endwith %}
|
||||
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$( function() {
|
||||
let $formset_container = $('[data-formset-prefix={{ formset.prefix }}]');
|
||||
$formset_container.formset();
|
||||
});
|
||||
</script>
|
35
kfet/cms/utils.py
Normal file
35
kfet/cms/utils.py
Normal file
|
@ -0,0 +1,35 @@
|
|||
from django.apps import apps
|
||||
|
||||
from wagtail.wagtailcore.models import Collection, Page
|
||||
|
||||
|
||||
def get_kfet_root_page():
|
||||
"""
|
||||
Returns the K-Fêt root page, or 'None' if it does not exist.
|
||||
"""
|
||||
from .models import KFetPage
|
||||
return KFetPage.objects.first()
|
||||
|
||||
|
||||
def get_kfet_root_collection():
|
||||
"""
|
||||
Returns the K-Fêt root collection, or 'None' if it does not exist.
|
||||
"""
|
||||
return Collection.objects.filter(name='K-Fêt').first()
|
||||
|
||||
|
||||
def get_page_model_names():
|
||||
"""
|
||||
Returns all model names of `Page` subclasses.
|
||||
|
||||
This uses the django apps registry (instead of `ContentType.objects.all()`)
|
||||
in order to be usuable even before migrations are applied. E.g. this can be
|
||||
used in `Field.__init__`.
|
||||
|
||||
Note these model names are the same in `model` attribute of `ContentType`
|
||||
objects.
|
||||
"""
|
||||
return [
|
||||
model._meta.model_name
|
||||
for model in apps.get_models() if issubclass(model, Page)
|
||||
]
|
73
kfet/cms/views.py
Normal file
73
kfet/cms/views.py
Normal file
|
@ -0,0 +1,73 @@
|
|||
from django.utils.translation import ugettext_lazy as _
|
||||
|
||||
from wagtail.wagtailadmin.forms import (
|
||||
BaseGroupCollectionMemberPermissionFormSet,
|
||||
)
|
||||
from wagtail.wagtailcore import hooks
|
||||
from wagtail.wagtailcore.models import Collection, Page
|
||||
|
||||
from .forms import (
|
||||
CmsGroupForm, SnippetsCmsGroupForm, prepare_page_permissions_formset,
|
||||
prepare_collection_member_permissions_formset,
|
||||
)
|
||||
from .utils import get_kfet_root_collection, get_kfet_root_page
|
||||
|
||||
|
||||
def get_kfetcms_group_formview_extra():
|
||||
forms = []
|
||||
|
||||
# Misc cms-related permissions.
|
||||
forms.append((CmsGroupForm, {'prefix': 'kfetcms'}))
|
||||
|
||||
# Snippets permissions.
|
||||
forms.append((SnippetsCmsGroupForm, {'prefix': 'kfetcms-snippets'}))
|
||||
|
||||
# Setup PagePermissionsFormSet for kfet root page descendants only.
|
||||
|
||||
root_page = get_kfet_root_page()
|
||||
|
||||
if root_page:
|
||||
pages = Page.objects.descendant_of(root_page, inclusive=True)
|
||||
forms.append(
|
||||
(prepare_page_permissions_formset(pages=pages), {})
|
||||
)
|
||||
|
||||
# Setup CollectionPermissions for kfet root collection descendants only.
|
||||
|
||||
root_collection = get_kfet_root_collection()
|
||||
|
||||
if root_collection:
|
||||
collections = Collection.objects.descendant_of(
|
||||
root_collection, inclusive=True)
|
||||
|
||||
# Retrieve forms based on CollectionMemberPermissionFormSet displayed
|
||||
# by Wagtail admin site.
|
||||
# http://docs.wagtail.io/en/stable/reference/hooks.html#register-group-permission-panel
|
||||
collectionmember_form_classes = []
|
||||
for fn in hooks.get_hooks('register_group_permission_panel'):
|
||||
form_cls = fn()
|
||||
if issubclass(
|
||||
form_cls,
|
||||
BaseGroupCollectionMemberPermissionFormSet
|
||||
):
|
||||
collectionmember_form_classes.append(form_cls)
|
||||
|
||||
# Apply choices limit.
|
||||
for form_cls in collectionmember_form_classes:
|
||||
forms.append((
|
||||
prepare_collection_member_permissions_formset(
|
||||
form_cls, collections=collections),
|
||||
{},
|
||||
))
|
||||
|
||||
# The 'extra' definition of kfetcms.
|
||||
|
||||
extra = {
|
||||
'title': _("Site"),
|
||||
'description': _(
|
||||
"Permissions liées aux pages à contenu libre."
|
||||
),
|
||||
'form_classes': forms,
|
||||
}
|
||||
|
||||
return extra
|
|
@ -4,6 +4,7 @@
|
|||
/* Libs customizations */
|
||||
@import url("libs/jconfirm-kfet.css");
|
||||
@import url("libs/multiple-select-kfet.css");
|
||||
@import url("libs/formset-kfet.css");
|
||||
|
||||
/* Base */
|
||||
@import url("base/misc.css");
|
||||
|
|
36
kfet/static/kfet/css/libs/formset-kfet.css
Normal file
36
kfet/static/kfet/css/libs/formset-kfet.css
Normal file
|
@ -0,0 +1,36 @@
|
|||
[data-formset-form] {
|
||||
margin-bottom: 5px;
|
||||
padding: 10px;
|
||||
|
||||
border: 1px solid #CCC;
|
||||
border-radius: 3px;
|
||||
box-shadow: inset 0 1px 1px rgba(0,0,0,.075);
|
||||
|
||||
transition: border 0.3s, color 0.3s;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
[data-formset-form] > :not(:last-child) {
|
||||
margin-right: 15px;
|
||||
}
|
||||
[data-formset-form] .form-actions {
|
||||
float: right;
|
||||
margin-left: 15px;
|
||||
margin-right: 0;
|
||||
}
|
||||
}
|
||||
|
||||
[data-formset-add] {
|
||||
position: relative;
|
||||
top: -5px;
|
||||
right: 0;
|
||||
}
|
||||
|
||||
[data-formset-form-deleted] {
|
||||
background: repeating-linear-gradient(
|
||||
45deg,
|
||||
#e9afb9, #e9afb9 2px, transparent 2px, transparent 12px
|
||||
);
|
||||
border: 1px solid #e9afb9;
|
||||
color: #999;
|
||||
}
|
|
@ -24,6 +24,7 @@
|
|||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/js/jquery-ui.min.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/js/jquery-confirm.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'js/jquery.formset.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/js/reconnecting-websocket.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/js/moment.js' %}"></script>
|
||||
<script type="text/javascript" src="{% static 'kfet/js/moment-fr.js' %}"></script>
|
||||
|
|
12
kfet/templates/kfet/formset_form_actions.html
Normal file
12
kfet/templates/kfet/formset_form_actions.html
Normal file
|
@ -0,0 +1,12 @@
|
|||
{% load i18n %}
|
||||
{% load widget_tweaks %}
|
||||
|
||||
<div class="form-group form-actions">
|
||||
{{ form.DELETE|add_class:"hide" }}
|
||||
<button type="button" class="btn btn-danger btn-sm" title="{% trans "Supprimer" %}" data-formset-delete-button>
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</button>
|
||||
<button type="button" class="btn btn-default btn-sm" title="{% trans "Restaurer" %}" data-formset-restore-button style="display: none">
|
||||
<span class="glyphicon glyphicon-plus"></span>
|
||||
</button>
|
||||
</div>
|
|
@ -1,5 +0,0 @@
|
|||
from django.template.defaulttags import register
|
||||
|
||||
@register.filter
|
||||
def get_item(dictionary, key):
|
||||
return dictionary.get(key)
|
8
kfet/templatetags/kfet_extras.py
Normal file
8
kfet/templatetags/kfet_extras.py
Normal file
|
@ -0,0 +1,8 @@
|
|||
from django.template.defaulttags import register
|
||||
|
||||
|
||||
@register.filter
|
||||
def get(o, key):
|
||||
if hasattr(o, 'get'):
|
||||
return o.get(key)
|
||||
return o[int(key)]
|
|
@ -26,5 +26,9 @@ python-dateutil
|
|||
wagtail==1.10.*
|
||||
wagtailmenus==2.2.*
|
||||
|
||||
# This fork enables restore of forms.
|
||||
# Original project: https://bitbucket.org/tim_heap/django-formset-js
|
||||
git+https://bitbucket.org/georgema1982/django-formset-js.git#egg=django-formset-js
|
||||
|
||||
# Production tools
|
||||
wheel
|
||||
|
|
Loading…
Reference in a new issue