15156 fix merge conflicts

This commit is contained in:
Arthur Hanson 2024-06-20 09:20:58 -07:00
commit 80b8fa60e3
22 changed files with 267 additions and 19 deletions

View File

@ -40,3 +40,7 @@ The security cipher used to apply wireless authentication. Options include:
### Pre-Shared Key ### Pre-Shared Key
The security key configured on each client to grant access to the secured wireless LAN. This applies only to certain authentication types. The security key configured on each client to grant access to the secured wireless LAN. This applies only to certain authentication types.
### Distance
The numeric distance of the link, including a unit designation (e.g. 100 meters or 25 feet).

View File

@ -0,0 +1,30 @@
# NetBox v4.1
## v4.1.0 (FUTURE)
### Breaking Changes
* Several filters deprecated in v4.0 have been removed (see [#15410](https://github.com/netbox-community/netbox/issues/15410)).
* The unit size for virtual disk size has been changed from 1 gigabyte to 1 megabyte. Existing values have been updated accordingly.
### New Features
### Enhancements
* [#7537](https://github.com/netbox-community/netbox/issues/7537) - Add a serial number field for virtual machines
* [#16359](https://github.com/netbox-community/netbox/issues/16359) - Enable plugins to embed content in the top navigation bar
### Other Changes
* [#14692](https://github.com/netbox-community/netbox/issues/14692) - Change atomic unit for virtual disks from 1GB to 1MB
* [#15410](https://github.com/netbox-community/netbox/issues/15410) - Removed various deprecated filters
* [#15908](https://github.com/netbox-community/netbox/issues/15908) - Indicate product edition in release data
* [#16388](https://github.com/netbox-community/netbox/issues/16388) - Move all change logging resources from `extras` to `core`
### REST API Changes
* The `/api/extras/object-changes/` endpoint has moved to `/api/core/object-changes/`
* virtualization.VirtualMachine
* Added the optional `serial` field
* wireless.WirelessLink
* Added the optional `distance` and `distance_unit` fields

View File

@ -296,6 +296,7 @@ nav:
- git Cheat Sheet: 'development/git-cheat-sheet.md' - git Cheat Sheet: 'development/git-cheat-sheet.md'
- Release Notes: - Release Notes:
- Summary: 'release-notes/index.md' - Summary: 'release-notes/index.md'
- Version 4.1: 'release-notes/version-4.1.md'
- Version 4.0: 'release-notes/version-4.0.md' - Version 4.0: 'release-notes/version-4.0.md'
- Version 3.7: 'release-notes/version-3.7.md' - Version 3.7: 'release-notes/version-3.7.md'
- Version 3.6: 'release-notes/version-3.6.md' - Version 3.6: 'release-notes/version-3.6.md'

View File

@ -656,11 +656,6 @@ class CableForm(TenancyForm, NetBoxModelForm):
'a_terminations_type', 'b_terminations_type', 'type', 'status', 'tenant_group', 'tenant', 'label', 'color', 'a_terminations_type', 'b_terminations_type', 'type', 'status', 'tenant_group', 'tenant', 'label', 'color',
'length', 'length_unit', 'description', 'comments', 'tags', 'length', 'length_unit', 'description', 'comments', 'tags',
] ]
error_messages = {
'length': {
'max_value': _('Maximum length is 32767 (any unit)')
}
}
class PowerPanelForm(NetBoxModelForm): class PowerPanelForm(NetBoxModelForm):

View File

@ -393,6 +393,8 @@ class CableTraceSVG:
labels = [f"{cable}"] if len(links) > 2 else [f"Wireless {cable}", cable.get_status_display()] labels = [f"{cable}"] if len(links) > 2 else [f"Wireless {cable}", cable.get_status_display()]
if cable.ssid: if cable.ssid:
description.append(f"{cable.ssid}") description.append(f"{cable.ssid}")
if cable.distance and cable.distance_unit:
description.append(f"{cable.distance} {cable.get_distance_unit_display()}")
near = [term for term in near_terminations if term.object == cable.interface_a] near = [term for term in near_terminations if term.object == cable.interface_a]
far = [term for term in far_terminations if term.object == cable.interface_b] far = [term for term in far_terminations if term.object == cable.interface_b]
if not (near and far): if not (near and far):

View File

@ -109,7 +109,7 @@ class CableTable(TenancyColumnsMixin, NetBoxTable):
status = columns.ChoiceFieldColumn() status = columns.ChoiceFieldColumn()
length = columns.TemplateColumn( length = columns.TemplateColumn(
template_code=CABLE_LENGTH, template_code=CABLE_LENGTH,
order_by=('_abs_length', 'length_unit') order_by=('_abs_length')
) )
color = columns.ColorColumn() color = columns.ColorColumn()
comments = columns.MarkdownColumn() comments = columns.MarkdownColumn()

View File

@ -17,7 +17,7 @@ def update_dashboard_widgets(apps, schema_editor):
for dashboard in Dashboard.objects.all(): for dashboard in Dashboard.objects.all():
for key, widget in dashboard.config.items(): for key, widget in dashboard.config.items():
if getattr(widget['config'], 'model') == 'extras.objectchange': if widget['config'].get('model') == 'extras.objectchange':
widget['config']['model'] = 'core.objectchange' widget['config']['model'] = 'core.objectchange'
elif models := widget['config'].get('models'): elif models := widget['config'].get('models'):
models = list(map(lambda x: x.replace('extras.objectchange', 'core.objectchange'), models)) models = list(map(lambda x: x.replace('extras.objectchange', 'core.objectchange'), models))
@ -44,6 +44,73 @@ class Migration(migrations.Migration):
name='ObjectChange', name='ObjectChange',
table='core_objectchange', table='core_objectchange',
), ),
# Rename PK sequence
migrations.RunSQL(
"ALTER TABLE extras_objectchange_id_seq"
" RENAME TO core_objectchange_id_seq"
),
# Rename indexes. Hashes generated by schema_editor._create_index_name()
migrations.RunSQL(
"ALTER INDEX extras_objectchange_pkey"
" RENAME TO core_objectchange_pkey"
),
migrations.RunSQL(
"ALTER INDEX extras_obje_changed_927fe5_idx"
" RENAME TO core_objectchange_changed_object_type_id_cha_79a9ed1e"
),
migrations.RunSQL(
"ALTER INDEX extras_obje_related_bfcdef_idx"
" RENAME TO core_objectchange_related_object_type_id_rel_a71d604a"
),
migrations.RunSQL(
"ALTER INDEX extras_objectchange_changed_object_type_id_b755bb60"
" RENAME TO core_objectchange_changed_object_type_id_2070ade6"
),
migrations.RunSQL(
"ALTER INDEX extras_objectchange_related_object_type_id_fe6e521f"
" RENAME TO core_objectchange_related_object_type_id_b80958af"
),
migrations.RunSQL(
"ALTER INDEX extras_objectchange_request_id_4ae21e90"
" RENAME TO core_objectchange_request_id_d9d160ac"
),
migrations.RunSQL(
"ALTER INDEX extras_objectchange_time_224380ea"
" RENAME TO core_objectchange_time_800f60a5"
),
migrations.RunSQL(
"ALTER INDEX extras_objectchange_user_id_7fdf8186"
" RENAME TO core_objectchange_user_id_2b2142be"
),
# Rename constraints
migrations.RunSQL(
"ALTER TABLE core_objectchange RENAME CONSTRAINT "
"extras_objectchange_changed_object_id_check TO "
"core_objectchange_changed_object_id_check"
),
migrations.RunSQL(
"ALTER TABLE core_objectchange RENAME CONSTRAINT "
"extras_objectchange_related_object_id_check TO "
"core_objectchange_related_object_id_check"
),
migrations.RunSQL(
"ALTER TABLE core_objectchange RENAME CONSTRAINT "
"extras_objectchange_changed_object_type__b755bb60_fk_django_co TO "
"core_objectchange_changed_object_type_id_2070ade6"
),
migrations.RunSQL(
"ALTER TABLE core_objectchange RENAME CONSTRAINT "
"extras_objectchange_related_object_type__fe6e521f_fk_django_co TO "
"core_objectchange_related_object_type_id_b80958af"
),
migrations.RunSQL(
"ALTER TABLE core_objectchange RENAME CONSTRAINT "
"extras_objectchange_user_id_7fdf8186_fk_auth_user_id TO "
"core_objectchange_user_id_2b2142be"
),
], ],
), ),
migrations.RunPython( migrations.RunPython(

View File

@ -34,6 +34,16 @@
<th scope="row">{% trans "Description" %}</th> <th scope="row">{% trans "Description" %}</th>
<td>{{ object.description|placeholder }}</td> <td>{{ object.description|placeholder }}</td>
</tr> </tr>
<tr>
<th scope="row">{% trans "Distance" %}</th>
<td>
{% if object.distance is not None %}
{{ object.distance|floatformat }} {{ object.get_distance_unit_display }}
{% else %}
{{ ''|placeholder }}
{% endif %}
</td>
</tr>
</table> </table>
</div> </div>
{% include 'inc/panels/tags.html' %} {% include 'inc/panels/tags.html' %}

View File

@ -20,12 +20,13 @@ class WirelessLinkSerializer(NetBoxModelSerializer):
tenant = TenantSerializer(nested=True, required=False, allow_null=True) tenant = TenantSerializer(nested=True, required=False, allow_null=True)
auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True) auth_type = ChoiceField(choices=WirelessAuthTypeChoices, required=False, allow_blank=True)
auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True) auth_cipher = ChoiceField(choices=WirelessAuthCipherChoices, required=False, allow_blank=True)
distance_unit = ChoiceField(choices=WirelessLinkDistanceUnitChoices, allow_blank=True, required=False, allow_null=True)
class Meta: class Meta:
model = WirelessLink model = WirelessLink
fields = [ fields = [
'id', 'url', 'display_url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'tenant', 'id', 'url', 'display_url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'tenant',
'auth_type', 'auth_cipher', 'auth_psk', 'description', 'comments', 'tags', 'custom_fields', 'auth_type', 'auth_cipher', 'auth_psk', 'distance', 'distance_unit', 'description',
'created', 'last_updated', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
] ]
brief_fields = ('id', 'url', 'display', 'ssid', 'description') brief_fields = ('id', 'url', 'display', 'ssid', 'description')

