Skip to content

Commit

Permalink
Issue/#2192 inclusions (#267)
Browse files Browse the repository at this point in the history
**Enhancements, Bug Fixes, and Code Refactoring**

- **Added:** Extension of list call functionality to accept expand parameters for enriched data retrieval.
- **Added:** Introduction of 'ExpandField' class to manage and process expand parameters.
- **Added:** 'Inclusion' class to facilitate data inclusion and enhance response customization.
- **Added:** Method for building inclusion schemas.
- **Added:** Recursion logic in later stages to support nested data inclusion.
- **Added:** 'Inclusions' class for streamlined management of included external API calls.
- **Added:** External API calls within the 'Inclusions' class for comprehensive data integration.
- **Added:** Clear and descriptive text to the expand filter for better understanding.
- **Added:** Validation mechanism and resolved issues with external API calls within 'Inclusions'.
- **Added:** Regex validator to enhance input validation.
- **Added:** Explanation regarding the use of regex validation.
- **Added:** Support for nested dictionary types like 'relevante_andere_zaken' in the expansions model.
- **Added:** Integration of the 'expand' feature into the OpenAPI Specification (OAS) and expanded GET detail endpoints.
- **Changed:** Hard-coded mappings from 'expensions.py' for increased flexibility.
- **Changed:** Relocated 'routers' import into a function to address circular import concerns.
- **Changed:** Reworked the expansions model to resolve previous errors and improve reliability.
- **Changed:** Various issues related to specific problem reports: #2280, #2279, #2269, #2270, #2271,  #2288, #2287.
- **Changed:** Updated OAS description and resolved a bug in the expansions.
- **Updated:** Requirements files, including 'psyopg2' for proper functionality.

These changes encompass a wide range of enhancements, bug fixes, and code clean-up, significantly improving the functionality, stability, and maintainability of the system. The introduction of expand parameters, 'ExpandField' class, 'Expand' class, and various bug fixes contribute to a more robust and efficient system.
  • Loading branch information
MatthijsBekendam authored Aug 22, 2023
1 parent 43f02f3 commit 10a15d3
Show file tree
Hide file tree
Showing 9 changed files with 840 additions and 7 deletions.
2 changes: 1 addition & 1 deletion INSTALL.rst
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
============
pip============
Installation
============

Expand Down
Empty file added src/__init__.py
Empty file.
648 changes: 648 additions & 0 deletions src/zrc/api/expansions.py

Large diffs are not rendered by default.

18 changes: 18 additions & 0 deletions src/zrc/api/filters.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from django.utils.translation import ugettext_lazy as _

from django_filters import filters
from drf_spectacular.types import OpenApiTypes
from drf_spectacular.utils import extend_schema_field
from vng_api_common.constants import VertrouwelijkheidsAanduiding
from vng_api_common.filtersets import FilterSet
from vng_api_common.utils import get_field_attribute, get_help_text
Expand All @@ -22,6 +24,11 @@ def get_most_recent_status(queryset, name, value):
return queryset.order_by("-datum_status_gezet")[:1]


def expand_filter(queryset, name, value):
"""expansion filter logic is placed at view level"""
return queryset


class MaximaleVertrouwelijkheidaanduidingFilter(filters.ChoiceFilter):
def __init__(self, *args, **kwargs):
kwargs.setdefault("choices", VertrouwelijkheidsAanduiding.choices)
Expand Down Expand Up @@ -126,6 +133,17 @@ class ZaakFilter(FilterSet):
help_text="Het veld waarop de resultaten geordend worden.",
)

expand = extend_schema_field(OpenApiTypes.STR)(
filters.CharFilter(
method=expand_filter,
help_text=_(
"Examples: \n"
"`expand=zaaktype, status, status.statustype, hoofdzaak.status.statustype, hoofdzaak.deelzaken.status.statustype`\n"
"Haal details van gelinkte resources direct op. Als je meerdere resources tegelijk wilt ophalen kun je deze scheiden met een komma. Voor het ophalen van resources die een laag dieper genest zijn wordt de punt-notatie gebruikt.",
),
)
)

class Meta:
model = Zaak
fields = {
Expand Down
166 changes: 166 additions & 0 deletions src/zrc/api/tests/test_zaken.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import unittest
import uuid
from datetime import date, timedelta
from unittest.mock import patch

Expand All @@ -15,6 +16,7 @@
RolOmschrijving,
RolTypes,
VertrouwelijkheidsAanduiding,
ZaakobjectTypes,
)
from vng_api_common.tests import (
JWTAuthMixin,
Expand All @@ -31,6 +33,7 @@
NatuurlijkPersoon,
NietNatuurlijkPersoon,
OrganisatorischeEenheid,
RelevanteZaakRelatie,
Vestiging,
Zaak,
)
Expand Down Expand Up @@ -59,6 +62,7 @@
SCOPE_ZAKEN_CREATE,
SCOPEN_ZAKEN_HEROPENEN,
)
from .test_zaakobject import OBJECT

