1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00
Jeremy Stretch deee36651d Merge pull request #10120 from arthanson/art-10086
fix for #10086 - change capitalization on wireless link table for Interface A, B and Auth Type
2022-08-24 08:46:24 -04:00

226 lines
5.8 KiB
Python

from django.apps import apps
from django.core.exceptions import ValidationError
from django.db import models
from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey
from dcim.choices import LinkStatusChoices
from dcim.constants import WIRELESS_IFACE_TYPES
from netbox.models import NestedGroupModel, NetBoxModel
from .choices import *
from .constants import *
__all__ = (
'WirelessLAN',
'WirelessLANGroup',
'WirelessLink',
)
class WirelessAuthenticationBase(models.Model):
"""
Abstract model for attaching attributes related to wireless authentication.
"""
auth_type = models.CharField(
max_length=50,
choices=WirelessAuthTypeChoices,
blank=True,
verbose_name="Auth Type",
)
auth_cipher = models.CharField(
max_length=50,
choices=WirelessAuthCipherChoices,
blank=True
)
auth_psk = models.CharField(
max_length=PSK_MAX_LENGTH,
blank=True,
verbose_name='Pre-shared key'
)
class Meta:
abstract = True
class WirelessLANGroup(NestedGroupModel):
"""
A nested grouping of WirelessLANs
"""
name = models.CharField(
max_length=100,
unique=True
)
slug = models.SlugField(
max_length=100,
unique=True
)
parent = TreeForeignKey(
to='self',
on_delete=models.CASCADE,
related_name='children',
blank=True,
null=True,
db_index=True
)
description = models.CharField(
max_length=200,
blank=True
)
class Meta:
ordering = ('name', 'pk')
unique_together = (
('parent', 'name')
)
verbose_name = 'Wireless LAN Group'
def __str__(self):
return self.name
def get_absolute_url(self):
return reverse('wireless:wirelesslangroup', args=[self.pk])
class WirelessLAN(WirelessAuthenticationBase, NetBoxModel):
"""
A wireless network formed among an arbitrary number of access point and clients.
"""
ssid = models.CharField(
max_length=SSID_MAX_LENGTH,
verbose_name='SSID'
)
group = models.ForeignKey(
to='wireless.WirelessLANGroup',
on_delete=models.SET_NULL,
related_name='wireless_lans',
blank=True,
null=True
)
vlan = models.ForeignKey(
to='ipam.VLAN',
on_delete=models.PROTECT,
blank=True,
null=True,
verbose_name='VLAN'
)
tenant = models.ForeignKey(
to='tenancy.Tenant',
on_delete=models.PROTECT,
related_name='wireless_lans',
blank=True,
null=True
)
description = models.CharField(
max_length=200,
blank=True
)
clone_fields = ('ssid', 'group', 'tenant', 'description')
class Meta:
ordering = ('ssid', 'pk')
verbose_name = 'Wireless LAN'
def __str__(self):
return self.ssid
def get_absolute_url(self):
return reverse('wireless:wirelesslan', args=[self.pk])
class WirelessLink(WirelessAuthenticationBase, NetBoxModel):
"""
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='+',
verbose_name="Interface A",
)
interface_b = models.ForeignKey(
to='dcim.Interface',
limit_choices_to={'type__in': WIRELESS_IFACE_TYPES},
on_delete=models.PROTECT,
related_name='+',
verbose_name="Interface B",
)
ssid = models.CharField(
max_length=SSID_MAX_LENGTH,
blank=True,
verbose_name='SSID'
)
status = models.CharField(
max_length=50,
choices=LinkStatusChoices,
default=LinkStatusChoices.STATUS_CONNECTED
)
tenant = models.ForeignKey(
to='tenancy.Tenant',
on_delete=models.PROTECT,
related_name='wireless_links',
blank=True,
null=True
)
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
)
clone_fields = ('ssid', 'status')
class Meta:
ordering = ['pk']
unique_together = ('interface_a', 'interface_b')
def __str__(self):
return f'#{self.pk}'
@classmethod
def get_prerequisite_models(cls):
return [apps.get_model('dcim.Interface'), ]
def get_absolute_url(self):
return reverse('wireless:wirelesslink', args=[self.pk])
def get_status_color(self):
return LinkStatusChoices.colors.get(self.status)
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)