View File

@ -481,3 +481,21 @@ class WirelessAuthCipherChoices(ChoiceSet):
(CIPHER_TKIP, 'TKIP'), (CIPHER_TKIP, 'TKIP'),
(CIPHER_AES, 'AES'), (CIPHER_AES, 'AES'),
) )
class WirelessLinkDistanceUnitChoices(ChoiceSet):
# Metric
UNIT_KILOMETER = 'km'
UNIT_METER = 'm'
# Imperial
UNIT_MILE = 'mi'
UNIT_FOOT = 'ft'
CHOICES = (
(UNIT_KILOMETER, _('Kilometers')),
(UNIT_METER, _('Meters')),
(UNIT_MILE, _('Miles')),
(UNIT_FOOT, _('Feet')),
)

View File

@ -105,7 +105,7 @@ class WirelessLinkFilterSet(NetBoxModelFilterSet, TenancyFilterSet):
class Meta: class Meta:
model = WirelessLink model = WirelessLink
fields = ('id', 'ssid', 'auth_psk', 'description') fields = ('id', 'ssid', 'auth_psk', 'distance', 'distance_unit', 'description')
def search(self, queryset, name, value): def search(self, queryset, name, value):
if not value.strip(): if not value.strip():

View File

@ -125,6 +125,17 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm):
required=False, required=False,
label=_('Pre-shared key') label=_('Pre-shared key')
) )
distance = forms.DecimalField(
label=_('Distance'),
min_value=0,
required=False
)
distance_unit = forms.ChoiceField(
label=_('Distance unit'),
choices=add_blank_choice(WirelessLinkDistanceUnitChoices),
required=False,
initial=''
)
description = forms.CharField( description = forms.CharField(
label=_('Description'), label=_('Description'),
max_length=200, max_length=200,
@ -135,8 +146,9 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm):
model = WirelessLink model = WirelessLink
fieldsets = ( fieldsets = (
FieldSet('ssid', 'status', 'tenant', 'description'), FieldSet('ssid', 'status', 'tenant', 'description'),
FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')) FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')),
FieldSet('distance', 'distance_unit', name=_('Attributes')),
) )
nullable_fields = ( nullable_fields = (
'ssid', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'comments', 'ssid', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'distance', 'comments',
) )

