Merge pull request #13142 from netbox-community/develop

Release v3.5.6
This commit is contained in:
Jeremy Stretch 2023-07-10 16:53:46 -04:00 committed by GitHub
commit ec0dbe33d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 40 additions and 30 deletions

View File

@ -14,7 +14,7 @@ body:
attributes: attributes:
label: NetBox version label: NetBox version
description: What version of NetBox are you currently running? description: What version of NetBox are you currently running?
placeholder: v3.5.5 placeholder: v3.5.6
validations: validations:
required: true required: true
- type: dropdown - type: dropdown

View File

@ -14,7 +14,7 @@ body:
attributes: attributes:
label: NetBox version label: NetBox version
description: What version of NetBox are you currently running? description: What version of NetBox are you currently running?
placeholder: v3.5.5 placeholder: v3.5.6
validations: validations:
required: true required: true
- type: dropdown - type: dropdown

View File

@ -1,5 +1,16 @@
# NetBox v3.5 # NetBox v3.5
## v3.5.6 (2023-07-10)
### Bug Fixes
* [#13061](https://github.com/netbox-community/netbox/issues/13061) - Fix display of last result for scripts & reports with a custom name defined
* [#13096](https://github.com/netbox-community/netbox/issues/13096) - Hide scheduling fields for all scripts with scheduling disabled
* [#13105](https://github.com/netbox-community/netbox/issues/13105) - Fix exception when attempting to allocate next available IP address from prefix marked as utilized
* [#13116](https://github.com/netbox-community/netbox/issues/13116) - Catch ProgrammingError exception when starting NetBox without pre-populated content types
---
## v3.5.5 (2023-07-06) ## v3.5.5 (2023-07-06)
### Enhancements ### Enhancements

View File

@ -56,10 +56,3 @@ class ScriptForm(BootstrapMixin, forms.Form):
self.cleaned_data['_schedule_at'] = local_now() self.cleaned_data['_schedule_at'] = local_now()
return self.cleaned_data return self.cleaned_data
@property
def requires_input(self):
"""
A boolean indicating whether the form requires user input (ignore the built-in fields).
"""
return bool(len(self.fields) > 3)

View File

@ -2,6 +2,7 @@ from django.apps import apps
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.aggregates import JSONBAgg from django.contrib.postgres.aggregates import JSONBAgg
from django.db.models import OuterRef, Subquery, Q from django.db.models import OuterRef, Subquery, Q
from django.db.utils import ProgrammingError
from extras.models.tags import TaggedItem from extras.models.tags import TaggedItem
from utilities.query_functions import EmptyGroupByJSONBAgg from utilities.query_functions import EmptyGroupByJSONBAgg
@ -160,7 +161,13 @@ class ObjectChangeQuerySet(RestrictedQuerySet):
def valid_models(self): def valid_models(self):
# Exclude any change records which refer to an instance of a model that's no longer installed. This # Exclude any change records which refer to an instance of a model that's no longer installed. This
# can happen when a plugin is removed but its data remains in the database, for example. # can happen when a plugin is removed but its data remains in the database, for example.
try:
content_types = ContentType.objects.get_for_models(*apps.get_models()).values()
except ProgrammingError:
# Handle the case where the database schema has not yet been initialized
content_types = ContentType.objects.none()
content_type_ids = set( content_type_ids = set(
ct.pk for ct in ContentType.objects.get_for_models(*apps.get_models()).values() ct.pk for ct in content_types
) )
return self.filter(changed_object_type_id__in=content_type_ids) return self.filter(changed_object_type_id__in=content_type_ids)

View File

@ -366,7 +366,7 @@ class BaseScript:
if self.fieldsets: if self.fieldsets:
fieldsets.extend(self.fieldsets) fieldsets.extend(self.fieldsets)
else: else:
fields = (name for name, _ in self._get_vars().items()) fields = list(name for name, _ in self._get_vars().items())
fieldsets.append(('Script Data', fields)) fieldsets.append(('Script Data', fields))
# Append the default fieldset if defined in the Meta class # Append the default fieldset if defined in the Meta class
@ -390,6 +390,11 @@ class BaseScript:
# Set initial "commit" checkbox state based on the script's Meta parameter # Set initial "commit" checkbox state based on the script's Meta parameter
form.fields['_commit'].initial = self.commit_default form.fields['_commit'].initial = self.commit_default
# Hide fields if scheduling has been disabled
if not self.scheduling_enabled:
form.fields['_schedule_at'].widget = forms.HiddenInput()
form.fields['_interval'].widget = forms.HiddenInput()
return form return form
# Logging # Logging

View File

@ -406,7 +406,7 @@ class Prefix(GetAvailablePrefixesMixin, PrimaryModel):
Return all available IPs within this prefix as an IPSet. Return all available IPs within this prefix as an IPSet.
""" """
if self.mark_utilized: if self.mark_utilized:
return list() return netaddr.IPSet()
prefix = netaddr.IPSet(self.prefix) prefix = netaddr.IPSet(self.prefix)
child_ips = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()]) child_ips = netaddr.IPSet([ip.address.ip for ip in self.get_child_ips()])

View File

@ -25,7 +25,7 @@ from netbox.constants import RQ_QUEUE_DEFAULT, RQ_QUEUE_HIGH, RQ_QUEUE_LOW
# Environment setup # Environment setup
# #
VERSION = '3.5.5' VERSION = '3.5.6'
# Hostname # Hostname
HOSTNAME = platform.node() HOSTNAME = platform.node()

View File

@ -52,7 +52,7 @@
<tbody> <tbody>
{% with jobs=module.get_latest_jobs %} {% with jobs=module.get_latest_jobs %}
{% for report_name, report in module.reports.items %} {% for report_name, report in module.reports.items %}
{% with last_job=jobs|get_key:report.name %} {% with last_job=jobs|get_key:report.class_name %}
<tr> <tr>
<td> <td>
<a href="{% url 'extras:report' module=module.python_name name=report.class_name %}" id="{{ report.module }}.{{ report.class_name }}">{{ report.name }}</a> <a href="{% url 'extras:report' module=module.python_name name=report.class_name %}" id="{{ report.module }}.{{ report.class_name }}">{{ report.name }}</a>

View File

@ -15,9 +15,9 @@
<form action="" method="post" enctype="multipart/form-data" class="form form-object-edit"> <form action="" method="post" enctype="multipart/form-data" class="form form-object-edit">
{% csrf_token %} {% csrf_token %}
<div class="field-group my-4"> <div class="field-group my-4">
{% if form.requires_input %} {# Render grouped fields according to declared fieldsets #}
{# Render grouped fields according to declared fieldsets #} {% for group, fields in script.get_fieldsets %}
{% for group, fields in script.get_fieldsets %} {% if fields %}
<div class="field-group mb-5"> <div class="field-group mb-5">
<div class="row mb-2"> <div class="row mb-2">
<h5 class="offset-sm-3">{{ group }}</h5> <h5 class="offset-sm-3">{{ group }}</h5>
@ -28,14 +28,8 @@
{% endwith %} {% endwith %}
{% endfor %} {% endfor %}
</div> </div>
{% endfor %} {% endif %}
{% else %} {% endfor %}
<div class="alert alert-info">
<i class="mdi mdi-information"></i>
This script does not require any input to run.
</div>
{% render_form form %}
{% endif %}
</div> </div>
<div class="float-end"> <div class="float-end">
<a href="{% url 'extras:script_list' %}" class="btn btn-outline-danger">Cancel</a> <a href="{% url 'extras:script_list' %}" class="btn btn-outline-danger">Cancel</a>

View File

@ -61,7 +61,7 @@
<td> <td>
{{ script_class.Meta.description|markdown|placeholder }} {{ script_class.Meta.description|markdown|placeholder }}
</td> </td>
{% with last_result=jobs|get_key:script_class.name %} {% with last_result=jobs|get_key:script_class.class_name %}
{% if last_result %} {% if last_result %}
<td> <td>
<a href="{% url 'extras:script_result' job_pk=last_result.pk %}">{{ last_result.created|annotated_date }}</a> <a href="{% url 'extras:script_result' job_pk=last_result.pk %}">{{ last_result.created|annotated_date }}</a>

View File

@ -1,7 +1,7 @@
bleach==6.0.0 bleach==6.0.0
boto3==1.27.1 boto3==1.28.1
Django==4.1.10 Django==4.1.10
django-cors-headers==4.1.0 django-cors-headers==4.2.0
django-debug-toolbar==4.1.0 django-debug-toolbar==4.1.0
django-filter==23.2 django-filter==23.2
django-graphiql-debug-toolbar==0.2.0 django-graphiql-debug-toolbar==0.2.0
@ -9,7 +9,7 @@ django-mptt==0.14
django-pglocks==1.0.4 django-pglocks==1.0.4
django-prometheus==2.3.1 django-prometheus==2.3.1
django-redis==5.3.0 django-redis==5.3.0
django-rich==1.6.0 django-rich==1.7.0
django-rq==2.8.1 django-rq==2.8.1
django-tables2==2.6.0 django-tables2==2.6.0
django-taggit==4.0.0 django-taggit==4.0.0
@ -29,7 +29,7 @@ netaddr==0.8.0
Pillow==10.0.0 Pillow==10.0.0
psycopg2-binary==2.9.6 psycopg2-binary==2.9.6
PyYAML==6.0 PyYAML==6.0
sentry-sdk==1.27.1 sentry-sdk==1.28.0
social-auth-app-django==5.2.0 social-auth-app-django==5.2.0
social-auth-core[openidconnect]==4.4.2 social-auth-core[openidconnect]==4.4.2
svgwrite==1.4.3 svgwrite==1.4.3