diff --git a/plugins/netbox-rps-plugin/netbox_rps_plugin/api/serializers.py b/plugins/netbox-rps-plugin/netbox_rps_plugin/api/serializers.py index ddbd1a167f193d47db991bbee19ab0ce82015707..8b59c3e22e925cc4bc23e53eaa8f415ae6c02348 100644 --- a/plugins/netbox-rps-plugin/netbox_rps_plugin/api/serializers.py +++ b/plugins/netbox-rps-plugin/netbox_rps_plugin/api/serializers.py @@ -123,7 +123,7 @@ class MappingSerializer(NetBoxModelSerializer): "proxy_cache", "proxy_read_timeout", "client_max_body_size", - "protocol", + "protocols", "sorry_page", "custom_fields", "created", diff --git a/plugins/netbox-rps-plugin/netbox_rps_plugin/filtersets.py b/plugins/netbox-rps-plugin/netbox_rps_plugin/filtersets.py index 5af9c7e27175c027714e108fb7a8b9e5aba5a9df..75b2202de0e5700f2da900b51f2b92ea6cdd8696 100644 --- a/plugins/netbox-rps-plugin/netbox_rps_plugin/filtersets.py +++ b/plugins/netbox-rps-plugin/netbox_rps_plugin/filtersets.py @@ -1,5 +1,6 @@ """Filtersets definitions""" +from django_filters import filters from netbox.filtersets import NetBoxModelFilterSet from django.db.models import Q from .models import Mapping, HttpHeader @@ -8,6 +9,8 @@ from .models import Mapping, HttpHeader class MappingFilterSet(NetBoxModelFilterSet): """Mapping filterset definition class""" + protocols = filters.CharFilter(lookup_expr="icontains") + class Meta: model = Mapping fields = ( @@ -17,7 +20,7 @@ class MappingFilterSet(NetBoxModelFilterSet): "target", "Comment", "webdav", - "protocol", + "protocols", "testingpage", "gzip_proxied", "keepalive_requests", diff --git a/plugins/netbox-rps-plugin/netbox_rps_plugin/forms.py b/plugins/netbox-rps-plugin/netbox_rps_plugin/forms.py index 09b1cdeca15b8e6712b0302185b23f30acb8f87a..eb869affa9243ed2288f2ff2a5eb69d8729ff5ce 100644 --- a/plugins/netbox-rps-plugin/netbox_rps_plugin/forms.py +++ b/plugins/netbox-rps-plugin/netbox_rps_plugin/forms.py @@ -23,6 +23,8 @@ from .models import ( class MappingForm(NetBoxModelForm): """Mapping form definition class""" + protocols = forms.MultipleChoiceField(choices=ProtocolChoices) + class Meta: model = Mapping fields = ( @@ -30,7 +32,7 @@ class MappingForm(NetBoxModelForm): "target", "authentication", "webdav", - "protocol", + "protocols", "testingpage", "gzip_proxied", "keepalive_requests", @@ -57,7 +59,7 @@ class MappingForm(NetBoxModelForm): "proxy_read_timeout": " Proxy read timeout (s)", "client_max_body_size": "Client max body size (MB)", "sorry_page": "Sorry Page URL", - "protocol": "Protocol", + "protocols": "Protocols", } @@ -78,7 +80,7 @@ class MappingFilterForm(NetBoxModelFilterSetForm): webdav = forms.BooleanField( required=False, widget=forms.Select(choices=BOOLEAN_WITH_BLANK_CHOICES) ) - protocol = forms.MultipleChoiceField( + protocols = forms.MultipleChoiceField( choices=ProtocolChoices, required=False, ) diff --git a/plugins/netbox-rps-plugin/netbox_rps_plugin/migrations/0010_alter_httpheader_options_alter_mapping_options_and_more.py b/plugins/netbox-rps-plugin/netbox_rps_plugin/migrations/0010_alter_httpheader_options_alter_mapping_options_and_more.py index 1c86d067c0d55e5f7f0f46f094041f219d31ae23..faef190c7eb724eb994f4d6f16d7a941723a82cb 100644 --- a/plugins/netbox-rps-plugin/netbox_rps_plugin/migrations/0010_alter_httpheader_options_alter_mapping_options_and_more.py +++ b/plugins/netbox-rps-plugin/netbox_rps_plugin/migrations/0010_alter_httpheader_options_alter_mapping_options_and_more.py @@ -1,9 +1,11 @@ """Migration File""" # pylint: disable=C0103 +import django.contrib.postgres.fields import django.core.validators from django.db import migrations, models import django.db.models.deletion +import netbox_rps_plugin.models class Migration(migrations.Migration): @@ -28,8 +30,12 @@ class Migration(migrations.Migration): ), migrations.AddField( model_name="mapping", - name="protocol", - field=models.CharField(default="http_https", max_length=32), + name="protocols", + field=django.contrib.postgres.fields.ArrayField( + base_field=models.CharField(max_length=32), + default=netbox_rps_plugin.models.default_protocol, + size=None, + ), ), migrations.AlterField( model_name="httpheader", diff --git a/plugins/netbox-rps-plugin/netbox_rps_plugin/models.py b/plugins/netbox-rps-plugin/netbox_rps_plugin/models.py index f1a8753943831fb118b9e89e1a358478c5433c2d..a647b473ad9536f8a291fc40852ab929560789e7 100644 --- a/plugins/netbox-rps-plugin/netbox_rps_plugin/models.py +++ b/plugins/netbox-rps-plugin/netbox_rps_plugin/models.py @@ -4,6 +4,7 @@ from django.conf import settings from django.db import models from django.urls import reverse from django.core.validators import URLValidator, MaxValueValidator, MinValueValidator +from django.contrib.postgres.fields.array import ArrayField from netbox.models import NetBoxModel from utilities.choices import ChoiceSet @@ -43,14 +44,20 @@ class ProtocolChoices(ChoiceSet): key = "Mapping.protocol" - DEFAULT_VALUE = "http_https" + HTTP_HTTPS = "http_https" + WEBSOCKET = "websocket" CHOICES = [ - ("http_https", "HTTP / HTTPS", "dark"), - ("websocket", "Websocket", "blue"), + (HTTP_HTTPS, "HTTP / HTTPS", "dark"), + (WEBSOCKET, "Websocket", "blue"), ] +def default_protocol(): + """Return the default protocols""" + return [ProtocolChoices.HTTP_HTTPS] + + class Mapping(NetBoxModel): """Mapping definition class""" @@ -105,12 +112,12 @@ class Mapping(NetBoxModel): validators=[URLValidator(message="It must be a url")], default=DEFAULT_SORRY_PAGE, ) - protocol = models.CharField( - max_length=32, - choices=ProtocolChoices, - default=ProtocolChoices.DEFAULT_VALUE, + protocols = ArrayField( + base_field=models.CharField(max_length=32, choices=ProtocolChoices), + null=False, blank=False, - verbose_name="Protocol", + verbose_name="Protocols", + default=default_protocol, ) class Meta: diff --git a/plugins/netbox-rps-plugin/netbox_rps_plugin/tables.py b/plugins/netbox-rps-plugin/netbox_rps_plugin/tables.py index 82ad1dd3467f868acad38d6185f27bc73951f27d..eee2f2a0f79877092c9c010e8ef0b737337afae1 100644 --- a/plugins/netbox-rps-plugin/netbox_rps_plugin/tables.py +++ b/plugins/netbox-rps-plugin/netbox_rps_plugin/tables.py @@ -27,7 +27,7 @@ class MappingTable(NetBoxTable): "authentication", "testingpage", "webdav", - "protocol", + "protocols", "Comment", "gzip_proxied", "keepalive_requests", @@ -46,7 +46,7 @@ class MappingTable(NetBoxTable): "target", "authentication", "webdav", - "protocol", + "protocols", "gzip_proxied", "keepalive_requests", "keepalive_timeout", diff --git a/plugins/netbox-rps-plugin/netbox_rps_plugin/templates/netbox_rps_plugin/mapping.html b/plugins/netbox-rps-plugin/netbox_rps_plugin/templates/netbox_rps_plugin/mapping.html index 6fd40a6fbac54fac70a2c5645f63e9978e5a8f79..27ef30549523254965960e41d1efe7f8f0b4db52 100644 --- a/plugins/netbox-rps-plugin/netbox_rps_plugin/templates/netbox_rps_plugin/mapping.html +++ b/plugins/netbox-rps-plugin/netbox_rps_plugin/templates/netbox_rps_plugin/mapping.html @@ -68,7 +68,7 @@ </tr> <tr> <th scope="row">Protocol</th> - <td>{{ object.get_protocol_display|placeholder }}</td> + <td>{{ object.protocols|placeholder }}</td> </tr> <tr> <th scope="row">Comment</th> diff --git a/plugins/netbox-rps-plugin/tests/e2e/test_mapping_creation.py b/plugins/netbox-rps-plugin/tests/e2e/test_mapping_creation.py index c70afbb002403b1b3e23a9bb1ee7533377bfc4ac..2ba1bb20521cd0ca50a3caa7f265589f2c927127 100644 --- a/plugins/netbox-rps-plugin/tests/e2e/test_mapping_creation.py +++ b/plugins/netbox-rps-plugin/tests/e2e/test_mapping_creation.py @@ -54,7 +54,7 @@ class TestMappingCreation(Base): content = json.loads(response.content) self.assertEqual(content["authentication"], "none") - self.assertEqual(content["protocol"], "http_https") + self.assertEqual(content["protocols"], ["http_https"]) if __name__ == "__main__": diff --git a/plugins/netbox-rps-plugin/tests/e2e/test_mapping_protocols.py b/plugins/netbox-rps-plugin/tests/e2e/test_mapping_protocols.py new file mode 100644 index 0000000000000000000000000000000000000000..7b2e2cb29e541dcf2ea14a22b0354b09cf4ae89f --- /dev/null +++ b/plugins/netbox-rps-plugin/tests/e2e/test_mapping_protocols.py @@ -0,0 +1,84 @@ +"""Test case for Mapping protocols""" + +import unittest +import json +import os +import requests +from .base import Base + + +HOST = os.getenv("HOST", default="localhost") +PORT = os.getenv("PORT", default="8080") +API_KEY = os.getenv("API_KEY", "only4testingpurpose") + + +class TestMappingProtocols(Base): + """Test case for Mapping protocols class""" + + def test_that_mapping_protocols_default_value_is_set(self) -> None: + """Test that mapping protocols default value is set""" + + response = requests.post( + url=f"http://{HOST}:{PORT}/api/plugins/rps/mapping/", + json={ + "source": "https://truc00.com/api", + "target": "http://10.10.10.10:1800/api", + }, + headers={"Authorization": f"Token {API_KEY}"}, + timeout=5, + ) + + self.assertEqual(response.status_code, 201) + + self.mapping_id = json.loads(response.content)["id"] + + content = json.loads(response.content) + + self.assertEqual(content["protocols"], ["http_https"]) + + def test_that_mapping_protocols_are_not_valid(self) -> None: + """Test that mapping protocols are not valid""" + + response = requests.post( + url=f"http://{HOST}:{PORT}/api/plugins/rps/mapping/", + json={ + "source": "https://truc00.com/api", + "target": "http://10.10.10.10:1800/api", + "protocols": ["thisisnotavalidprotocol", "websocket", "anotherone"], + }, + headers={"Authorization": f"Token {API_KEY}"}, + timeout=5, + ) + + self.assertEqual(response.status_code, 400) + self.assertEqual( + response.content, + b'{"protocols":{"0":["\\"thisisnotavalidprotocol\\" is not a valid choice."],' + + b'"2":["\\"anotherone\\" is not a valid choice."]}}', + ) + + def test_that_mapping_protocols_are_valid(self) -> None: + """Test that mapping protocols are not valid""" + + response = requests.post( + url=f"http://{HOST}:{PORT}/api/plugins/rps/mapping/", + json={ + "source": "https://truc00.com/api", + "target": "http://10.10.10.10:1800/api", + "protocols": ["http_https", "websocket"], + }, + headers={"Authorization": f"Token {API_KEY}"}, + timeout=5, + ) + + self.assertEqual(response.status_code, 201) + + self.mapping_id = json.loads(response.content)["id"] + + content = json.loads(response.content) + + self.assertEqual(content["protocols"], ["http_https", "websocket"]) + + +if __name__ == "__main__": + unittest.main()