From 954e29aec3bfefeab1cebfffbe97a7520406ecd0 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 12 Nov 2024 12:19:37 -0500 Subject: [PATCH 1/6] Fixes #17972: Force evaluation of LOGIN_REQUIRED when requesting static media (#17990) --- netbox/netbox/tests/test_views.py | 20 +++++++++++++++++++- netbox/netbox/urls.py | 5 ++--- netbox/netbox/views/misc.py | 10 ++++++++++ 3 files changed, 31 insertions(+), 4 deletions(-) diff --git a/netbox/netbox/tests/test_views.py b/netbox/netbox/tests/test_views.py index ccba73baa..50cfa5755 100644 --- a/netbox/netbox/tests/test_views.py +++ b/netbox/netbox/tests/test_views.py @@ -1,7 +1,7 @@ import urllib.parse from django.urls import reverse -from django.test import override_settings +from django.test import Client, override_settings from dcim.models import Site from netbox.constants import EMPTY_TABLE_TEXT @@ -74,3 +74,21 @@ class SearchViewTestCase(TestCase): self.assertHttpStatus(response, 200) content = str(response.content) self.assertIn(EMPTY_TABLE_TEXT, content) + + +class MediaViewTestCase(TestCase): + + def test_media_login_required(self): + url = reverse('media', kwargs={'path': 'foo.txt'}) + response = Client().get(url) + + # Unauthenticated request should redirect to login page + self.assertHttpStatus(response, 302) + + @override_settings(LOGIN_REQUIRED=False) + def test_media_login_not_required(self): + url = reverse('media', kwargs={'path': 'foo.txt'}) + response = Client().get(url) + + # Unauthenticated request should return a 404 (not found) + self.assertHttpStatus(response, 404) diff --git a/netbox/netbox/urls.py b/netbox/netbox/urls.py index b0175ec04..b91ee295d 100644 --- a/netbox/netbox/urls.py +++ b/netbox/netbox/urls.py @@ -2,7 +2,6 @@ from django.conf import settings from django.conf.urls import include from django.urls import path from django.views.decorators.cache import cache_page -from django.views.static import serve from drf_spectacular.views import SpectacularAPIView, SpectacularRedocView, SpectacularSwaggerView from account.views import LoginView, LogoutView @@ -10,7 +9,7 @@ from netbox.api.views import APIRootView, StatusView from netbox.graphql.schema import schema from netbox.graphql.views import NetBoxGraphQLView from netbox.plugins.urls import plugin_patterns, plugin_api_patterns -from netbox.views import HomeView, StaticMediaFailureView, SearchView, htmx +from netbox.views import HomeView, MediaView, StaticMediaFailureView, SearchView, htmx _patterns = [ @@ -69,7 +68,7 @@ _patterns = [ path('graphql/', NetBoxGraphQLView.as_view(schema=schema), name='graphql'), # Serving static media in Django to pipe it through LoginRequiredMiddleware - path('media/', serve, {'document_root': settings.MEDIA_ROOT}), + path('media/', MediaView.as_view(), name='media'), path('media-failure/', StaticMediaFailureView.as_view(), name='media_failure'), # Plugins diff --git a/netbox/netbox/views/misc.py b/netbox/netbox/views/misc.py index c584e99e4..f28b0f7b1 100644 --- a/netbox/netbox/views/misc.py +++ b/netbox/netbox/views/misc.py @@ -8,6 +8,7 @@ from django.core.cache import cache from django.shortcuts import redirect, render from django.utils.translation import gettext_lazy as _ from django.views.generic import View +from django.views.static import serve from django_tables2 import RequestConfig from packaging import version @@ -23,6 +24,7 @@ from utilities.views import ConditionalLoginRequiredMixin __all__ = ( 'HomeView', + 'MediaView', 'SearchView', ) @@ -115,3 +117,11 @@ class SearchView(ConditionalLoginRequiredMixin, View): 'form': form, 'table': table, }) + + +class MediaView(ConditionalLoginRequiredMixin, View): + """ + Wrap Django's serve() view to enforce LOGIN_REQUIRED for static media. + """ + def get(self, request, path): + return serve(request, path, document_root=settings.MEDIA_ROOT) From 2ed0534117af7247ca56ee43c6175f79a5ca6f41 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 12 Nov 2024 13:58:48 -0500 Subject: [PATCH 2/6] Fixes #17963: Fix selection of all listed objects during bulk edit --- netbox/netbox/views/generic/bulk_views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 4b2f1ae28..7158f056a 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -698,7 +698,7 @@ class BulkEditView(GetReturnURLMixin, BaseMultiObjectView): logger.debug("Form validation failed") else: - form = self.form(request.POST, initial=initial_data) + form = self.form(initial=initial_data) restrict_form_fields(form, request.user) # Retrieve objects being edited From c34fea6c9bb89e543139b93ed75ff55567bdd553 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 12 Nov 2024 12:11:44 -0500 Subject: [PATCH 3/6] Fixes #17969: Fix system info export when a config revision exists --- netbox/core/tests/test_views.py | 29 +++++++++++++++++++++++++++++ netbox/core/views.py | 6 +----- 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/netbox/core/tests/test_views.py b/netbox/core/tests/test_views.py index 01912b4d6..047b51ef6 100644 --- a/netbox/core/tests/test_views.py +++ b/netbox/core/tests/test_views.py @@ -346,3 +346,32 @@ class BackgroundTaskTestCase(TestCase): self.assertIn(str(worker1.name), str(response.content)) self.assertIn('Birth', str(response.content)) self.assertIn('Total working time', str(response.content)) + + +class SystemTestCase(TestCase): + + def setUp(self): + super().setUp() + + self.user.is_staff = True + self.user.save() + + def test_system_view_default(self): + # Test UI render + response = self.client.get(reverse('core:system')) + self.assertEqual(response.status_code, 200) + + # Test export + response = self.client.get(f"{reverse('core:system')}?export=true") + self.assertEqual(response.status_code, 200) + + def test_system_view_with_config_revision(self): + ConfigRevision.objects.create() + + # Test UI render + response = self.client.get(reverse('core:system')) + self.assertEqual(response.status_code, 200) + + # Test export + response = self.client.get(f"{reverse('core:system')}?export=true") + self.assertEqual(response.status_code, 200) diff --git a/netbox/core/views.py b/netbox/core/views.py index 3c5319626..ecbf11e32 100644 --- a/netbox/core/views.py +++ b/netbox/core/views.py @@ -626,11 +626,7 @@ class SystemView(UserPassesTestMixin, View): } # Configuration - try: - config = ConfigRevision.objects.get(pk=cache.get('config_version')) - except ConfigRevision.DoesNotExist: - # Fall back to using the active config data if no record is found - config = get_config() + config = get_config() # Raw data export if 'export' in request.GET: From 9c532c7d896e5c3ce248ffff74c9236025d00d86 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 12 Nov 2024 14:53:57 -0500 Subject: [PATCH 4/6] Fixes #17986: Correct label for disk size when bulk editing virtual machines (#17992) * Fixes #17986: Correct label for disk size when bulk editing virtual machines * Correct label for VirtualDisk.size --- netbox/virtualization/forms/bulk_edit.py | 4 ++-- netbox/virtualization/forms/filtersets.py | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/netbox/virtualization/forms/bulk_edit.py b/netbox/virtualization/forms/bulk_edit.py index 2bd3434ac..771edb09f 100644 --- a/netbox/virtualization/forms/bulk_edit.py +++ b/netbox/virtualization/forms/bulk_edit.py @@ -171,7 +171,7 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): ) disk = forms.IntegerField( required=False, - label=_('Disk (GB)') + label=_('Disk (MB)') ) description = forms.CharField( label=_('Description'), @@ -331,7 +331,7 @@ class VirtualDiskBulkEditForm(NetBoxModelBulkEditForm): ) size = forms.IntegerField( required=False, - label=_('Size (GB)') + label=_('Size (MB)') ) description = forms.CharField( label=_('Description'), diff --git a/netbox/virtualization/forms/filtersets.py b/netbox/virtualization/forms/filtersets.py index 7c040d948..9d5ca019a 100644 --- a/netbox/virtualization/forms/filtersets.py +++ b/netbox/virtualization/forms/filtersets.py @@ -248,7 +248,7 @@ class VirtualDiskFilterForm(NetBoxModelFilterSetForm): label=_('Virtual machine') ) size = forms.IntegerField( - label=_('Size (GB)'), + label=_('Size (MB)'), required=False, min_value=1 ) From 256d69d08bf97fc723d2798acbe22e199a7291a0 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 12 Nov 2024 15:56:29 -0500 Subject: [PATCH 5/6] Update changelog --- docs/release-notes/version-4.1.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/release-notes/version-4.1.md b/docs/release-notes/version-4.1.md index 7b4e18919..b94374721 100644 --- a/docs/release-notes/version-4.1.md +++ b/docs/release-notes/version-4.1.md @@ -1,5 +1,22 @@ # NetBox v4.1 +## v4.1.7 (FUTURE) + +### Enhancements + +* [#15239](https://github.com/netbox-community/netbox/issues/15239) - Enable adding/removing individual VLANs while bulk editing device interfaces +* [#17871](https://github.com/netbox-community/netbox/issues/17871) - Enable the assignment/removal of virtualization cluster via device bulk edit + +### Bug Fixes + +* [#17901](https://github.com/netbox-community/netbox/issues/17901) - Ensure GraphiQL UI resources are served locally +* [#17963](https://github.com/netbox-community/netbox/issues/17963) - Fix selection of all listed objects during bulk edit +* [#17969](https://github.com/netbox-community/netbox/issues/17969) - Fix system info export when a config revision exists +* [#17972](https://github.com/netbox-community/netbox/issues/17972) - Force evaluation of `LOGIN_REQUIRED` when requesting static media +* [#17986](https://github.com/netbox-community/netbox/issues/17986) - Correct labels for virtual machine & virtual disk size properties + +--- + ## v4.1.6 (2024-10-31) ### Bug Fixes From 05daa16aedab1142b56d1bbfc6d524199868aa86 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 13 Nov 2024 05:02:11 +0000 Subject: [PATCH 6/6] Update source translation strings --- netbox/translations/en/LC_MESSAGES/django.po | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/netbox/translations/en/LC_MESSAGES/django.po b/netbox/translations/en/LC_MESSAGES/django.po index 01e151c84..1d35fb8b2 100644 --- a/netbox/translations/en/LC_MESSAGES/django.po +++ b/netbox/translations/en/LC_MESSAGES/django.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: PACKAGE VERSION\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2024-11-08 05:01+0000\n" +"POT-Creation-Date: 2024-11-13 05:01+0000\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -2452,11 +2452,11 @@ msgstr "" msgid "Failed to stop job {id}" msgstr "" -#: netbox/core/views.py:678 +#: netbox/core/views.py:674 msgid "Plugins catalog could not be loaded" msgstr "" -#: netbox/core/views.py:712 +#: netbox/core/views.py:708 #, python-brace-format msgid "Plugin {name} not found" msgstr "" @@ -11141,7 +11141,7 @@ msgstr "" msgid "{class_name} must implement get_children()" msgstr "" -#: netbox/netbox/views/misc.py:44 +#: netbox/netbox/views/misc.py:46 msgid "" "There was an error loading the dashboard configuration. A default dashboard " "is in use." @@ -14848,12 +14848,12 @@ msgid "Memory (MB)" msgstr "" #: netbox/virtualization/forms/bulk_edit.py:174 -msgid "Disk (GB)" +msgid "Disk (MB)" msgstr "" #: netbox/virtualization/forms/bulk_edit.py:334 #: netbox/virtualization/forms/filtersets.py:251 -msgid "Size (GB)" +msgid "Size (MB)" msgstr "" #: netbox/virtualization/forms/bulk_import.py:44