View File

@ -112,10 +112,16 @@ class WirelessLinkImportForm(NetBoxModelImportForm):
required=False, required=False,
help_text=_('Authentication cipher') help_text=_('Authentication cipher')
) )
distance_unit = CSVChoiceField(
label=_('Distance unit'),
choices=WirelessLinkDistanceUnitChoices,
required=False,
help_text=_('Distance unit')
)
class Meta: class Meta:
model = WirelessLink model = WirelessLink
fields = ( fields = (
'interface_a', 'interface_b', 'ssid', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk', 'description', 'interface_a', 'interface_b', 'ssid', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk',
'comments', 'tags', 'distance', 'distance_unit', 'description', 'comments', 'tags',
) )

View File

@ -71,7 +71,7 @@ class WirelessLinkFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
model = WirelessLink model = WirelessLink
fieldsets = ( fieldsets = (
FieldSet('q', 'filter_id', 'tag'), FieldSet('q', 'filter_id', 'tag'),
FieldSet('ssid', 'status', name=_('Attributes')), FieldSet('ssid', 'status', 'distance', 'distance_unit', name=_('Attributes')),
FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')), FieldSet('tenant_group_id', 'tenant_id', name=_('Tenant')),
FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')), FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')),
) )
@ -98,4 +98,13 @@ class WirelessLinkFilterForm(TenancyFilterForm, NetBoxModelFilterSetForm):
label=_('Pre-shared key'), label=_('Pre-shared key'),
required=False required=False
) )
distance = forms.DecimalField(
label=_('Distance'),
required=False,
)
distance_unit = forms.ChoiceField(
label=_('Distance unit'),
choices=add_blank_choice(WirelessLinkDistanceUnitChoices),
required=False
)
tag = TagFilterField(model) tag = TagFilterField(model)