# ZTC
ZTC_ROOT = "https://example.com/ztc/api/v1"
Expand Down Expand Up @@ -1149,6 +1153,168 @@ def test_rol_vestiging_vestigings_nummer(self):
self.assertEqual(response.data["count"], 1)


@override_settings(
LINK_FETCHER="vng_api_common.mocks.link_fetcher_200",
ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient",
)
class ZakenExpandTests(ZaakInformatieObjectSyncMixin, JWTAuthMixin, APITestCase):
heeft_alle_autorisaties = True
ZTC_ROOT = "https://example.com/ztc/api/v1"
CATALOGUS = f"{ZTC_ROOT}/catalogus/878a3318-5950-4642-8715-189745f91b04"
ZAAKTYPE = f"{CATALOGUS}/zaaktypen/283ffaf5-8470-457b-8064-90e5728f413f"
EIGENSCHAP = f"{ZTC_ROOT}/eigenschappen/f420c3e0-8345-44d9-a981-0f424538b9e9"
ZAAKOBJECTTYPE = (
"http://testserver/api/v1/zaakobjecttypen/c340323d-31a5-46b4-93e8-fdc2d621be13"
)
INFORMATIEOBJECT = f"http://example.com/drc/api/v1/enkelvoudiginformatieobjecten/{uuid.uuid4().hex}"

