mirror of
https://github.com/netbox-community/netbox.git
synced 2025-09-06 14:23:36 -06:00
Fixes: #19669 - Add an API endpoint to download image attachments
This commit is contained in:
parent
ffa9a52667
commit
f48e1cb534
@ -1,5 +1,7 @@
|
|||||||
|
from django.conf import settings
|
||||||
from django.http import Http404
|
from django.http import Http404
|
||||||
from django.shortcuts import get_object_or_404
|
from django.shortcuts import get_object_or_404
|
||||||
|
from django.views.static import serve
|
||||||
from django_rq.queues import get_connection
|
from django_rq.queues import get_connection
|
||||||
from drf_spectacular.utils import extend_schema, extend_schema_view
|
from drf_spectacular.utils import extend_schema, extend_schema_view
|
||||||
from rest_framework import status
|
from rest_framework import status
|
||||||
@ -32,6 +34,7 @@ class ExtrasRootView(APIRootView):
|
|||||||
"""
|
"""
|
||||||
Extras API root view
|
Extras API root view
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def get_view_name(self):
|
def get_view_name(self):
|
||||||
return 'Extras'
|
return 'Extras'
|
||||||
|
|
||||||
@ -40,6 +43,7 @@ class ExtrasRootView(APIRootView):
|
|||||||
# EventRules
|
# EventRules
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class EventRuleViewSet(NetBoxModelViewSet):
|
class EventRuleViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = EventRule.objects.all()
|
queryset = EventRule.objects.all()
|
||||||
@ -51,6 +55,7 @@ class EventRuleViewSet(NetBoxModelViewSet):
|
|||||||
# Webhooks
|
# Webhooks
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class WebhookViewSet(NetBoxModelViewSet):
|
class WebhookViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = Webhook.objects.all()
|
queryset = Webhook.objects.all()
|
||||||
@ -62,6 +67,7 @@ class WebhookViewSet(NetBoxModelViewSet):
|
|||||||
# Custom fields
|
# Custom fields
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class CustomFieldViewSet(NetBoxModelViewSet):
|
class CustomFieldViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = CustomField.objects.select_related('choice_set')
|
queryset = CustomField.objects.select_related('choice_set')
|
||||||
@ -89,9 +95,7 @@ class CustomFieldChoiceSetViewSet(NetBoxModelViewSet):
|
|||||||
|
|
||||||
# Paginate data
|
# Paginate data
|
||||||
if page := self.paginate_queryset(choices):
|
if page := self.paginate_queryset(choices):
|
||||||
data = [
|
data = [{'id': c[0], 'display': c[1]} for c in page]
|
||||||
{'id': c[0], 'display': c[1]} for c in page
|
|
||||||
]
|
|
||||||
else:
|
else:
|
||||||
data = []
|
data = []
|
||||||
|
|
||||||
@ -102,6 +106,7 @@ class CustomFieldChoiceSetViewSet(NetBoxModelViewSet):
|
|||||||
# Custom links
|
# Custom links
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class CustomLinkViewSet(NetBoxModelViewSet):
|
class CustomLinkViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = CustomLink.objects.all()
|
queryset = CustomLink.objects.all()
|
||||||
@ -113,6 +118,7 @@ class CustomLinkViewSet(NetBoxModelViewSet):
|
|||||||
# Export templates
|
# Export templates
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class ExportTemplateViewSet(SyncedDataMixin, NetBoxModelViewSet):
|
class ExportTemplateViewSet(SyncedDataMixin, NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = ExportTemplate.objects.all()
|
queryset = ExportTemplate.objects.all()
|
||||||
@ -124,6 +130,7 @@ class ExportTemplateViewSet(SyncedDataMixin, NetBoxModelViewSet):
|
|||||||
# Saved filters
|
# Saved filters
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class SavedFilterViewSet(NetBoxModelViewSet):
|
class SavedFilterViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = SavedFilter.objects.all()
|
queryset = SavedFilter.objects.all()
|
||||||
@ -135,6 +142,7 @@ class SavedFilterViewSet(NetBoxModelViewSet):
|
|||||||
# Table Configs
|
# Table Configs
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class TableConfigViewSet(NetBoxModelViewSet):
|
class TableConfigViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = TableConfig.objects.all()
|
queryset = TableConfig.objects.all()
|
||||||
@ -146,6 +154,7 @@ class TableConfigViewSet(NetBoxModelViewSet):
|
|||||||
# Bookmarks
|
# Bookmarks
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class BookmarkViewSet(NetBoxModelViewSet):
|
class BookmarkViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = Bookmark.objects.all()
|
queryset = Bookmark.objects.all()
|
||||||
@ -157,6 +166,7 @@ class BookmarkViewSet(NetBoxModelViewSet):
|
|||||||
# Notifications & subscriptions
|
# Notifications & subscriptions
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class NotificationViewSet(NetBoxModelViewSet):
|
class NotificationViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = Notification.objects.all()
|
queryset = Notification.objects.all()
|
||||||
@ -178,6 +188,7 @@ class SubscriptionViewSet(NetBoxModelViewSet):
|
|||||||
# Tags
|
# Tags
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class TagViewSet(NetBoxModelViewSet):
|
class TagViewSet(NetBoxModelViewSet):
|
||||||
queryset = Tag.objects.all()
|
queryset = Tag.objects.all()
|
||||||
serializer_class = serializers.TagSerializer
|
serializer_class = serializers.TagSerializer
|
||||||
@ -194,17 +205,30 @@ class TaggedItemViewSet(RetrieveModelMixin, ListModelMixin, BaseViewSet):
|
|||||||
# Image attachments
|
# Image attachments
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class ImageAttachmentViewSet(NetBoxModelViewSet):
|
class ImageAttachmentViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = ImageAttachment.objects.all()
|
queryset = ImageAttachment.objects.all()
|
||||||
serializer_class = serializers.ImageAttachmentSerializer
|
serializer_class = serializers.ImageAttachmentSerializer
|
||||||
filterset_class = filtersets.ImageAttachmentFilterSet
|
filterset_class = filtersets.ImageAttachmentFilterSet
|
||||||
|
|
||||||
|
@action(
|
||||||
|
methods=['GET'],
|
||||||
|
detail=True,
|
||||||
|
url_path='download',
|
||||||
|
url_name='download',
|
||||||
|
)
|
||||||
|
def download(self, request, pk, *args, **kwargs):
|
||||||
|
obj = get_object_or_404(self.queryset, pk=pk)
|
||||||
|
# Render and return the elevation as an SVG drawing with the correct content type
|
||||||
|
return serve(request, obj.image.path, document_root=settings.MEDIA_ROOT)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Journal entries
|
# Journal entries
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class JournalEntryViewSet(NetBoxModelViewSet):
|
class JournalEntryViewSet(NetBoxModelViewSet):
|
||||||
metadata_class = ContentTypeMetadata
|
metadata_class = ContentTypeMetadata
|
||||||
queryset = JournalEntry.objects.all()
|
queryset = JournalEntry.objects.all()
|
||||||
@ -216,6 +240,7 @@ class JournalEntryViewSet(NetBoxModelViewSet):
|
|||||||
# Config contexts
|
# Config contexts
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class ConfigContextViewSet(SyncedDataMixin, NetBoxModelViewSet):
|
class ConfigContextViewSet(SyncedDataMixin, NetBoxModelViewSet):
|
||||||
queryset = ConfigContext.objects.all()
|
queryset = ConfigContext.objects.all()
|
||||||
serializer_class = serializers.ConfigContextSerializer
|
serializer_class = serializers.ConfigContextSerializer
|
||||||
@ -226,6 +251,7 @@ class ConfigContextViewSet(SyncedDataMixin, NetBoxModelViewSet):
|
|||||||
# Config templates
|
# Config templates
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class ConfigTemplateViewSet(SyncedDataMixin, ConfigTemplateRenderMixin, NetBoxModelViewSet):
|
class ConfigTemplateViewSet(SyncedDataMixin, ConfigTemplateRenderMixin, NetBoxModelViewSet):
|
||||||
queryset = ConfigTemplate.objects.all()
|
queryset = ConfigTemplate.objects.all()
|
||||||
serializer_class = serializers.ConfigTemplateSerializer
|
serializer_class = serializers.ConfigTemplateSerializer
|
||||||
@ -247,6 +273,7 @@ class ConfigTemplateViewSet(SyncedDataMixin, ConfigTemplateRenderMixin, NetBoxMo
|
|||||||
# Scripts
|
# Scripts
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
@extend_schema_view(
|
@extend_schema_view(
|
||||||
update=extend_schema(request=serializers.ScriptInputSerializer),
|
update=extend_schema(request=serializers.ScriptInputSerializer),
|
||||||
partial_update=extend_schema(request=serializers.ScriptInputSerializer),
|
partial_update=extend_schema(request=serializers.ScriptInputSerializer),
|
||||||
@ -287,10 +314,7 @@ class ScriptViewSet(ModelViewSet):
|
|||||||
raise PermissionDenied("This user does not have permission to run scripts.")
|
raise PermissionDenied("This user does not have permission to run scripts.")
|
||||||
|
|
||||||
script = self._get_script(pk)
|
script = self._get_script(pk)
|
||||||
input_serializer = serializers.ScriptInputSerializer(
|
input_serializer = serializers.ScriptInputSerializer(data=request.data, context={'script': script})
|
||||||
data=request.data,
|
|
||||||
context={'script': script}
|
|
||||||
)
|
|
||||||
|
|
||||||
# Check that at least one RQ worker is running
|
# Check that at least one RQ worker is running
|
||||||
if not Worker.count(get_connection('default')):
|
if not Worker.count(get_connection('default')):
|
||||||
@ -305,7 +329,7 @@ class ScriptViewSet(ModelViewSet):
|
|||||||
commit=input_serializer.data['commit'],
|
commit=input_serializer.data['commit'],
|
||||||
job_timeout=script.python_class.job_timeout,
|
job_timeout=script.python_class.job_timeout,
|
||||||
schedule_at=input_serializer.validated_data.get('schedule_at'),
|
schedule_at=input_serializer.validated_data.get('schedule_at'),
|
||||||
interval=input_serializer.validated_data.get('interval')
|
interval=input_serializer.validated_data.get('interval'),
|
||||||
)
|
)
|
||||||
serializer = serializers.ScriptDetailSerializer(script, context={'request': request})
|
serializer = serializers.ScriptDetailSerializer(script, context={'request': request})
|
||||||
|
|
||||||
@ -318,10 +342,12 @@ class ScriptViewSet(ModelViewSet):
|
|||||||
# Object types
|
# Object types
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class ObjectTypeViewSet(ReadOnlyModelViewSet):
|
class ObjectTypeViewSet(ReadOnlyModelViewSet):
|
||||||
"""
|
"""
|
||||||
Read-only list of ObjectTypes.
|
Read-only list of ObjectTypes.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
permission_classes = [IsAuthenticatedOrLoginNotRequired]
|
permission_classes = [IsAuthenticatedOrLoginNotRequired]
|
||||||
queryset = ObjectType.objects.order_by('app_label', 'model')
|
queryset = ObjectType.objects.order_by('app_label', 'model')
|
||||||
serializer_class = serializers.ObjectTypeSerializer
|
serializer_class = serializers.ObjectTypeSerializer
|
||||||
@ -332,6 +358,7 @@ class ObjectTypeViewSet(ReadOnlyModelViewSet):
|
|||||||
# User dashboard
|
# User dashboard
|
||||||
#
|
#
|
||||||
|
|
||||||
|
|
||||||
class DashboardView(RetrieveUpdateDestroyAPIView):
|
class DashboardView(RetrieveUpdateDestroyAPIView):
|
||||||
queryset = Dashboard.objects.all()
|
queryset = Dashboard.objects.all()
|
||||||
serializer_class = serializers.DashboardSerializer
|
serializer_class = serializers.DashboardSerializer
|
||||||
|
Loading…
Reference in New Issue
Block a user