View File

@ -159,7 +159,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
fieldsets = ( fieldsets = (
FieldSet('site_a', 'location_a', 'device_a', 'interface_a', name=_('Side A')), FieldSet('site_a', 'location_a', 'device_a', 'interface_a', name=_('Side A')),
FieldSet('site_b', 'location_b', 'device_b', 'interface_b', name=_('Side B')), FieldSet('site_b', 'location_b', 'device_b', 'interface_b', name=_('Side B')),
FieldSet('status', 'ssid', 'description', 'tags', name=_('Link')), FieldSet('status', 'ssid', 'distance', 'distance_unit', 'description', 'tags', name=_('Link')),
FieldSet('tenant_group', 'tenant', name=_('Tenancy')), FieldSet('tenant_group', 'tenant', name=_('Tenancy')),
FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')), FieldSet('auth_type', 'auth_cipher', 'auth_psk', name=_('Authentication')),
) )
@ -168,8 +168,8 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm):
model = WirelessLink model = WirelessLink
fields = [ fields = [
'site_a', 'location_a', 'device_a', 'interface_a', 'site_b', 'location_b', 'device_b', 'interface_b', 'site_a', 'location_a', 'device_a', 'interface_a', 'site_b', 'location_b', 'device_b', 'interface_b',
'status', 'ssid', 'tenant_group', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk', 'description', 'status', 'ssid', 'tenant_group', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk',
'comments', 'tags', 'distance', 'distance_unit', 'description', 'comments', 'tags',
] ]
widgets = { widgets = {
'auth_psk': PasswordInput( 'auth_psk': PasswordInput(

View File

@ -0,0 +1,28 @@
# Generated by Django 5.0.6 on 2024-06-12 18:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('wireless', '0001_squashed_0008'),
]
operations = [
migrations.AddField(
model_name='wirelesslink',
name='_abs_distance',
field=models.DecimalField(blank=True, decimal_places=4, max_digits=10, null=True),
),
migrations.AddField(
model_name='wirelesslink',
name='distance',
field=models.DecimalField(blank=True, decimal_places=2, max_digits=8, null=True),
),
migrations.AddField(
model_name='wirelesslink',
name='distance_unit',
field=models.CharField(blank=True, max_length=50),
),
]

View File

@ -6,6 +6,7 @@ from django.utils.translation import gettext_lazy as _
from dcim.choices import LinkStatusChoices from dcim.choices import LinkStatusChoices
from dcim.constants import WIRELESS_IFACE_TYPES from dcim.constants import WIRELESS_IFACE_TYPES
from netbox.models import NestedGroupModel, PrimaryModel from netbox.models import NestedGroupModel, PrimaryModel
from utilities.conversion import to_meters
from .choices import * from .choices import *
from .constants import * from .constants import *
@ -160,6 +161,26 @@ class WirelessLink(WirelessAuthenticationBase, PrimaryModel):
choices=LinkStatusChoices, choices=LinkStatusChoices,
default=LinkStatusChoices.STATUS_CONNECTED default=LinkStatusChoices.STATUS_CONNECTED
) )
distance = models.DecimalField(
verbose_name=_('distance'),
max_digits=8,
decimal_places=2,
blank=True,
null=True
)
distance_unit = models.CharField(
verbose_name=_('distance unit'),
max_length=50,
choices=WirelessLinkDistanceUnitChoices,
blank=True,
)
# Stores the normalized distance (in meters) for database ordering
_abs_distance = models.DecimalField(
max_digits=10,
decimal_places=4,
blank=True,
null=True
)
tenant = models.ForeignKey( tenant = models.ForeignKey(
to='tenancy.Tenant', to='tenancy.Tenant',
on_delete=models.PROTECT, on_delete=models.PROTECT,
@ -208,6 +229,11 @@ class WirelessLink(WirelessAuthenticationBase, PrimaryModel):
return LinkStatusChoices.colors.get(self.status) return LinkStatusChoices.colors.get(self.status)
def clean(self): def clean(self):
super().clean()
# Validate distance and distance_unit
if self.distance is not None and not self.distance_unit:
raise ValidationError(_("Must specify a unit when setting a wireless distance"))
# Validate interface types # Validate interface types
if self.interface_a.type not in WIRELESS_IFACE_TYPES: if self.interface_a.type not in WIRELESS_IFACE_TYPES:
@ -224,6 +250,15 @@ class WirelessLink(WirelessAuthenticationBase, PrimaryModel):
}) })
def save(self, *args, **kwargs): def save(self, *args, **kwargs):
# Store the given distance (if any) in meters for use in database ordering
if self.distance is not None and self.distance_unit:
self._abs_distance = to_meters(self.distance, self.distance_unit)
else:
self._abs_distance = None
# Clear distance_unit if no distance is defined
if self.distance is None:
self.distance_unit = ''
# Store the parent Device for the A and B interfaces # Store the parent Device for the A and B interfaces
self._interface_a_device = self.interface_a.device self._interface_a_device = self.interface_a.device

