mirror of
https://github.com/netbox-community/netbox.git
synced 2024-05-10 07:54:54 +00:00
Implement ObjectPermissionManager
This commit is contained in:
@@ -56,21 +56,12 @@ class ObjectPermissionBackend(ModelBackend):
|
||||
if model._meta.model_name != model_name:
|
||||
raise ValueError(f"Invalid permission {perm} for model {model}")
|
||||
|
||||
# Retrieve user's permissions for this model
|
||||
# This can probably be cached
|
||||
obj_permissions = ObjectPermission.objects.filter(
|
||||
Q(users=user_obj) | Q(groups__user=user_obj),
|
||||
model=ContentType.objects.get_for_model(obj),
|
||||
**{f'can_{action}': True}
|
||||
)
|
||||
|
||||
for perm in obj_permissions:
|
||||
|
||||
# Attempt to retrieve the model from the database using the
|
||||
# attributes defined in the ObjectPermission. If we have a
|
||||
# match, assert that the user has permission.
|
||||
if model.objects.filter(pk=obj.pk, **perm.attrs).exists():
|
||||
return True
|
||||
# Attempt to retrieve the model from the database using the
|
||||
# attributes defined in the ObjectPermission. If we have a
|
||||
# match, assert that the user has permission.
|
||||
attrs = ObjectPermission.objects.get_attr_constraints(user_obj, obj, action)
|
||||
if model.objects.filter(pk=obj.pk, **attrs).exists():
|
||||
return True
|
||||
|
||||
|
||||
class RemoteUserBackend(ViewExemptModelBackend, RemoteUserBackend_):
|
||||
|
@@ -4,7 +4,7 @@ from copy import deepcopy
|
||||
|
||||
from django.contrib import messages
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.core.exceptions import FieldDoesNotExist, ValidationError
|
||||
from django.core.exceptions import FieldDoesNotExist, ObjectDoesNotExist, ValidationError
|
||||
from django.db import transaction, IntegrityError
|
||||
from django.db.models import ManyToManyField, ProtectedError
|
||||
from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput, Textarea
|
||||
@@ -23,6 +23,7 @@ from django_tables2 import RequestConfig
|
||||
|
||||
from extras.models import CustomField, CustomFieldValue, ExportTemplate
|
||||
from extras.querysets import CustomFieldQueryset
|
||||
from users.models import ObjectPermission
|
||||
from utilities.exceptions import AbortTransaction
|
||||
from utilities.forms import BootstrapMixin, CSVDataField, TableConfigForm
|
||||
from utilities.utils import csv_format, prepare_cloned_fields
|
||||
@@ -262,32 +263,43 @@ class ObjectEditView(GetReturnURLMixin, View):
|
||||
if form.is_valid():
|
||||
logger.debug("Form validation was successful")
|
||||
|
||||
obj = form.save()
|
||||
msg = '{} {}'.format(
|
||||
'Created' if not form.instance.pk else 'Modified',
|
||||
self.queryset.model._meta.verbose_name
|
||||
)
|
||||
logger.info(f"{msg} {obj} (PK: {obj.pk})")
|
||||
if hasattr(obj, 'get_absolute_url'):
|
||||
msg = '{} <a href="{}">{}</a>'.format(msg, obj.get_absolute_url(), escape(obj))
|
||||
else:
|
||||
msg = '{} {}'.format(msg, escape(obj))
|
||||
messages.success(request, mark_safe(msg))
|
||||
try:
|
||||
with transaction.atomic():
|
||||
obj = form.save()
|
||||
|
||||
if '_addanother' in request.POST:
|
||||
# Check that the new object conforms with any assigned object-level permissions
|
||||
self.queryset.get(pk=obj.pk)
|
||||
|
||||
# If the object has clone_fields, pre-populate a new instance of the form
|
||||
if hasattr(obj, 'clone_fields'):
|
||||
url = '{}?{}'.format(request.path, prepare_cloned_fields(obj))
|
||||
return redirect(url)
|
||||
msg = '{} {}'.format(
|
||||
'Created' if not form.instance.pk else 'Modified',
|
||||
self.queryset.model._meta.verbose_name
|
||||
)
|
||||
logger.info(f"{msg} {obj} (PK: {obj.pk})")
|
||||
if hasattr(obj, 'get_absolute_url'):
|
||||
msg = '{} <a href="{}">{}</a>'.format(msg, obj.get_absolute_url(), escape(obj))
|
||||
else:
|
||||
msg = '{} {}'.format(msg, escape(obj))
|
||||
messages.success(request, mark_safe(msg))
|
||||
|
||||
return redirect(request.get_full_path())
|
||||
if '_addanother' in request.POST:
|
||||
|
||||
return_url = form.cleaned_data.get('return_url')
|
||||
if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()):
|
||||
return redirect(return_url)
|
||||
else:
|
||||
return redirect(self.get_return_url(request, obj))
|
||||
# If the object has clone_fields, pre-populate a new instance of the form
|
||||
if hasattr(obj, 'clone_fields'):
|
||||
url = '{}?{}'.format(request.path, prepare_cloned_fields(obj))
|
||||
return redirect(url)
|
||||
|
||||
return redirect(request.get_full_path())
|
||||
|
||||
return_url = form.cleaned_data.get('return_url')
|
||||
if return_url is not None and is_safe_url(url=return_url, allowed_hosts=request.get_host()):
|
||||
return redirect(return_url)
|
||||
else:
|
||||
return redirect(self.get_return_url(request, obj))
|
||||
|
||||
except ObjectDoesNotExist:
|
||||
logger.debug("Object save failed due to object-level permissions violation")
|
||||
# TODO: Link user to personal permissions view
|
||||
form.add_error(None, "Object save failed due to object-level permissions violation")
|
||||
|
||||
else:
|
||||
logger.debug("Form validation failed")
|
||||
|
Reference in New Issue
Block a user