Просмотр исходного кода

Closes #4324: Add CSV import view for services

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

+ 1 - 0
docs/release-notes/version-2.7.md

@@ -3,6 +3,7 @@
 ## Enhancements
 
 * [#4323](https://github.com/netbox-community/netbox/issues/4323) - Add bulk edit view for power panels
+* [#4324](https://github.com/netbox-community/netbox/issues/4324) - Add CSV import view for services
 
 ---
 

+ 31 - 0
netbox/ipam/forms.py

@@ -1382,6 +1382,37 @@ class ServiceFilterForm(BootstrapMixin, CustomFieldFilterForm):
     tag = TagFilterField(model)
 
 
+class ServiceCSVForm(CustomFieldModelCSVForm):
+    device = FlexibleModelChoiceField(
+        queryset=Device.objects.all(),
+        required=False,
+        to_field_name='name',
+        help_text='Name or ID of device',
+        error_messages={
+            'invalid_choice': 'Device not found.',
+        }
+    )
+    virtual_machine = FlexibleModelChoiceField(
+        queryset=VirtualMachine.objects.all(),
+        required=False,
+        to_field_name='name',
+        help_text='Name or ID of virtual machine',
+        error_messages={
+            'invalid_choice': 'Virtual machine not found.',
+        }
+    )
+    protocol = CSVChoiceField(
+        choices=ServiceProtocolChoices,
+        help_text='IP protocol'
+    )
+
+    class Meta:
+        model = Service
+        fields = Service.csv_headers
+        help_texts = {
+        }
+
+
 class ServiceBulkEditForm(BootstrapMixin, CustomFieldBulkEditForm):
     pk = forms.ModelMultipleChoiceField(
         queryset=Service.objects.all(),

+ 1 - 1
netbox/ipam/models.py

@@ -1027,7 +1027,7 @@ class Service(ChangeLoggedModel, CustomFieldModel):
 
     tags = TaggableManager(through=TaggedItem)
 
-    csv_headers = ['device', 'virtual_machine', 'name', 'protocol', 'description']
+    csv_headers = ['device', 'virtual_machine', 'name', 'protocol', 'port', 'description']
 
     class Meta:
         ordering = ('protocol', 'port', 'pk')  # (protocol, port) may be non-unique

+ 7 - 3
netbox/ipam/tests/test_views.py

@@ -334,9 +334,6 @@ class VLANTestCase(ViewTestCases.PrimaryObjectViewTestCase):
 class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
     model = Service
 
-    # Disable inapplicable tests
-    test_import_objects = None
-
     # TODO: Resolve URL for Service creation
     test_create_object = None
 
@@ -366,6 +363,13 @@ class ServiceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
             'tags': 'Alpha,Bravo,Charlie',
         }
 
+        cls.csv_data = (
+            "device,name,protocol,port,description",
+            "Device 1,Service 1,TCP,1,First service",
+            "Device 1,Service 2,TCP,2,Second service",
+            "Device 1,Service 3,UDP,3,Third service",
+        )
+
         cls.bulk_edit_data = {
             'protocol': ServiceProtocolChoices.PROTOCOL_UDP,
             'port': 888,

+ 1 - 0
netbox/ipam/urls.py

@@ -94,6 +94,7 @@ urlpatterns = [
 
     # Services
     path('services/', views.ServiceListView.as_view(), name='service_list'),
+    path('services/import/', views.ServiceBulkImportView.as_view(), name='service_import'),
     path('services/edit/', views.ServiceBulkEditView.as_view(), name='service_bulk_edit'),
     path('services/delete/', views.ServiceBulkDeleteView.as_view(), name='service_bulk_delete'),
     path('services/<int:pk>/', views.ServiceView.as_view(), name='service'),

+ 7 - 0
netbox/ipam/views.py

@@ -1015,6 +1015,13 @@ class ServiceCreateView(PermissionRequiredMixin, ObjectEditView):
         return service.parent.get_absolute_url()
 
 
+class ServiceBulkImportView(PermissionRequiredMixin, BulkImportView):
+    permission_required = 'ipam.add_service'
+    model_form = forms.ServiceCSVForm
+    table = tables.ServiceTable
+    default_return_url = 'ipam:service_list'
+
+
 class ServiceEditView(ServiceCreateView):
     permission_required = 'ipam.change_service'
 

+ 5 - 0
netbox/templates/inc/nav_menu.html

@@ -338,6 +338,11 @@
                         <li class="divider"></li>
                         <li class="dropdown-header">Services</li>
                         <li{% if not perms.ipam.view_service %} class="disabled"{% endif %}>
+                            {% if perms.ipam.add_vservice %}
+                                <div class="buttons pull-right">
+                                    <a href="{% url 'ipam:service_import' %}" class="btn btn-xs btn-info" title="Import"><i class="fa fa-download"></i></a>
+                                </div>
+                            {% endif %}
                             <a href="{% url 'ipam:service_list' %}">Services</a>
                         </li>
                     </ul>