def get_paginated_results( client: Client, resource: str, minimum=None, *args, **kwargs ) -> list: query_params = kwargs.get("query_params", {}) results = [] response = client.list(resource, *args, **kwargs) results += response["results"] if minimum and len(results) >= minimum: return results while response["next"]: next_url = urlparse(response["next"]) query = parse_qs(next_url.query) new_page = int(query["page"][0]) query_params["page"] = [new_page] kwargs["query_params"] = query_params response = client.list(resource, *args, **kwargs) results += response["results"] if minimum and len(results) >= minimum: return results return results
def test_set_client_base_url(): Client.load_config(CONFIG_FILE) client = Client("client1") client.base_url = "https://another.example" assert client.base_url == "https://another.example"
def ready(self): Client.load_config( vrl={ 'scheme': 'https', 'host': 'ref.tst.vng.cloud', 'port': 443, 'auth': None, })
def test_client_loading(): Client.load_config(zrc={ "scheme": "http", "host": "localhost", "port": 8000 }) client = Client("zrc") assert client.base_url == "http://localhost:8000/api/v1/"
def test_client_from_url_thread_safe(): client1 = Client.from_url( "https://example.com/api/v1/zaken/7C61204C-BFD8-4A66-B826-5DF8CB7F9A60" ) client2 = Client.from_url( "https://example2.com/api/v2/zaken/7C61204C-BFD8-4A66-B826-5DF8CB7F9A60" ) assert client1.base_url == "https://example.com/api/v1/" assert client2.base_url == "https://example2.com/api/v2/"
def test_client_from_static_config(): Client.load_config(CONFIG_FILE) client = Client("client1") assert ( repr(client) == "<Client: service='client1' base_url='https://example.com/api/v1/'>") assert client.base_url == "https://example.com/api/v1/" assert client.auth.client_id == "some-client-id" assert client.auth.secret == "oh-no"
def test_client_loading(): Client.load_config(zrc={ 'scheme': 'http', 'host': 'localhost', 'port': 8000, }) client = Client('zrc') assert client.base_url == 'http://localhost:8000/api/v1/' # reset class # FIXME: this is very un-pythonic, find a better caching solution Client.CONFIG = None
def sync_delete_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) # Define the remote resource with which we need to interact resource = "objectinformatieobject" client = Client.from_url(relation.informatieobject) client.auth = APICredential.get_auth(relation.informatieobject) # Retrieve the url of the relation between the object and # the informatieobject response = client.list( resource, query_params={ "object": zaak_url, "informatieobject": relation.informatieobject, }, ) try: relation_url = response[0]["url"] except IndexError as exc: msg = "No relations found in DRC for this Zaak" logger.error(msg, exc_info=1) raise IndexError(msg) from exc try: client.delete(resource, url=relation_url) except Exception as exc: logger.error(f"Could not delete remote relation", exc_info=1) raise SyncError(f"Could not delete remote relation") from exc
def test_load_with_auth(): Client.load_config( zrc={ "scheme": "http", "host": "localhost", "port": 8000, "auth": {"client_id": "foo", "secret": "bar"}, } ) client = Client("zrc") credentials = client.auth.credentials() assert "Authorization" in credentials bits = credentials["Authorization"].split(".") assert len(bits) == 3
def get_client(url: str, url_is_api_root=False) -> Optional[Client]: """ Get a client instance for the given URL. If the setting CUSTOM_CLIENT_FETCHER is defined, then this callable is invoked. Otherwise we fall back on the default implementation. If no suitable client is found, ``None`` is returned. """ custom_client_fetcher = getattr(settings, "CUSTOM_CLIENT_FETCHER", None) if custom_client_fetcher: client_getter = import_string(custom_client_fetcher) return client_getter(url) # default implementation Client = import_string(settings.ZDS_CLIENT_CLASS) if url_is_api_root and not url.endswith("/"): url = f"{url}/" client = Client.from_url(url) if client is None: return None APICredential = apps.get_model("vng_api_common", "APICredential") if url_is_api_root: client.base_url = url client.auth = APICredential.get_auth(url) return client
def get_client(cls) -> Client: """ Construct a client, prepared with the required auth. """ config = cls.get_solo() if getattr(settings, "CUSTOM_CLIENT_FETCHER", None): client = import_string(settings.CUSTOM_CLIENT_FETCHER)(config.api_root) return client else: Client = import_string(settings.ZDS_CLIENT_CLASS) api_root = config.api_root if not api_root: raise ImproperlyConfigured( f"Configure the API root in '{cls._meta.verbose_name}'" ) if not api_root.endswith("/"): api_root = f"{api_root}/" client = Client.from_url(api_root) client.base_url = api_root client.auth = APICredential.get_auth(api_root) return client
def sync_create(relation: ZaakInformatieObject): operation = 'create' # build the URL of the Zaak path = reverse('zaak-detail', kwargs={ 'version': settings.REST_FRAMEWORK['DEFAULT_VERSION'], 'uuid': relation.zaak.uuid, }) domain = Site.objects.get_current().domain protocol = 'https' if settings.IS_HTTPS else 'http' zaak_url = f'{protocol}://{domain}{path}' logger.info("Zaak: %s", zaak_url) logger.info("Informatieobject: %s", relation.informatieobject) # Define the remote resource with which we need to interact resource = 'objectinformatieobject' client = Client.from_url(relation.informatieobject) client.auth = APICredential.get_auth(relation.informatieobject) try: client.create( resource, { 'object': zaak_url, 'informatieobject': relation.informatieobject, 'objectType': 'zaak' }) except Exception as exc: logger.error(f"Could not {operation} remote relation", exc_info=1) raise SyncError(f"Could not {operation} remote relation") from exc
def sync(relation: ObjectInformatieObject, operation: str): # build the URL of the informatieobject path = reverse('enkelvoudiginformatieobject-detail', kwargs={ 'version': settings.REST_FRAMEWORK['DEFAULT_VERSION'], 'uuid': relation.informatieobject.uuid, }) domain = Site.objects.get_current().domain protocol = 'https' if settings.IS_HTTPS else 'http' informatieobject_url = f'{protocol}://{domain}{path}' logger.info("Remote object: %s", relation.object) logger.info("Informatieobject: %s", informatieobject_url) # figure out which remote resource we need to interact with resource = f"{relation.object_type}informatieobject" client = Client.from_url(relation.object) try: pattern = get_operation_url(client.schema, f'{resource}_{operation}', pattern_only=True) except ValueError as exc: raise SyncError("Could not determine remote operation") from exc # we enforce in the standard that it's a subresource so that we can do this. # The real resource URL is extracted from the ``openapi.yaml`` based on # the operation params = extract_params(f"{relation.object}/irrelevant", pattern) try: operation_function = getattr(client, operation) operation_function(resource, {'informatieobject': informatieobject_url}, **params) except Exception as exc: logger.error(f"Could not {operation} remote relation", exc_info=1) raise SyncError(f"Could not {operation} remote relation") from exc
def register(self) -> None: """ Registers the webhook with the notification component. """ dummy_detail_url = urljoin(self.config.api_root, f'foo/{uuid.uuid4()}') client = Client.from_url(dummy_detail_url) # This authentication is to create a subscription at the NC. client.auth = APICredential.get_auth( self.config.api_root, scopes=[SCOPE_NOTIFICATIES_CONSUMEREN_LABEL]) # This authentication is for the NC to call us. Thus, it's *not* for # calling the NC to create a subscription. self_auth = ClientAuth(client_id=self.client_id, secret=self.secret, scopes=[SCOPE_NOTIFICATIES_PUBLICEREN_LABEL]) data = { 'callbackUrl': self.callback_url, 'auth': self_auth.credentials()['Authorization'], 'kanalen': [ { "naam": channel, # FIXME: You need to be able to configure these. "filters": {}, } for channel in self.channels ], } # register the subscriber subscriber = client.create('abonnement', data=data) self._subscription = subscriber['url'] self.save(update_fields=['_subscription'])
def sync_create_zaakcontactmoment(relation: ZaakContactMoment): zaak_url = get_absolute_url("zaak-detail", relation.zaak.uuid) logger.info("Zaak: %s", zaak_url) logger.info("Contactmoment: %s", relation.contactmoment) # Define the remote resource with which we need to interact resource = "objectcontactmoment" client = Client.from_url(relation.contactmoment) client.auth = APICredential.get_auth(relation.contactmoment) try: response = client.create( resource, { "object": zaak_url, "contactmoment": relation.contactmoment, "objectType": "zaak", }, ) except Exception as exc: logger.error(f"Could not create remote relation", exc_info=1) raise SyncError(f"Could not create remote relation") from exc # save ZaakBesluit url for delete signal relation._objectcontactmoment = response["url"] relation.save()
def test_regression_double_slashes(): object_url = "http://example.com/api/v1/zaken/28dcfc90-2d26-4d4e-8261-a9202ee56185" client = Client.from_url(object_url) # prevents http request to fetch the schema client._schema = { "openapi": "3.0.0", "servers": [{"url": "/api/v1"}], "paths": { "/zaken/{zaak_uuid}/informatieobjecten": { "post": {"operationId": "zaakinformatieobject_create"} } }, } pattern = get_operation_url( client.schema, "zaakinformatieobject_create", pattern_only=True ) params = extract_params("{}/irrelevant".format(object_url), pattern) url = get_operation_url( client.schema, "zaakinformatieobject_create", base_url=client.base_url, **params ) assert ( url == "/api/v1/zaken/28dcfc90-2d26-4d4e-8261-a9202ee56185/informatieobjecten" )
def test_schema_with_local_references(): Client.load_config(dummy={"scheme": "https", "host": "example.com"}, ) client = Client("dummy") client._schema = { "openapi": "3.0.0", "servers": [{ "url": "/api/v1" }], "paths": { "/api/packages/{packageId}": { "get": { "tags": ["Packages"], "operationId": "api.packages._packageId.get", "summary": "Retrieves a specified package.", "description": "Retrieves information about a single document package.", "parameters": [{ "$ref": "#/components/parameters/packageId" }], } } }, "components": { "parameters": { "packageId": { "name": "packageId", "description": "The unique package id.", "in": "path", "required": True, "schema": { "type": "string", "example": "asd0sdf08gdfg3njkfg0345dg=", }, } } }, } # Parameter #/components/parameters/packageId has value of 'in' != "headers", so no headers will be returned headers = get_headers(spec=client._schema, operation="api.packages._packageId.get") assert headers == {}
def sync_delete_zaakverzoek(relation: ZaakVerzoek): resource = "objectverzoek" client = Client.from_url(relation.verzoek) client.auth = APICredential.get_auth(relation.verzoek) try: client.delete(resource, url=relation._objectverzoek) except Exception as exc: logger.error(f"Could not delete remote relation", exc_info=1) raise SyncError(f"Could not delete remote relation") from exc
def sync_delete_zaakcontactmoment(relation: ZaakContactMoment): resource = "objectcontactmoment" client = Client.from_url(relation.contactmoment) client.auth = APICredential.get_auth(relation.contactmoment) try: client.delete(resource, url=relation._objectcontactmoment) except Exception as exc: logger.error(f"Could not delete remote relation", exc_info=1) raise SyncError(f"Could not delete remote relation") from exc
def test_schema_non_required_header_params_in_local_references(): Client.load_config(dummy={"scheme": "https", "host": "example.com"}, ) client = Client("dummy") client._schema = { "openapi": "3.0.0", "servers": [{ "url": "/api/v1" }], "paths": { "/api/packages/": { "get": { "tags": ["Packages"], "operationId": "api.packages._packageId.get", "summary": "Retrieves a specified package.", "description": "Retrieves information about a single document package.", "parameters": [{ "$ref": "#/components/parameters/testHeader" }], } } }, "components": { "parameters": { "testHeader": { "in": "header", "name": "Accept-Crs", "description": "test param", "schema": { "type": "string", "enum": ["EPSG:4326"] }, }, } }, } headers = get_headers(spec=client._schema, operation="api.packages._packageId.get") assert headers == {}
def test_load_with_auth(): Client.load_config(zrc={ 'scheme': 'http', 'host': 'localhost', 'port': 8000, 'auth': { 'client_id': 'foo', 'secret': 'bar', } }) client = Client('zrc') credentials = client.auth.credentials() assert 'Authorization' in credentials bits = credentials['Authorization'].split('.') assert len(bits) == 3 # reset class # FIXME: this is very un-pythonic, find a better caching solution Client.CONFIG = None
def get_client(self): """ Return a properly configured `Client` instance. :return: A `Client` instance. """ base_path = '' if self.base_url: o = urlparse(self.base_url) base_path = o.path return Client('ztc', base_path)
def test_partial_update_request(): auth = {"client_id": "yes", "secret": "oh-no"} Client.load_config(dummy={ "scheme": "https", "host": "example.com", "auth": auth }) client = Client("dummy") client._schema = SCHEMA with requests_mock.Mocker() as m: m.patch( "https://example.com/api/v1/some-resource/1", json={"id": 1}, status_code=200, ) response = client.partial_update("some-resource", id=1, data={"foo": "bar"}) assert response["id"] == 1 assert m.last_request.json() == {"foo": "bar"} assert m.last_request.method == "PATCH" assert "Authorization" in m.last_request.headers
def test_create_request_extra_headers(): auth = {"client_id": "yes", "secret": "oh-no"} Client.load_config(dummy={ "scheme": "https", "host": "example.com", "auth": auth }) client = Client("dummy") client._schema = SCHEMA with requests_mock.Mocker() as m: m.post("https://example.com/api/v1/some-resource", json={"id": 1}, status_code=201) response = client.create( "some-resource", data={"foo": "bar"}, request_kwargs={"headers": { "X-Api-Version": "1.0.2" }}, ) assert response["id"] == 1 assert m.last_request.json() == {"foo": "bar"} assert m.last_request.headers["X-Api-Version"] == "1.0.2"
def get_client(self, service): """ Return a properly configured `Client` instance. :param service: The service key for this client. :return: A `Client` instance. """ base_url = getattr(self, '{}_base_url'.format(service)) base_path = '' if base_url: o = urlparse(base_url) base_path = o.path return Client(service, base_path)
def __init__(self): config = { 'zrc': { 'scheme': settings.ZRC_SCHEME, 'host': settings.ZRC_HOST, 'port': settings.ZRC_PORT, 'auth': settings.ZRC_AUTH, }, 'drc': { 'scheme': settings.DRC_SCHEME, 'host': settings.DRC_HOST, 'port': settings.DRC_PORT, 'auth': settings.DRC_AUTH, }, 'ztc': { 'scheme': settings.ZTC_SCHEME, 'host': settings.ZTC_HOST, 'port': settings.ZTC_PORT, 'auth': settings.ZTC_AUTH, } } Client.load_config(**config)
class SelectieLijstProcestypenListView(ZACViewMixin, TemplateView): template_name = 'demo/selectielijst/procestype_list.html' title = 'Selectielijst' subtitle = 'Procestypen/resultaten ter ondersteuning van ZTC' def _pre_dispatch(self, request, *args, **kwargs): self.vrl_client = Client('vrl', base_path='/referentielijsten/api/v1/') def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) procestypen = self.vrl_client.list('procestype') context['rows'] = procestypen return context
def test_read_request_explicit_url(): Client.load_config(dummy={"scheme": "https", "host": "example.com"}) client = Client("dummy") client._schema = SCHEMA resource_url = "https://example.com/api/v1/some-resource/2" with requests_mock.Mocker() as m: m.get(resource_url, json={"ok": "yarp"}) response = client.retrieve("some-resource", url=resource_url) assert response == {"ok": "yarp"} assert m.last_request.url == resource_url
def test_delete_request(): auth = {"client_id": "yes", "secret": "oh-no"} Client.load_config(dummy={ "scheme": "https", "host": "example.com", "auth": auth }) client = Client("dummy") client._schema = SCHEMA with requests_mock.Mocker() as m: m.delete("https://example.com/api/v1/some-resource/1", status_code=204) client.delete("some-resource", id=1) assert m.last_request.method == "DELETE" assert "Authorization" in m.last_request.headers
def test_kwargs_forwarded_to_requests(): Client.load_config(dummy={"scheme": "https", "host": "example.com"}) client = Client("dummy") client._schema = SCHEMA with requests_mock.Mocker() as m: m.get("https://example.com/api/v1/some-resource", json=[{"ok": "yes"}]) client.list( "some-resource", request_kwargs={"headers": { "Other-Header": "value", }}, ) assert "Other-Header" in m.last_request.headers assert m.last_request.headers["Other-Header"] == "value"