From 7e1d558428a389f13958cb51b83d3205febadcf1 Mon Sep 17 00:00:00 2001 From: Jason Novinger Date: Wed, 14 May 2025 09:36:35 -0500 Subject: [PATCH] Fixes #19415: Increased Circuit/WirelessLink absolute distance upper limit Also adds form validation that provides a useful message to the user rather than a 500 error with potentially little information. --- netbox/circuits/forms/model_forms.py | 3 ++- netbox/netbox/models/mixins.py | 4 ++-- netbox/utilities/forms/mixins.py | 34 ++++++++++++++++++++++++++++ netbox/wireless/forms/model_forms.py | 3 ++- 4 files changed, 40 insertions(+), 4 deletions(-) diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py index 6f8ab783d..ce09862ae 100644 --- a/netbox/circuits/forms/model_forms.py +++ b/netbox/circuits/forms/model_forms.py @@ -16,6 +16,7 @@ from utilities.forms import get_field_value from utilities.forms.fields import ( CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, ) +from utilities.forms.mixins import DistanceValidationMixin from utilities.forms.rendering import FieldSet, InlineFields from utilities.forms.widgets import DatePicker, HTMXSelect, NumberWithOptions from utilities.templatetags.builtins.filters import bettertitle @@ -105,7 +106,7 @@ class CircuitTypeForm(NetBoxModelForm): ] -class CircuitForm(TenancyForm, NetBoxModelForm): +class CircuitForm(DistanceValidationMixin, TenancyForm, NetBoxModelForm): provider = DynamicModelChoiceField( label=_('Provider'), queryset=Provider.objects.all(), diff --git a/netbox/netbox/models/mixins.py b/netbox/netbox/models/mixins.py index dc706c7c2..9f2c3ca6d 100644 --- a/netbox/netbox/models/mixins.py +++ b/netbox/netbox/models/mixins.py @@ -55,7 +55,7 @@ class WeightMixin(models.Model): class DistanceMixin(models.Model): distance = models.DecimalField( verbose_name=_('distance'), - max_digits=8, + max_digits=16, decimal_places=2, blank=True, null=True @@ -69,7 +69,7 @@ class DistanceMixin(models.Model): ) # Stores the normalized distance (in meters) for database ordering _abs_distance = models.DecimalField( - max_digits=10, + max_digits=18, decimal_places=4, blank=True, null=True diff --git a/netbox/utilities/forms/mixins.py b/netbox/utilities/forms/mixins.py index e89fbb520..ea16002a0 100644 --- a/netbox/utilities/forms/mixins.py +++ b/netbox/utilities/forms/mixins.py @@ -3,6 +3,8 @@ import time from django import forms from django.utils.translation import gettext_lazy as _ +from utilities.conversion import to_meters + __all__ = ( 'CheckLastUpdatedMixin', ) @@ -44,3 +46,35 @@ class CheckLastUpdatedMixin(forms.Form): "This object has been modified since the form was rendered. Please consult the object's change " "log for details." )) + + +class DistanceValidationMixin(forms.Form): + def clean(self): + super().clean() + + # validate max distance in meters based on model + # breakpoint() + distance = self.cleaned_data.get('distance', None) + unit = self.cleaned_data.get('distance_unit', None) + if distance and unit: + model_class = self._meta.model + distance_field = model_class._meta.get_field('distance') + max_digits = distance_field.max_digits - distance_field.decimal_places + max_distance = 10 ** max_digits + + abs_distance = to_meters(distance, unit) + + if abs_distance > max_distance: + raise forms.ValidationError(_( + "{distance} {unit} ({abs_distance} m) exceeds the maximum allowed distance for " + "{model._meta.verbose_name} distance. Distance must normalize to no more than " + "{max_distance} meters.".format( + distance=distance, + unit=unit, + abs_distance=abs_distance, + model=model_class, + max_distance=max_distance + ) + )) + + self.cleaned_data['_abs_distance'] = abs_distance diff --git a/netbox/wireless/forms/model_forms.py b/netbox/wireless/forms/model_forms.py index 56422ab57..08f418e3c 100644 --- a/netbox/wireless/forms/model_forms.py +++ b/netbox/wireless/forms/model_forms.py @@ -7,6 +7,7 @@ from ipam.models import VLAN from netbox.forms import NetBoxModelForm from tenancy.forms import TenancyForm from utilities.forms.fields import CommentField, DynamicModelChoiceField, SlugField +from utilities.forms.mixins import DistanceValidationMixin from utilities.forms.rendering import FieldSet, InlineFields from wireless.models import * @@ -73,7 +74,7 @@ class WirelessLANForm(ScopedForm, TenancyForm, NetBoxModelForm): } -class WirelessLinkForm(TenancyForm, NetBoxModelForm): +class WirelessLinkForm(DistanceValidationMixin, TenancyForm, NetBoxModelForm): site_a = DynamicModelChoiceField( queryset=Site.objects.all(), required=False,