From ab489befe6c2ae4051927e1800184ec47954facd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?V=C3=ADctor=20Fern=C3=A1ndez=20Poyatos?= Date: Sun, 1 Dec 2024 16:57:59 +0100 Subject: [PATCH] feat(provider): add include query parameter for provider_groups (#5974) --- api/src/backend/api/specs/v1.yaml | 53 +++++++++++++++++++++++++ api/src/backend/api/tests/test_views.py | 39 ++++++++++++++++++ api/src/backend/api/v1/serializers.py | 11 +++++ 3 files changed, 103 insertions(+) diff --git a/api/src/backend/api/specs/v1.yaml b/api/src/backend/api/specs/v1.yaml index 5f35529f9f..5a299cb706 100644 --- a/api/src/backend/api/specs/v1.yaml +++ b/api/src/backend/api/specs/v1.yaml @@ -1862,6 +1862,7 @@ paths: - alias - connection - secret + - provider_groups - url description: endpoint return only specific fields in the response on a per-type basis by including a fields[TYPE] query parameter. @@ -1978,6 +1979,17 @@ paths: schema: type: string format: date-time + - in: query + name: include + schema: + type: array + items: + type: string + enum: + - provider_groups + description: include query parameter to allow the client to customize which + related resources should be returned. + explode: false - name: page[number] required: false in: query @@ -2071,6 +2083,7 @@ paths: - alias - connection - secret + - provider_groups - url description: endpoint return only specific fields in the response on a per-type basis by including a fields[TYPE] query parameter. @@ -2082,6 +2095,17 @@ paths: format: uuid description: A UUID string identifying this provider. required: true + - in: query + name: include + schema: + type: array + items: + type: string + enum: + - provider_groups + description: include query parameter to allow the client to customize which + related resources should be returned. + explode: false tags: - Provider security: @@ -6045,6 +6069,35 @@ components: - data description: The identifier of the related object. title: Resource Identifier + provider_groups: + type: object + properties: + data: + type: array + items: + type: object + properties: + id: + type: string + format: uuid + title: Resource Identifier + description: The identifier of the related object. + type: + type: string + enum: + - provider-groups + title: Resource Type Name + description: The [type](https://jsonapi.org/format/#document-resource-object-identification) + member is used to describe resource objects that share common + attributes and relationships. + required: + - id + - type + required: + - data + description: A related resource object from type provider-groups + title: provider-groups + readOnly: true required: - secret ProviderCreate: diff --git a/api/src/backend/api/tests/test_views.py b/api/src/backend/api/tests/test_views.py index 80d3bb8b64..55198515ae 100644 --- a/api/src/backend/api/tests/test_views.py +++ b/api/src/backend/api/tests/test_views.py @@ -784,11 +784,50 @@ class TestMembershipViewSet: @pytest.mark.django_db class TestProviderViewSet: + @pytest.fixture(scope="function") + def create_provider_group_relationship( + self, tenants_fixture, providers_fixture, provider_groups_fixture + ): + tenant, *_ = tenants_fixture + provider1, *_ = providers_fixture + provider_group1, *_ = provider_groups_fixture + provider_group_membership = ProviderGroupMembership.objects.create( + tenant=tenant, provider=provider1, provider_group=provider_group1 + ) + return provider_group_membership + def test_providers_list(self, authenticated_client, providers_fixture): response = authenticated_client.get(reverse("provider-list")) assert response.status_code == status.HTTP_200_OK assert len(response.json()["data"]) == len(providers_fixture) + @pytest.mark.parametrize( + "include_values, expected_resources", + [ + ("provider_groups", ["provider-groups"]), + ], + ) + def test_providers_list_include( + self, + include_values, + expected_resources, + authenticated_client, + providers_fixture, + create_provider_group_relationship, + ): + response = authenticated_client.get( + reverse("provider-list"), {"include": include_values} + ) + assert response.status_code == status.HTTP_200_OK + assert len(response.json()["data"]) == len(providers_fixture) + assert "included" in response.json() + + included_data = response.json()["included"] + for expected_type in expected_resources: + assert any( + d.get("type") == expected_type for d in included_data + ), f"Expected type '{expected_type}' not found in included data" + def test_providers_retrieve(self, authenticated_client, providers_fixture): provider1, *_ = providers_fixture response = authenticated_client.get( diff --git a/api/src/backend/api/v1/serializers.py b/api/src/backend/api/v1/serializers.py index 3c9d42bdef..2b28ee4063 100644 --- a/api/src/backend/api/v1/serializers.py +++ b/api/src/backend/api/v1/serializers.py @@ -389,6 +389,12 @@ class ProviderGroupSerializer(RLSSerializer, BaseWriteSerializer): } +class ProviderGroupIncludedSerializer(RLSSerializer, BaseWriteSerializer): + class Meta: + model = ProviderGroup + fields = ["id", "name"] + + class ProviderGroupUpdateSerializer(RLSSerializer, BaseWriteSerializer): """ Serializer for updating the ProviderGroup model. @@ -452,6 +458,10 @@ class ProviderSerializer(RLSSerializer): provider = ProviderEnumSerializerField() connection = serializers.SerializerMethodField(read_only=True) + included_serializers = { + "provider_groups": "api.v1.serializers.ProviderGroupIncludedSerializer", + } + class Meta: model = Provider fields = [ @@ -464,6 +474,7 @@ class ProviderSerializer(RLSSerializer): "connection", # "scanner_args", "secret", + "provider_groups", "url", ]