From d157818d7e7dd28e3b8d61456f1aecf66b8f1a31 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 3 Jun 2020 09:43:46 -0400 Subject: [PATCH] Rename attrs to constraints --- netbox/netbox/authentication.py | 28 +++++++++---------- netbox/netbox/tests/test_authentication.py | 26 ++++++++--------- netbox/users/admin.py | 26 ++++++++--------- .../users/migrations/0008_objectpermission.py | 4 +-- netbox/users/models.py | 4 +-- netbox/utilities/testing/testcases.py | 18 ++++++------ 6 files changed, 52 insertions(+), 54 deletions(-) diff --git a/netbox/netbox/authentication.py b/netbox/netbox/authentication.py index a219c1498..02b0be0f3 100644 --- a/netbox/netbox/authentication.py +++ b/netbox/netbox/authentication.py @@ -28,16 +28,16 @@ class ObjectPermissionBackend(ModelBackend): Q(groups__user=user_obj) ).prefetch_related('object_types') - # Create a dictionary mapping permissions to their attributes + # Create a dictionary mapping permissions to their constraints perms = dict() for obj_perm in object_permissions: for object_type in obj_perm.object_types.all(): for action in obj_perm.actions: perm_name = f"{object_type.app_label}.{action}_{object_type.model}" if perm_name in perms: - perms[perm_name].append(obj_perm.attrs) + perms[perm_name].append(obj_perm.constraints) else: - perms[perm_name] = [obj_perm.attrs] + perms[perm_name] = [obj_perm.constraints] return perms @@ -71,20 +71,20 @@ class ObjectPermissionBackend(ModelBackend): raise ValueError(f"Invalid permission {perm} for model {model}") # Compile a query filter that matches all instances of the specified model - obj_perm_attrs = self.get_all_permissions(user_obj)[perm] - attrs = Q() - for perm_attrs in obj_perm_attrs: - if perm_attrs: - attrs |= Q(**perm_attrs) + obj_perm_constraints = self.get_all_permissions(user_obj)[perm] + constraints = Q() + for perm_constraints in obj_perm_constraints: + if perm_constraints: + constraints |= Q(**perm_constraints) else: - # Found ObjectPermission with null attrs; allow model-level access - attrs = Q() + # Found ObjectPermission with null constraints; allow model-level access + constraints = Q() break # Permission to perform the requested action on the object depends on whether the specified object matches - # the specified attributes. Note that this check is made against the *database* record representing the object, + # the specified constraints. Note that this check is made against the *database* record representing the object, # not the instance itself. - return model.objects.filter(attrs, pk=obj.pk).exists() + return model.objects.filter(constraints, pk=obj.pk).exists() class RemoteUserBackend(_RemoteUserBackend): @@ -111,11 +111,11 @@ class RemoteUserBackend(_RemoteUserBackend): # Assign default object permissions to the user permissions_list = [] - for permission_name, attrs in settings.REMOTE_AUTH_DEFAULT_PERMISSIONS.items(): + for permission_name, constraints in settings.REMOTE_AUTH_DEFAULT_PERMISSIONS.items(): try: object_type, action = resolve_permission_ct(permission_name) # TODO: Merge multiple actions into a single ObjectPermission per content type - obj_perm = ObjectPermission(actions=[action], attrs=attrs) + obj_perm = ObjectPermission(actions=[action], constraints=constraints) obj_perm.save() obj_perm.users.add(user) obj_perm.object_types.add(object_type) diff --git a/netbox/netbox/tests/test_authentication.py b/netbox/netbox/tests/test_authentication.py index db63faffd..0e9bea90d 100644 --- a/netbox/netbox/tests/test_authentication.py +++ b/netbox/netbox/tests/test_authentication.py @@ -202,7 +202,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view'] ) obj_perm.save() @@ -226,7 +226,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view'] ) obj_perm.save() @@ -260,7 +260,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view', 'add'] ) obj_perm.save() @@ -307,7 +307,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view', 'change'] ) obj_perm.save() @@ -350,7 +350,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view', 'delete'] ) obj_perm.save() @@ -398,7 +398,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['add'] ) obj_perm.save() @@ -447,7 +447,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['change'] ) obj_perm.save() @@ -491,7 +491,7 @@ class ObjectPermissionViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view', 'delete'] ) obj_perm.save() @@ -562,7 +562,7 @@ class ObjectPermissionAPIViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view'] ) obj_perm.save() @@ -589,7 +589,7 @@ class ObjectPermissionAPIViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['view'] ) obj_perm.save() @@ -616,7 +616,7 @@ class ObjectPermissionAPIViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['add'] ) obj_perm.save() @@ -645,7 +645,7 @@ class ObjectPermissionAPIViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['change'] ) obj_perm.save() @@ -680,7 +680,7 @@ class ObjectPermissionAPIViewTestCase(TestCase): # Assign object permission obj_perm = ObjectPermission( - attrs={'site__name': 'Site 1'}, + constraints={'site__name': 'Site 1'}, actions=['delete'] ) obj_perm.save() diff --git a/netbox/users/admin.py b/netbox/users/admin.py index 80283340d..cc7a1b379 100644 --- a/netbox/users/admin.py +++ b/netbox/users/admin.py @@ -37,7 +37,7 @@ class UserConfigInline(admin.TabularInline): class ObjectPermissionInline(admin.TabularInline): model = AdminUser.object_permissions.through - fields = ['object_types', 'actions', 'attrs'] + fields = ['object_types', 'actions', 'constraints'] readonly_fields = fields extra = 0 verbose_name = 'Permission' @@ -48,8 +48,8 @@ class ObjectPermissionInline(admin.TabularInline): def actions(self, instance): return ', '.join(instance.objectpermission.actions) - def attrs(self, instance): - return instance.objectpermission.attrs + def constraints(self, instance): + return instance.objectpermission.constraints def has_add_permission(self, request, obj): # Don't allow the creation of new ObjectPermission assignments via this form @@ -113,8 +113,8 @@ class ObjectPermissionForm(forms.ModelForm): exclude = [] help_texts = { 'actions': 'Actions granted in addition to those listed above', - 'attrs': 'JSON expression of a queryset filter that will return only permitted objects. Leave null to ' - 'match all objects of this type.' + 'constraints': 'JSON expression of a queryset filter that will return only permitted objects. Leave null ' + 'to match all objects of this type.' } labels = { 'actions': 'Additional actions' @@ -143,7 +143,7 @@ class ObjectPermissionForm(forms.ModelForm): def clean(self): object_types = self.cleaned_data['object_types'] - attrs = self.cleaned_data['attrs'] + constraints = self.cleaned_data['constraints'] # Append any of the selected CRUD checkboxes to the actions list if not self.cleaned_data.get('actions'): @@ -156,16 +156,16 @@ class ObjectPermissionForm(forms.ModelForm): if not self.cleaned_data['actions']: raise ValidationError("At least one action must be selected.") - # Validate the specified model attributes by attempting to execute a query. We don't care whether the query - # returns anything; we just want to make sure the specified attributes are valid. - if attrs: + # Validate the specified model constraints by attempting to execute a query. We don't care whether the query + # returns anything; we just want to make sure the specified constraints are valid. + if constraints: for ct in object_types: model = ct.model_class() try: - model.objects.filter(**attrs).exists() + model.objects.filter(**constraints).exists() except FieldError as e: raise ValidationError({ - 'attrs': f'Invalid attributes for {model}: {e}' + 'constraints': f'Invalid filter for {model}: {e}' }) @@ -182,13 +182,13 @@ class ObjectPermissionAdmin(admin.ModelAdmin): 'fields': (('can_view', 'can_add', 'can_change', 'can_delete'), 'actions') }), ('Constraints', { - 'fields': ('attrs',) + 'fields': ('constraints',) }), ) filter_horizontal = ('object_types', 'groups', 'users') form = ObjectPermissionForm list_display = [ - 'list_models', 'list_users', 'list_groups', 'actions', 'attrs', + 'list_models', 'list_users', 'list_groups', 'actions', 'constraints', ] list_filter = [ 'groups', 'users' diff --git a/netbox/users/migrations/0008_objectpermission.py b/netbox/users/migrations/0008_objectpermission.py index 4f301264e..3f16e1ee8 100644 --- a/netbox/users/migrations/0008_objectpermission.py +++ b/netbox/users/migrations/0008_objectpermission.py @@ -1,5 +1,3 @@ -# Generated by Django 3.0.6 on 2020-05-29 14:59 - from django.conf import settings import django.contrib.postgres.fields import django.contrib.postgres.fields.jsonb @@ -20,7 +18,7 @@ class Migration(migrations.Migration): name='ObjectPermission', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)), - ('attrs', django.contrib.postgres.fields.jsonb.JSONField(blank=True, null=True)), + ('constraints', django.contrib.postgres.fields.jsonb.JSONField(blank=True, null=True)), ('actions', django.contrib.postgres.fields.ArrayField(base_field=models.CharField(max_length=30), size=None)), ('object_types', models.ManyToManyField(limit_choices_to={'app_label__in': ['circuits', 'dcim', 'extras', 'ipam', 'secrets', 'tenancy', 'virtualization']}, related_name='object_permissions', to='contenttypes.ContentType')), ('groups', models.ManyToManyField(blank=True, related_name='object_permissions', to='auth.Group')), diff --git a/netbox/users/models.py b/netbox/users/models.py index 255980dfc..b340ce90f 100644 --- a/netbox/users/models.py +++ b/netbox/users/models.py @@ -252,10 +252,10 @@ class ObjectPermission(models.Model): }, related_name='object_permissions' ) - attrs = JSONField( + constraints = JSONField( blank=True, null=True, - verbose_name='Attributes' + help_text="Queryset filter matching the applicable objects of the selected type(s)" ) actions = ArrayField( base_field=models.CharField(max_length=30), diff --git a/netbox/utilities/testing/testcases.py b/netbox/utilities/testing/testcases.py index 3cf6a9df6..0db0ff936 100644 --- a/netbox/utilities/testing/testcases.py +++ b/netbox/utilities/testing/testcases.py @@ -180,7 +180,7 @@ class ViewTestCases: # Add object-level permission obj_perm = ObjectPermission( - attrs={'pk': instance1.pk}, + constraints={'pk': instance1.pk}, actions=['view'] ) obj_perm.save() @@ -245,7 +245,7 @@ class ViewTestCases: # Assign object-level permission obj_perm = ObjectPermission( - attrs={'pk__gt': 0}, # Dummy permission to allow all + constraints={'pk__gt': 0}, # Dummy permission to allow all actions=['add'] ) obj_perm.save() @@ -265,7 +265,7 @@ class ViewTestCases: self.assertInstanceEqual(self.model.objects.order_by('pk').last(), self.form_data) # Nullify ObjectPermission to disallow new object creation - obj_perm.attrs = {'pk': 0} + obj_perm.constraints = {'pk': 0} obj_perm.save() # Try to create a non-permitted object @@ -328,7 +328,7 @@ class ViewTestCases: # Assign object-level permission obj_perm = ObjectPermission( - attrs={'pk': instance1.pk}, + constraints={'pk': instance1.pk}, actions=['change'] ) obj_perm.save() @@ -406,7 +406,7 @@ class ViewTestCases: # Assign object-level permission obj_perm = ObjectPermission( - attrs={'pk': instance1.pk}, + constraints={'pk': instance1.pk}, actions=['delete'] ) obj_perm.save() @@ -480,7 +480,7 @@ class ViewTestCases: # Add object-level permission obj_perm = ObjectPermission( - attrs={'pk': instance1.pk}, + constraints={'pk': instance1.pk}, actions=['view'] ) obj_perm.save() @@ -579,7 +579,7 @@ class ViewTestCases: # Assign object-level permission obj_perm = ObjectPermission( - attrs={'pk__gt': 0}, # Dummy permission to allow all + constraints={'pk__gt': 0}, # Dummy permission to allow all actions=['add'] ) obj_perm.save() @@ -651,7 +651,7 @@ class ViewTestCases: # Assign object-level permission obj_perm = ObjectPermission( - attrs={'pk__in': list(pk_list)}, + constraints={'pk__in': list(pk_list)}, actions=['change'] ) obj_perm.save() @@ -718,7 +718,7 @@ class ViewTestCases: # Assign object-level permission obj_perm = ObjectPermission( - attrs={'pk__in': list(pk_list)}, + constraints={'pk__in': list(pk_list)}, actions=['delete'] ) obj_perm.save()