Merge branch 'develop' into 11432-device-field

This commit is contained in:
Arthur 2023-04-10 10:21:04 -07:00
commit 418fa2f6e9
9 changed files with 69 additions and 23 deletions

View File

@ -18,4 +18,4 @@ interface.
Default: False
This parameter serves as a safeguard to prevent some potentially dangerous behavior, such as generating new database schema migrations. Set this to `True` **only** if you are actively developing the NetBox code base.
This parameter serves as a safeguard to prevent some potentially dangerous behavior, such as generating new database schema migrations. Additionally, enabling this setting disables the debug warning banner in the UI. Set this to `True` **only** if you are actively developing the NetBox code base.

View File

@ -132,7 +132,7 @@ Once you have created a report, it will appear in the reports list. Initially, r
!!! note
To run a report, a user must be assigned the `extras.run_report` permission. This is achieved by assigning the user (or group) a permission on the Report object and specifying the `run` action in the admin UI as shown below.
![Adding the run action to a permission](/media/admin_ui_run_permission.png)
![Adding the run action to a permission](../media/admin_ui_run_permission.png)
### Via the Web UI

View File

@ -4,11 +4,13 @@
### Enhancements
* [#11453](https://github.com/netbox-community/netbox/issues/11453) - Display a warning banner when `DEBUG` is enabled
* [#12007](https://github.com/netbox-community/netbox/issues/12007) - Enable filtering of VM Interfaces by assigned VLAN
* [#12095](https://github.com/netbox-community/netbox/issues/12095) - Specify UTF-8 encoding for default export template MIME type
### Bug Fixes
* [#10615](https://github.com/netbox-community/netbox/issues/10615) - Fix filtering of cable terminations by A/B end
* [#11746](https://github.com/netbox-community/netbox/issues/11746) - Fix cleanup of object data when deleting a custom field
* [#12011](https://github.com/netbox-community/netbox/issues/12011) - Fix KeyError exception when attempting to add module bays in bulk
* [#12074](https://github.com/netbox-community/netbox/issues/12074) - Fix the automatic assignment of racks to devices via the REST API

View File

@ -1354,6 +1354,24 @@ class CommonInterfaceFilterSet(django_filters.FilterSet):
label=_('L2VPN'),
)
def filter_vlan_id(self, queryset, name, value):
value = value.strip()
if not value:
return queryset
return queryset.filter(
Q(untagged_vlan_id=value) |
Q(tagged_vlans=value)
)
def filter_vlan(self, queryset, name, value):
value = value.strip()
if not value:
return queryset
return queryset.filter(
Q(untagged_vlan_id__vid=value) |
Q(tagged_vlans__vid=value)
)
class InterfaceFilterSet(
ModularDeviceComponentFilterSet,
@ -1461,24 +1479,6 @@ class InterfaceFilterSet(
except Device.DoesNotExist:
return queryset.none()
def filter_vlan_id(self, queryset, name, value):
value = value.strip()
if not value:
return queryset
return queryset.filter(
Q(untagged_vlan_id=value) |
Q(tagged_vlans=value)
)
def filter_vlan(self, queryset, name, value):
value = value.strip()
if not value:
return queryset
return queryset.filter(
Q(untagged_vlan_id__vid=value) |
Q(tagged_vlans__vid=value)
)
def filter_kind(self, queryset, name, value):
value = value.strip().lower()
return {
@ -1667,12 +1667,14 @@ class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
field_name='terminations__termination_type'
)
termination_a_id = MultiValueNumberFilter(
method='filter_by_cable_end_a',
field_name='terminations__termination_id'
)
termination_b_type = ContentTypeFilter(
field_name='terminations__termination_type'
)
termination_b_id = MultiValueNumberFilter(
method='filter_by_cable_end_b',
field_name='terminations__termination_id'
)
type = django_filters.MultipleChoiceFilter(
@ -1730,6 +1732,18 @@ class CableFilterSet(TenancyFilterSet, NetBoxModelFilterSet):
# Supported objects: device, rack, location, site
return queryset.filter(**{f'terminations___{name}__in': value}).distinct()
def filter_by_cable_end(self, queryset, name, value, side):
# Filter by termination id and cable_end type
return queryset.filter(**{f'{name}__in': value, 'terminations__cable_end': side}).distinct()
def filter_by_cable_end_a(self, queryset, name, value):
# Filter by termination id and cable_end type
return self.filter_by_cable_end(queryset, name, value, CableEndChoices.SIDE_A)
def filter_by_cable_end_b(self, queryset, name, value):
# Filter by termination id and cable_end type
return self.filter_by_cable_end(queryset, name, value, CableEndChoices.SIDE_B)
class CableTerminationFilterSet(BaseFilterSet):
termination_type = ContentTypeFilter()

View File

@ -97,6 +97,12 @@ class CustomFieldSerializer(ValidatedModelSerializer):
'validation_minimum', 'validation_maximum', 'validation_regex', 'choices', 'created', 'last_updated',
]
def validate_type(self, value):
if self.instance and self.instance.type != value:
raise serializers.ValidationError('Changing the type of custom fields is not supported.')
return value
def get_data_type(self, obj):
types = CustomFieldTypeChoices
if obj.type == types.TYPE_INTEGER:

View File

@ -1,6 +1,7 @@
import json
from django import forms
from django.db.models import Q
from django.contrib.contenttypes.models import ContentType
from django.utils.translation import gettext as _
@ -37,7 +38,7 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm):
object_type = ContentTypeChoiceField(
queryset=ContentType.objects.all(),
# TODO: Come up with a canonical way to register suitable models
limit_choices_to=FeatureQuery('webhooks'),
limit_choices_to=FeatureQuery('webhooks').get_query() | Q(app_label='auth', model__in=['user', 'group']),
required=False,
help_text=_("Type of the related object (for object/multi-object fields only)")
)
@ -64,6 +65,13 @@ class CustomFieldForm(BootstrapMixin, forms.ModelForm):
'ui_visibility': StaticSelect(),
}
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Disable changing the type of a CustomField as it almost universally causes errors if custom field data is already present.
if self.instance.pk:
self.fields['type'].disabled = True
class CustomLinkForm(BootstrapMixin, forms.ModelForm):
content_types = ContentTypeMultipleChoiceField(

View File

@ -102,6 +102,11 @@ class CustomFieldTest(APIViewTestCases.APIViewTestCase):
bulk_update_data = {
'description': 'New description',
}
update_data = {
'content_types': ['dcim.device'],
'name': 'New_Name',
'description': 'New description',
}
@classmethod
def setUpTestData(cls):

View File

@ -70,10 +70,17 @@ Blocks:
</div>
{% endif %}
{% if settings.DEBUG and not settings.DEVELOPER %}
<div class="alert alert-warning text-center mx-3" role="alert">
<strong><i class="mdi mdi-alert"></i> Debug mode is enabled.</strong>
Performance may be limited. Debugging should never be enabled on a production system.
</div>
{% endif %}
{% if config.MAINTENANCE_MODE %}
<div class="alert alert-warning text-center mx-3" role="alert">
<h4><i class="mdi mdi-alert"></i> Maintenance Mode</h4>
<span>NetBox is currently in maintenance mode. Functionality may be limited.</span>
<h5><i class="mdi mdi-alert"></i> Maintenance Mode</h5>
NetBox is currently in maintenance mode. Functionality may be limited.
</div>
{% endif %}

View File

@ -48,6 +48,10 @@ def get_viewname(model, action=None, rest_api=False):
if is_plugin:
viewname = f'plugins-api:{app_label}-api:{model_name}'
else:
# Alter the app_label for group and user model_name to point to users app
if app_label == 'auth' and model_name in ['group', 'user']:
app_label = 'users'
viewname = f'{app_label}-api:{model_name}'
# Append the action, if any
if action: