ipfabric_netbox 4.3.0b6__py3-none-any.whl → 4.3.0b7__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of ipfabric_netbox might be problematic. Click here for more details.

@@ -6,7 +6,7 @@ class NetboxIPFabricConfig(PluginConfig):
6
6
  name = "ipfabric_netbox"
7
7
  verbose_name = "NetBox IP Fabric SoT Plugin"
8
8
  description = "Sync IP Fabric into NetBox"
9
- version = "4.3.0b6"
9
+ version = "4.3.0b7"
10
10
  base_url = "ipfabric"
11
11
  min_version = "4.4.0"
12
12
 
@@ -176,6 +176,7 @@ class IPFabricSnapshotSerializer(NestedGroupModelSerializer):
176
176
 
177
177
  class IPFabricSyncSerializer(NestedGroupModelSerializer):
178
178
  snapshot_data = IPFabricSnapshotSerializer(nested=True)
179
+ parameters = serializers.JSONField()
179
180
 
180
181
  class Meta:
181
182
  model = IPFabricSync
@@ -244,3 +245,7 @@ class IPFabricIngestionIssueSerializer(NestedGroupModelSerializer):
244
245
  "message",
245
246
  "model",
246
247
  )
248
+
249
+
250
+ class EmptySerializer(serializers.Serializer):
251
+ pass
@@ -1,10 +1,15 @@
1
+ from core.api.serializers_.jobs import JobSerializer
2
+ from django.core.exceptions import PermissionDenied
1
3
  from django.db import transaction
4
+ from django.http import HttpResponseBadRequest
5
+ from drf_spectacular.utils import extend_schema
2
6
  from netbox.api.viewsets import NetBoxModelViewSet
3
7
  from netbox.api.viewsets import NetBoxReadOnlyModelViewSet
4
8
  from rest_framework.decorators import action
5
9
  from rest_framework.response import Response
6
10
  from utilities.query import count_related
7
11
 
12
+ from .serializers import EmptySerializer
8
13
  from .serializers import IPFabricIngestionIssueSerializer
9
14
  from .serializers import IPFabricIngestionSerializer
10
15
  from .serializers import IPFabricRelationshipFieldSerializer
@@ -56,6 +61,27 @@ class IPFabricSyncViewSet(NetBoxModelViewSet):
56
61
  queryset = IPFabricSync.objects.all()
57
62
  serializer_class = IPFabricSyncSerializer
58
63
 
64
+ @extend_schema(
65
+ methods=["post"],
66
+ request=EmptySerializer(),
67
+ responses={201: JobSerializer()},
68
+ )
69
+ @action(detail=True, methods=["post"])
70
+ def sync(self, request, pk):
71
+ if not request.user.has_perm("ipfabric_netbox.sync_ipfabricsync"):
72
+ raise PermissionDenied(
73
+ "This user does not have permission to sync IPFabricSync."
74
+ )
75
+ sync = self.get_object()
76
+ if not sync.ready_for_sync:
77
+ return HttpResponseBadRequest(
78
+ f"Sync '{sync.name}' is not ready to be synced."
79
+ )
80
+ job = sync.enqueue_sync_job(user=request.user, adhoc=True)
81
+ return Response(
82
+ JobSerializer(job, context={"request": request}).data, status=201
83
+ )
84
+
59
85
 
60
86
  class IPFabricIngestionViewSet(NetBoxReadOnlyModelViewSet):
61
87
  queryset = IPFabricIngestion.objects.all()
@@ -122,3 +148,24 @@ class IPFabricSourceViewSet(NetBoxModelViewSet):
122
148
  )
123
149
  serializer_class = IPFabricSourceSerializer
124
150
  filterset_class = IPFabricSourceFilterSet
