From c24286e986392ce173709c51b8a1178628ab6e29 Mon Sep 17 00:00:00 2001 From: enrico Date: Tue, 12 Jul 2022 16:00:00 +0200 Subject: [PATCH 1/6] user group restriction --- README.md | 15 ++++++++++++++- massadmin/massadmin.py | 17 +++++++++++++---- massadmin/settings.py | 2 ++ 3 files changed, 29 insertions(+), 5 deletions(-) mode change 100644 => 100755 README.md mode change 100644 => 100755 massadmin/massadmin.py mode change 100644 => 100755 massadmin/settings.py diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 8aee174..93bd816 --- a/README.md +++ b/README.md @@ -54,7 +54,7 @@ See [Django Docs on the subject](https://docs.djangoproject.com/en/dev/ref/contr ### Enable Mass Edit for specific models -By default, all models registered in the admin will get `Mass Edit` action. +By default, all models registered in the admin will get `Mass Edit` action, for all site users. If you wish to disable this, add this to settings file: @@ -72,6 +72,19 @@ class MyModelAdmin(MassEditMixin, admin.ModelAdmin): ... ``` +### Restrict Mass actions enabled users + +You can restrict Mass edit action to those users belonging to a specified group name. + +``` python +MASSEDIT = { + 'ADD_ACTION_GLOBALLY': False, + 'MASS_USERS_GROUP': 'somegroup' +} +``` + +Note that user user restriction has effect only in conjunction with 'ADD_ACTION_GLOBALLY' variable set to false. + ### Session-based URLs Django-mass-edit will keep IDs for selected objects in URL, e.g: diff --git a/massadmin/massadmin.py b/massadmin/massadmin.py old mode 100644 new mode 100755 index 31e9109..fa163d0 --- a/massadmin/massadmin.py +++ b/massadmin/massadmin.py @@ -387,7 +387,16 @@ def mass_change_view( obj=obj) -class MassEditMixin: - actions = ( - mass_change_selected, - ) +class MassEditMixin(object): + + def get_actions(self, request): + actions = super(MassEditMixin, self).get_actions(request) + + if settings.MASS_USERS_GROUP and settings.MASS_USERS_GROUP in [g.name for g in request.user.groups.all()]: + actions[mass_change_selected.__name__] = ( + mass_change_selected, + mass_change_selected.__name__, + mass_change_selected.short_description + ) + + return actions diff --git a/massadmin/settings.py b/massadmin/settings.py old mode 100644 new mode 100755 index 5acf235..de1758e --- a/massadmin/settings.py +++ b/massadmin/settings.py @@ -4,6 +4,7 @@ _default_settings = { 'ADD_ACTION_GLOBALLY': True, 'SESSION_BASED_URL_THRESHOLD': 500, + 'MASS_USERS_GROUP': None, } _settings = getattr(settings, 'MASSEDIT', _default_settings) @@ -15,3 +16,4 @@ def _get_value(name): ADD_ACTION_GLOBALLY = _get_value('ADD_ACTION_GLOBALLY') SESSION_BASED_URL_THRESHOLD = _get_value('SESSION_BASED_URL_THRESHOLD') +MASS_USERS_GROUP = _get_value('MASS_USERS_GROUP') From d91a5c351bcfd21944ba9ff28953168a130aac5f Mon Sep 17 00:00:00 2001 From: Enrico Ferreguti Date: Tue, 9 Aug 2022 16:45:18 +0200 Subject: [PATCH 2/6] exclude db from repo --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index cbb74dd..dbc3102 100755 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.pyc settings_local.py django_mass_edit.egg-info +db.sqlite3 .idea .coverage .tox From 3e7243bbadba6bc52976bf29318c1f28ed8e7153 Mon Sep 17 00:00:00 2001 From: Enrico Ferreguti Date: Tue, 9 Aug 2022 16:46:26 +0200 Subject: [PATCH 3/6] add missing FieldsetsAdminModel migration --- ...odel_alter_customadminmodel_id_and_more.py | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) create mode 100644 tests/migrations/0003_fieldsetsadminmodel_alter_customadminmodel_id_and_more.py diff --git a/tests/migrations/0003_fieldsetsadminmodel_alter_customadminmodel_id_and_more.py b/tests/migrations/0003_fieldsetsadminmodel_alter_customadminmodel_id_and_more.py new file mode 100644 index 0000000..d9796b4 --- /dev/null +++ b/tests/migrations/0003_fieldsetsadminmodel_alter_customadminmodel_id_and_more.py @@ -0,0 +1,37 @@ +# Generated by Django 4.1 on 2022-08-09 09:20 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tests', '0002_auto_20211217_0041'), + ] + + operations = [ + migrations.CreateModel( + name='FieldsetsAdminModel', + fields=[ + ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), + ('first_name', models.CharField(max_length=32)), + ('middle_name', models.CharField(max_length=32)), + ('last_name', models.CharField(max_length=32)), + ], + ), + migrations.AlterField( + model_name='customadminmodel', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='customadminmodel2', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + migrations.AlterField( + model_name='inheritedadminmodel', + name='id', + field=models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID'), + ), + ] From 73d6395330f3d746b16603acfbe3f6fbf4e707e0 Mon Sep 17 00:00:00 2001 From: Enrico Ferreguti Date: Tue, 9 Aug 2022 16:52:46 +0200 Subject: [PATCH 4/6] mass edit group to mass edit permission --- mass_demo/settings.py | 6 +++++- massadmin/massadmin.py | 27 +++++++++++++++------------ massadmin/models.py | 15 +++++++++++++++ massadmin/settings.py | 2 -- 4 files changed, 35 insertions(+), 15 deletions(-) create mode 100644 massadmin/models.py diff --git a/mass_demo/settings.py b/mass_demo/settings.py index b9bbef0..34d954a 100644 --- a/mass_demo/settings.py +++ b/mass_demo/settings.py @@ -44,7 +44,7 @@ ] -ALLOWED_HOSTS = [] +ALLOWED_HOSTS = ['*'] # Application definition @@ -102,3 +102,7 @@ # https://docs.djangoproject.com/en/1.7/howto/static-files/ STATIC_URL = '/static/' + +MASSEDIT = { + 'ADD_ACTION_GLOBALLY': False, +} diff --git a/massadmin/massadmin.py b/massadmin/massadmin.py index 264f50c..76ec5c3 100755 --- a/massadmin/massadmin.py +++ b/massadmin/massadmin.py @@ -55,11 +55,13 @@ from django.utils.encoding import force_unicode as force_str from django.utils.safestring import mark_safe from django.contrib.admin.views.decorators import staff_member_required +from django.contrib.auth.decorators import permission_required from django.http import Http404, HttpResponseRedirect from django.utils.html import escape from django.shortcuts import render from django.forms.formsets import all_valid from django.contrib.admin.templatetags.admin_urls import add_preserved_filters +from django.contrib import messages from . import settings @@ -94,12 +96,21 @@ def get_mass_change_redirect_url(model_meta, pk_list, session): mass_change_selected.short_description = _('Mass Edit') +def get_changelist_url(model, admin_name='admin'): + opts = model._meta + return reverse("{}:{}_{}_changelist".format( + admin_name, opts.app_label, opts.model_name)) + + def mass_change_view(request, app_name, model_name, object_ids, admin_site=None): if object_ids.startswith("session-"): object_ids = request.session.get(object_ids) model = get_model(app_name, model_name) - ma = MassAdmin(model, admin_site or admin.site) - return ma.mass_change_view(request, object_ids) + if request.user.has_perm('massadmin.can_mass_edit'): + ma = MassAdmin(model, admin_site or admin.site) + return ma.mass_change_view(request, object_ids) + else: + return HttpResponseRedirect(get_changelist_url(model)) mass_change_view = staff_member_required(mass_change_view) @@ -354,14 +365,6 @@ def mass_change_view( except Exception: pass - # Buggy! Use at your own risk - # inline_admin_formsets = [] - # for inline, formset in zip(self.inline_instances, formsets): - # fieldsets = list(inline.get_fieldsets(request, obj)) - # inline_admin_formset = helpers.InlineAdminFormSet(inline, formset, fieldsets) - # inline_admin_formsets.append(inline_admin_formset) - # media = media + inline_admin_formset.media - context = { 'title': _('Change %s') % force_str(opts.verbose_name), 'adminform': adminForm, @@ -390,9 +393,9 @@ def mass_change_view( class MassEditMixin(object): def get_actions(self, request): - actions = super(MassEditMixin, self).get_actions(request) + actions = super().get_actions(request) - if settings.MASS_USERS_GROUP and settings.MASS_USERS_GROUP in [g.name for g in request.user.groups.all()]: + if request.user.has_perm("massadmin.can_mass_edit"): actions[mass_change_selected.__name__] = ( mass_change_selected, mass_change_selected.__name__, diff --git a/massadmin/models.py b/massadmin/models.py new file mode 100644 index 0000000..c16e180 --- /dev/null +++ b/massadmin/models.py @@ -0,0 +1,15 @@ +from django.db import models + +class RightsSupport(models.Model): + + class Meta: + + managed = False # No database table creation or deletion \ + # operations will be performed for this model. + + default_permissions = () # disable "add", "change", "delete" + # and "view" default permissions + + permissions = ( + ('can_mass_edit', 'Can perform mass editing'), + ) \ No newline at end of file diff --git a/massadmin/settings.py b/massadmin/settings.py index de1758e..5acf235 100755 --- a/massadmin/settings.py +++ b/massadmin/settings.py @@ -4,7 +4,6 @@ _default_settings = { 'ADD_ACTION_GLOBALLY': True, 'SESSION_BASED_URL_THRESHOLD': 500, - 'MASS_USERS_GROUP': None, } _settings = getattr(settings, 'MASSEDIT', _default_settings) @@ -16,4 +15,3 @@ def _get_value(name): ADD_ACTION_GLOBALLY = _get_value('ADD_ACTION_GLOBALLY') SESSION_BASED_URL_THRESHOLD = _get_value('SESSION_BASED_URL_THRESHOLD') -MASS_USERS_GROUP = _get_value('MASS_USERS_GROUP') From ddaa491bb8221ddc3e8cb5518cf1d9a3e6668c96 Mon Sep 17 00:00:00 2001 From: Enrico Ferreguti Date: Sat, 27 Aug 2022 13:03:07 +0200 Subject: [PATCH 5/6] code cleanup --- massadmin/massadmin.py | 2 -- massadmin/models.py | 23 +++++++++++------------ 2 files changed, 11 insertions(+), 14 deletions(-) diff --git a/massadmin/massadmin.py b/massadmin/massadmin.py index 76ec5c3..2a33099 100755 --- a/massadmin/massadmin.py +++ b/massadmin/massadmin.py @@ -55,13 +55,11 @@ from django.utils.encoding import force_unicode as force_str from django.utils.safestring import mark_safe from django.contrib.admin.views.decorators import staff_member_required -from django.contrib.auth.decorators import permission_required from django.http import Http404, HttpResponseRedirect from django.utils.html import escape from django.shortcuts import render from django.forms.formsets import all_valid from django.contrib.admin.templatetags.admin_urls import add_preserved_filters -from django.contrib import messages from . import settings diff --git a/massadmin/models.py b/massadmin/models.py index c16e180..0feb1b6 100644 --- a/massadmin/models.py +++ b/massadmin/models.py @@ -1,15 +1,14 @@ from django.db import models - + + class RightsSupport(models.Model): - + class Meta: - - managed = False # No database table creation or deletion \ - # operations will be performed for this model. - - default_permissions = () # disable "add", "change", "delete" - # and "view" default permissions - - permissions = ( - ('can_mass_edit', 'Can perform mass editing'), - ) \ No newline at end of file + + managed = False + + default_permissions = () + + permissions = ( + ('can_mass_edit', 'Can perform mass editing'), + ) From 461e64e77bbc2fa830cf33e5a168f22e975b69ab Mon Sep 17 00:00:00 2001 From: enrico ferreguti Date: Sat, 27 Aug 2022 18:14:54 +0200 Subject: [PATCH 6/6] doc update --- README.md | 17 ++++++----------- 1 file changed, 6 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 93bd816..7429c44 100755 --- a/README.md +++ b/README.md @@ -64,6 +64,8 @@ MASSEDIT = { } ``` +Keep in mind that, disabling the option, a massedit permission has to be specifically assigned to the authorized users as explained below. + Then, to add the mass edit action to specific models, use the provided mixin: ``` python from massadmin.massadmin import MassEditMixin @@ -72,18 +74,11 @@ class MyModelAdmin(MassEditMixin, admin.ModelAdmin): ... ``` -### Restrict Mass actions enabled users - -You can restrict Mass edit action to those users belonging to a specified group name. - -``` python -MASSEDIT = { - 'ADD_ACTION_GLOBALLY': False, - 'MASS_USERS_GROUP': 'somegroup' -} -``` +### Restrict Mass actions to enabled users -Note that user user restriction has effect only in conjunction with 'ADD_ACTION_GLOBALLY' variable set to false. +Mass edit action are restricted by default to those users that have the apposite 'Can perform mass editing' permission. +This permission can be assigned as other django permissions assigning directy to the user the `massadmin | rights support | Can perform mass editing` or assigning it to a group and then assigning the group to all the desired users. +Note that the user restriction has effect only in conjunction with 'ADD_ACTION_GLOBALLY' variable set to false. ### Session-based URLs