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

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

@@ -1,7 +1,7 @@
 from rest_framework import serializers
 from rest_framework import serializers
 from taggit_serializer.serializers import TaggitSerializer, TagListSerializerField
 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 circuits.models import Provider, Circuit, CircuitTermination, CircuitType
 from dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer
 from dcim.api.nested_serializers import NestedCableSerializer, NestedSiteSerializer
 from dcim.api.serializers import ConnectedEndpointSerializer
 from dcim.api.serializers import ConnectedEndpointSerializer
@@ -41,7 +41,7 @@ class CircuitTypeSerializer(ValidatedModelSerializer):
 
 
 class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
 class CircuitSerializer(TaggitSerializer, CustomFieldModelSerializer):
     provider = NestedProviderSerializer()
     provider = NestedProviderSerializer()
-    status = ChoiceField(choices=CIRCUIT_STATUS_CHOICES, required=False)
+    status = ChoiceField(choices=CircuitStatusChoices, required=False)
     type = NestedCircuitTypeSerializer()
     type = NestedCircuitTypeSerializer()
     tenant = NestedTenantSerializer(required=False, allow_null=True)
     tenant = NestedTenantSerializer(required=False, allow_null=True)
     tags = TagListSerializerField(required=False)
     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
 # CircuitTermination sides
 TERM_SIDE_A = 'A'
 TERM_SIDE_A = 'A'
 TERM_SIDE_Z = 'Z'
 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 extras.filters import CustomFieldFilterSet
 from tenancy.filtersets import TenancyFilterSet
 from tenancy.filtersets import TenancyFilterSet
 from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
 from utilities.filters import NameSlugSearchFilterSet, NumericInFilter, TagFilter, TreeNodeMultipleChoiceFilter
+from .choices import *
 from .constants import *
 from .constants import *
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 
 
@@ -84,7 +85,7 @@ class CircuitFilter(CustomFieldFilterSet, TenancyFilterSet):
         label='Circuit type (slug)',
         label='Circuit type (slug)',
     )
     )
     status = django_filters.MultipleChoiceFilter(
     status = django_filters.MultipleChoiceFilter(
-        choices=CIRCUIT_STATUS_CHOICES,
+        choices=CircuitStatusChoices,
         null_value=None
         null_value=None
     )
     )
     site_id = django_filters.ModelMultipleChoiceFilter(
     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,
     APISelect, APISelectMultiple, add_blank_choice, BootstrapMixin, CommentField, CSVChoiceField,
     FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
     FilterChoiceField, SmallTextarea, SlugField, StaticSelect2, StaticSelect2Multiple
 )
 )
+from .choices import CircuitStatusChoices
 from .constants import *
 from .constants import *
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 from .models import Circuit, CircuitTermination, CircuitType, Provider
 
 
@@ -194,7 +195,7 @@ class CircuitCSVForm(forms.ModelForm):
         }
         }
     )
     )
     status = CSVChoiceField(
     status = CSVChoiceField(
-        choices=CIRCUIT_STATUS_CHOICES,
+        choices=CircuitStatusChoices,
         required=False,
         required=False,
         help_text='Operational status'
         help_text='Operational status'
     )
     )
@@ -235,7 +236,7 @@ class CircuitBulkEditForm(BootstrapMixin, AddRemoveTagsForm, CustomFieldBulkEdit
         )
         )
     )
     )
     status = forms.ChoiceField(
     status = forms.ChoiceField(
-        choices=add_blank_choice(CIRCUIT_STATUS_CHOICES),
+        choices=add_blank_choice(CircuitStatusChoices),
         required=False,
         required=False,
         initial='',
         initial='',
         widget=StaticSelect2()
         widget=StaticSelect2()
@@ -292,7 +293,7 @@ class CircuitFilterForm(BootstrapMixin, TenancyFilterForm, CustomFieldFilterForm
         )
         )
     )
     )
     status = forms.MultipleChoiceField(
     status = forms.MultipleChoiceField(
-        choices=CIRCUIT_STATUS_CHOICES,
+        choices=CircuitStatusChoices,
         required=False,
         required=False,
         widget=StaticSelect2Multiple()
         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 extras.models import CustomFieldModel, ObjectChange, TaggedItem
 from utilities.models import ChangeLoggedModel
 from utilities.models import ChangeLoggedModel
 from utilities.utils import serialize_object
 from utilities.utils import serialize_object
+from .choices import *
 from .constants import *
 from .constants import *
 
 
 
 
@@ -132,9 +133,10 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
         on_delete=models.PROTECT,
         on_delete=models.PROTECT,
         related_name='circuits'
         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(
     tenant = models.ForeignKey(
         to='tenancy.Tenant',
         to='tenancy.Tenant',
@@ -171,6 +173,15 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
         'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'commit_rate', 'description', 'comments',
         '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:
     class Meta:
         ordering = ['provider', 'cid']
         ordering = ['provider', 'cid']
         unique_together = ['provider', 'cid']
         unique_together = ['provider', 'cid']
@@ -195,7 +206,7 @@ class Circuit(ChangeLoggedModel, CustomFieldModel):
         )
         )
 
 
     def get_status_class(self):
     def get_status_class(self):
-        return STATUS_CLASSES[self.status]
+        return self.STATUS_CLASS_MAP.get(self.status)
 
 
     def _get_termination(self, side):
     def _get_termination(self, side):
         for ct in self.terminations.all():
         for ct in self.terminations.all():

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

@@ -1,9 +1,10 @@
 from django.urls import reverse
 from django.urls import reverse
 from rest_framework import status
 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 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.constants import GRAPH_TYPE_PROVIDER
 from extras.models import Graph
 from extras.models import Graph
 from utilities.testing import APITestCase
 from utilities.testing import APITestCase
@@ -250,7 +251,7 @@ class CircuitTest(APITestCase):
             'cid': 'TEST0004',
             'cid': 'TEST0004',
             'provider': self.provider1.pk,
             'provider': self.provider1.pk,
             'type': self.circuittype1.pk,
             'type': self.circuittype1.pk,
-            'status': CIRCUIT_STATUS_ACTIVE,
+            'status': CircuitStatusChoices.STATUS_ACTIVE,
         }
         }
 
 
         url = reverse('circuits-api:circuit-list')
         url = reverse('circuits-api:circuit-list')
@@ -270,19 +271,19 @@ class CircuitTest(APITestCase):
                 'cid': 'TEST0004',
                 'cid': 'TEST0004',
                 'provider': self.provider1.pk,
                 'provider': self.provider1.pk,
                 'type': self.circuittype1.pk,
                 'type': self.circuittype1.pk,
-                'status': CIRCUIT_STATUS_ACTIVE,
+                'status': CircuitStatusChoices.STATUS_ACTIVE,
             },
             },
             {
             {
                 'cid': 'TEST0005',
                 'cid': 'TEST0005',
                 'provider': self.provider1.pk,
                 'provider': self.provider1.pk,
                 'type': self.circuittype1.pk,
                 'type': self.circuittype1.pk,
-                'status': CIRCUIT_STATUS_ACTIVE,
+                'status': CircuitStatusChoices.STATUS_ACTIVE,
             },
             },
             {
             {
                 'cid': 'TEST0006',
                 'cid': 'TEST0006',
                 'provider': self.provider1.pk,
                 'provider': self.provider1.pk,
                 'type': self.circuittype1.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
     Metaclass for ChoiceSet
     """
     """
     def __call__(cls, *args, **kwargs):
     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', ())
         return getattr(cls, 'CHOICES', ())
 
 
     def __iter__(cls):
     def __iter__(cls):