151
+
152
+ @extend_schema(
153
+ methods=["post"],
154
+ request=EmptySerializer(),
155
+ responses={201: JobSerializer()},
156
+ )
157
+ @action(detail=True, methods=["post"])
158
+ def sync(self, request, pk):
159
+ if not request.user.has_perm("ipfabric_netbox.sync_ipfabricsource"):
160
+ raise PermissionDenied(
161
+ "This user does not have permission to sync IPFabricSource."
162
+ )
163
+ source = self.get_object()
164
+ if not source.ready_for_sync:
165
+ return HttpResponseBadRequest(
166
+ f"Source '{source.name}' is not ready to be synced."
167
+ )
168
+ job = source.enqueue_sync_job(request=request)
169
+ return Response(
170
+ JobSerializer(job, context={"request": request}).data, status=201
171
+ )
ipfabric_netbox/forms.py CHANGED
@@ -802,11 +802,7 @@ class IPFabricSyncForm(NetBoxModelForm):
802
802
  ]
803
803
  self.instance.parameters = parameters
804
804
  self.instance.status = DataSourceStatusChoices.NEW
805
-
806
- object = super().save(*args, **kwargs)
807
- if object.scheduled:
808
- object.enqueue_sync_job()
809
- return object
805
+ return super().save(*args, **kwargs)
810
806
 
811
807
 
812
808
  class IPFabricSyncBulkEditForm(NetBoxModelBulkEditForm):
ipfabric_netbox/models.py CHANGED
@@ -669,6 +669,11 @@ class IPFabricSync(IPFabricClient, JobsMixin, TagsMixin, ChangeLoggedModel):
669
669
  def get_status_color(self):
670
670
  return DataSourceStatusChoices.colors.get(self.status)
671
671
 
672
+ def save(self, *args, **kwargs):
673
+ super().save(*args, **kwargs)
674
+ if self.scheduled:
675
+ self.enqueue_sync_job()
676
+
672
677
  @property
673
678
  def ready_for_sync(self):
674
679
  if self.status not in (DataSourceStatusChoices.SYNCING,):
@@ -58,7 +58,7 @@
58
58
  </tr>
59
59
  <tr>
60
60
  <th scope="row">Schedule</th>
61
- <td><div>{{ object.scheduled }}</div></td>
61
+ <td><div>{% if scheduled_job %}<a href="{% url 'core:job' pk=scheduled_job.pk %}">{{ object.scheduled }}</a>{% else %} {{ object.scheduled | placeholder }} {% endif %}</div></td>
62
62
  </tr>
63
63
  <tr>
64
64
  <th scope="row">Interval</th>
@@ -1,3 +1,4 @@
1
+ from core.choices import DataSourceStatusChoices
1
2
  from django.contrib.contenttypes.models import ContentType
2
3
  from django.utils import timezone
3
4
  from rest_framework import status
@@ -15,7 +16,7 @@ from ipfabric_netbox.models import IPFabricTransformMap
15
16
  from ipfabric_netbox.models import IPFabricTransformMapGroup
16
17
 
17
18
 
18
- BASE = "/api/plugins/ipfabric/"
19
+ BASE = "/api/plugins/ipfabric"
19
20
 
20
21
 
21
22
  class IPFabricTransformMapGroupTest(APIViewTestCases.APIViewTestCase):
@@ -36,10 +37,10 @@ class IPFabricTransformMapGroupTest(APIViewTestCases.APIViewTestCase):
36
37
  }
37
38
 
38
39
  def _get_list_url(self):
39
- return f"{BASE}transform-map-group/"
40
+ return f"{BASE}/transform-map-group/"
40
41
 
41
42
  def _get_detail_url(self, instance):
42
- return f"{BASE}transform-map-group/{instance.pk}/"
43
+ return f"{BASE}/transform-map-group/{instance.pk}/"
43
44
 
44
45
  @classmethod
45
46
  def setUpTestData(cls):
@@ -62,10 +63,10 @@ class IPFabricTransformMapTest(APIViewTestCases.APIViewTestCase):
62
63
  ]
63
64
 
64
65
  def _get_list_url(self):
65
- return f"{BASE}transform-map/"
66
+ return f"{BASE}/transform-map/"
66
67
 
67
68
  def _get_detail_url(self, instance):
68
- return f"{BASE}transform-map/{instance.pk}/"
69
+ return f"{BASE}/transform-map/{instance.pk}/"
69
70
 
