ipfabric_netbox 4.0.1b0__py3-none-any.whl → 4.0.1b2__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.

@@ -3,6 +3,7 @@
3
3
  {% load helpers %}
4
4
  {% load plugins %}
5
5
  {% load render_table from django_tables2 %}
6
+ {% load ipfabric_netbox_helpers %}
6
7
 
7
8
  {% block extra_controls %}
8
9
  {% if perms.ipfabric_netbox.start_sync %}
@@ -81,8 +82,22 @@
81
82
  {% for name, field in object.parameters.items %}
82
83
  <tr>
83
84
  <th scope="row">{{ name }}</th>
84
- <td>{{ object.parameters|get_key:name|placeholder }}</td>
85
- </tr>
85
+ <td>
86
+ {% if name == "groups" %}
87
+ {{"["}}
88
+ {% for group_id in object.parameters|get_key:name %}
89
+ {% with group=group_id|resolve_object:"ipfabric_netbox.IPFabricTransformMapGroup" %}
90
+ <a href="{% url 'plugins:ipfabric_netbox:ipfabrictransformmapgroup' pk=group.pk %}">{{ group }}</a>{% if not forloop.last %}, {% endif %}
91
+ {% endwith %}
92
+ {% empty %}
93
+ <span class="text-muted">No groups assigned</span>
94
+ {% endfor %}
95
+ {{"]"}}
96
+ {% else %}
97
+ {{ object.parameters|get_key:name|placeholder }}
98
+ {% endif %}
99
+ </td>
100
+ </tr>
86
101
  {% empty %}
87
102
  <tr>
88
103
  <td colspan="2" class="text-muted">
@@ -4,6 +4,18 @@
4
4
  {% load plugins %}
5
5
  {% load render_table from django_tables2 %}
6
6
 
7
+ {% block extra_controls %}
8
+ <a href="#"
9
+ hx-get="{% url 'plugins:ipfabric_netbox:ipfabrictransformmap_clone' pk=object.pk %}"
10
+ hx-target="#htmx-modal-content"
11
+ class="btn btn-primary"
12
+ data-bs-toggle="modal"
13
+ data-bs-target="#htmx-modal" disabled
14
+ >
15
+ <span class="mdi mdi-content-copy" aria-hidden="true"></span>&nbsp;Clone
16
+ </a>
17
+ {% endblock %}
18
+
7
19
  {% block content %}
8
20
  <div class="row mb-3">
9
21
  <div class="col col-md-6">
@@ -15,6 +27,10 @@
15
27
  <th scope="row">Name</th>
16
28
  <td>{{ object.name }}</td>
17
29
  </tr>
30
+ <tr>
31
+ <th scope="row">Group</th>
32
+ <td>{{ object.group | linkify | placeholder}}</td>
33
+ </tr>
18
34
  <tr>
19
35
  <th scope="row">Source Model</th>
20
36
  <td>ipfabric | {{ object.source_model }}</td>
@@ -23,7 +39,6 @@
23
39
  <th scope="row">Target Model</th>
24
40
  <td>{{ object.target_model }}</td>
25
41
  </tr>
26
- </tr>
27
42
  </table>
28
43
  </div>
29
44
  </div>
