1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Rename attrs to constraints

This commit is contained in:
Jeremy Stretch
2020-06-03 09:43:46 -04:00
parent ddcd172af1
commit d157818d7e
6 changed files with 52 additions and 54 deletions

View File

@ -28,16 +28,16 @@ class ObjectPermissionBackend(ModelBackend):
Q(groups__user=user_obj) Q(groups__user=user_obj)
).prefetch_related('object_types') ).prefetch_related('object_types')
# Create a dictionary mapping permissions to their attributes # Create a dictionary mapping permissions to their constraints
perms = dict() perms = dict()
for obj_perm in object_permissions: for obj_perm in object_permissions:
for object_type in obj_perm.object_types.all(): for object_type in obj_perm.object_types.all():
for action in obj_perm.actions: for action in obj_perm.actions:
perm_name = f"{object_type.app_label}.{action}_{object_type.model}" perm_name = f"{object_type.app_label}.{action}_{object_type.model}"
if perm_name in perms: if perm_name in perms:
perms[perm_name].append(obj_perm.attrs) perms[perm_name].append(obj_perm.constraints)
else: else:
perms[perm_name] = [obj_perm.attrs] perms[perm_name] = [obj_perm.constraints]
return perms return perms
@ -71,20 +71,20 @@ class ObjectPermissionBackend(ModelBackend):
raise ValueError(f"Invalid permission {perm} for model {model}") raise ValueError(f"Invalid permission {perm} for model {model}")
# Compile a query filter that matches all instances of the specified model # Compile a query filter that matches all instances of the specified model
obj_perm_attrs = self.get_all_permissions(user_obj)[perm] obj_perm_constraints = self.get_all_permissions(user_obj)[perm]
attrs = Q() constraints = Q()
for perm_attrs in obj_perm_attrs: for perm_constraints in obj_perm_constraints:
if perm_attrs: if perm_constraints:
attrs |= Q(**perm_attrs) constraints |= Q(**perm_constraints)
else: else:
# Found ObjectPermission with null attrs; allow model-level access # Found ObjectPermission with null constraints; allow model-level access
attrs = Q() constraints = Q()
break break
# Permission to perform the requested action on the object depends on whether the specified object matches # 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. # 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): class RemoteUserBackend(_RemoteUserBackend):
@ -111,11 +111,11 @@ class RemoteUserBackend(_RemoteUserBackend):
# Assign default object permissions to the user # Assign default object permissions to the user
permissions_list = [] 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: try:
object_type, action = resolve_permission_ct(permission_name) object_type, action = resolve_permission_ct(permission_name)
# TODO: Merge multiple actions into a single ObjectPermission per content type # 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.save()
obj_perm.users.add(user) obj_perm.users.add(user)
obj_perm.object_types.add(object_type) obj_perm.object_types.add(object_type)

View File

@ -202,7 +202,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view'] actions=['view']
) )
obj_perm.save() obj_perm.save()
@ -226,7 +226,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view'] actions=['view']
) )
obj_perm.save() obj_perm.save()
@ -260,7 +260,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view', 'add'] actions=['view', 'add']
) )
obj_perm.save() obj_perm.save()
@ -307,7 +307,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view', 'change'] actions=['view', 'change']
) )
obj_perm.save() obj_perm.save()
@ -350,7 +350,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view', 'delete'] actions=['view', 'delete']
) )
obj_perm.save() obj_perm.save()
@ -398,7 +398,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['add'] actions=['add']
) )
obj_perm.save() obj_perm.save()
@ -447,7 +447,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['change'] actions=['change']
) )
obj_perm.save() obj_perm.save()
@ -491,7 +491,7 @@ class ObjectPermissionViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view', 'delete'] actions=['view', 'delete']
) )
obj_perm.save() obj_perm.save()
@ -562,7 +562,7 @@ class ObjectPermissionAPIViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view'] actions=['view']
) )
obj_perm.save() obj_perm.save()
@ -589,7 +589,7 @@ class ObjectPermissionAPIViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['view'] actions=['view']
) )
obj_perm.save() obj_perm.save()
@ -616,7 +616,7 @@ class ObjectPermissionAPIViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['add'] actions=['add']
) )
obj_perm.save() obj_perm.save()
@ -645,7 +645,7 @@ class ObjectPermissionAPIViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['change'] actions=['change']
) )
obj_perm.save() obj_perm.save()
@ -680,7 +680,7 @@ class ObjectPermissionAPIViewTestCase(TestCase):
# Assign object permission # Assign object permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'site__name': 'Site 1'}, constraints={'site__name': 'Site 1'},
actions=['delete'] actions=['delete']
) )
obj_perm.save() obj_perm.save()

View File

@ -37,7 +37,7 @@ class UserConfigInline(admin.TabularInline):
class ObjectPermissionInline(admin.TabularInline): class ObjectPermissionInline(admin.TabularInline):
model = AdminUser.object_permissions.through model = AdminUser.object_permissions.through
fields = ['object_types', 'actions', 'attrs'] fields = ['object_types', 'actions', 'constraints']
readonly_fields = fields readonly_fields = fields
extra = 0 extra = 0
verbose_name = 'Permission' verbose_name = 'Permission'
@ -48,8 +48,8 @@ class ObjectPermissionInline(admin.TabularInline):
def actions(self, instance): def actions(self, instance):
return ', '.join(instance.objectpermission.actions) return ', '.join(instance.objectpermission.actions)
def attrs(self, instance): def constraints(self, instance):
return instance.objectpermission.attrs return instance.objectpermission.constraints
def has_add_permission(self, request, obj): def has_add_permission(self, request, obj):
# Don't allow the creation of new ObjectPermission assignments via this form # Don't allow the creation of new ObjectPermission assignments via this form
@ -113,8 +113,8 @@ class ObjectPermissionForm(forms.ModelForm):
exclude = [] exclude = []
help_texts = { help_texts = {
'actions': 'Actions granted in addition to those listed above', '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 ' 'constraints': 'JSON expression of a queryset filter that will return only permitted objects. Leave null '
'match all objects of this type.' 'to match all objects of this type.'
} }
labels = { labels = {
'actions': 'Additional actions' 'actions': 'Additional actions'
@ -143,7 +143,7 @@ class ObjectPermissionForm(forms.ModelForm):
def clean(self): def clean(self):
object_types = self.cleaned_data['object_types'] 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 # Append any of the selected CRUD checkboxes to the actions list
if not self.cleaned_data.get('actions'): if not self.cleaned_data.get('actions'):
@ -156,16 +156,16 @@ class ObjectPermissionForm(forms.ModelForm):
if not self.cleaned_data['actions']: if not self.cleaned_data['actions']:
raise ValidationError("At least one action must be selected.") 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 # 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 attributes are valid. # returns anything; we just want to make sure the specified constraints are valid.
if attrs: if constraints:
for ct in object_types: for ct in object_types:
model = ct.model_class() model = ct.model_class()
try: try:
model.objects.filter(**attrs).exists() model.objects.filter(**constraints).exists()
except FieldError as e: except FieldError as e:
raise ValidationError({ 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') 'fields': (('can_view', 'can_add', 'can_change', 'can_delete'), 'actions')
}), }),
('Constraints', { ('Constraints', {
'fields': ('attrs',) 'fields': ('constraints',)
}), }),
) )
filter_horizontal = ('object_types', 'groups', 'users') filter_horizontal = ('object_types', 'groups', 'users')
form = ObjectPermissionForm form = ObjectPermissionForm
list_display = [ list_display = [
'list_models', 'list_users', 'list_groups', 'actions', 'attrs', 'list_models', 'list_users', 'list_groups', 'actions', 'constraints',
] ]
list_filter = [ list_filter = [
'groups', 'users' 'groups', 'users'

View File

@ -1,5 +1,3 @@
# Generated by Django 3.0.6 on 2020-05-29 14:59
from django.conf import settings from django.conf import settings
import django.contrib.postgres.fields import django.contrib.postgres.fields
import django.contrib.postgres.fields.jsonb import django.contrib.postgres.fields.jsonb
@ -20,7 +18,7 @@ class Migration(migrations.Migration):
name='ObjectPermission', name='ObjectPermission',
fields=[ fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False)), ('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)), ('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')), ('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')), ('groups', models.ManyToManyField(blank=True, related_name='object_permissions', to='auth.Group')),

View File

@ -252,10 +252,10 @@ class ObjectPermission(models.Model):
}, },
related_name='object_permissions' related_name='object_permissions'
) )
attrs = JSONField( constraints = JSONField(
blank=True, blank=True,
null=True, null=True,
verbose_name='Attributes' help_text="Queryset filter matching the applicable objects of the selected type(s)"
) )
actions = ArrayField( actions = ArrayField(
base_field=models.CharField(max_length=30), base_field=models.CharField(max_length=30),

View File

@ -180,7 +180,7 @@ class ViewTestCases:
# Add object-level permission # Add object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk': instance1.pk}, constraints={'pk': instance1.pk},
actions=['view'] actions=['view']
) )
obj_perm.save() obj_perm.save()
@ -245,7 +245,7 @@ class ViewTestCases:
# Assign object-level permission # Assign object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk__gt': 0}, # Dummy permission to allow all constraints={'pk__gt': 0}, # Dummy permission to allow all
actions=['add'] actions=['add']
) )
obj_perm.save() obj_perm.save()
@ -265,7 +265,7 @@ class ViewTestCases:
self.assertInstanceEqual(self.model.objects.order_by('pk').last(), self.form_data) self.assertInstanceEqual(self.model.objects.order_by('pk').last(), self.form_data)
# Nullify ObjectPermission to disallow new object creation # Nullify ObjectPermission to disallow new object creation
obj_perm.attrs = {'pk': 0} obj_perm.constraints = {'pk': 0}
obj_perm.save() obj_perm.save()
# Try to create a non-permitted object # Try to create a non-permitted object
@ -328,7 +328,7 @@ class ViewTestCases:
# Assign object-level permission # Assign object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk': instance1.pk}, constraints={'pk': instance1.pk},
actions=['change'] actions=['change']
) )
obj_perm.save() obj_perm.save()
@ -406,7 +406,7 @@ class ViewTestCases:
# Assign object-level permission # Assign object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk': instance1.pk}, constraints={'pk': instance1.pk},
actions=['delete'] actions=['delete']
) )
obj_perm.save() obj_perm.save()
@ -480,7 +480,7 @@ class ViewTestCases:
# Add object-level permission # Add object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk': instance1.pk}, constraints={'pk': instance1.pk},
actions=['view'] actions=['view']
) )
obj_perm.save() obj_perm.save()
@ -579,7 +579,7 @@ class ViewTestCases:
# Assign object-level permission # Assign object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk__gt': 0}, # Dummy permission to allow all constraints={'pk__gt': 0}, # Dummy permission to allow all
actions=['add'] actions=['add']
) )
obj_perm.save() obj_perm.save()
@ -651,7 +651,7 @@ class ViewTestCases:
# Assign object-level permission # Assign object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk__in': list(pk_list)}, constraints={'pk__in': list(pk_list)},
actions=['change'] actions=['change']
) )
obj_perm.save() obj_perm.save()
@ -718,7 +718,7 @@ class ViewTestCases:
# Assign object-level permission # Assign object-level permission
obj_perm = ObjectPermission( obj_perm = ObjectPermission(
attrs={'pk__in': list(pk_list)}, constraints={'pk__in': list(pk_list)},
actions=['delete'] actions=['delete']
) )
obj_perm.save() obj_perm.save()