From 90e9f344944ef192b4b3ebc56a895d93e2995440 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Wed, 13 Oct 2021 09:46:17 -0400 Subject: [PATCH] Add WirelessLink model --- netbox/dcim/migrations/0136_wireless.py | 8 +- netbox/dcim/migrations/0137_wireless.py | 19 +++++ netbox/netbox/navigation_menu.py | 1 + .../wireless/inc/wirelesslink_interface.html | 20 +++++ netbox/templates/wireless/wirelesslan.html | 2 +- netbox/templates/wireless/wirelesslink.html | 48 +++++++++++ netbox/wireless/api/nested_serializers.py | 11 ++- netbox/wireless/api/serializers.py | 17 +++- netbox/wireless/api/urls.py | 1 + netbox/wireless/api/views.py | 12 +-- netbox/wireless/filtersets.py | 22 +++++ netbox/wireless/forms/bulk_edit.py | 27 +++++- netbox/wireless/forms/bulk_import.py | 17 +++- netbox/wireless/forms/filtersets.py | 28 ++++++- netbox/wireless/forms/models.py | 29 ++++++- netbox/wireless/migrations/0001_initial.py | 34 -------- netbox/wireless/migrations/0001_wireless.py | 57 +++++++++++++ netbox/wireless/models.py | 83 ++++++++++++++++++- netbox/wireless/tables.py | 25 +++++- netbox/wireless/urls.py | 12 +++ netbox/wireless/views.py | 43 ++++++++++ 21 files changed, 458 insertions(+), 58 deletions(-) create mode 100644 netbox/dcim/migrations/0137_wireless.py create mode 100644 netbox/templates/wireless/inc/wirelesslink_interface.html create mode 100644 netbox/templates/wireless/wirelesslink.html delete mode 100644 netbox/wireless/migrations/0001_initial.py create mode 100644 netbox/wireless/migrations/0001_wireless.py diff --git a/netbox/dcim/migrations/0136_wireless.py b/netbox/dcim/migrations/0136_wireless.py index 108e63802..3b33f7d3f 100644 --- a/netbox/dcim/migrations/0136_wireless.py +++ b/netbox/dcim/migrations/0136_wireless.py @@ -1,10 +1,11 @@ +# Generated by Django 3.2.8 on 2021-10-13 13:44 + from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ - ('wireless', '0001_initial'), ('dcim', '0135_location_tenant'), ] @@ -19,9 +20,4 @@ class Migration(migrations.Migration): name='rf_channel_width', field=models.PositiveSmallIntegerField(blank=True, null=True), ), - migrations.AddField( - model_name='interface', - name='wireless_lans', - field=models.ManyToManyField(blank=True, related_name='interfaces', to='wireless.WirelessLAN'), - ), ] diff --git a/netbox/dcim/migrations/0137_wireless.py b/netbox/dcim/migrations/0137_wireless.py new file mode 100644 index 000000000..9108735a1 --- /dev/null +++ b/netbox/dcim/migrations/0137_wireless.py @@ -0,0 +1,19 @@ +# Generated by Django 3.2.8 on 2021-10-13 13:44 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0136_wireless'), + ('wireless', '0001_wireless'), + ] + + operations = [ + migrations.AddField( + model_name='interface', + name='wireless_lans', + field=models.ManyToManyField(blank=True, related_name='interfaces', to='wireless.WirelessLAN'), + ), + ] diff --git a/netbox/netbox/navigation_menu.py b/netbox/netbox/navigation_menu.py index 073189d31..b3e11f6ce 100644 --- a/netbox/netbox/navigation_menu.py +++ b/netbox/netbox/navigation_menu.py @@ -196,6 +196,7 @@ WIRELESS_MENU = Menu( label='Wireless', items=( get_model_item('wireless', 'wirelesslan', 'Wireless LANs'), + get_model_item('wireless', 'wirelesslink', 'Wirelesss Links', actions=['import']), ), ), ), diff --git a/netbox/templates/wireless/inc/wirelesslink_interface.html b/netbox/templates/wireless/inc/wirelesslink_interface.html new file mode 100644 index 000000000..9c4669ad1 --- /dev/null +++ b/netbox/templates/wireless/inc/wirelesslink_interface.html @@ -0,0 +1,20 @@ + + + + + + + + + + + + + +
Device + {{ interface.device }} +
Interface + {{ interface }} +
Type + {{ interface.get_type_display }} +
diff --git a/netbox/templates/wireless/wirelesslan.html b/netbox/templates/wireless/wirelesslan.html index 98bde8688..f8fabf558 100644 --- a/netbox/templates/wireless/wirelesslan.html +++ b/netbox/templates/wireless/wirelesslan.html @@ -30,7 +30,7 @@ - {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='dcim:site_list' %} + {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='wireless:wirelesslan_list' %} {% plugin_left_page object %}
diff --git a/netbox/templates/wireless/wirelesslink.html b/netbox/templates/wireless/wirelesslink.html new file mode 100644 index 000000000..6196adae4 --- /dev/null +++ b/netbox/templates/wireless/wirelesslink.html @@ -0,0 +1,48 @@ +{% extends 'generic/object.html' %} +{% load helpers %} +{% load plugins %} + +{% block content %} +
+
+
+
Interface A
+
+ {% include 'wireless/inc/wirelesslink_interface.html' with interface=object.interface_a %} +
+
+
+
Link Properties
+
+ + + + + + + + + +
SSID{{ object.ssid|placeholder }}
Description{{ object.description|placeholder }}
+
+
+ {% plugin_left_page object %} +
+
+
+
Interface B
+
+ {% include 'wireless/inc/wirelesslink_interface.html' with interface=object.interface_b %} +
+
+ {% include 'inc/custom_fields_panel.html' %} + {% include 'extras/inc/tags_panel.html' with tags=object.tags.all url='wireless:wirelesslink_list' %} + {% plugin_right_page object %} +
+
+
+
+ {% plugin_full_width_page object %} +
+
+{% endblock %} diff --git a/netbox/wireless/api/nested_serializers.py b/netbox/wireless/api/nested_serializers.py index e290653a2..5a8cf6671 100644 --- a/netbox/wireless/api/nested_serializers.py +++ b/netbox/wireless/api/nested_serializers.py @@ -5,12 +5,21 @@ from wireless.models import * __all__ = ( 'NestedWirelessLANSerializer', + 'NestedWirelessLinkSerializer', ) class NestedWirelessLANSerializer(WritableNestedSerializer): - url = serializers.HyperlinkedIdentityField(view_name='wireless-api:ssid-detail') + url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail') class Meta: model = WirelessLAN fields = ['id', 'url', 'display', 'ssid'] + + +class NestedWirelessLinkSerializer(WritableNestedSerializer): + url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail') + + class Meta: + model = WirelessLink + fields = ['id', 'url', 'display', 'ssid'] diff --git a/netbox/wireless/api/serializers.py b/netbox/wireless/api/serializers.py index 08642259f..90515f53e 100644 --- a/netbox/wireless/api/serializers.py +++ b/netbox/wireless/api/serializers.py @@ -1,16 +1,19 @@ from rest_framework import serializers +from dcim.api.serializers import NestedInterfaceSerializer from ipam.api.serializers import NestedVLANSerializer from netbox.api.serializers import PrimaryModelSerializer from wireless.models import * +from .nested_serializers import * __all__ = ( 'WirelessLANSerializer', + 'WirelessLinkSerializer', ) class WirelessLANSerializer(PrimaryModelSerializer): - url = serializers.HyperlinkedIdentityField(view_name='wireless-api:ssid-detail') + url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslan-detail') vlan = NestedVLANSerializer(required=False, allow_null=True) class Meta: @@ -18,3 +21,15 @@ class WirelessLANSerializer(PrimaryModelSerializer): fields = [ 'id', 'url', 'display', 'ssid', 'description', 'vlan', ] + + +class WirelessLinkSerializer(PrimaryModelSerializer): + url = serializers.HyperlinkedIdentityField(view_name='wireless-api:wirelesslink-detail') + interface_a = NestedInterfaceSerializer() + interface_b = NestedInterfaceSerializer() + + class Meta: + model = WirelessLAN + fields = [ + 'id', 'url', 'display', 'interface_a', 'interface_b', 'ssid', 'description', + ] diff --git a/netbox/wireless/api/urls.py b/netbox/wireless/api/urls.py index 638f31bbf..431bb05f8 100644 --- a/netbox/wireless/api/urls.py +++ b/netbox/wireless/api/urls.py @@ -6,6 +6,7 @@ router = OrderedDefaultRouter() router.APIRootView = views.WirelessRootView router.register('wireless-lans', views.WirelessLANViewSet) +router.register('wireless-links', views.WirelessLinkViewSet) app_name = 'wireless-api' urlpatterns = router.urls diff --git a/netbox/wireless/api/views.py b/netbox/wireless/api/views.py index a09b2e23d..aa361a7f7 100644 --- a/netbox/wireless/api/views.py +++ b/netbox/wireless/api/views.py @@ -14,11 +14,13 @@ class WirelessRootView(APIRootView): return 'Wireless' -# -# Providers -# - class WirelessLANViewSet(CustomFieldModelViewSet): - queryset = WirelessLAN.objects.prefetch_related('tags') + queryset = WirelessLAN.objects.prefetch_related('vlan', 'tags') serializer_class = serializers.WirelessLANSerializer filterset_class = filtersets.WirelessLANFilterSet + + +class WirelessLinkViewSet(CustomFieldModelViewSet): + queryset = WirelessLink.objects.prefetch_related('interface_a', 'interface_b', 'tags') + serializer_class = serializers.WirelessLinkSerializer + filterset_class = filtersets.WirelessLinkFilterSet diff --git a/netbox/wireless/filtersets.py b/netbox/wireless/filtersets.py index c148354a0..7341ada9d 100644 --- a/netbox/wireless/filtersets.py +++ b/netbox/wireless/filtersets.py @@ -7,6 +7,7 @@ from .models import * __all__ = ( 'WirelessLANFilterSet', + 'WirelessLinkFilterSet', ) @@ -29,3 +30,24 @@ class WirelessLANFilterSet(PrimaryModelFilterSet): Q(description__icontains=value) ) return queryset.filter(qs_filter) + + +class WirelessLinkFilterSet(PrimaryModelFilterSet): + q = django_filters.CharFilter( + method='search', + label='Search', + ) + tag = TagFilter() + + class Meta: + model = WirelessLink + fields = ['id', 'ssid'] + + def search(self, queryset, name, value): + if not value.strip(): + return queryset + qs_filter = ( + Q(ssid__icontains=value) | + Q(description__icontains=value) + ) + return queryset.filter(qs_filter) diff --git a/netbox/wireless/forms/bulk_edit.py b/netbox/wireless/forms/bulk_edit.py index c11a16239..65666ccb1 100644 --- a/netbox/wireless/forms/bulk_edit.py +++ b/netbox/wireless/forms/bulk_edit.py @@ -4,9 +4,11 @@ from dcim.models import * from extras.forms import AddRemoveTagsForm, CustomFieldModelBulkEditForm from ipam.models import VLAN from utilities.forms import BootstrapMixin, DynamicModelChoiceField +from wireless.constants import SSID_MAX_LENGTH __all__ = ( 'WirelessLANBulkEditForm', + 'WirelessLinkBulkEditForm', ) @@ -19,11 +21,30 @@ class WirelessLANBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldMode queryset=VLAN.objects.all(), required=False, ) + ssid = forms.CharField( + max_length=SSID_MAX_LENGTH, + required=False + ) description = forms.CharField( required=False ) class Meta: - nullable_fields = [ - 'vlan', 'description', - ] + nullable_fields = ['vlan', 'ssid', 'description'] + + +class WirelessLinkBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldModelBulkEditForm): + pk = forms.ModelMultipleChoiceField( + queryset=PowerFeed.objects.all(), + widget=forms.MultipleHiddenInput + ) + ssid = forms.CharField( + max_length=SSID_MAX_LENGTH, + required=False + ) + description = forms.CharField( + required=False + ) + + class Meta: + nullable_fields = ['ssid', 'description'] diff --git a/netbox/wireless/forms/bulk_import.py b/netbox/wireless/forms/bulk_import.py index 5dc07f91a..caf322dc1 100644 --- a/netbox/wireless/forms/bulk_import.py +++ b/netbox/wireless/forms/bulk_import.py @@ -1,10 +1,12 @@ +from dcim.models import Interface from extras.forms import CustomFieldModelCSVForm from ipam.models import VLAN from utilities.forms import CSVModelChoiceField -from wireless.models import WirelessLAN +from wireless.models import * __all__ = ( 'WirelessLANCSVForm', + 'WirelessLinkCSVForm', ) @@ -18,3 +20,16 @@ class WirelessLANCSVForm(CustomFieldModelCSVForm): class Meta: model = WirelessLAN fields = ('ssid', 'description', 'vlan') + + +class WirelessLinkCSVForm(CustomFieldModelCSVForm): + interface_a = CSVModelChoiceField( + queryset=Interface.objects.all() + ) + interface_b = CSVModelChoiceField( + queryset=Interface.objects.all() + ) + + class Meta: + model = WirelessLink + fields = ('interface_a', 'interface_b', 'ssid', 'description') diff --git a/netbox/wireless/forms/filtersets.py b/netbox/wireless/forms/filtersets.py index 99e38918e..fa1912099 100644 --- a/netbox/wireless/forms/filtersets.py +++ b/netbox/wireless/forms/filtersets.py @@ -3,7 +3,12 @@ from django.utils.translation import gettext as _ from extras.forms import CustomFieldModelFilterForm from utilities.forms import BootstrapMixin, TagFilterField -from .models import WirelessLAN +from wireless.models import * + +__all__ = ( + 'WirelessLANFilterForm', + 'WirelessLinkFilterForm', +) class WirelessLANFilterForm(BootstrapMixin, CustomFieldModelFilterForm): @@ -16,4 +21,25 @@ class WirelessLANFilterForm(BootstrapMixin, CustomFieldModelFilterForm): widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), label=_('Search') ) + ssid = forms.CharField( + required=False, + label='SSID' + ) + tag = TagFilterField(model) + + +class WirelessLinkFilterForm(BootstrapMixin, CustomFieldModelFilterForm): + model = WirelessLink + field_groups = [ + ['q', 'tag'], + ] + q = forms.CharField( + required=False, + widget=forms.TextInput(attrs={'placeholder': _('All Fields')}), + label=_('Search') + ) + ssid = forms.CharField( + required=False, + label='SSID' + ) tag = TagFilterField(model) diff --git a/netbox/wireless/forms/models.py b/netbox/wireless/forms/models.py index 95b43c7d3..08e864340 100644 --- a/netbox/wireless/forms/models.py +++ b/netbox/wireless/forms/models.py @@ -1,11 +1,13 @@ +from dcim.models import Interface from extras.forms import CustomFieldModelForm from extras.models import Tag from ipam.models import VLAN from utilities.forms import BootstrapMixin, DynamicModelChoiceField, DynamicModelMultipleChoiceField -from wireless.models import WirelessLAN +from wireless.models import * __all__ = ( 'WirelessLANForm', + 'WirelessLinkForm', ) @@ -28,3 +30,28 @@ class WirelessLANForm(BootstrapMixin, CustomFieldModelForm): ('Wireless LAN', ('ssid', 'description', 'tags')), ('VLAN', ('vlan',)), ) + + +class WirelessLinkForm(BootstrapMixin, CustomFieldModelForm): + interface_a = DynamicModelChoiceField( + queryset=Interface.objects.all(), + query_params={ + 'kind': 'wireless' + } + ) + interface_b = DynamicModelChoiceField( + queryset=Interface.objects.all(), + query_params={ + 'kind': 'wireless' + } + ) + tags = DynamicModelMultipleChoiceField( + queryset=Tag.objects.all(), + required=False + ) + + class Meta: + model = WirelessLink + fields = [ + 'interface_a', 'interface_b', 'ssid', 'description', 'tags', + ] diff --git a/netbox/wireless/migrations/0001_initial.py b/netbox/wireless/migrations/0001_initial.py deleted file mode 100644 index c93a17190..000000000 --- a/netbox/wireless/migrations/0001_initial.py +++ /dev/null @@ -1,34 +0,0 @@ -import django.core.serializers.json -from django.db import migrations, models -import django.db.models.deletion -import taggit.managers - - -class Migration(migrations.Migration): - - initial = True - - dependencies = [ - ('ipam', '0050_iprange'), - ('extras', '0062_clear_secrets_changelog'), - ] - - operations = [ - migrations.CreateModel( - name='WirelessLAN', - fields=[ - ('created', models.DateField(auto_now_add=True, null=True)), - ('last_updated', models.DateTimeField(auto_now=True, null=True)), - ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), - ('id', models.BigAutoField(primary_key=True, serialize=False)), - ('ssid', models.CharField(max_length=32)), - ('description', models.CharField(blank=True, max_length=200)), - ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), - ('vlan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ipam.vlan')), - ], - options={ - 'verbose_name': 'Wireless LAN', - 'ordering': ('ssid', 'pk'), - }, - ), - ] diff --git a/netbox/wireless/migrations/0001_wireless.py b/netbox/wireless/migrations/0001_wireless.py new file mode 100644 index 000000000..2fb07e5fd --- /dev/null +++ b/netbox/wireless/migrations/0001_wireless.py @@ -0,0 +1,57 @@ +# Generated by Django 3.2.8 on 2021-10-13 13:44 + +import django.core.serializers.json +from django.db import migrations, models +import django.db.models.deletion +import taggit.managers + + +class Migration(migrations.Migration): + + initial = True + + dependencies = [ + ('dcim', '0136_wireless'), + ('extras', '0062_clear_secrets_changelog'), + ('ipam', '0050_iprange'), + ] + + operations = [ + migrations.CreateModel( + name='WirelessLAN', + fields=[ + ('created', models.DateField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('ssid', models.CharField(max_length=32)), + ('description', models.CharField(blank=True, max_length=200)), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ('vlan', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.PROTECT, to='ipam.vlan')), + ], + options={ + 'verbose_name': 'Wireless LAN', + 'ordering': ('ssid', 'pk'), + }, + ), + migrations.CreateModel( + name='WirelessLink', + fields=[ + ('created', models.DateField(auto_now_add=True, null=True)), + ('last_updated', models.DateTimeField(auto_now=True, null=True)), + ('custom_field_data', models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder)), + ('id', models.BigAutoField(primary_key=True, serialize=False)), + ('ssid', models.CharField(blank=True, max_length=32)), + ('description', models.CharField(blank=True, max_length=200)), + ('_interface_a_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device')), + ('_interface_b_device', models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.CASCADE, related_name='+', to='dcim.device')), + ('interface_a', models.ForeignKey(limit_choices_to={'type__in': ['ieee802.11a', 'ieee802.11g', 'ieee802.11n', 'ieee802.11ac', 'ieee802.11ad', 'ieee802.11ax']}, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='dcim.interface')), + ('interface_b', models.ForeignKey(limit_choices_to={'type__in': ['ieee802.11a', 'ieee802.11g', 'ieee802.11n', 'ieee802.11ac', 'ieee802.11ad', 'ieee802.11ax']}, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='dcim.interface')), + ('tags', taggit.managers.TaggableManager(through='extras.TaggedItem', to='extras.Tag')), + ], + options={ + 'ordering': ['pk'], + 'unique_together': {('interface_a', 'interface_b')}, + }, + ), + ] diff --git a/netbox/wireless/models.py b/netbox/wireless/models.py index 363631ef5..41f3dbf6d 100644 --- a/netbox/wireless/models.py +++ b/netbox/wireless/models.py @@ -6,19 +6,22 @@ from dcim.constants import WIRELESS_IFACE_TYPES from extras.utils import extras_features from netbox.models import BigIDModel, PrimaryModel from utilities.querysets import RestrictedQuerySet +from .constants import SSID_MAX_LENGTH __all__ = ( 'WirelessLAN', + 'WirelessLink', ) @extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks') class WirelessLAN(PrimaryModel): """ - A service set identifier belonging to a wireless network. + A wireless network formed among an arbitrary number of access point and clients. """ ssid = models.CharField( - max_length=32 + max_length=SSID_MAX_LENGTH, + verbose_name='SSID' ) vlan = models.ForeignKey( to='ipam.VLAN', @@ -42,4 +45,78 @@ class WirelessLAN(PrimaryModel): return self.ssid def get_absolute_url(self): - return reverse('wireless:ssid', args=[self.pk]) + return reverse('wireless:wirelesslan', args=[self.pk]) + + +@extras_features('custom_fields', 'custom_links', 'export_templates', 'tags', 'webhooks') +class WirelessLink(PrimaryModel): + """ + A point-to-point connection between two wireless Interfaces. + """ + interface_a = models.ForeignKey( + to='dcim.Interface', + limit_choices_to={'type__in': WIRELESS_IFACE_TYPES}, + on_delete=models.PROTECT, + related_name='+' + ) + interface_b = models.ForeignKey( + to='dcim.Interface', + limit_choices_to={'type__in': WIRELESS_IFACE_TYPES}, + on_delete=models.PROTECT, + related_name='+' + ) + ssid = models.CharField( + max_length=SSID_MAX_LENGTH, + blank=True, + verbose_name='SSID' + ) + description = models.CharField( + max_length=200, + blank=True + ) + + # Cache the associated device for the A and B interfaces. This enables filtering of WirelessLinks by their + # associated Devices. + _interface_a_device = models.ForeignKey( + to='dcim.Device', + on_delete=models.CASCADE, + related_name='+', + blank=True, + null=True + ) + _interface_b_device = models.ForeignKey( + to='dcim.Device', + on_delete=models.CASCADE, + related_name='+', + blank=True, + null=True + ) + + objects = RestrictedQuerySet.as_manager() + + class Meta: + ordering = ['pk'] + unique_together = ('interface_a', 'interface_b') + + def get_absolute_url(self): + return reverse('wireless:wirelesslink', args=[self.pk]) + + def clean(self): + + # Validate interface types + if self.interface_a.type not in WIRELESS_IFACE_TYPES: + raise ValidationError({ + 'interface_a': f"{self.interface_a.get_type_display()} is not a wireless interface." + }) + if self.interface_b.type not in WIRELESS_IFACE_TYPES: + raise ValidationError({ + 'interface_a': f"{self.interface_b.get_type_display()} is not a wireless interface." + }) + + def save(self, *args, **kwargs): + + # Store the parent Device for the A and B interfaces + self._interface_a_device = self.interface_a.device + self._interface_b_device = self.interface_b.device + + super().save(*args, **kwargs) diff --git a/netbox/wireless/tables.py b/netbox/wireless/tables.py index 133353f57..31c9e56a8 100644 --- a/netbox/wireless/tables.py +++ b/netbox/wireless/tables.py @@ -1,10 +1,11 @@ import django_tables2 as tables -from .models import WirelessLAN +from .models import * from utilities.tables import BaseTable, TagColumn, ToggleColumn __all__ = ( 'WirelessLANTable', + 'WirelessLinkTable', ) @@ -21,3 +22,25 @@ class WirelessLANTable(BaseTable): model = WirelessLAN fields = ('pk', 'ssid', 'description', 'vlan') default_columns = ('pk', 'ssid', 'description', 'vlan') + + +class WirelessLinkTable(BaseTable): + pk = ToggleColumn() + id = tables.Column( + linkify=True, + verbose_name='ID' + ) + interface_a = tables.Column( + linkify=True + ) + interface_b = tables.Column( + linkify=True + ) + tags = TagColumn( + url_name='wireless:wirelesslink_list' + ) + + class Meta(BaseTable.Meta): + model = WirelessLink + fields = ('pk', 'id', 'interface_a', 'interface_b', 'ssid', 'description') + default_columns = ('pk', 'id', 'interface_a', 'interface_b', 'ssid', 'description') diff --git a/netbox/wireless/urls.py b/netbox/wireless/urls.py index c30ca472c..21d704e6a 100644 --- a/netbox/wireless/urls.py +++ b/netbox/wireless/urls.py @@ -19,4 +19,16 @@ urlpatterns = ( path('wireless-lans//changelog/', ObjectChangeLogView.as_view(), name='wirelesslan_changelog', kwargs={'model': WirelessLAN}), path('wireless-lans//journal/', ObjectJournalView.as_view(), name='wirelesslan_journal', kwargs={'model': WirelessLAN}), + # Wireless links + path('wireless-links/', views.WirelessLinkListView.as_view(), name='wirelesslink_list'), + path('wireless-links/add/', views.WirelessLinkEditView.as_view(), name='wirelesslink_add'), + path('wireless-links/import/', views.WirelessLinkBulkImportView.as_view(), name='wirelesslink_import'), + path('wireless-links/edit/', views.WirelessLinkBulkEditView.as_view(), name='wirelesslink_bulk_edit'), + path('wireless-links/delete/', views.WirelessLinkBulkDeleteView.as_view(), name='wirelesslink_bulk_delete'), + path('wireless-links//', views.WirelessLinkView.as_view(), name='wirelesslink'), + path('wireless-links//edit/', views.WirelessLinkEditView.as_view(), name='wirelesslink_edit'), + path('wireless-links//delete/', views.WirelessLinkDeleteView.as_view(), name='wirelesslink_delete'), + path('wireless-links//changelog/', ObjectChangeLogView.as_view(), name='wirelesslink_changelog', kwargs={'model': WirelessLink}), + path('wireless-links//journal/', ObjectJournalView.as_view(), name='wirelesslink_journal', kwargs={'model': WirelessLink}), + ) diff --git a/netbox/wireless/views.py b/netbox/wireless/views.py index 6e1c0b1b7..041ffbd42 100644 --- a/netbox/wireless/views.py +++ b/netbox/wireless/views.py @@ -44,3 +44,46 @@ class WirelessLANBulkDeleteView(generic.BulkDeleteView): queryset = WirelessLAN.objects.all() filterset = filtersets.WirelessLANFilterSet table = tables.WirelessLANTable + + +# +# Wireless Links +# + +class WirelessLinkListView(generic.ObjectListView): + queryset = WirelessLink.objects.all() + filterset = filtersets.WirelessLinkFilterSet + filterset_form = forms.WirelessLinkFilterForm + table = tables.WirelessLinkTable + + +class WirelessLinkView(generic.ObjectView): + queryset = WirelessLink.objects.all() + + +class WirelessLinkEditView(generic.ObjectEditView): + queryset = WirelessLink.objects.all() + model_form = forms.WirelessLinkForm + + +class WirelessLinkDeleteView(generic.ObjectDeleteView): + queryset = WirelessLink.objects.all() + + +class WirelessLinkBulkImportView(generic.BulkImportView): + queryset = WirelessLink.objects.all() + model_form = forms.WirelessLinkCSVForm + table = tables.WirelessLinkTable + + +class WirelessLinkBulkEditView(generic.BulkEditView): + queryset = WirelessLink.objects.all() + filterset = filtersets.WirelessLinkFilterSet + table = tables.WirelessLinkTable + form = forms.WirelessLinkBulkEditForm + + +class WirelessLinkBulkDeleteView(generic.BulkDeleteView): + queryset = WirelessLink.objects.all() + filterset = filtersets.WirelessLinkFilterSet + table = tables.WirelessLinkTable