View File

@ -0,0 +1,4 @@
WIRELESS_LINK_DISTANCE = """
{% load helpers %}
{% if record.distance %}{{ record.distance|floatformat:"-2" }} {{ record.distance_unit }}{% endif %}
"""

View File

@ -4,6 +4,7 @@ import django_tables2 as tables
from netbox.tables import NetBoxTable, columns from netbox.tables import NetBoxTable, columns
from tenancy.tables import TenancyColumnsMixin from tenancy.tables import TenancyColumnsMixin
from wireless.models import * from wireless.models import *
from .template_code import WIRELESS_LINK_DISTANCE
__all__ = ( __all__ = (
'WirelessLinkTable', 'WirelessLinkTable',
@ -36,6 +37,10 @@ class WirelessLinkTable(TenancyColumnsMixin, NetBoxTable):
verbose_name=_('Interface B'), verbose_name=_('Interface B'),
linkify=True linkify=True
) )
distance = columns.TemplateColumn(
template_code=WIRELESS_LINK_DISTANCE,
order_by=('_abs_distance')
)
tags = columns.TagColumn( tags = columns.TagColumn(
url_name='wireless:wirelesslink_list' url_name='wireless:wirelesslink_list'
) )
@ -44,7 +49,8 @@ class WirelessLinkTable(TenancyColumnsMixin, NetBoxTable):
model = WirelessLink model = WirelessLink
fields = ( fields = (
'pk', 'id', 'status', 'device_a', 'interface_a', 'device_b', 'interface_b', 'ssid', 'tenant', 'pk', 'id', 'status', 'device_a', 'interface_a', 'device_b', 'interface_b', 'ssid', 'tenant',
'tenant_group', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'tags', 'created', 'last_updated', 'tenant_group', 'distance', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'tags',
'created', 'last_updated',
) )
default_columns = ( default_columns = (
'pk', 'id', 'status', 'device_a', 'interface_a', 'device_b', 'interface_b', 'ssid', 'auth_type', 'pk', 'id', 'status', 'device_a', 'interface_a', 'device_b', 'interface_b', 'ssid', 'auth_type',

View File

@ -113,6 +113,8 @@ class WirelessLinkTest(APIViewTestCases.APIViewTestCase):
brief_fields = ['description', 'display', 'id', 'ssid', 'url'] brief_fields = ['description', 'display', 'id', 'ssid', 'url']
bulk_update_data = { bulk_update_data = {
'status': 'planned', 'status': 'planned',
'distance': 100,
'distance_unit': 'm',
} }
@classmethod @classmethod

View File

@ -260,6 +260,8 @@ class WirelessLinkTestCase(TestCase, ChangeLoggedFilterSetTests):
auth_cipher=WirelessAuthCipherChoices.CIPHER_AUTO, auth_cipher=WirelessAuthCipherChoices.CIPHER_AUTO,
auth_psk='PSK1', auth_psk='PSK1',
tenant=tenants[0], tenant=tenants[0],
distance=10,
distance_unit=WirelessLinkDistanceUnitChoices.UNIT_FOOT,
description='foobar1' description='foobar1'
).save() ).save()
WirelessLink( WirelessLink(
@ -271,6 +273,8 @@ class WirelessLinkTestCase(TestCase, ChangeLoggedFilterSetTests):
auth_cipher=WirelessAuthCipherChoices.CIPHER_TKIP, auth_cipher=WirelessAuthCipherChoices.CIPHER_TKIP,
auth_psk='PSK2', auth_psk='PSK2',
tenant=tenants[1], tenant=tenants[1],
distance=20,
distance_unit=WirelessLinkDistanceUnitChoices.UNIT_METER,
description='foobar2' description='foobar2'
).save() ).save()
WirelessLink( WirelessLink(
@ -281,6 +285,8 @@ class WirelessLinkTestCase(TestCase, ChangeLoggedFilterSetTests):
auth_type=WirelessAuthTypeChoices.TYPE_WPA_PERSONAL, auth_type=WirelessAuthTypeChoices.TYPE_WPA_PERSONAL,
auth_cipher=WirelessAuthCipherChoices.CIPHER_AES, auth_cipher=WirelessAuthCipherChoices.CIPHER_AES,
auth_psk='PSK3', auth_psk='PSK3',
distance=30,
distance_unit=WirelessLinkDistanceUnitChoices.UNIT_METER,
tenant=tenants[2], tenant=tenants[2],
).save() ).save()
WirelessLink( WirelessLink(
@ -313,6 +319,14 @@ class WirelessLinkTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'auth_psk': ['PSK1', 'PSK2']} params = {'auth_psk': ['PSK1', 'PSK2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_distance(self):
params = {'distance': [10, 20]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_distance_unit(self):
params = {'distance_unit': WirelessLinkDistanceUnitChoices.UNIT_FOOT}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
def test_description(self): def test_description(self):
params = {'description': ['foobar1', 'foobar2']} params = {'description': ['foobar1', 'foobar2']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2) self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -160,6 +160,8 @@ class WirelessLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
'interface_a': interfaces[6].pk, 'interface_a': interfaces[6].pk,
'interface_b': interfaces[7].pk, 'interface_b': interfaces[7].pk,
'status': LinkStatusChoices.STATUS_PLANNED, 'status': LinkStatusChoices.STATUS_PLANNED,
'distance': 100,
'distance_unit': WirelessLinkDistanceUnitChoices.UNIT_FOOT,
'tenant': tenants[1].pk, 'tenant': tenants[1].pk,
'tags': [t.pk for t in tags], 'tags': [t.pk for t in tags],
} }
@ -180,4 +182,6 @@ class WirelessLinkTestCase(ViewTestCases.PrimaryObjectViewTestCase):
cls.bulk_edit_data = { cls.bulk_edit_data = {
'status': LinkStatusChoices.STATUS_PLANNED, 'status': LinkStatusChoices.STATUS_PLANNED,
'distance': 50,
'distance_unit': WirelessLinkDistanceUnitChoices.UNIT_METER,
} }