70
71
  @classmethod
71
72
  def setUpTestData(cls):
@@ -132,10 +133,10 @@ class IPFabricTransformFieldTest(APIViewTestCases.APIViewTestCase):
132
133
  ]
133
134
 
134
135
  def _get_list_url(self):
135
- return f"{BASE}transform-field/"
136
+ return f"{BASE}/transform-field/"
136
137
 
137
138
  def _get_detail_url(self, instance):
138
- return f"{BASE}transform-field/{instance.pk}/"
139
+ return f"{BASE}/transform-field/{instance.pk}/"
139
140
 
140
141
  @classmethod
141
142
  def setUpTestData(cls):
@@ -235,10 +236,10 @@ class IPFabricRelationshipFieldTest(APIViewTestCases.APIViewTestCase):
235
236
  ]
236
237
 
237
238
  def _get_list_url(self):
238
- return f"{BASE}relationship-field/"
239
+ return f"{BASE}/relationship-field/"
239
240
 
240
241
  def _get_detail_url(self, instance):
241
- return f"{BASE}relationship-field/{instance.pk}/"
242
+ return f"{BASE}/relationship-field/{instance.pk}/"
242
243
 
243
244
  @classmethod
244
245
  def setUpTestData(cls):
@@ -340,10 +341,10 @@ class IPFabricSourceTest(APIViewTestCases.APIViewTestCase):
340
341
  graphql_base_name = "ipfabric_source"
341
342
 
342
343
  def _get_list_url(self):
343
- return f"{BASE}source/"
344
+ return f"{BASE}/source/"
344
345
 
345
346
  def _get_detail_url(self, instance):
346
- return f"{BASE}source/{instance.pk}/"
347
+ return f"{BASE}/source/{instance.pk}/"
347
348
 
348
349
  @classmethod
349
350
  def setUpTestData(cls):
@@ -387,6 +388,66 @@ class IPFabricSourceTest(APIViewTestCases.APIViewTestCase):
387
388
  },
388
389
  ]
389
390
 
391
+ def test_sync_action_success(self):
392
+ """Test successful sync action with proper permissions and ready source."""
393
+ self.add_permissions(
394
+ "ipfabric_netbox.add_ipfabricsource",
395
+ "ipfabric_netbox.sync_ipfabricsource",
396
+ )
397
+ # Get the first source from setUpTestData
398
+ source = IPFabricSource.objects.first()
399
+ # Set status to make ready_for_sync return True
400
+ source.status = DataSourceStatusChoices.COMPLETED
401
+ source.save()
402
+
403
+ with self.settings(CELERY_TASK_ALWAYS_EAGER=True):
404
+ # Create a mock job object to simulate enqueue_sync_job response
405
+ from unittest.mock import Mock, patch
406
+
407
+ mock_job = Mock()
408
+ mock_job.id = "test-job-123"
409
+ mock_job.status = "queued"
410
+
411
+ with patch.object(source, "enqueue_sync_job", return_value=mock_job):
412
+ url = f"{BASE}/source/{source.pk}/sync/"
413
+ response = self.client.post(url, **self.header)
414
+
415
+ self.assertHttpStatus(response, status.HTTP_201_CREATED)
416
+ self.assertIn("id", response.data)
417
+
418
+ def test_sync_action_permission_denied(self):
419
+ """Test sync action without proper permissions."""
420
+ # Note: Not adding sync_ipfabricsource permission
421
+ self.add_permissions(
422
+ "ipfabric_netbox.add_ipfabricsource",
423
+ )
424
+
425
+ source = IPFabricSource.objects.first()
426
+ url = f"{BASE}/source/{source.pk}/sync/"
427
+ response = self.client.post(url, **self.header)
428
+
429
+ self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
430
+
431
+ def test_sync_action_not_ready(self):
432
+ """Test sync action when source is not ready for sync."""
433
+ self.add_permissions(
434
+ "ipfabric_netbox.add_ipfabricsource",
435
+ "ipfabric_netbox.sync_ipfabricsource",
436
+ )
437
+
438
+ source = IPFabricSource.objects.first()
439
+ # Set status to make ready_for_sync return False
440
+ source.status = DataSourceStatusChoices.SYNCING
441
+ source.save()
442
+
443
+ url = f"{BASE}/source/{source.pk}/sync/"
444
+ response = self.client.post(url, **self.header)
445
+
446
+ self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
447
+ self.assertIn(
448
+ f"Source '{source.name}' is not ready to be synced.", str(response.content)
449
+ )
450
+
390
451
 
