From d52a6d3b1090f408882e0875e04fb739fb492b75 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Thu, 9 Nov 2023 16:04:38 -0500 Subject: [PATCH 01/16] PRVB --- docs/release-notes/version-3.6.md | 4 ++++ netbox/netbox/settings.py | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/docs/release-notes/version-3.6.md b/docs/release-notes/version-3.6.md index 646c2019ea1..b8d3162181e 100644 --- a/docs/release-notes/version-3.6.md +++ b/docs/release-notes/version-3.6.md @@ -1,5 +1,9 @@ # NetBox v3.6 +## v3.6.6 (FUTURE) + +--- + ## v3.6.5 (2023-11-09) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index eac1c3c3777..5a5a899849e 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ # Environment setup # -VERSION = '3.6.5' +VERSION = '3.6.6-dev' # Hostname HOSTNAME = platform.node() From 40763b58bdad0892efff418ade3d98fc8cf184d6 Mon Sep 17 00:00:00 2001 From: Arthur Hanson Date: Tue, 28 Nov 2023 14:01:03 -0800 Subject: [PATCH 02/16] 14299 change webhook timestamp to isoformat (#14331) * 14299 change timestamp to isoformat * Omit redundant str() casting --------- Co-authored-by: Jeremy Stretch --- netbox/core/models/jobs.py | 2 +- netbox/extras/webhooks.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/core/models/jobs.py b/netbox/core/models/jobs.py index 61b0e64fab0..d52cbe165ca 100644 --- a/netbox/core/models/jobs.py +++ b/netbox/core/models/jobs.py @@ -229,7 +229,7 @@ def trigger_webhooks(self, event): model_name=self.object_type.model, event=event, data=self.data, - timestamp=str(timezone.now()), + timestamp=timezone.now().isoformat(), username=self.user.username, retry=get_rq_retry() ) diff --git a/netbox/extras/webhooks.py b/netbox/extras/webhooks.py index 1fc869ee8e3..a22f73c27e4 100644 --- a/netbox/extras/webhooks.py +++ b/netbox/extras/webhooks.py @@ -115,7 +115,7 @@ def flush_webhooks(queue): event=data['event'], data=data['data'], snapshots=data['snapshots'], - timestamp=str(timezone.now()), + timestamp=timezone.now().isoformat(), username=data['username'], request_id=data['request_id'], retry=get_rq_retry() From 7d413ea3c2dccb78010a4664a23ac1c2b5494a8a Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 28 Nov 2023 17:02:07 -0500 Subject: [PATCH 03/16] Fixes #14343: Set order_by accessor for asn_asdot column (#14369) --- netbox/ipam/tables/asn.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/ipam/tables/asn.py b/netbox/ipam/tables/asn.py index 6bb15523ec7..bbe38dc1a33 100644 --- a/netbox/ipam/tables/asn.py +++ b/netbox/ipam/tables/asn.py @@ -48,6 +48,7 @@ class ASNTable(TenancyColumnsMixin, NetBoxTable): asn_asdot = tables.Column( accessor=tables.A('asn_asdot'), linkify=True, + order_by=tables.A('asn'), verbose_name=_('ASDOT') ) site_count = columns.LinkedCountColumn( From 080da68b6adfd9e9d93c4ec2af92e997dc26e6c8 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 28 Nov 2023 14:46:36 -0500 Subject: [PATCH 04/16] Fixes #14349: Fix custom validation support for DataSource --- netbox/core/models/data.py | 1 + 1 file changed, 1 insertion(+) diff --git a/netbox/core/models/data.py b/netbox/core/models/data.py index 54a43c7ef9f..9e41e84461d 100644 --- a/netbox/core/models/data.py +++ b/netbox/core/models/data.py @@ -122,6 +122,7 @@ def ready_for_sync(self): ) def clean(self): + super().clean() # Ensure URL scheme matches selected type if self.type == DataSourceTypeChoices.LOCAL and self.url_scheme not in ('file', ''): From fc7d6e1387b3fcfd0490f94f249f54cea68bda04 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 28 Nov 2023 17:04:10 -0500 Subject: [PATCH 05/16] Fixes #14325: Ensure expanded numeric arrays are ordered (#14370) * Fixes #14325: Ensure expanded numeric arrays are ordered * Remove redundant casting to --- netbox/utilities/forms/utils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/utilities/forms/utils.py b/netbox/utilities/forms/utils.py index 4d737f16321..64864a6c130 100644 --- a/netbox/utilities/forms/utils.py +++ b/netbox/utilities/forms/utils.py @@ -40,7 +40,7 @@ def parse_numeric_range(string, base=10): except ValueError: raise forms.ValidationError(f'Range "{dash_range}" is invalid.') values.extend(range(begin, end)) - return list(set(values)) + return sorted(set(values)) def parse_alphanumeric_range(string): From 01ba4ce129aa89d74a41b4fbd6994d7559019f96 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 28 Nov 2023 16:58:13 -0500 Subject: [PATCH 06/16] Fixes #14242: Enable export templates for contact assignments --- netbox/tenancy/models/contacts.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/netbox/tenancy/models/contacts.py b/netbox/tenancy/models/contacts.py index e8327248d14..96ea053f7d5 100644 --- a/netbox/tenancy/models/contacts.py +++ b/netbox/tenancy/models/contacts.py @@ -5,7 +5,7 @@ from django.utils.translation import gettext_lazy as _ from netbox.models import ChangeLoggedModel, NestedGroupModel, OrganizationalModel, PrimaryModel -from netbox.models.features import TagsMixin +from netbox.models.features import ExportTemplatesMixin, TagsMixin from tenancy.choices import * __all__ = ( @@ -109,7 +109,7 @@ def get_absolute_url(self): return reverse('tenancy:contact', args=[self.pk]) -class ContactAssignment(ChangeLoggedModel, TagsMixin): +class ContactAssignment(ChangeLoggedModel, ExportTemplatesMixin, TagsMixin): content_type = models.ForeignKey( to=ContentType, on_delete=models.CASCADE From 792b353f6477ce9bb3bc2a234dd6313c9fa38402 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Tue, 28 Nov 2023 14:40:54 -0500 Subject: [PATCH 07/16] Fixes #14363: Fix bulk editing of interfaces assigned to VM with no cluster --- netbox/virtualization/forms/bulk_edit.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/netbox/virtualization/forms/bulk_edit.py b/netbox/virtualization/forms/bulk_edit.py index a33ffac5376..e5ab24f2ee0 100644 --- a/netbox/virtualization/forms/bulk_edit.py +++ b/netbox/virtualization/forms/bulk_edit.py @@ -294,9 +294,10 @@ def __init__(self, *args, **kwargs): # Check interface sites. First interface should set site, further interfaces will either continue the # loop or reset back to no site and break the loop. for interface in interfaces: + vm_site = interface.virtual_machine.site or interface.virtual_machine.cluster.site if site is None: - site = interface.virtual_machine.cluster.site - elif interface.virtual_machine.cluster.site is not site: + site = vm_site + elif vm_site is not site: site = None break From c43c63a817444703f068cb6b05fd4b5c5a702f5e Mon Sep 17 00:00:00 2001 From: Josef Johansson Date: Wed, 29 Nov 2023 08:31:33 +0100 Subject: [PATCH 08/16] 14346 fix missing function call convert In PR #13958 (commit 8224644) _get_report was modified to do the call on the variable without changing the call later on. This commit fixes that and removes the call on the variable. Signed-off-by: Josef Johansson --- netbox/extras/api/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/extras/api/views.py b/netbox/extras/api/views.py index f518275e0ed..830982e7455 100644 --- a/netbox/extras/api/views.py +++ b/netbox/extras/api/views.py @@ -283,7 +283,7 @@ def run(self, request, pk): # Retrieve and run the Report. This will create a new Job. module, report_cls = self._get_report(pk) - report = report_cls() + report = report_cls input_serializer = serializers.ReportInputSerializer( data=request.data, context={'report': report} From 3a3d43911cd45e1b9ed09a39f8e172f987ed36f8 Mon Sep 17 00:00:00 2001 From: Vincent Simonin Date: Wed, 29 Nov 2023 21:59:54 +0100 Subject: [PATCH 09/16] Fixed password was not hashed on REST API update (#14340) * Fixed password was not hashed on REST API update * When we updated a user password with a REST API call the password was stored in clear in plain text in the database. * Following code review * Move test on UserTest class * Call `super().update()` in overriding `update` method * Return directly the result of `super().update()` --- netbox/users/api/serializers.py | 10 ++++++++++ netbox/users/tests/test_api.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 42 insertions(+) diff --git a/netbox/users/api/serializers.py b/netbox/users/api/serializers.py index 75ab877cf88..c9775e39a5e 100644 --- a/netbox/users/api/serializers.py +++ b/netbox/users/api/serializers.py @@ -52,6 +52,16 @@ def create(self, validated_data): return user + def update(self, instance, validated_data): + """ + Ensure proper updated password hash generation. + """ + password = validated_data.pop('password', None) + if password is not None: + instance.set_password(password) + + return super().update(instance, validated_data) + @extend_schema_field(OpenApiTypes.STR) def get_display(self, obj): if full_name := obj.get_full_name(): diff --git a/netbox/users/tests/test_api.py b/netbox/users/tests/test_api.py index 0011424107b..090ccc263d4 100644 --- a/netbox/users/tests/test_api.py +++ b/netbox/users/tests/test_api.py @@ -54,6 +54,38 @@ def setUpTestData(cls): ) User.objects.bulk_create(users) + def test_that_password_is_changed(self): + """ + Test that password is changed + """ + + obj_perm = ObjectPermission( + name='Test permission', + actions=['change'] + ) + obj_perm.save() + obj_perm.users.add(self.user) + obj_perm.object_types.add(ContentType.objects.get_for_model(self.model)) + + user_credentials = { + 'username': 'user1', + 'password': 'abc123', + } + user = User.objects.create_user(**user_credentials) + + data = { + 'password': 'newpassword' + } + url = reverse('users-api:user-detail', kwargs={'pk': user.id}) + + response = self.client.patch(url, data, format='json', **self.header) + + self.assertEqual(response.status_code, 200) + + updated_user = User.objects.get(id=user.id) + + self.assertTrue(updated_user.check_password(data['password'])) + class GroupTest(APIViewTestCases.APIViewTestCase): model = Group From ff021a8e4ece4655590e5555c030ed0220543f32 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Thu, 30 Nov 2023 02:50:59 +0530 Subject: [PATCH 10/16] Adds region hierarchy in templates (#14213) * initial work to render hierarchical region #13735 * adds site display #13735 * cleanup #13735 * adds display region tag #13735 * refactored region hierarchy #13735 * refactored region hierarchy #13735 * renamed display_region to nested_tree #13735 * Make render_tree suitable for generic use * Remove errant item from __all__ --------- Co-authored-by: Jeremy Stretch --- netbox/templates/dcim/device.html | 23 ++----------- netbox/templates/dcim/rack.html | 23 +++++-------- netbox/templates/dcim/rackreservation.html | 38 +++++++++++----------- netbox/templates/dcim/site.html | 19 ++--------- netbox/templates/ipam/prefix.html | 20 ++++++------ netbox/templates/ipam/vlan.html | 20 ++++++------ netbox/utilities/templatetags/mptt.py | 20 ++++++++++++ 7 files changed, 73 insertions(+), 90 deletions(-) create mode 100644 netbox/utilities/templatetags/mptt.py diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index 5fa6a3314a3..39e78c81b7f 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -5,6 +5,7 @@ {% load helpers %} {% load plugins %} {% load i18n %} +{% load mptt %} {% block content %}
@@ -15,16 +16,7 @@
{% trans "Device" %}
- + @@ -32,16 +24,7 @@
{% trans "Device" %}
- + diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index 671c7ab2eb2..857061d00b9 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -4,6 +4,7 @@ {% load static %} {% load plugins %} {% load i18n %} +{% load mptt %} {% block content %}
@@ -15,26 +16,18 @@
{% trans "Region" %} - {% if object.site.region %} - {% for region in object.site.region.get_ancestors %} - {{ region|linkify }} / - {% endfor %} - {{ object.site.region|linkify }} - {% else %} - {{ ''|placeholder }} - {% endif %} - {% nested_tree object.site.region %}
{% trans "Site" %}
{% trans "Location" %} - {% if object.location %} - {% for location in object.location.get_ancestors %} - {{ location|linkify }} / - {% endfor %} - {{ object.location|linkify }} - {% else %} - {{ ''|placeholder }} - {% endif %} - {% nested_tree object.location %}
{% trans "Rack" %}
- + + + + + - + diff --git a/netbox/templates/dcim/rackreservation.html b/netbox/templates/dcim/rackreservation.html index 8edb75f324f..3d145145fd1 100644 --- a/netbox/templates/dcim/rackreservation.html +++ b/netbox/templates/dcim/rackreservation.html @@ -4,6 +4,7 @@ {% load static %} {% load plugins %} {% load i18n %} +{% load mptt %} {% block breadcrumbs %} {{ block.super }} @@ -20,25 +21,24 @@
{% trans "Site" %}{% trans "Region" %} - {% if object.site.region %} - {{ object.site.region|linkify }} / - {% endif %} - {{ object.site|linkify }} + {% nested_tree object.site.region %}
{% trans "Site" %}{{ object.site|linkify }}
{% trans "Location" %} - {% if object.location %} - {% for location in object.location.get_ancestors %} - {{ location|linkify }} / - {% endfor %} - {{ object.location|linkify }} - {% else %} - {{ ''|placeholder }} - {% endif %} - {% nested_tree object.location %}
{% trans "Facility ID" %}
- {% with rack=object.rack %} - - - - - - - - - - - - - {% endwith %} + + + + + + + + + + + + + + + +
{% trans "Site" %} - {% if rack.site.region %} - {{ rack.site.region|linkify }} / - {% endif %} - {{ rack.site|linkify }} -
{% trans "Location" %}{{ rack.location|linkify|placeholder }}
{% trans "Rack" %}{{ rack|linkify }}
{% trans "Region" %} + {% nested_tree object.rack.site.region %} +
{% trans "Site" %}{{ object.rack.site|linkify }}
{% trans "Location" %}{{ object.rack.location|linkify|placeholder }}
{% trans "Rack" %}{{ object.rack|linkify }}
diff --git a/netbox/templates/dcim/site.html b/netbox/templates/dcim/site.html index 7f43a0ab33a..16a87018279 100644 --- a/netbox/templates/dcim/site.html +++ b/netbox/templates/dcim/site.html @@ -3,6 +3,7 @@ {% load plugins %} {% load tz %} {% load i18n %} +{% load mptt %} {% block breadcrumbs %} {{ block.super }} @@ -29,27 +30,13 @@
{% trans "Site" %}
{% trans "Region" %} - {% if object.region %} - {% for region in object.region.get_ancestors %} - {{ region|linkify }} / - {% endfor %} - {{ object.region|linkify }} - {% else %} - {{ ''|placeholder }} - {% endif %} + {% nested_tree object.region %} {% trans "Group" %} - {% if object.group %} - {% for group in object.group.get_ancestors %} - {{ group|linkify }} / - {% endfor %} - {{ object.group|linkify }} - {% else %} - {{ ''|placeholder }} - {% endif %} + {% nested_tree object.group %} diff --git a/netbox/templates/ipam/prefix.html b/netbox/templates/ipam/prefix.html index 71b240cedef..ec6138d69b4 100644 --- a/netbox/templates/ipam/prefix.html +++ b/netbox/templates/ipam/prefix.html @@ -3,6 +3,7 @@ {% load helpers %} {% load plugins %} {% load i18n %} +{% load mptt %} {% block content %}
@@ -44,18 +45,17 @@
{% trans "Prefix" %}
{% endif %} + {% if object.site.region %} + + {% trans "Region" %} + + {% nested_tree object.site.region %} + + + {% endif %} {% trans "Site" %} - - {% if object.site %} - {% if object.site.region %} - {{ object.site.region|linkify }} / - {% endif %} - {{ object.site|linkify }} - {% else %} - {{ ''|placeholder }} - {% endif %} - + {{ object.site|linkify|placeholder }} {% trans "VLAN" %} diff --git a/netbox/templates/ipam/vlan.html b/netbox/templates/ipam/vlan.html index 4ca045d4b4d..a5ed9d643fb 100644 --- a/netbox/templates/ipam/vlan.html +++ b/netbox/templates/ipam/vlan.html @@ -3,6 +3,7 @@ {% load render_table from django_tables2 %} {% load plugins %} {% load i18n %} +{% load mptt %} {% block content %}
@@ -13,18 +14,17 @@
+ {% if object.site.region %} + + + + + {% endif %} - + diff --git a/netbox/utilities/templatetags/mptt.py b/netbox/utilities/templatetags/mptt.py new file mode 100644 index 00000000000..783c2654f6b --- /dev/null +++ b/netbox/utilities/templatetags/mptt.py @@ -0,0 +1,20 @@ +from django import template +from django.utils.safestring import mark_safe + +register = template.Library() + + +@register.simple_tag() +def nested_tree(obj): + """ + Renders the entire hierarchy of a recursively-nested object (such as Region or SiteGroup). + """ + if not obj: + return mark_safe('—') + + nodes = obj.get_ancestors(include_self=True) + return mark_safe( + ' / '.join( + f'{node}' for node in nodes + ) + ) From 290aae592dc670857b00de082cec9677e203ff68 Mon Sep 17 00:00:00 2001 From: Abhimanyu Saharan Date: Thu, 30 Nov 2023 02:55:16 +0530 Subject: [PATCH 11/16] Raises validation error if file path and root are not unique (#14232) * raises validation error if file path and root are not unique #14187 * review changes #14187 --- netbox/core/models/files.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/netbox/core/models/files.py b/netbox/core/models/files.py index 38d82463eca..a9e0e7f0069 100644 --- a/netbox/core/models/files.py +++ b/netbox/core/models/files.py @@ -2,6 +2,7 @@ import os from django.conf import settings +from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse from django.utils.translation import gettext as _ @@ -84,6 +85,14 @@ def sync_data(self): self.file_path = os.path.basename(self.data_path) self.data_file.write_to_disk(self.full_path, overwrite=True) + def clean(self): + super().clean() + + # Ensure that the file root and path make a unique pair + if self._meta.model.objects.filter(file_root=self.file_root, file_path=self.file_path).exclude(pk=self.pk).exists(): + raise ValidationError( + f"A {self._meta.verbose_name.lower()} with this file path already exists ({self.file_root}/{self.file_path}).") + def delete(self, *args, **kwargs): # Delete file from disk try: From 6dddb6c9d22f751dc50b4b0267a768236bd275b1 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 29 Nov 2023 16:37:08 -0500 Subject: [PATCH 12/16] Fixes #14199: Fix jobs count for reports with a custom name --- netbox/extras/views.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/netbox/extras/views.py b/netbox/extras/views.py index 55b73d29d3a..2c59c52350b 100644 --- a/netbox/extras/views.py +++ b/netbox/extras/views.py @@ -1073,7 +1073,7 @@ def get(self, request, module, name): jobs = Job.objects.filter( object_type=object_type, object_id=module.pk, - name=report.name + name=report.class_name ) jobs_table = JobTable( From 82591ad8a1ed590721f96a5778d21e4f78d9daa7 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 29 Nov 2023 16:47:26 -0500 Subject: [PATCH 13/16] Fixes #14056: Record a pre-change snapshot when bulk editing objects via CSV --- netbox/netbox/views/generic/bulk_views.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 676e3f5afe3..c5a08c80a2d 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -394,6 +394,10 @@ def create_and_update_objects(self, form, request): form.add_error('data', f"Row {i}: Object with ID {object_id} does not exist") raise ValidationError('') + # Take a snapshot for change logging + if instance.pk and hasattr(instance, 'snapshot'): + instance.snapshot() + # Instantiate the model form for the object model_form_kwargs = { 'data': record, From ac3fc25dfdc09a9c6fb3de76bc2cf3993e45626d Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 29 Nov 2023 16:55:10 -0500 Subject: [PATCH 14/16] Fixes #14239: Fix CustomFieldChoiceSet search filter --- netbox/extras/filtersets.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/netbox/extras/filtersets.py b/netbox/extras/filtersets.py index fec06726357..b33e7048843 100644 --- a/netbox/extras/filtersets.py +++ b/netbox/extras/filtersets.py @@ -122,8 +122,7 @@ def search(self, queryset, name, value): return queryset return queryset.filter( Q(name__icontains=value) | - Q(description__icontains=value) | - Q(extra_choices__contains=value) + Q(description__icontains=value) ) def filter_by_choice(self, queryset, name, value): From 0a8eb7fcbe7beb20738aeacc5c0d3eac288cefcf Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 29 Nov 2023 17:25:10 -0500 Subject: [PATCH 15/16] Update changelog --- docs/release-notes/version-3.6.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/docs/release-notes/version-3.6.md b/docs/release-notes/version-3.6.md index b8d3162181e..ddf571965a7 100644 --- a/docs/release-notes/version-3.6.md +++ b/docs/release-notes/version-3.6.md @@ -2,6 +2,25 @@ ## v3.6.6 (FUTURE) +### Enhancements + +* [#13735](https://github.com/netbox-community/netbox/issues/13735) - Show complete region hierarchy in UI for all relevant objects + +### Bug Fixes + +* [#14056](https://github.com/netbox-community/netbox/issues/14056) - Record a pre-change snapshot when bulk editing objects via CSV +* [#14187](https://github.com/netbox-community/netbox/issues/14187) - Raise a validation error when attempting to create a duplicate script or report +* [#14199](https://github.com/netbox-community/netbox/issues/14199) - Fix jobs list for reports with a custom name +* [#14239](https://github.com/netbox-community/netbox/issues/14239) - Fix CustomFieldChoiceSet search filter +* [#14242](https://github.com/netbox-community/netbox/issues/14242) - Enable export templates for contact assignments +* [#14299](https://github.com/netbox-community/netbox/issues/14299) - Webhook timestamps should be in proper ISO 8601 format +* [#14325](https://github.com/netbox-community/netbox/issues/14325) - Fix numeric ordering of service ports +* [#14339](https://github.com/netbox-community/netbox/issues/14339) - Correctly hash local user password when set via REST API +* [#14343](https://github.com/netbox-community/netbox/issues/14343) - Fix ordering ASN table by ASDOT column +* [#14346](https://github.com/netbox-community/netbox/issues/14346) - Fix running reports via REST API +* [#14349](https://github.com/netbox-community/netbox/issues/14349) - Fix custom validation support for remote data sources +* [#14363](https://github.com/netbox-community/netbox/issues/14363) - Fix bulk editing of interfaces assigned to VM with no cluster + --- ## v3.6.5 (2023-11-09) From 04fd45581d1213af0da12e7ffe74b88b5f5866b0 Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Wed, 29 Nov 2023 19:16:30 -0500 Subject: [PATCH 16/16] Release v3.6.6 --- .github/ISSUE_TEMPLATE/bug_report.yaml | 2 +- .github/ISSUE_TEMPLATE/feature_request.yaml | 2 +- docs/release-notes/version-3.6.md | 2 +- netbox/netbox/settings.py | 2 +- requirements.txt | 18 +++++++++--------- 5 files changed, 13 insertions(+), 13 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yaml b/.github/ISSUE_TEMPLATE/bug_report.yaml index 48c14a2daf0..5e936c5ec16 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yaml +++ b/.github/ISSUE_TEMPLATE/bug_report.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.6.5 + placeholder: v3.6.6 validations: required: true - type: dropdown diff --git a/.github/ISSUE_TEMPLATE/feature_request.yaml b/.github/ISSUE_TEMPLATE/feature_request.yaml index 0525659aee9..34103e61615 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yaml +++ b/.github/ISSUE_TEMPLATE/feature_request.yaml @@ -14,7 +14,7 @@ body: attributes: label: NetBox version description: What version of NetBox are you currently running? - placeholder: v3.6.5 + placeholder: v3.6.6 validations: required: true - type: dropdown diff --git a/docs/release-notes/version-3.6.md b/docs/release-notes/version-3.6.md index ddf571965a7..6f81e45261c 100644 --- a/docs/release-notes/version-3.6.md +++ b/docs/release-notes/version-3.6.md @@ -1,6 +1,6 @@ # NetBox v3.6 -## v3.6.6 (FUTURE) +## v3.6.6 (2023-11-29) ### Enhancements diff --git a/netbox/netbox/settings.py b/netbox/netbox/settings.py index 5a5a899849e..9072dd36466 100644 --- a/netbox/netbox/settings.py +++ b/netbox/netbox/settings.py @@ -25,7 +25,7 @@ # Environment setup # -VERSION = '3.6.6-dev' +VERSION = '3.6.6' # Hostname HOSTNAME = platform.node() diff --git a/requirements.txt b/requirements.txt index 16bafe62fe3..b99f16e76be 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,18 +1,18 @@ bleach==6.1.0 Django==4.2.7 -django-cors-headers==4.3.0 +django-cors-headers==4.3.1 django-debug-toolbar==4.2.0 -django-filter==23.3 +django-filter==23.4 django-graphiql-debug-toolbar==0.2.0 django-mptt==0.14.0 django-pglocks==1.0.4 django-prometheus==2.3.1 django-redis==5.4.0 django-rich==1.8.0 -django-rq==2.8.1 +django-rq==2.9.0 django-tables2==2.6.0 django-taggit==4.0.0 -django-timezone-field==6.0.1 +django-timezone-field==6.1.0 djangorestframework==3.14.0 drf-spectacular==0.26.5 drf-spectacular-sidecar==2023.10.1 @@ -21,16 +21,16 @@ graphene-django==3.0.0 gunicorn==21.2.0 Jinja2==3.1.2 Markdown==3.3.7 -mkdocs-material==9.4.8 -mkdocstrings[python-legacy]==0.23.0 +mkdocs-material==9.4.14 +mkdocstrings[python-legacy]==0.24.0 netaddr==0.9.0 Pillow==10.1.0 -psycopg[binary,pool]==3.1.12 +psycopg[binary,pool]==3.1.13 PyYAML==6.0.1 requests==2.31.0 -sentry-sdk==1.34.0 +sentry-sdk==1.38.0 social-auth-app-django==5.4.0 -social-auth-core[openidconnect]==4.5.0 +social-auth-core[openidconnect]==4.5.1 svgwrite==1.4.3 tablib==3.5.0 tzdata==2023.3
{% trans "Region" %} + {% nested_tree object.site.region %} +
{% trans "Site" %} - {% if object.site %} - {% if object.site.region %} - {{ object.site.region|linkify }} / - {% endif %} - {{ object.site|linkify }} - {% else %} - {{ ''|placeholder }} - {% endif %} - {{ object.site|linkify|placeholder }}
{% trans "Group" %}