Jeremy Stretch 6 лет назад
Родитель
Сommit
e09ad6915f

+ 2 - 2
netbox/circuits/api/serializers.py

@@ -1,7 +1,7 @@
 from rest_framework import serializers
 from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
 
-from circuits.constants import CIRCUIT_STATUS_CHOICES
+from circuits.choices import CircuitStatusChoices
 from circuits.models import Provider, Circuit, CircuitTermination, CircuitType
 from dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer
 from dcim.api.serializers import ConnectedEndpointSerializer
@@ -41,7 +41,7 @@ class CircuitTypeSerializer(ValidatedModelSerializer):
 
 class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
     provider = NestedProviderSerializer()
-    status = ChoiceField(choices=CIRCUIT_STATUS_CHOICES, required=False)
+    status = ChoiceField(choices=CircuitStatusChoices, required=False)
     type = NestedCircuitTypeSerializer()
     tenant = NestedTenantSerializer(required=False, allow_null=True)
     tags = TagListSerializerField(required=False)

+ 29 - 0
netbox/circuits/choices.py

@@ -0,0 +1,29 @@
+from utilities.choices import ChoiceSet
+
+
+class CircuitStatusChoices(ChoiceSet):
+
+    STATUS_DEPROVISIONING = 'deprovisioning'
+    STATUS_ACTIVE = 'active'
+    STATUS_PLANNED = 'planned'
+    STATUS_PROVISIONING = 'provisioning'
+    STATUS_OFFLINE = 'offline'
+    STATUS_DECOMMISSIONED = 'decommissioned'
+
+    CHOICES = (
+        (STATUS_PLANNED, 'Planned'),
+        (STATUS_PROVISIONING, 'Provisioning'),
+        (STATUS_ACTIVE, 'Active'),
+        (STATUS_OFFLINE, 'Offline'),
+        (STATUS_DEPROVISIONING, 'Deprovisioning'),
+        (STATUS_DECOMMISSIONED, 'Decommissioned'),
+    )
+
+    LEGACY_MAP = {
+        STATUS_DEPROVISIONING: 0,
+        STATUS_ACTIVE: 1,
+        STATUS_PLANNED: 2,
+        STATUS_PROVISIONING: 3,
+        STATUS_OFFLINE: 4,
+        STATUS_DECOMMISSIONED: 5,
+    }

+ 0 - 16
netbox/circuits/constants.py

@@ -1,19 +1,3 @@
-# Circuit statuses
-CIRCUIT_STATUS_DEPROVISIONING = 0
-CIRCUIT_STATUS_ACTIVE = 1
-CIRCUIT_STATUS_PLANNED = 2
-CIRCUIT_STATUS_PROVISIONING = 3
-CIRCUIT_STATUS_OFFLINE = 4
-CIRCUIT_STATUS_DECOMMISSIONED = 5
-CIRCUIT_STATUS_CHOICES = [
-    [CIRCUIT_STATUS_PLANNED, 'Planned'],
-    [CIRCUIT_STATUS_PROVISIONING, 'Provisioning'],
-    [CIRCUIT_STATUS_ACTIVE, 'Active'],
-    [CIRCUIT_STATUS_OFFLINE, 'Offline'],
-    [CIRCUIT_STATUS_DEPROVISIONING, 'Deprovisioning'],
-    [CIRCUIT_STATUS_DECOMMISSIONED, 'Decommissioned'],
-]
-
 # CircuitTermination sides
 TERM_SIDE_A = 'A'
 TERM_SIDE_Z = 'Z'

+ 2 - 1
netbox/circuits/filters.py

@@ -5,6 +5,7 @@ from dcim.models import Region, Site
 from extras.filters import CustomFieldFilterSet
 from tenancy.filtersets import TenancyFilterSet
 from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
+from .choices import *
 from .constants import *
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 
@@ -84,7 +85,7 @@ class CircuitFilter(CustomFieldFilterSet, TenancyFilterSet):
         label='Circuit type (slug)',
     )
     status = django_filters.MultipleChoiceFilter(
-        choices=CIRCUIT_STATUS_CHOICES,
+        choices=CircuitStatusChoices,
         null_value=None
     )
     site_id = django_filters.ModelMultipleChoiceFilter(

+ 4 - 3
netbox/circuits/forms.py

@@ -9,6 +9,7 @@ from utilities.forms import (
     APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
     FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
 )
+from .choices import CircuitStatusChoices
 from .constants import *
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 
@@ -194,7 +195,7 @@ class CircuitCSVForm(forms.ModelForm):
         }
     )
     status = CSVChoiceField(
-        choices=CIRCUIT_STATUS_CHOICES,
+        choices=CircuitStatusChoices,
         required=False,
         help_text='Operational status'
     )
@@ -235,7 +236,7 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
         )
     )
     status = forms.ChoiceField(
-        choices=add_blank_choice(CIRCUIT_STATUS_CHOICES),
+        choices=add_blank_choice(CircuitStatusChoices),
         required=False,
         initial='',
         widget=StaticSelect2()
@@ -292,7 +293,7 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm
         )
     )
     status = forms.MultipleChoiceField(
-        choices=CIRCUIT_STATUS_CHOICES,
+        choices=CircuitStatusChoices,
         required=False,
         widget=StaticSelect2Multiple()
     )

+ 37 - 0
netbox/circuits/migrations/0016_circuit_status_slug.py

