From 46e3883f19a8cb25230910e5cca6f6f9e6e6d704 Mon Sep 17 00:00:00 2001 From: jeremystretch <jstretch@ns1.com> Date: Fri, 18 Nov 2022 15:22:24 -0500 Subject: [PATCH] Closes #815: Enable specifying terminations when bulk importing circuits --- docs/release-notes/version-3.4.md | 4 ++++ netbox/circuits/forms/bulk_import.py | 26 ++++++++++++++++++++++- netbox/circuits/tests/test_views.py | 7 ++++++ netbox/circuits/views.py | 10 +++++++++ netbox/netbox/views/generic/bulk_views.py | 2 +- 5 files changed, 47 insertions(+), 2 deletions(-) diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index ee07fa83c..651dc4f82 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -2,6 +2,10 @@ ## v3.4.0 (FUTURE) +### Enhancements + +* [#815](https://github.com/netbox-community/netbox/issues/815) - Enable specifying terminations when bulk importing circuits + ### Bug Fixes * [#10946](https://github.com/netbox-community/netbox/issues/10946) - Fix AttributeError exception when viewing a device with a primary IP and no platform assigned diff --git a/netbox/circuits/forms/bulk_import.py b/netbox/circuits/forms/bulk_import.py index 9566c2e12..b61fb1bc7 100644 --- a/netbox/circuits/forms/bulk_import.py +++ b/netbox/circuits/forms/bulk_import.py @@ -1,12 +1,16 @@ +from django import forms + from circuits.choices import CircuitStatusChoices from circuits.models import * +from dcim.models import Site from django.utils.translation import gettext as _ from netbox.forms import NetBoxModelImportForm from tenancy.models import Tenant -from utilities.forms import CSVChoiceField, CSVModelChoiceField, SlugField +from utilities.forms import BootstrapMixin, CSVChoiceField, CSVModelChoiceField, SlugField __all__ = ( 'CircuitImportForm', + 'CircuitTerminationImportForm', 'CircuitTypeImportForm', 'ProviderImportForm', 'ProviderNetworkImportForm', @@ -76,3 +80,23 @@ class CircuitImportForm(NetBoxModelImportForm): 'cid', 'provider', 'type', 'status', 'tenant', 'install_date', 'termination_date', 'commit_rate', 'description', 'comments', 'tags' ] + + +class CircuitTerminationImportForm(BootstrapMixin, forms.ModelForm): + site = CSVModelChoiceField( + queryset=Site.objects.all(), + to_field_name='name', + required=False + ) + provider_network = CSVModelChoiceField( + queryset=ProviderNetwork.objects.all(), + to_field_name='name', + required=False + ) + + class Meta: + model = CircuitTermination + fields = [ + 'circuit', 'term_side', 'site', 'provider_network', 'port_speed', 'upstream_speed', 'xconnect_id', + 'pp_info', 'description', + ] diff --git a/netbox/circuits/tests/test_views.py b/netbox/circuits/tests/test_views.py index 54d001c8d..231d6a43c 100644 --- a/netbox/circuits/tests/test_views.py +++ b/netbox/circuits/tests/test_views.py @@ -108,6 +108,13 @@ class CircuitTypeTestCase(ViewTestCases.OrganizationalObjectViewTestCase): class CircuitTestCase(ViewTestCases.PrimaryObjectViewTestCase): model = Circuit + def setUp(self): + super().setUp() + + self.add_permissions( + 'circuits.add_circuittermination', + ) + @classmethod def setUpTestData(cls): diff --git a/netbox/circuits/views.py b/netbox/circuits/views.py index 5fe8eb7b7..3168509ba 100644 --- a/netbox/circuits/views.py +++ b/netbox/circuits/views.py @@ -233,6 +233,16 @@ class CircuitBulkImportView(generic.BulkImportView): queryset = Circuit.objects.all() model_form = forms.CircuitImportForm table = tables.CircuitTable + additional_permissions = [ + 'circuits.add_circuittermination', + ] + related_object_forms = { + 'terminations': forms.CircuitTerminationImportForm, + } + + def prep_related_object_data(self, parent, data): + data.update({'circuit': parent}) + return data class CircuitBulkEditView(generic.BulkEditView): diff --git a/netbox/netbox/views/generic/bulk_views.py b/netbox/netbox/views/generic/bulk_views.py index 444004623..445bfa261 100644 --- a/netbox/netbox/views/generic/bulk_views.py +++ b/netbox/netbox/views/generic/bulk_views.py @@ -458,7 +458,7 @@ class BulkImportView(GetReturnURLMixin, BaseMultiObjectView): 'return_url': self.get_return_url(request), }) - except ValidationError: + except (AbortTransaction, ValidationError): clear_webhooks.send(sender=self) except (AbortRequest, PermissionsViolation) as e: