ipfabric_netbox 4.0.1b0__py3-none-any.whl → 4.0.1b1__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.
- ipfabric_netbox/__init__.py +13 -1
- ipfabric_netbox/api/serializers.py +13 -0
- ipfabric_netbox/api/urls.py +2 -0
- ipfabric_netbox/api/views.py +7 -0
- ipfabric_netbox/choices.py +17 -0
- ipfabric_netbox/filtersets.py +38 -0
- ipfabric_netbox/forms.py +79 -3
- ipfabric_netbox/migrations/0001_initial_squashed_0013_switch_to_branching_plugin.py +1 -1
- ipfabric_netbox/migrations/0014_ipfabrictransformmapgroup_ipfabrictransformmap_group.py +65 -0
- ipfabric_netbox/models.py +85 -11
- ipfabric_netbox/navigation.py +15 -1
- ipfabric_netbox/signals.py +17 -0
- ipfabric_netbox/tables.py +18 -2
- ipfabric_netbox/templates/ipfabric_netbox/inc/clone_form.html +27 -0
- ipfabric_netbox/templates/ipfabric_netbox/ipfabricsync.html +17 -2
- ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmap.html +16 -1
- ipfabric_netbox/templates/ipfabric_netbox/ipfabrictransformmapgroup.html +35 -0
- ipfabric_netbox/templatetags/__init__.py +0 -0
- ipfabric_netbox/templatetags/ipfabric_netbox_helpers.py +17 -0
- ipfabric_netbox/tests/test_models.py +0 -2
- ipfabric_netbox/urls.py +25 -0
- ipfabric_netbox/utilities/ipfutils.py +8 -12
- ipfabric_netbox/utilities/transform_map.py +7 -6
- ipfabric_netbox/views.py +191 -5
- {ipfabric_netbox-4.0.1b0.dist-info → ipfabric_netbox-4.0.1b1.dist-info}/METADATA +1 -1
- {ipfabric_netbox-4.0.1b0.dist-info → ipfabric_netbox-4.0.1b1.dist-info}/RECORD +27 -22
- {ipfabric_netbox-4.0.1b0.dist-info → ipfabric_netbox-4.0.1b1.dist-info}/WHEEL +0 -0
|
@@ -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>
|
|
85
|
-
|
|
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> 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
|
|
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
|
-
|
|
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.
|
|
186
|
+
transform_map = self.transform_maps.get(
|
|
189
187
|
target_model__app_label=app, target_model__model=model
|
|
190
|
-
)
|
|
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.
|
|
452
|
+
int_transform_map = self.transform_maps.get(
|
|
455
453
|
target_model__app_label="dcim", target_model__model="interface"
|
|
456
|
-
)
|
|
457
|
-
int_name_field_map = int_transform_map.field_maps.
|
|
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.
|
|
128
|
-
|
|
129
|
-
|
|
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.
|
|
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():
|