Allow bypass of "write" permission for render endpoint.

This commit is contained in:
Daniel Sheppard 2024-02-23 16:37:32 -06:00
parent edb7d24b45
commit 7600adc1e1
2 changed files with 27 additions and 1 deletions

View File

@ -4,6 +4,8 @@ from rest_framework.renderers import JSONRenderer
from rest_framework.response import Response from rest_framework.response import Response
from rest_framework.status import HTTP_400_BAD_REQUEST 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 netbox.api.renderers import TextRenderer
from .nested_serializers import NestedConfigTemplateSerializer from .nested_serializers import NestedConfigTemplateSerializer
@ -61,14 +63,23 @@ class ConfigTemplateRenderMixin:
class RenderConfigMixin(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_qs = self.queryset
super().initial(request, *args, **kwargs)
""" """
Provides a /render-config/ endpoint for REST API views whose model may have a ConfigTemplate assigned. 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): def render_config(self, request, pk):
""" """
Resolve and render the preferred ConfigTemplate for this Device. Resolve and render the preferred ConfigTemplate for this Device.
""" """
self.queryset = self.original_queryset.restrict(request.user, 'view')
instance = self.get_object() instance = self.get_object()
object_type = instance._meta.model_name object_type = instance._meta.model_name
configtemplate = instance.get_config_template() configtemplate = instance.get_config_template()

View File

@ -124,6 +124,21 @@ class TokenPermissions(DjangoObjectPermissions):
return super().has_object_permission(request, view, obj) 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): class IsAuthenticatedOrLoginNotRequired(BasePermission):
""" """
Returns True if the user is authenticated or LOGIN_REQUIRED is False. Returns True if the user is authenticated or LOGIN_REQUIRED is False.