Fix logic for upper range boundaries

This commit is contained in:
Jeremy Stretch 2024-07-15 16:27:38 -04:00
parent f6c2396a30
commit c1a0eb8b37
6 changed files with 19 additions and 14 deletions

View File

@ -10,7 +10,9 @@ def move_min_max(apps, schema_editor):
VLANGroup = apps.get_model('ipam', 'VLANGroup')
for group in VLANGroup.objects.all():
if group.min_vid or group.max_vid:
group.vlan_id_ranges = [NumericRange(group.min_vid, group.max_vid)]
group.vlan_id_ranges = [
NumericRange(group.min_vid, group.max_vid, bounds='[]')
]
group._total_vlan_ids = 0
for vlan_range in group.vlan_id_ranges:
@ -31,7 +33,7 @@ class Migration(migrations.Migration):
name='vlan_id_ranges',
field=django.contrib.postgres.fields.ArrayField(
base_field=django.contrib.postgres.fields.ranges.IntegerRangeField(),
default=ipam.models.vlans.default_vland_id_ranges,
default=ipam.models.vlans.default_vlan_id_ranges,
size=None
),
),

View File

@ -21,7 +21,7 @@ __all__ = (
)
def default_vland_id_ranges():
def default_vlan_id_ranges():
return [
NumericRange(VLAN_VID_MIN, VLAN_VID_MAX, bounds='[]')
]
@ -57,7 +57,7 @@ class VLANGroup(OrganizationalModel):
vlan_id_ranges = ArrayField(
IntegerRangeField(),
verbose_name=_('VLAN ID ranges'),
default=default_vland_id_ranges
default=default_vlan_id_ranges
)
_total_vlan_ids = models.PositiveBigIntegerField(
default=VLAN_VID_MAX - VLAN_VID_MIN + 1
@ -120,7 +120,7 @@ class VLANGroup(OrganizationalModel):
"""
available_vlans = {}
for vlan_range in self.vlan_id_ranges:
available_vlans = {vid for vid in range(vlan_range.lower, vlan_range.upper + 1)}
available_vlans = {vid for vid in range(vlan_range.lower, vlan_range.upper)}
available_vlans -= set(VLAN.objects.filter(group=self).values_list('vid', flat=True))
return sorted(available_vlans)

View File

@ -9,6 +9,7 @@ from utilities.querysets import RestrictedQuerySet
__all__ = (
'ASNRangeQuerySet',
'PrefixQuerySet',
'VLANGroupQuerySet',
'VLANQuerySet',
)

View File

@ -168,7 +168,7 @@ class IntegerRangeSerializer(serializers.Serializer):
if type(data[0]) is not int or type(data[1]) is not int:
raise ValidationError(_("Range boundaries must be defined as integers."))
return NumericRange(data[0], data[1])
return NumericRange(data[0], data[1], bounds='[]')
def to_representation(self, instance):
return instance.lower, instance.upper
return instance.lower, instance.upper - 1

View File

@ -138,27 +138,25 @@ def ranges_to_string(ranges):
"""
Generate a human-friendly string from a set of ranges. Intended for use with ArrayField.
For example:
[Range(1, 100), Range(200, 300)] => "1-100, 200-300"
[[1, 100)], [200, 300)] => "1-99,200-299"
"""
if not ranges:
return ''
return ', '.join([f"{r.lower}-{r.upper}" for r in ranges])
return ','.join([f"{r.lower}-{r.upper - 1}" for r in ranges])
def string_to_range_array(value):
"""
Given a string in the format "1-100, 200-300" create an array of ranges. Intended for use with ArrayField.
For example:
"1-100, 200-300" => [1-100, 200-300]
"1-99,200-299" => [NumericRange(1, 100), NumericRange(200, 300)]
"""
if not value:
return None
ranges = value.split(",")
values = []
for dash_range in value.split(','):
if '-' not in dash_range:
return None
lower, upper = dash_range.split('-')
values.append(NumericRange(int(lower), int(upper)))
values.append(NumericRange(int(lower), int(upper), bounds='[]'))
return values

View File

@ -2,7 +2,7 @@ import json
from django.contrib.auth import get_user_model
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields import ArrayField
from django.contrib.postgres.fields import ArrayField, RangeField
from django.core.exceptions import FieldDoesNotExist
from django.db.models import ManyToManyField, ManyToManyRel, JSONField
from django.forms.models import model_to_dict
@ -12,6 +12,7 @@ from taggit.managers import TaggableManager
from core.models import ObjectType
from users.models import ObjectPermission
from utilities.data import ranges_to_string
from utilities.object_types import object_type_identifier
from utilities.permissions import resolve_permission_type
from .utils import DUMMY_CF_DATA, extract_form_failures
@ -139,6 +140,9 @@ class ModelTestCase(TestCase):
if type(field.base_field) is ArrayField:
# Handle nested arrays (e.g. choice sets)
model_dict[key] = '\n'.join([f'{k},{v}' for k, v in value])
elif issubclass(type(field.base_field), RangeField):
# Handle arrays of numeric ranges (e.g. VLANGroup VLAN ID ranges)
model_dict[key] = ranges_to_string(value)
else:
model_dict[key] = ','.join([str(v) for v in value])