This commit is contained in:
Daniel Sheppard 2024-04-23 17:10:06 +02:00 committed by GitHub
commit 0d191df148
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 29 additions and 3 deletions

View File

@ -1277,7 +1277,7 @@ class DeviceTest(APIViewTestCases.APIViewTestCase):
device.config_template = configtemplate
device.save()
self.add_permissions('dcim.add_device')
self.add_permissions('dcim.view_device')
url = reverse('dcim-api:device-detail', kwargs={'pk': device.pk}) + 'render-config/'
response = self.client.post(url, {}, format='json', **self.header)
self.assertHttpStatus(response, status.HTTP_200_OK)

View File

@ -4,6 +4,8 @@ from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST
from dcim.models import Device
from netbox.api.authentication import ViewOnlyPermissions
from netbox.api.renderers import TextRenderer
from .nested_serializers import NestedConfigTemplateSerializer
@ -61,14 +63,23 @@ class ConfigTemplateRenderMixin:
class RenderConfigMixin(ConfigTemplateRenderMixin):
"""
Override initial() to save a copy of the queryset for "un-restricting" the queryset when rendering.
"""
def initial(self, request, *args, **kwargs):
self.original_queryset = self.queryset
super().initial(request, *args, **kwargs)
"""
Provides a /render-config/ endpoint for REST API views whose model may have a ConfigTemplate assigned.
"""
@action(detail=True, methods=['post'], url_path='render-config', renderer_classes=[JSONRenderer, TextRenderer])
@action(detail=True, methods=['post'], url_path='render-config', renderer_classes=[JSONRenderer, TextRenderer],
permission_classes=[ViewOnlyPermissions])
def render_config(self, request, pk):
"""
Resolve and render the preferred ConfigTemplate for this Device.
"""
self.queryset = self.original_queryset.restrict(request.user, 'view')
instance = self.get_object()
object_type = instance._meta.model_name
configtemplate = instance.get_config_template()

View File

@ -124,6 +124,21 @@ class TokenPermissions(DjangoObjectPermissions):
return super().has_object_permission(request, view, obj)
class ViewOnlyPermissions(TokenPermissions):
"""
Override the stock perm_map to require only view permissions
"""
perms_map = {
'GET': ['%(app_label)s.view_%(model_name)s'],
'OPTIONS': [],
'HEAD': ['%(app_label)s.view_%(model_name)s'],
'POST': ['%(app_label)s.view_%(model_name)s'],
'PUT': ['%(app_label)s.view_%(model_name)s'],
'PATCH': ['%(app_label)s.view_%(model_name)s'],
'DELETE': ['%(app_label)s.view_%(model_name)s'],
}
class IsAuthenticatedOrLoginNotRequired(BasePermission):
"""
Returns True if the user is authenticated or LOGIN_REQUIRED is False.

View File

@ -239,7 +239,7 @@ class VirtualMachineTest(APIViewTestCases.APIViewTestCase):
vm.config_template = configtemplate
vm.save()
self.add_permissions('virtualization.add_virtualmachine')
self.add_permissions('virtualization.view_virtualmachine')
url = reverse('virtualization-api:virtualmachine-detail', kwargs={'pk': vm.pk}) + 'render-config/'
response = self.client.post(url, {}, format='json', **self.header)
self.assertHttpStatus(response, status.HTTP_200_OK)