@@ -0,0 +1,35 @@
1
+ {% extends 'generic/object.html' %}
2
+ {% load static %}
3
+ {% load helpers %}
4
+ {% load plugins %}
5
+ {% load render_table from django_tables2 %}
6
+
7
+ {% block content %}
8
+ <div class="row mb-3">
9
+ <div class="col col-md-6">
10
+ <div class="card">
11
+ <h5 class="card-header">Transform Map Group Information</h5>
12
+ <div class="card-body">
13
+ <table class="table table-hover attr-table">
14
+ <tr>
15
+ <th scope="row">Name</th>
16
+ <td>{{ object.name }}</td>
17
+ </tr>
18
+ <tr>
19
+ <th scope="row">Description</th>
20
+ <td>{{ object.description | placeholder }}</td>
21
+ </tr>
22
+ </tr>
23
+ </table>
24
+ </div>
25
+ </div>
26
+ {% plugin_left_page object %}
27
+ </div>
28
+ <div class="col col-12 col-md-6">
29
+ {% include 'inc/panels/related_objects.html' %}
30
+ {% include 'inc/panels/comments.html' %}
31
+ {% include 'inc/panels/custom_fields.html' %}
32
+ {% plugin_right_page object %}
33
+ </div>
34
+ </div>
35
+ {% endblock %}
File without changes
@@ -0,0 +1,17 @@
1
+ from django import template
2
+ from django.apps import apps
3
+
4
+ register = template.Library()
5
+
6
+
7
+ @register.filter()
8
+ def resolve_object(pk, model_path):
9
+ """
10
+ Usage: {{ pk|resolve_object:"app_label.ModelName" }}
11
+ """
12
+ try:
13
+ app_label, model_name = model_path.split(".")
14
+ model = apps.get_model(app_label, model_name)
15
+ return model.objects.get(pk=pk)
16
+ except Exception:
17
+ return None
@@ -139,7 +139,6 @@ class IPFabricTransformMapModelTestCase(TestCase):
139
139
  )
140
140
 