@@ -0,0 +1,37 @@
+# Generated by Django 2.2.6 on 2019-11-07 03:36
+
+from django.db import migrations, models
+
+
+CIRCUIT_STATUS_CHOICES = (
+    (0, 'deprovisioning'),
+    (1, 'active'),
+    (2, 'planned'),
+    (3, 'provisioning'),
+    (4, 'offline'),
+    (5, 'decommissioned')
+)
+
+
+def circuit_status_to_slug(apps, schema_editor):
+    Circuit = apps.get_model('circuits', 'Circuit')
+    for id, slug in CIRCUIT_STATUS_CHOICES:
+        Circuit.objects.filter(status=str(id)).update(status=slug)
+
+
+class Migration(migrations.Migration):
+
+    dependencies = [
+        ('circuits', '0015_custom_tag_models'),
+    ]
+
+    operations = [
+        migrations.AlterField(
+            model_name='circuit',
+            name='status',
+            field=models.CharField(default='active', max_length=50),
+        ),
+        migrations.RunPython(
+            code=circuit_status_to_slug
+        )
+    ]

+ 15 - 4
netbox/circuits/models.py

@@ -9,6 +9,7 @@ from dcim.models import CableTermination
 from extras.models import CustomFieldModel, ObjectChange, TaggedItem
 from utilities.models import ChangeLoggedModel
 from utilities.utils import serialize_object
+from .choices import *
 from .constants import *
 
 
@@ -132,9 +133,10 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
         on_delete=models.PROTECT,
         related_name='circuits'
     )
-    status = models.PositiveSmallIntegerField(
-        choices=CIRCUIT_STATUS_CHOICES,
-        default=CIRCUIT_STATUS_ACTIVE
+    status = models.CharField(
+        max_length=50,
+        choices=CircuitStatusChoices,
+        default=CircuitStatusChoices.STATUS_ACTIVE
     )
     tenant = models.ForeignKey(
         to='tenancy.Tenant',
@@ -171,6 +173,15 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
         'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
     ]
 
+    STATUS_CLASS_MAP = {
+        CircuitStatusChoices.STATUS_DEPROVISIONING: 'warning',
+        CircuitStatusChoices.STATUS_ACTIVE: 'success',
+        CircuitStatusChoices.STATUS_PLANNED: 'info',
+        CircuitStatusChoices.STATUS_PROVISIONING: 'primary',
+        CircuitStatusChoices.STATUS_OFFLINE: 'danger',
+        CircuitStatusChoices.STATUS_DECOMMISSIONED: 'default',
+    }
+
     class Meta:
         ordering = ['provider', 'cid']
         unique_together = ['provider', 'cid']
@@ -195,7 +206,7 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
         )
 
     def get_status_class(self):
-        return STATUS_CLASSES[self.status]
+        return self.STATUS_CLASS_MAP.get(self.status)
 
     def _get_termination(self, side):
         for ct in self.terminations.all():

+ 7 - 6
netbox/circuits/tests/test_api.py

@@ -1,9 +1,10 @@
 from django.urls import reverse
 from rest_framework import status
 
-from circuits.constants import CIRCUIT_STATUS_ACTIVE, TERM_SIDE_A, TERM_SIDE_Z
+from circuits.choices import CircuitStatusChoices
+from circuits.constants import TERM_SIDE_A, TERM_SIDE_Z
 from circuits.models import Circuit, CircuitTermination, CircuitType, Provider
-from dcim.models import Device, DeviceRole, DeviceType, Interface, Manufacturer, Site
+from dcim.models import Site
 from extras.constants import GRAPH_TYPE_PROVIDER
 from extras.models import Graph
 from utilities.testing import APITestCase
@@ -250,7 +251,7 @@ class CircuitTest(APITestCase):
             'cid': 'TEST0004',
             'provider': self.provider1.pk,
             'type': self.circuittype1.pk,
-            'status': CIRCUIT_STATUS_ACTIVE,
+            'status': CircuitStatusChoices.STATUS_ACTIVE,
         }
 
         url = reverse('circuits-api:circuit-list')
@@ -270,19 +271,19 @@ class CircuitTest(APITestCase):
                 'cid': 'TEST0004',
                 'provider': self.provider1.pk,
                 'type': self.circuittype1.pk,
-                'status': CIRCUIT_STATUS_ACTIVE,
+                'status': CircuitStatusChoices.STATUS_ACTIVE,
             },
             {
                 'cid': 'TEST0005',
                 'provider': self.provider1.pk,
                 'type': self.circuittype1.pk,
-                'status': CIRCUIT_STATUS_ACTIVE,
+                'status': CircuitStatusChoices.STATUS_ACTIVE,
             },
             {
                 'cid': 'TEST0006',
                 'provider': self.provider1.pk,
                 'type': self.circuittype1.pk,
-                'status': CIRCUIT_STATUS_ACTIVE,
+                'status': CircuitStatusChoices.STATUS_ACTIVE,
             },
         ]
 

+ 1 - 1
netbox/utilities/choices.py

@@ -3,7 +3,7 @@ class ChoiceSetMeta(type):
     Metaclass for ChoiceSet
     """
     def __call__(cls, *args, **kwargs):
-        # Django will check if a choices value is callable, and if so assume that it returns an iterable
+        # Django will check if a 'choices' value is callable, and if so assume that it returns an iterable
         return getattr(cls, 'CHOICES', ())
 
     def __iter__(cls):