@override_settings(ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient")
@patch("vng_api_common.validators.fetcher")
@patch("vng_api_common.validators.obj_has_shape", return_value=True)
def test_list_expand_filter_few_levels_deep(self, *mocks):
zaak = ZaakFactory.create()

# zaak.zaaktype = "https://catalogi-api.test.vng.cloud/api/v1/zaaktypen/7e3353ef-d5da-4c1d-9155-a79c89194121"
#
# zaak2 = ZaakFactory.create()
# zaak2.zaaktype = "https://catalogi-api.test.vng.cloud/api/v1/zaaktypen/ed15c69d-15cd-4bc7-bc1a-b5d21d45dc36"
# zaak2.save()

url = reverse("zaak-detail", kwargs={"uuid": zaak.uuid})

zaakrelatie = RelevanteZaakRelatie.objects.create(
zaak=zaak, url=url, aard_relatie="test"
)
zaak.relevante_andere_zaken.add(zaakrelatie)
zaak.save()

zaakeigenschap = ZaakEigenschapFactory.create(
zaak=zaak, eigenschap=self.EIGENSCHAP, waarde="This is a value"
)
zaakeigenschap2 = ZaakEigenschapFactory.create(
zaak=zaak, eigenschap=self.EIGENSCHAP, waarde="This is a value"
)
zaakeigenschap3 = ZaakEigenschapFactory.create(
zaak=zaak, eigenschap=self.EIGENSCHAP, waarde="This is a value"
)

# zaakeigenschap = ZaakEigenschapFactory.create(
# zaak=zaak2, eigenschap=self.EIGENSCHAP, waarde="This is a value"
# )
zaakobject = ZaakObjectFactory.create(
zaak=zaak,
object=OBJECT,
object_type=ZaakobjectTypes.besluit,
zaakobjecttype=self.ZAAKOBJECTTYPE,
)
# zaakobject = ZaakObjectFactory.create(
# zaak=zaak2,
# object=OBJECT,
# object_type=ZaakobjectTypes.besluit,
# zaakobjecttype=self.ZAAKOBJECTTYPE,
# )
zio = ZaakInformatieObjectFactory.create(zaak=zaak)
#
rol = RolFactory.create(
zaak=zaak,
)
# rol.roltype = "https://catalogi-api.test.vng.cloud/api/v1/roltypen/d03562e0-2feb-4d46-bf56-ed1d71122996"
# rol.save()

# zaakobject.zaakobjecttype = "https://catalogi-api.test.vng.cloud/api/v1/zaakobjecttypen/f5a24710-6902-44f3-b4dd-9e75bd4c1403"
# zaakobject.save()

status1 = StatusFactory.create(zaak=zaak)
rol.statussen.add(status1)

rol2 = RolFactory.create(
zaak=zaak,
)
rol3 = RolFactory.create(
zaak=zaak,
)
rol4 = RolFactory.create(
zaak=zaak,
)
rol2.statussen.add(status1)

url = reverse("zaak-list")
expand_params = [
"rollen.statussen.zaak.rollen,zaakinformatieobjecten,zaakobjecten.zaak,eigenschappen",
"relevanteAndereZaken.zaaktype",
"zaaktype.besluittypen,status.statustype,zaaktype.catalogus",
"rollen.zaak.rollen.zaak.rollen",
"zaaktype,rollen.statussen.zaak,status.zaak,zaakobjecten,zaakinformatieobjecten",
"zaaktype.catalogus.zaaktypen",
"zaaktype.besluittypen.zaaktypen",
"status.statustype,status.gezetdoor",
"zaaktype.gerelateerdeZaaktypen",
"zaaktype.zaakobjecttypen,zaaktype.statustypen",
"zaaktype.deelzaaktypen",
"zaaktype.eigenschappen.statustype",
"rollen.statussen,rollen.zaak",
"zaaktype.eigenschappen.catalogus,zaaktype.eigenschappen.zaaktype,zaaktype.eigenschappen.statustype",
"status,zaaktype",
"zaaktype,hoofdzaak,deelzaken,relevanteAndereZaken,eigenschappen,rollen,status,zaakobjecten,resultaat",
"status.zaak,status.statustype,status.gezetdoor",
"rollen.roltype",
"zaakobjecten.zaakobjecttype",
]
for param in expand_params:
with self.subTest(param=param):
response = self.client.get(
url,
{"expand": param},
**ZAAK_READ_KWARGS,
)
self.assertEqual(response.status_code, status.HTTP_200_OK)
# from pprint import pprint
#
# pprint(response.json()["results"][0]["_expand"])

@override_settings(ZDS_CLIENT_CLASS="vng_api_common.mocks.MockClient")
@patch("vng_api_common.validators.fetcher")
@patch("vng_api_common.validators.obj_has_shape", return_value=True)
def test_get_expand_filter_few_levels_deep(self, *mocks):
zaak = ZaakFactory.create()
zaak2 = ZaakFactory.create()

url = reverse("zaak-detail", kwargs={"uuid": zaak.uuid})

zaakrelatie = RelevanteZaakRelatie.objects.create(
zaak=zaak, url=url, aard_relatie="test"
)
zaak.relevante_andere_zaken.add(zaakrelatie)
zaak.save()

zaakobject = ZaakObjectFactory.create(
zaak=zaak,
object=OBJECT,
object_type=ZaakobjectTypes.besluit,
zaakobjecttype=self.ZAAKOBJECTTYPE,
)

zio = ZaakInformatieObjectFactory.create(zaak=zaak)

rol = RolFactory.create(
zaak=zaak,
)

status1 = StatusFactory.create(zaak=zaak)
rol.statussen.add(status1)

rol2 = RolFactory.create(
zaak=zaak,
)

response = self.client.get(
url,
{"expand": "rollen.statussen,rollen.zaak"},
**ZAAK_READ_KWARGS,
)
self.assertEqual(response.status_code, status.HTTP_200_OK)


class ZakenWerkVoorraadTests(JWTAuthMixin, APITestCase):
"""
Test that the queries to build up a 'werkvoorraad' work as expected.
Expand Down
5 changes: 2 additions & 3 deletions src/zrc/api/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,5 @@ def get_absolute_url(url_name: str, uuid: str) -> str:
url_name,
kwargs={"version": settings.REST_FRAMEWORK["DEFAULT_VERSION"], "uuid": uuid},
)
domain = Site.objects.get_current().domain
protocol = "https" if settings.IS_HTTPS else "http"
return f"{protocol}://{domain}{path}"
domain = settings.ZRC_BASE_URL
return f"{domain}{path}"
3 changes: 3 additions & 0 deletions src/zrc/api/viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@

from .audits import AUDIT_ZRC
from .data_filtering import ListFilterByAuthorizationsMixin
from .expansions import ExpandFieldValidator, ExpansionMixin
from .filters import (
KlantContactFilter,
ResultaatFilter,
Expand Down Expand Up @@ -195,6 +196,8 @@ class ZaakViewSet(
GeoMixin,
SearchMixin,
CheckQueryParamsMixin,
ExpandFieldValidator,
ExpansionMixin,
ListFilterByAuthorizationsMixin,
viewsets.ModelViewSet,
):
Expand Down
4 changes: 2 additions & 2 deletions src/zrc/conf/includes/api.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
REST_FRAMEWORK["PAGE_SIZE"] = 100

DOCUMENTATION_INFO_MODULE = "zrc.api.schema"

ZRC_BASE_URL = os.getenv("ZRC_BASE_URL", "https://zaken-api.test.vng.cloud")
SPECTACULAR_SETTINGS = BASE_SPECTACULAR_SETTINGS.copy()
SPECTACULAR_SETTINGS.update(
{
Expand All @@ -17,7 +17,7 @@
# e.g. [{'url': 'https://example.com/v1', 'description': 'Text'}, ...]
"SERVERS": [
{
"url": "https://zaken-api.vng.cloud/api/v1",
"url": "https://zaken-api.vng.cloud/api/v1/",
"description": "Productie Omgeving",
}
],
Expand Down
1 change: 0 additions & 1 deletion src/zrc/sync/signals.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ class SyncError(Exception):

def sync_create_zio(relation: ZaakInformatieObject):
zaak_url = get_absolute_url("zaak-detail", relation.zaak.uuid)

logger.info("Zaak: %s", zaak_url)
logger.info("Informatieobject: %s", relation.informatieobject)

Expand Down

0 comments on commit 10a15d3

Please sign in to comment.