141
141
  runner = IPFabricSyncRunner(
142
- transform_map=IPFabricTransformMap,
143
142
  settings={
144
143
  "site": True,
145
144
  "sites": [],
@@ -325,7 +324,6 @@ class IPFabricTransformMapModelTestCase(TestCase):
325
324
  sync = IPFabricSync.objects.get(name="ingest")
326
325
 
327
326
  runner = IPFabricSyncRunner(
328
- transform_map=IPFabricTransformMap,
329
327
  settings={
330
328
  "site": True,
331
329
  "sites": [],
ipfabric_netbox/urls.py CHANGED
@@ -78,6 +78,31 @@ urlpatterns = (
78
78
  "ingestion/<int:pk>/",
79
79
  include(get_model_urls("ipfabric_netbox", "ipfabricingestion")),
80
80
  ),
81
+ # Transform Map Group
82
+ path(
83
+ "transform-map-group/",
84
+ views.IPFabricTransformMapGroupListView.as_view(),
85
+ name="ipfabrictransformmapgroup_list",
86
+ ),
87
+ path(
88
+ "transform-map-group/add",
89
+ views.IPFabricTransformMapGroupEditView.as_view(),
90
+ name="ipfabrictransformmapgroup_add",
91
+ ),
92
+ path(
93
+ "transform-map-group/delete/",
94
+ views.IPFabricTransformMapGroupBulkDeleteView.as_view(),
95
+ name="ipfabrictransformmapgroup_bulk_delete",
96
+ ),
97
+ path(
98
+ "transform-map-group/<int:pk>/",
99
+ include(get_model_urls("ipfabric_netbox", "ipfabrictransformmapgroup")),
100
+ ),
101
+ path(
102
+ "transform-map-group/<int:pk>/delete/",
103
+ views.IPFabricTransformMapGroupDeleteView.as_view(),
104
+ name="ipfabrictransformmapgroup_delete",
105
+ ),
81
106
  # Transform Map
82
107
  path(
83
108
  "transform-map/",
@@ -60,7 +60,7 @@ def render_jinja2(template_code, context):
60
60
 
61
61
 
62
62
  class IPFabric(object):
63
- def __init__(self, parameters=None, transform_map=None) -> None:
63
+ def __init__(self, parameters=None) -> None:
64
64
  if parameters:
65
65
  self.ipf = IPFClient(**parameters, unloaded=True)
66
66
  else:
@@ -70,7 +70,6 @@ class IPFabric(object):
70
70
  self.ipf._client.headers[
71
71
  "user-agent"
72
72
  ] += f'; ipfabric-netbox/{metadata.version("ipfabric-netbox")}' # noqa: E702
73
- self.transform_map = transform_map
74
73
 
75
74
  def get_snapshots(self) -> dict:
76
75
  formatted_snapshots = {}
@@ -129,8 +128,7 @@ class IPFabric(object):
129
128
  class IPFabricSyncRunner(object):
130
129
  def __init__(
131
130
  self,
132
- transform_map,
133
- sync=None,
131
+ sync,
134
132
  client: IPFabric = None,
135
133
  ingestion=None,
136
134
  settings: dict = None,
@@ -138,8 +136,8 @@ class IPFabricSyncRunner(object):
138
136
  self.client = client
139
137
  self.settings = settings
140
138
  self.ingestion = ingestion
141
- self.transform_map = transform_map
142
139
  self.sync = sync
140
+ self.transform_maps = sync.get_transform_maps(sync.parameters.get("groups"))
143
141
  if hasattr(self.sync, "logger"):
144
142
  self.logger = self.sync.logger
145
143
 
@@ -185,9 +183,9 @@ class IPFabricSyncRunner(object):
185
183
  return connection_name
186
184
 
187
185
  def get_model_or_update(self, app, model, data):
188
- transform_map = self.transform_map.objects.filter(
186
+ transform_map = self.transform_maps.get(
189
187
  target_model__app_label=app, target_model__model=model
190
- ).first()
188
+ )
191
189
 
192
190
  if not transform_map:
193
191
  raise SystemError(f"No transform map available for {app}: {model}")
@@ -451,12 +449,10 @@ class IPFabricSyncRunner(object):
451
449
 
452
450
  interface_key = "nameOriginal"
453
451
  try:
454
- int_transform_map = self.transform_map.objects.filter(
452
+ int_transform_map = self.transform_maps.get(
455
453
  target_model__app_label="dcim", target_model__model="interface"
456
- ).first()
457
- int_name_field_map = int_transform_map.field_maps.filter(
458
- target_field="name"
459
- ).first()
454
+ )
455
+ int_name_field_map = int_transform_map.field_maps.get(target_field="name")
460
456
  interface_key = int_name_field_map.source_field
461
457
  except Exception as e:
462
458
  self.logger.log_failure(
@@ -1,14 +1,14 @@
1
1
  import importlib.resources
2
2
  import json
3
3
 
4
- from django.apps import apps
4
+ from django.apps import apps as django_apps
5
5
 
6
6
  # These functions are used in the migration file to prepare the transform maps
7
7
  # Because of this we have to use historical models
8
8
  # see https://docs.djangoproject.com/en/5.1/topics/migrations/#historical-models
9
9
 
10
10
 
11
- def build_fields(data):
11
+ def build_fields(data, apps):
12
12
  ContentType = apps.get_model("contenttypes", "ContentType")
13
13
  if "target_model" in data:
14
14
  ct = ContentType.objects.get_for_model(
@@ -29,20 +29,21 @@ def build_fields(data):
29
29
  return data
30
30
 
31
31
 
32
- def build_transform_maps(data):
32
+ def build_transform_maps(data, apps: django_apps = None):
33
+ apps = apps or django_apps
33
34
  IPFabricTransformMap = apps.get_model("ipfabric_netbox", "IPFabricTransformMap")
34
35
  IPFabricTransformField = apps.get_model("ipfabric_netbox", "IPFabricTransformField")
35
36
  IPFabricRelationshipField = apps.get_model(
36
37
  "ipfabric_netbox", "IPFabricRelationshipField"
37
38
  )
38
39
  for tm in data:
39
- field_data = build_fields(tm["data"])
40
+ field_data = build_fields(tm["data"], apps)
40
41
  tm_obj = IPFabricTransformMap.objects.create(**field_data)
41
42
  for fm in tm["field_maps"]:
42
- field_data = build_fields(fm)
43
+ field_data = build_fields(fm, apps)
43
44
  IPFabricTransformField.objects.create(transform_map=tm_obj, **field_data)
44
45
  for rm in tm["relationship_maps"]:
45
- relationship_data = build_fields(rm)
46
+ relationship_data = build_fields(rm, apps)
46
47
  IPFabricRelationshipField.objects.create(
47
48
  transform_map=tm_obj, **relationship_data
48
49
  )
ipfabric_netbox/views.py CHANGED
@@ -6,6 +6,8 @@ from django.contrib.auth.mixins import LoginRequiredMixin
6
6
  from django.core.cache import cache
7
7
  from django.core.exceptions import ValidationError
8
8
  from django.db import models
9
+ from django.db import transaction
10
+ from django.http import HttpResponse
9
11
  from django.shortcuts import get_object_or_404
10
12
  from django.shortcuts import redirect
11
13
  from django.shortcuts import render
@@ -20,10 +22,12 @@ from netbox.views.generic.base import BaseObjectView
20
22
  from netbox_branching.models import ChangeDiff
21
23
  from utilities.data import shallow_compare_dict
22
24
  from utilities.forms import ConfirmationForm
25
+ from utilities.forms import restrict_form_fields
23
26
  from utilities.paginator import EnhancedPaginator
24
27
  from utilities.paginator import get_paginate_count
25
28
  from utilities.query import count_related
26
29
  from utilities.views import get_viewname
30
+ from utilities.views import GetRelatedModelsMixin
27
31
  from utilities.views import register_model_view
28
32
  from utilities.views import ViewTab
29
33
 
@@ -32,6 +36,8 @@ from .filtersets import IPFabricIngestionChangeFilterSet
32
36
  from .filtersets import IPFabricIngestionFilterSet
33
37
  from .filtersets import IPFabricSnapshotFilterSet
34
38
  from .filtersets import IPFabricSourceFilterSet
39
+ from .filtersets import IPFabricTransformMapFilterSet
40
+ from .filtersets import IPFabricTransformMapGroupFilterSet
35
41
  from .forms import IPFabricIngestionFilterForm
36
42
  from .forms import IPFabricIngestionMergeForm
37
43
  from .forms import IPFabricRelationshipFieldForm
@@ -41,7 +47,9 @@ from .forms import IPFabricSourceForm
41
47
  from .forms import IPFabricSyncForm
42
48
  from .forms import IPFabricTableForm
43
49
  from .forms import IPFabricTransformFieldForm
50
+ from .forms import IPFabricTransformMapCloneForm
44
51
  from .forms import IPFabricTransformMapForm
52
+ from .forms import IPFabricTransformMapGroupForm
45
53
  from .models import IPFabricData
46
54
  from .models import IPFabricIngestion
47
55
  from .models import IPFabricRelationshipField
@@ -50,6 +58,7 @@ from .models import IPFabricSource
50
58
  from .models import IPFabricSync
51
59
  from .models import IPFabricTransformField
52
60
  from .models import IPFabricTransformMap
61
+ from .models import IPFabricTransformMapGroup
53
62
  from .tables import DeviceIPFTable
54
63
  from .tables import IPFabricDataTable
55
64
  from .tables import IPFabricIngestionChangesTable
@@ -58,6 +67,7 @@ from .tables import IPFabricRelationshipFieldTable
58
67
  from .tables import IPFabricSnapshotTable
59
68
  from .tables import IPFabricSourceTable
60
69
  from .tables import IPFabricTransformFieldTable
70
+ from .tables import IPFabricTransformMapGroupTable
61
71
  from .tables import IPFabricTransformMapTable
62
72
  from .utilities.ipfutils import IPFabric
63
73
  from .utilities.transform_map import build_transform_maps
@@ -102,6 +112,44 @@ class IPFabricRelationshipFieldListView(generic.ObjectListView):
102
112
  table = IPFabricRelationshipFieldTable
103
113
 
104
114
 
115
+ # Transform Map Group
116
+
117
+
118
+ class IPFabricTransformMapGroupListView(generic.ObjectListView):
119
+ queryset = IPFabricTransformMapGroup.objects.annotate(
120
+ maps_count=models.Count("transform_maps")
121
+ )
122
+ table = IPFabricTransformMapGroupTable
123
+ filterset = IPFabricTransformMapGroupFilterSet
124
+
125
+
126
+ @register_model_view(IPFabricTransformMapGroup, "edit")
127
+ class IPFabricTransformMapGroupEditView(generic.ObjectEditView):
128
+ queryset = IPFabricTransformMapGroup.objects.all()
129
+ form = IPFabricTransformMapGroupForm
130
+ default_return_url = "plugins:ipfabric_netbox:ipfabrictransformmapgroup_list"
131
+
132
+
133
+ class IPFabricTransformMapGroupDeleteView(generic.ObjectDeleteView):
134
+ queryset = IPFabricTransformMapGroup.objects.all()
135
+ default_return_url = "plugins:ipfabric_netbox:ipfabrictransformmapgroup_list"
136
+
137
+
138
+ class IPFabricTransformMapGroupBulkDeleteView(generic.BulkDeleteView):
139
+ queryset = IPFabricTransformMapGroup.objects.all()
140
+ table = IPFabricTransformMapGroupTable
141
+
142
+
143
+ @register_model_view(IPFabricTransformMapGroup)
144
+ class IPFabricTransformMapGroupView(GetRelatedModelsMixin, generic.ObjectView):
145
+ queryset = IPFabricTransformMapGroup.objects.all()
146
+
147
+ def get_extra_context(self, request, instance):
148
+ return {
149
+ "related_models": self.get_related_models(request, instance, omit=[]),
150
+ }
151
+
152
+
105
153
  # Transform Map
106
154
 
107
155
 
@@ -109,6 +157,7 @@ class IPFabricTransformMapListView(generic.ObjectListView):
109
157
  queryset = IPFabricTransformMap.objects.all()
110
158
  table = IPFabricTransformMapTable
111
159
  template_name = "ipfabric_netbox/ipfabrictransformmap_list.html"
160
+ filterset = IPFabricTransformMapFilterSet
112
161
 
113
162
 
114
163
  class IPFabricTransformMapRestoreView(generic.ObjectListView):
@@ -124,11 +173,16 @@ class IPFabricTransformMapRestoreView(generic.ObjectListView):
124
173
  form_url = reverse(viewname)
125
174
  form = ConfirmationForm(initial=request.GET)
126
175
  dependent_objects = {
127
- IPFabricTransformMap: IPFabricTransformMap.objects.all(),
128
- IPFabricTransformField: IPFabricTransformField.objects.all(),
129
- IPFabricRelationshipField: IPFabricRelationshipField.objects.all(),
176
+ IPFabricTransformMap: IPFabricTransformMap.objects.filter(
177
+ group__isnull=True
178
+ ),
179
+ IPFabricTransformField: IPFabricTransformField.objects.filter(
180
+ transform_map__group__isnull=True
181
+ ),
182
+ IPFabricRelationshipField: IPFabricRelationshipField.objects.filter(
183
+ transform_map__group__isnull=True
184
+ ),
130
185
  }
131
- print(dependent_objects)
132
186
  return render(
133
187
  request,
134
188
  "ipfabric_netbox/ipfabrictransformmap_restore.html",
@@ -140,7 +194,7 @@ class IPFabricTransformMapRestoreView(generic.ObjectListView):
140
194
  )
141
195
 
142
196
  def post(self, request):
143
- IPFabricTransformMap.objects.all().delete()
197
+ IPFabricTransformMap.objects.filter(group__isnull=True).delete()
144
198
  build_transform_maps(data=get_transform_map())
145
199
  return redirect("plugins:ipfabric_netbox:ipfabrictransformmap_list")
146
200
 
@@ -152,6 +206,115 @@ class IPFabricTransformMapEditView(generic.ObjectEditView):
152
206
  default_return_url = "plugins:ipfabric_netbox:ipfabrictransformmap_list"
153
207
 
154
208
 
209
+ @register_model_view(IPFabricTransformMap, "clone")
210
+ class IPFabricTransformMapCloneView(BaseObjectView):
211
+ queryset = IPFabricTransformMap.objects.all()
212
+ template_name = "ipfabric_netbox/inc/clone_form.html"
213
+ form = IPFabricTransformMapCloneForm
214
+
215
+ def get_required_permission(self):
216
+ return "ipfabric_netbox.ipfabrictransformmap_add"
217
+
218
+ def get(self, request, pk):
219
+ obj = get_object_or_404(self.queryset, pk=pk)
220
+ if request.htmx:
221
+ viewname = get_viewname(self.queryset.model, action="clone")
222
+ form_url = reverse(viewname, kwargs={"pk": obj.pk})
223
+ initial = request.GET.copy()
224
+ initial["name"] = f"Clone of {obj.name}"
225
+ form = self.form(initial=initial)
226
+ restrict_form_fields(form, request.user)
227
+ return render(
228
+ request,
229
+ self.template_name,
230
+ {
231
+ "object": obj,
232
+ "form": form,
233
+ "pk": pk,
234
+ "form_url": form_url,
235
+ },
236
+ )
237
+ return redirect(obj.get_absolute_url())
238
+
239
+ def post(self, request, pk):
240
+ obj = get_object_or_404(self.queryset, pk=pk)
241
+ form = self.form(request.POST)
242
+ restrict_form_fields(form, request.user)
243
+ try:
244
+ if form.is_valid():
245
+ with transaction.atomic():
246
+ fields = IPFabricTransformField.objects.filter(transform_map=obj)
247
+ relationships = IPFabricRelationshipField.objects.filter(
248
+ transform_map=obj
249
+ )
250
+ # Clone the transform map
251
+ new_map = obj
252
+ new_map.pk = None
253
+ new_map.id = None
254
+ new_map.name = form.cleaned_data["name"]
255
+ new_map.group = form.cleaned_data["group"]
256
+ new_map.full_clean()
257
+ new_map.save()
258
+ new_map.refresh_from_db()
259
+
260
+ # Clone related transform fields
261
+ if form.cleaned_data["clone_fields"]:
262
+ for field in fields:
263
+ field.pk = None
264
+ field.id = None
265
+ field.transform_map = new_map
266
+ field.full_clean()
267
+ field.save()
268
+
269
+ # Clone related relationship fields
270
+ if form.cleaned_data["clone_relationships"]:
271
+ for rel in relationships:
272
+ rel.pk = None
273
+ rel.id = None
274
+ rel.transform_map = new_map
275
+ rel.full_clean()
276
+ rel.save()
277
+
278
+ return_url = reverse(
279
+ "plugins:ipfabric_netbox:ipfabrictransformmap", args=[obj.pk]
280
+ )
281
+ if request.htmx:
282
+ response = HttpResponse()
283
+ response["HX-Redirect"] = return_url
284
+ return response
285
+ return redirect(return_url)
286
+ except ValidationError as err:
287
+ if not err.error_dict:
288
+ form.add_error(None, err)
289
+ else:
290
+ # This serves to show errors in the form directly
291
+ for field, error in err.error_dict.items():
292
+ if field in form.fields:
293
+ form.add_error(field, error)
294
+ else:
295
+ form.add_error(None, error)
296
+ if request.htmx:
297
+ response = render(
298
+ request,
299
+ "ipfabric_netbox/inc/clone_form.html",
300
+ {
301
+ "form": form,
302
+ "object": obj,
303
+ "pk": pk,
304
+ },
305
+ )
306
+ response["X-Debug-HTMX-Partial"] = "true"
307
+ return response
308
+ return render(
309
+ request,
310
+ self.template_name,
311
+ {
312
+ "form": form,
313
+ "object": obj,
314
+ },
315
+ )
316
+
317
+
155
318
  class IPFabricTransformMapDeleteView(generic.ObjectDeleteView):
156
319
  queryset = IPFabricTransformMap.objects.all()
157
320
  default_return_url = "plugins:ipfabric_netbox:ipfabrictransformmap_list"
@@ -462,6 +625,26 @@ class IPFabricSyncBulkDeleteView(generic.BulkDeleteView):
462
625
  table = IPFabricSnapshotTable
463
626
 
464
627
 
628
+ @register_model_view(IPFabricSync, "transformmaps")
629
+ class IPFabricTransformMapTabView(generic.ObjectChildrenView):
630
+ queryset = IPFabricSync.objects.all()
631
+ child_model = IPFabricTransformMap
632
+ table = IPFabricTransformMapTable
633
+ template_name = "generic/object_children.html"
634
+ tab = ViewTab(
635
+ label="Transform Maps",
636
+ badge=lambda obj: obj.get_transform_maps(
637
+ obj.parameters.get("groups", []) if obj.parameters else []
638
+ ).count(),
639
+ permission="ipfabric_netbox.view_ipfabrictransformmap",
640
+ )
641
+
642
+ def get_children(self, request, parent):
643
+ return parent.get_transform_maps(
644
+ parent.parameters.get("groups", []) if parent.parameters else []
645
+ )
646
+
647
+
465
648
  # Ingestion
466
649
  class IPFabricIngestionListView(generic.ObjectListView):
467
650
  queryset = IPFabricIngestion.objects.annotate(
@@ -555,6 +738,7 @@ class IPFabricIngestionMergeView(BaseObjectView):
555
738
  viewname = get_viewname(self.queryset.model, action="merge")
556
739
  form_url = reverse(viewname, kwargs={"pk": obj.pk})
557
740
  form = self.form(initial=request.GET)
741
+ restrict_form_fields(form, request.user)
558
742
  return render(
559
743
  request,
560
744
  "ipfabric_netbox/inc/merge_form.html",
@@ -572,6 +756,7 @@ class IPFabricIngestionMergeView(BaseObjectView):
572
756
  def post(self, request, pk):
573
757
  ingestion = get_object_or_404(self.queryset, pk=pk)
574
758
  form = self.form(request.POST)
759
+ restrict_form_fields(form, request.user)
575
760
  if form.is_valid():
576
761
  job = ingestion.enqueue_merge_job(
577
762
  user=request.user, remove_branch=form.cleaned_data["remove_branch"]
@@ -697,6 +882,7 @@ class IPFabricTable(View):
697
882
  if "table" in request.GET
698
883
  else IPFabricTableForm()
699
884
  )
885
+ restrict_form_fields(form, request.user)
700
886
  data = None
701
887
 
702
888
  if form.is_valid():
@@ -828,7 +1014,7 @@ class IPFabricSourceTopology(LoginRequiredMixin, View):
828
1014
  error = None
829
1015
  except Exception as e:
830
1016
  error = e
831
- svg_data = link = None
1017
+ svg_data = link = snapshot_data = source = None
832
1018
 
833
1019
  return render(
834
1020
  request,
@@ -844,3 +1030,4 @@ class IPFabricSourceTopology(LoginRequiredMixin, View):
844
1030
  "error": error,
845
1031
  },
846
1032
  )
1033
+ return None
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.3
2
2
  Name: ipfabric_netbox
3
- Version: 4.0.1b0
3
+ Version: 4.0.1b2
4
4
  Summary: NetBox plugin to sync IP Fabric data into NetBox
5
5
  License: MIT
6
6
  Keywords: netbox,ipfabric,plugin,sync
@@ -15,18 +15,12 @@ Classifier: Programming Language :: Python :: 3.11
15
15
  Classifier: Programming Language :: Python :: 3.12
16
16
  Classifier: Programming Language :: Python :: 3.13
17
17
  Provides-Extra: ipfabric-6-10
18
- Provides-Extra: ipfabric-6-6
19
- Provides-Extra: ipfabric-6-7
20
- Provides-Extra: ipfabric-6-8
21
- Provides-Extra: ipfabric-6-9
22
18
  Provides-Extra: ipfabric-7-0
23
- Requires-Dist: ipfabric (>=6.10.0,<6.11.0) ; extra != "ipfabric_6_6" and extra != "ipfabric_6_7" and extra != "ipfabric_6_8" and extra != "ipfabric_6_9" and extra == "ipfabric_6_10" and extra != "ipfabric_7_0"
24
- Requires-Dist: ipfabric (>=6.6.0,<6.7.0) ; extra == "ipfabric_6_6" and extra != "ipfabric_6_7" and extra != "ipfabric_6_8" and extra != "ipfabric_6_9" and extra != "ipfabric_6_10" and extra != "ipfabric_7_0"
25
- Requires-Dist: ipfabric (>=6.6.4) ; extra != "ipfabric_6_6" and extra != "ipfabric_6_7" and extra != "ipfabric_6_8" and extra != "ipfabric_6_9" and extra != "ipfabric_6_10" and extra != "ipfabric_7_0"
26
- Requires-Dist: ipfabric (>=6.7.0,<6.8.0) ; extra != "ipfabric_6_6" and extra == "ipfabric_6_7" and extra != "ipfabric_6_8" and extra != "ipfabric_6_9" and extra != "ipfabric_6_10" and extra != "ipfabric_7_0"
27
- Requires-Dist: ipfabric (>=6.8.0,<6.9.0) ; extra != "ipfabric_6_6" and extra != "ipfabric_6_7" and extra == "ipfabric_6_8" and extra != "ipfabric_6_9" and extra != "ipfabric_6_10" and extra != "ipfabric_7_0"
28
- Requires-Dist: ipfabric (>=6.9.0,<6.10.0) ; extra != "ipfabric_6_6" and extra != "ipfabric_6_7" and extra != "ipfabric_6_8" and extra == "ipfabric_6_9" and extra != "ipfabric_6_10" and extra != "ipfabric_7_0"
29
- Requires-Dist: ipfabric (>=7.0.0,<7.1.0) ; extra != "ipfabric_6_6" and extra != "ipfabric_6_7" and extra != "ipfabric_6_8" and extra != "ipfabric_6_9" and extra != "ipfabric_6_10" and extra == "ipfabric_7_0"
19
+ Provides-Extra: ipfabric-7-2
20
+ Requires-Dist: ipfabric (>=6.10.0,<6.11.0) ; extra == "ipfabric_6_10" and extra != "ipfabric_7_0" and extra != "ipfabric_7_2"
21
+ Requires-Dist: ipfabric (>=6.6.4) ; extra != "ipfabric_6_10" and extra != "ipfabric_7_0" and extra != "ipfabric_7_2"
22
+ Requires-Dist: ipfabric (>=7.0.0,<7.1.0) ; extra != "ipfabric_6_10" and extra == "ipfabric_7_0" and extra != "ipfabric_7_2"
23
+ Requires-Dist: ipfabric (>=7.2.0,<7.3.0) ; extra != "ipfabric_6_10" and extra != "ipfabric_7_0" and extra == "ipfabric_7_2"
30
24
  Requires-Dist: netboxlabs-netbox-branching (>=0.5.5,<0.6.0)
31
25
  Requires-Dist: netutils
32
26
  Project-URL: Bug Tracker, https://gitlab.com/ip-fabric/integrations/ipfabric-netbox-sync/-/issues