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 diff --git a/README.md b/README.md old mode 100644 new mode 100755 index 8aee174..7429c44 --- 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: @@ -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,6 +74,12 @@ class MyModelAdmin(MassEditMixin, admin.ModelAdmin): ... ``` +### Restrict Mass actions to enabled users + +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 Django-mass-edit will keep IDs for selected objects in URL, e.g: 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 old mode 100644 new mode 100755 index 4eb51db..2a33099 --- a/massadmin/massadmin.py +++ b/massadmin/massadmin.py @@ -94,12 +94,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 +363,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, @@ -387,7 +388,16 @@ def mass_change_view( obj=obj) -class MassEditMixin: - actions = ( - mass_change_selected, - ) +class MassEditMixin(object): + + def get_actions(self, request): + actions = super().get_actions(request) + + if request.user.has_perm("massadmin.can_mass_edit"): + actions[mass_change_selected.__name__] = ( + mass_change_selected, + mass_change_selected.__name__, + mass_change_selected.short_description + ) + + return actions diff --git a/massadmin/models.py b/massadmin/models.py new file mode 100644 index 0000000..0feb1b6 --- /dev/null +++ b/massadmin/models.py @@ -0,0 +1,14 @@ +from django.db import models + + +class RightsSupport(models.Model): + + class Meta: + + managed = False + + default_permissions = () + + permissions = ( + ('can_mass_edit', 'Can perform mass editing'), + ) diff --git a/massadmin/settings.py b/massadmin/settings.py old mode 100644 new mode 100755 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'), + ), + ]