From f9f0f6380562e9d1c4911dec08406ebf1f43b0f9 Mon Sep 17 00:00:00 2001 From: Jannis Leidel Date: Tue, 7 Jul 2009 02:12:08 +0200 Subject: [PATCH] Added site-wide admin action (1.1 only) for editing permissions of arbitrary objects. --- example/urls.py | 3 +- src/authority/__init__.py | 3 + src/authority/actions.py | 102 ++++++++++++++++++ .../admin/edit_inline/action_tabular.html | 66 ++++++++++++ .../admin/permission_change_form.html | 57 ++++++++++ 5 files changed, 230 insertions(+), 1 deletion(-) create mode 100644 src/authority/actions.py create mode 100644 src/authority/templates/admin/edit_inline/action_tabular.html create mode 100644 src/authority/templates/admin/permission_change_form.html diff --git a/example/urls.py b/example/urls.py index a6a9549..b6c82be 100644 --- a/example/urls.py +++ b/example/urls.py @@ -10,7 +10,8 @@ authority.autodiscover() handler500 # Pyflakes urlpatterns = patterns('', - (r'^admin/(.*)', admin.site.root), + #(r'^admin/(.*)', admin.site.root), + ('^admin/', include(admin.site.urls)), (r'^perms/', include('authority.urls')), (r'^accounts/login/$', 'django.contrib.auth.views.login'), url(r'^(?P[\/0-9A-Za-z]+)$', 'example.exampleapp.views.top_secret'), diff --git a/src/authority/__init__.py b/src/authority/__init__.py index 54896bb..bb2f74f 100644 --- a/src/authority/__init__.py +++ b/src/authority/__init__.py @@ -27,3 +27,6 @@ def autodiscover(): __import__("%s.permissions" % app) app_path = sys.modules["%s.permissions" % app] LOADING = False + + # Register the "edit_permission" action with the default admin site + from authority import actions diff --git a/src/authority/actions.py b/src/authority/actions.py new file mode 100644 index 0000000..8c249fc --- /dev/null +++ b/src/authority/actions.py @@ -0,0 +1,102 @@ +from django import forms, template +from django.core.exceptions import PermissionDenied +from django.contrib.admin import helpers, site, ACTION_CHECKBOX_NAME +from django.shortcuts import render_to_response +from django.utils.encoding import force_unicode +from django.utils.html import escape +from django.utils.safestring import mark_safe +from django.utils.text import capfirst +from django.utils.translation import ugettext_lazy, ugettext as _ +from django.contrib.contenttypes.models import ContentType +from django.forms.formsets import all_valid + +try: + set +except NameError: + from sets import Set as set # Python 2.3 fallback + +try: + from django.contrib.admin import actions +except ImportError: + actions = False + +from authority.admin import PermissionInline + +class ActionPermissionInline(PermissionInline): + raw_id_fields = () + template = 'admin/edit_inline/action_tabular.html' + +class ActionErrorList(forms.util.ErrorList): + def __init__(self, inline_formsets): + for inline_formset in inline_formsets: + self.extend(inline_formset.non_form_errors()) + for errors_in_inline_form in inline_formset.errors: + self.extend(errors_in_inline_form.values()) + +def edit_permissions(modeladmin, request, queryset): + opts = modeladmin.model._meta + app_label = opts.app_label + selected = request.POST.getlist(ACTION_CHECKBOX_NAME) + inline = ActionPermissionInline(queryset.model, modeladmin.admin_site) + formsets = [] + for obj in queryset: + prefixes = {} + FormSet = inline.get_formset(request, obj) + prefix = "%s-%s" % (FormSet.get_default_prefix(), obj.pk) + prefixes[prefix] = prefixes.get(prefix, 0) + 1 + if prefixes[prefix] != 1: + prefix = "%s-%s-%s" % (prefix, prefixes[prefix]) + if request.POST.get('post'): + formset = FormSet(data=request.POST, files=request.FILES, + instance=obj, prefix=prefix) + else: + formset = FormSet(instance=obj, prefix=prefix) + formsets.append(formset) + + media = modeladmin.media + inline_admin_formsets = [] + for formset in formsets: + fieldsets = list(inline.get_fieldsets(request)) + inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets) + inline_admin_formsets.append(inline_admin_formset) + media = media + inline_admin_formset.media + + ordered_objects = opts.get_ordered_objects() + if request.POST.get('post'): + if all_valid(formsets): + for formset in formsets: + formset.save() + return None + + context = { + 'errors': ActionErrorList(formsets), + 'title': _('Permissions for %s') % force_unicode(opts.verbose_name_plural), + 'inline_admin_formsets': inline_admin_formsets, + 'root_path': modeladmin.admin_site.root_path, + 'app_label': app_label, + 'change': True, + 'ordered_objects': ordered_objects, + 'form_url': mark_safe(''), + 'opts': opts, + 'target_opts': queryset.model._meta, + 'content_type_id': ContentType.objects.get_for_model(queryset.model).id, + 'save_as': False, + 'save_on_top': False, + 'is_popup': False, + 'media': mark_safe(media), + 'show_delete': False, + 'action_checkbox_name': helpers.ACTION_CHECKBOX_NAME, + 'queryset': queryset, + "object_name": force_unicode(opts.verbose_name), + } + template_name = getattr(modeladmin, 'permission_change_form_template', [ + "admin/%s/%s/permission_change_form.html" % (app_label, opts.object_name.lower()), + "admin/%s/permission_change_form.html" % app_label, + "admin/permission_change_form.html" + ]) + return render_to_response(template_name, context, + context_instance=template.RequestContext(request)) +edit_permissions.short_description = _("Permissions for selected %(verbose_name_plural)s") + +if actions: + site.add_action(edit_permissions) diff --git a/src/authority/templates/admin/edit_inline/action_tabular.html b/src/authority/templates/admin/edit_inline/action_tabular.html new file mode 100644 index 0000000..1d6a65c --- /dev/null +++ b/src/authority/templates/admin/edit_inline/action_tabular.html @@ -0,0 +1,66 @@ +{% load i18n %} +
+ + +
diff --git a/src/authority/templates/admin/permission_change_form.html b/src/authority/templates/admin/permission_change_form.html new file mode 100644 index 0000000..85d0fe5 --- /dev/null +++ b/src/authority/templates/admin/permission_change_form.html @@ -0,0 +1,57 @@ +{% extends "admin/base_site.html" %} +{% load i18n admin_modify adminmedia %} + +{% block extrahead %}{{ block.super }} + +{{ media }} +{% endblock %} + +{% block extrastyle %}{{ block.super }}{% endblock %} + +{% block coltype %}{% if ordered_objects %}colMS{% else %}colM{% endif %}{% endblock %} + +{% block bodyclass %}{{ opts.app_label }}-{{ opts.object_name.lower }} change-form{% endblock %} + +{% block breadcrumbs %}{% if not is_popup %} + +{% endif %}{% endblock %} + +{% block content %}
+
+
+{% if is_popup %}{% endif %} +{% if save_on_top %}{% submit_row %}{% endif %} +{% if errors %} +

+ {% blocktrans count errors|length as counter %}Please correct the error below.{% plural %}Please correct the errors below.{% endblocktrans %} +

+
    {% for error in adminform.form.non_field_errors %}
  • {{ error }}
  • {% endfor %}
+{% endif %} + +{% for fieldset in adminform %} + {% include "admin/includes/fieldset.html" %} +{% endfor %} + +{% for inline_admin_formset in inline_admin_formsets %} + {% include inline_admin_formset.opts.template %} +{% endfor %} + +{% block after_related_objects %}{% endblock %} + +
+ +
+ +
+{% for obj in queryset %} + +{% endfor %} + + +
+{% endblock %}