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.
This commit is contained in:
Jason Novinger 2025-05-14 09:36:35 -05:00
parent 6b9b5c4184
commit 7e1d558428
4 changed files with 40 additions and 4 deletions

View File

@ -16,6 +16,7 @@ from utilities.forms import get_field_value
from utilities.forms.fields import ( from utilities.forms.fields import (
CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField, CommentField, ContentTypeChoiceField, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SlugField,
) )
from utilities.forms.mixins import DistanceValidationMixin
from utilities.forms.rendering import FieldSet, InlineFields from utilities.forms.rendering import FieldSet, InlineFields
from utilities.forms.widgets import DatePicker, HTMXSelect, NumberWithOptions from utilities.forms.widgets import DatePicker, HTMXSelect, NumberWithOptions
from utilities.templatetags.builtins.filters import bettertitle 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( provider = DynamicModelChoiceField(
label=_('Provider'), label=_('Provider'),
queryset=Provider.objects.all(), queryset=Provider.objects.all(),

View File

@ -55,7 +55,7 @@ class WeightMixin(models.Model):
class DistanceMixin(models.Model): class DistanceMixin(models.Model):
distance = models.DecimalField( distance = models.DecimalField(
verbose_name=_('distance'), verbose_name=_('distance'),
max_digits=8, max_digits=16,
decimal_places=2, decimal_places=2,
blank=True, blank=True,
null=True null=True
@ -69,7 +69,7 @@ class DistanceMixin(models.Model):
) )
# Stores the normalized distance (in meters) for database ordering # Stores the normalized distance (in meters) for database ordering
_abs_distance = models.DecimalField( _abs_distance = models.DecimalField(
max_digits=10, max_digits=18,
decimal_places=4, decimal_places=4,
blank=True, blank=True,
null=True null=True

View File

@ -3,6 +3,8 @@ import time
from django import forms from django import forms
from django.utils.translation import gettext_lazy as _ from django.utils.translation import gettext_lazy as _
from utilities.conversion import to_meters
__all__ = ( __all__ = (
'CheckLastUpdatedMixin', '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 " "This object has been modified since the form was rendered. Please consult the object's change "
"log for details." "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

View File

@ -7,6 +7,7 @@ from ipam.models import VLAN
from netbox.forms import NetBoxModelForm from netbox.forms import NetBoxModelForm
from tenancy.forms import TenancyForm from tenancy.forms import TenancyForm
from utilities.forms.fields import CommentField, DynamicModelChoiceField, SlugField from utilities.forms.fields import CommentField, DynamicModelChoiceField, SlugField
from utilities.forms.mixins import DistanceValidationMixin
from utilities.forms.rendering import FieldSet, InlineFields from utilities.forms.rendering import FieldSet, InlineFields
from wireless.models import * 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( site_a = DynamicModelChoiceField(
queryset=Site.objects.all(), queryset=Site.objects.all(),
required=False, required=False,