391
452
  class IPFabricSnapshotTest(
392
453
  APIViewTestCases.GetObjectViewTestCase,
@@ -407,10 +468,10 @@ class IPFabricSnapshotTest(
407
468
  ]
408
469
 
409
470
  def _get_list_url(self):
410
- return f"{BASE}snapshot/"
471
+ return f"{BASE}/snapshot/"
411
472
 
412
473
  def _get_detail_url(self, instance):
413
- return f"{BASE}snapshot/{instance.pk}/"
474
+ return f"{BASE}/snapshot/{instance.pk}/"
414
475
 
415
476
  @classmethod
416
477
  def setUpTestData(cls):
@@ -468,7 +529,7 @@ class IPFabricSnapshotTest(
468
529
  def test_sites_action_lists_all_and_filters(self):
469
530
  self.add_permissions("ipfabric_netbox.view_ipfabricsnapshot")
470
531
  # list all
471
- url = f"{BASE}snapshot/{self.snapshots[0].pk}/sites/"
532
+ url = f"{BASE}/snapshot/{self.snapshots[0].pk}/sites/"
472
533
  resp = self.client.get(url, **self.header)
473
534
  self.assertHttpStatus(resp, status.HTTP_200_OK)
474
535
  body = resp.json()
@@ -477,7 +538,7 @@ class IPFabricSnapshotTest(
477
538
  labels = [i["name"] for i in body["results"]]
478
539
  self.assertEqual(labels, self.snapshots[0].data["sites"])
479
540
  # filter
480
- url = f"{BASE}snapshot/{self.snapshots[0].pk}/sites/?q=site"
541
+ url = f"{BASE}/snapshot/{self.snapshots[0].pk}/sites/?q=site"
481
542
  resp = self.client.get(url, **self.header)
482
543
  self.assertHttpStatus(resp, status.HTTP_200_OK)
483
544
  body = resp.json()
@@ -496,7 +557,7 @@ class IPFabricSnapshotTest(
496
557
  IPFabricData.objects.filter(snapshot_data=self.snapshots[0]).count(), 0
497
558
  )
498
559
  # PATCH raw
499
- url = f"{BASE}snapshot/{self.snapshots[0].pk}/raw/"
560
+ url = f"{BASE}/snapshot/{self.snapshots[0].pk}/raw/"
500
561
  payload = {
501
562
  "data": [
502
563
  {"data": {"example": 1}, "type": "device"},
@@ -550,10 +611,10 @@ class IPFabricSyncTest(APIViewTestCases.APIViewTestCase):
550
611
  }
551
612
 
552
613
  def _get_list_url(self):
553
- return f"{BASE}sync/"
614
+ return f"{BASE}/sync/"
554
615
 
555
616
  def _get_detail_url(self, instance):
556
- return f"{BASE}sync/{instance.pk}/"
617
+ return f"{BASE}/sync/{instance.pk}/"
557
618
 
558
619
  @classmethod
559
620
  def setUpTestData(cls):
@@ -637,6 +698,72 @@ class IPFabricSyncTest(APIViewTestCases.APIViewTestCase):
637
698
  cls.create_data[1]["parameters"] = {"ipaddress": True, "prefix": True}
638
699
  cls.create_data[2]["parameters"] = {"device": True, "interface": True}
639
700
 
701
+ def test_sync_action_success(self):
702
+ """Test successful sync action with proper permissions and ready sync."""
703
+ self.add_permissions(
704
+ "ipfabric_netbox.add_ipfabricsync",
705
+ "ipfabric_netbox.sync_ipfabricsync",
706
+ )
707
+ # Get the first sync from setUpTestData
708
+ sync = IPFabricSync.objects.first()
709
+ # Set status and ensure snapshot has data to make ready_for_sync return True
710
+ sync.status = DataSourceStatusChoices.COMPLETED
711
+ sync.save()
712
+
713
+ # Ensure the snapshot has data
714
+ sync.snapshot_data.source.type = (
715
+ "local" # For local type, ready_for_sync checks are simpler
716
+ )
717
+ sync.snapshot_data.source.save()
718
+
719
+ with self.settings(CELERY_TASK_ALWAYS_EAGER=True):
720
+ # Create a mock job object to simulate enqueue_sync_job response
721
+ from unittest.mock import Mock, patch
722
+
723
+ mock_job = Mock()
724
+ mock_job.id = "test-sync-job-456"
725
+ mock_job.status = "queued"
726
+
727
+ with patch.object(sync, "enqueue_sync_job", return_value=mock_job):
728
+ url = f"{BASE}/sync/{sync.pk}/sync/"
729
+ response = self.client.post(url, **self.header)
730
+
731
+ self.assertHttpStatus(response, status.HTTP_201_CREATED)
732
+ self.assertIn("id", response.data)
733
+
734
+ def test_sync_action_permission_denied(self):
735
+ """Test sync action without proper permissions."""
736
+ # Note: Not adding sync_ipfabricsource permission
737
+ self.add_permissions(
738
+ "ipfabric_netbox.add_ipfabricsync",
739
+ )
740
+
741
+ sync = IPFabricSync.objects.first()
742
+ url = f"{BASE}/sync/{sync.pk}/sync/"
743
+ response = self.client.post(url, **self.header)
744
+
745
+ self.assertHttpStatus(response, status.HTTP_403_FORBIDDEN)
746
+
747
+ def test_sync_action_not_ready(self):
748
+ """Test sync action when sync is not ready for sync."""
749
+ self.add_permissions(
750
+ "ipfabric_netbox.add_ipfabricsync",
751
+ "ipfabric_netbox.sync_ipfabricsync",
752
+ )
753
+
754
+ sync = IPFabricSync.objects.first()
755
+ # Set status to make ready_for_sync return False
756
+ sync.status = DataSourceStatusChoices.SYNCING
757
+ sync.save()
758
+
759
+ url = f"{BASE}/sync/{sync.pk}/sync/"
760
+ response = self.client.post(url, **self.header)
761
+
762
+ self.assertHttpStatus(response, status.HTTP_400_BAD_REQUEST)
763
+ self.assertIn(
764
+ f"Sync '{sync.name}' is not ready to be synced.", str(response.content)
765
+ )
766
+
640
767
 
641
768
  class IPFabricIngestionTest(
642
769
  APIViewTestCases.GetObjectViewTestCase,
@@ -653,10 +780,10 @@ class IPFabricIngestionTest(
653
780
  ]
654
781
 
655
782
  def _get_list_url(self):
656
- return f"{BASE}ingestion/"
783
+ return f"{BASE}/ingestion/"
657
784
 
658
785
  def _get_detail_url(self, instance):
659
- return f"{BASE}ingestion/{instance.pk}/"
786
+ return f"{BASE}/ingestion/{instance.pk}/"
660
787
 
661
788
  @classmethod
662
789
  def setUpTestData(cls):
@@ -754,10 +881,10 @@ class IPFabricIngestionIssueTest(
754
881
  ]
755
882
 
756
883
  def _get_list_url(self):
757
- return f"{BASE}ingestion-issues/"
884
+ return f"{BASE}/ingestion-issues/"
758
885
 
759
886
  def _get_detail_url(self, instance):
760
- return f"{BASE}ingestion-issues/{instance.pk}/"
887
+ return f"{BASE}/ingestion-issues/{instance.pk}/"
761
888
 
762
889
  @classmethod
763
890
  def setUpTestData(cls):
@@ -1,4 +1,5 @@
1
1
  import random
2
+ from datetime import timedelta
2
3
  from unittest.mock import patch
3
4
  from uuid import uuid4
4
5
 
@@ -611,7 +612,7 @@ class IPFabricSyncTestCase(
611
612
  # ViewTestCases.BulkImportObjectsViewTestCase,
612
613
  ):
613
614
  model = IPFabricSync
614
- user_permissions = ("ipfabric_netbox.start_ipfabricsync",)
615
+ user_permissions = ("ipfabric_netbox.sync_ipfabricsync",)
615
616
 
616
617
  @classmethod
617
618
  def setUpTestData(cls):
@@ -656,6 +657,8 @@ class IPFabricSyncTestCase(
656
657
  status=DataSourceStatusChoices.NEW,
657
658
  parameters=get_parameters(),
658
659
  last_synced=timezone.now(),
660
+ scheduled=timezone.now() + timedelta(hours=6),
661
+ interval=123456,
659
662
  ),
660
663
  IPFabricSync(
661
664
  name="Sync Job 2",
ipfabric_netbox/views.py CHANGED
@@ -782,7 +782,15 @@ class IPFabricSyncView(generic.ObjectView):
782
782
 
783
783
  last_ingestion = instance.ipfabricingestion_set.last()
784
784
 
785
- return {"format": format, "last_ingestion": last_ingestion}
785
+ scheduled_job = None
786
+ if instance.scheduled:
787
+ scheduled_job = instance.jobs.filter(scheduled=instance.scheduled).last()
788
+
789
+ return {
790
+ "format": format,
791
+ "last_ingestion": last_ingestion,
792
+ "scheduled_job": scheduled_job,
793
+ }
786
794
 
787
795
 
788
796
  @register_model_view(IPFabricSync, "sync")
@@ -790,7 +798,7 @@ class IPFabricStartSyncView(BaseObjectView):
790
798
  queryset = IPFabricSync.objects.all()
791
799
 
792
800
  def get_required_permission(self):
793
- return "ipfabric_netbox.start_ipfabricsync"
801
+ return "ipfabric_netbox.sync_ipfabricsync"
794
802
 
795
803
  def get(self, request, pk):
796
804
  ipfabric = get_object_or_404(self.queryset, pk=pk)
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: ipfabric_netbox
3
- Version: 4.3.0b6
3
+ Version: 4.3.0b7
4
4
  Summary: NetBox plugin to sync IP Fabric data into NetBox
5
5
  License: MIT
6
6
  Keywords: netbox,ipfabric,plugin,sync
@@ -1,13 +1,13 @@
1
- ipfabric_netbox/__init__.py,sha256=-W7W2QVW8zRl8VHGc4Pgv6uo7r0otVcpDjE3vuvPyFw,674
1
+ ipfabric_netbox/__init__.py,sha256=p6HeR0kRnjcO4U5wSyEk81T3wJrEExUzfnzzvurzjl4,674
2
2
  ipfabric_netbox/api/__init__.py,sha256=XRclTGWVR0ZhAAwgYul5Wm_loug5_hUjEumbLQEwKYM,47
3
- ipfabric_netbox/api/serializers.py,sha256=7cmVsIzGzz9u6htLKizLr2Ar0OC7uV8rMX3U7EzRmG4,6482
3
+ ipfabric_netbox/api/serializers.py,sha256=lr_PWG0tqAxaKtkIIm8Gx2B-tn9yENQIfKY9cvu8Cco,6581
4
4
  ipfabric_netbox/api/urls.py,sha256=1fXXVTxNY5E64Nfz6b7zXD9bZI3FcefuxAWKMe0w_QU,1240
5
- ipfabric_netbox/api/views.py,sha256=gluK311fDx3sLsQ6iE6O1M_s3Kz1_sjD0sfmWR_UE2Q,5064
5
+ ipfabric_netbox/api/views.py,sha256=qOBTIzPtOBY75tTjirsTBbiRXrQQid478Tp15-WKbmQ,6859
6
6
  ipfabric_netbox/choices.py,sha256=gXRV_c04OnQl_kJTsAH1k88u8PWbiVXvcYwufZPKMdM,5035
7
7
  ipfabric_netbox/data/transform_map.json,sha256=4PsucgMHcLW3SPoKEptQCd0gA5tCF4hjrR4bGQFCWy8,21744
8
8
  ipfabric_netbox/exceptions.py,sha256=DT4dpbakvqoROtBR_F0LzvQCMNWpGhufFcUbZTx0OLY,2655
9
9
  ipfabric_netbox/filtersets.py,sha256=vaWlxf8DTwduv_aQ35kJxwyzmM1XvE781GjUj2z4QGQ,7845
10
- ipfabric_netbox/forms.py,sha256=nSEOlqPDvxgFuWVVmRf4AvubfMEAqh0ZlyyfoMQurCk,50024
10
+ ipfabric_netbox/forms.py,sha256=WI1OypOG4Zqry6jiH991ZBVBMnfwzUDhNJAZCUQNaUg,49932
11
11
  ipfabric_netbox/graphql/__init__.py,sha256=-a5w_VY7pc-RVt8MvThkTzeAqCC3xCan4Ue6iMefmjI,754
12
12
  ipfabric_netbox/graphql/enums.py,sha256=QFhwiwUKJekxQfsOGk_-70_WnkzrKEP_zIBMrin0S0Q,1343
13
13
  ipfabric_netbox/graphql/filters.py,sha256=B8xy9r9a18vWfV6a6tHXAN1FUcoxI6MOrbsdNmzusNI,12991
@@ -35,7 +35,7 @@ ipfabric_netbox/migrations/0017_ipfabricsync_update_custom_fields.py,sha256=IVbA
35
35
  ipfabric_netbox/migrations/0018_remove_type_field.py,sha256=ffxW6IS3BLCbvM5M9DbDb_x6spMmRxnV1iq8IuXxMGw,385
36
36
  ipfabric_netbox/migrations/0019_alter_ipfabrictransformmap_options_and_more.py,sha256=ieDVedt9KpJBicAiC3kdZXzHeos12N0L9EdRXKmIVgY,501
37
37
  ipfabric_netbox/migrations/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
38
- ipfabric_netbox/models.py,sha256=czXxzdEWyVJKDEG1cK9tDvnoltD2guv42UboK0Cekis,36956
38
+ ipfabric_netbox/models.py,sha256=P2oLmXDgDswrPDMtvQcuy_inl53-RBcghoV7Uu2I3q4,37095
39
39
  ipfabric_netbox/navigation.py,sha256=2dEJ_wKHb52Tl0FOV1TH3JbxRe8YZ56ewrTsBFGKpCg,2210
40
40
  ipfabric_netbox/signals.py,sha256=cGa5PVD2i24pGXiVNfbu6ruIDqPVdwKQHTSWe9Ura84,1838
41
41
  ipfabric_netbox/tables.py,sha256=BpPmL6-KClX16Ol_PIADyOx9NtDR9oauXH5iO4GeSoI,9008
@@ -54,7 +54,7 @@ ipfabric_netbox/templates/ipfabric_netbox/ipfabric_table.html,sha256=TsF34lK2CyD
54
54
  ipfabric_netbox/templates/ipfabric_netbox/ipfabricingestion.html,sha256=fm_X2FLnoTS6s6AL3WmU6p3puDojROSkPG0jA4EBQeM,4435
55
55
  ipfabric_netbox/templates/ipfabric_netbox/ipfabricsnapshot.html,sha256=hj8ORs_4mM_xTjmw3McHN-da5seC8nbbkzobn0f1TSc,3482
56
56
  ipfabric_netbox/templates/ipfabric_netbox/ipfabricsource.html,sha256=DQOA2TA7f1nI5YpxXthS1VzjIU1kMZus37l6bYSCauE,3869
57
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html,sha256=vgkxhJBWnfuZmDxfstLFJEAXc7FCY8Q7Hcu2MydI45A,4480
57
+ ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html,sha256=dt8HYuHCzIN4otLS9QK3e1aES14isFI-1jyp8jrENXU,4616
58
58
  ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap.html,sha256=qFo_Ku5oksx5co4HVtVq0xAVFI6CLWs-iBrwYzGsEGA,1460
59
59
  ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_list.html,sha256=p8zqn0-B6mawSUM3zQrus6dsKUM5SRBTO0X94pLboX8,452
60
60
  ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap_restore.html,sha256=TV7gAZWtSd-c7mzOen_nv7Z8MZr2Vw8vkHP4zW9au4w,2580
@@ -71,17 +71,17 @@ ipfabric_netbox/templatetags/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NM
71
71
  ipfabric_netbox/templatetags/ipfabric_netbox_helpers.py,sha256=STw4pAd2qG7hgf-O6UNTwsO5VqEa_gxf5wLv50BWL4Q,417
72
72
  ipfabric_netbox/tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
73
73
  ipfabric_netbox/tests/api/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
74
- ipfabric_netbox/tests/api/test_api.py,sha256=-pW0xRqHUEr574HFL27C3FE77slI_bEh3Y5nfPDfcao,30283
74
+ ipfabric_netbox/tests/api/test_api.py,sha256=9o9k4kfnT3Zz9Hg0qnI0_XASt6pi5BCZQ3RhBjsb_iE,35215
75
75
  ipfabric_netbox/tests/test_forms.py,sha256=C8giV6E3PbMB9_864C12ebvfQ3Vlvdn39VIQQSP6GV8,61566
76
76
  ipfabric_netbox/tests/test_models.py,sha256=FFrIT5xxv_yvujKpxGjRJPNPBDF2Pqi8zbY0vxuJeQs,16043
77
- ipfabric_netbox/tests/test_views.py,sha256=ofKGbj3aSzl9l0CrdeLpcXBnCpVfsodKfYB9Q4L_F_c,87645
77
+ ipfabric_netbox/tests/test_views.py,sha256=6R4Ri8Y54Eg-9u5nmrWLNOp0794Y-JugcBAJGk22GEc,87771
78
78
  ipfabric_netbox/urls.py,sha256=qF2BzZEDnPRd3opFaRfiMdaarYKFfv69iMaAbU2rsBU,2702
79
79
  ipfabric_netbox/utilities/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
80
80
  ipfabric_netbox/utilities/ipfutils.py,sha256=wFmL5oriuF-is1ZlrIcLmoeYUY5ih-CA9weRQrx5AiA,31885
81
81
  ipfabric_netbox/utilities/logging.py,sha256=GYknjocMN6LQ2873_az3y0RKm29TCXaWviUIIneH-x0,3445
82
82
  ipfabric_netbox/utilities/nbutils.py,sha256=kFBEiJOGvr_49hJWCS2duXojx2-A9kVk0Xp_vj0ohfs,2641
83
83
  ipfabric_netbox/utilities/transform_map.py,sha256=GpM_7Mm6FE0qV2qbyj4YfDn0l-JkeeEHQOZkNVSSHk4,2391
84
- ipfabric_netbox/views.py,sha256=np1aYd9tBy7yERAhtwXMJvi2vDoXTkTx_ayLglw1LJ0,44521
85
- ipfabric_netbox-4.3.0b6.dist-info/METADATA,sha256=yIiT8CpHWwHj8ynUd48Q1YFpHwheTUaMtQ_aBKedL8I,4754
86
- ipfabric_netbox-4.3.0b6.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
87
- ipfabric_netbox-4.3.0b6.dist-info/RECORD,,
84
+ ipfabric_netbox/views.py,sha256=n3tTDs1xOAY5xtcMmhM6VrnpEr-2IzqeliFNgthQf1U,44746
85
+ ipfabric_netbox-4.3.0b7.dist-info/METADATA,sha256=zK1X88R7MzrYCMgp9AGN-V0DWgjSJUJwuuS-NcEYtKo,4754
86
+ ipfabric_netbox-4.3.0b7.dist-info/WHEEL,sha256=zp0Cn7JsFoX2ATtOhtaFYIiE2rmFAD4OcMhtUki8W3U,88
87
+ ipfabric_netbox-4.3.0b7.dist-info/RECORD,,