From bc4eba21f44ebe7201e8b61e3b58341e4b297fc7 Mon Sep 17 00:00:00 2001 From: GDay <1939656+GDay@users.noreply.github.com> Date: Wed, 20 Sep 2023 00:30:41 +0200 Subject: [PATCH 1/2] Add usage of previous result in the same integration --- back/admin/integrations/models.py | 4 +++ back/admin/integrations/tests.py | 55 +++++++++++++++++++++++++++++++ back/admin/integrations/utils.py | 20 ++++++++++- docs/Integrations.md | 8 +++++ 4 files changed, 86 insertions(+), 1 deletion(-) diff --git a/back/admin/integrations/models.py b/back/admin/integrations/models.py index 2e3c9bc9f..8bb15f742 100644 --- a/back/admin/integrations/models.py +++ b/back/admin/integrations/models.py @@ -243,6 +243,7 @@ def renew_key(self): def execute(self, new_hire, params): self.params = params + self.params["responses"] = [] if self.has_user_context: self.params |= new_hire.extra_fields self.new_hire = new_hire @@ -288,6 +289,9 @@ def execute(self, new_hire, params): pass return False, response + # save json response temporarily to be reused in other parts + self.params["responses"].append(response) + # Run all post requests (notifications) for item in self.manifest.get("post_execute_notification", []): if item["type"] == "email": diff --git a/back/admin/integrations/tests.py b/back/admin/integrations/tests.py index 0694b4e0e..5ef5d84fc 100644 --- a/back/admin/integrations/tests.py +++ b/back/admin/integrations/tests.py @@ -7,6 +7,7 @@ from django.urls import reverse from django.utils import timezone +from admin.integrations.utils import get_value_from_notation from admin.integrations.models import Integration from organization.models import Notification @@ -491,3 +492,57 @@ def test_slack_connect(client, django_user_model): assert Integration.objects.filter(integration=Integration.Type.SLACK_BOT).exists() assert "Slack has successfully been connected." in response.content.decode() + + +@pytest.mark.django_db +def test_get_value_from_notation(): + # test deep lookup through dictionaries + test_data = {"one": {"0": {"deep": "yes"}}} + + # the 0 gets used as a prop + result = get_value_from_notation("one.0.deep", test_data) + assert result == "yes" + + # test lookup with array inbetween + test_data = {"one": [{"deep": "yes"}]} + + # the 0 gets used as the index for the array + result = get_value_from_notation("one.0.deep", test_data) + assert result == "yes" + + # test invalid lookup with array inbetween + test_data = {"one": [{"deep": "yes"}]} + + # the 1 gets used as the index for the array, but we don't have it, so raise error + with pytest.raises(KeyError): + get_value_from_notation("one.1.deep", test_data) + + # test normal invalid lookup + test_data = {"one": "yes"} + with pytest.raises(KeyError): + get_value_from_notation("two", test_data) + + +@pytest.mark.django_db +@patch( + "admin.integrations.models.Integration.run_request", + Mock(return_value=(True, {"details": "DOSOMETHING#"})), +) +def test_integration_reuse_data_from_previous_request( + client, django_user_model, new_hire_factory, custom_integration_factory +): + client.force_login( + django_user_model.objects.create(role=get_user_model().Role.ADMIN) + ) + integration = custom_integration_factory( + manifest={ + "execute": [{"url": "http://localhost/", "method": "POST"}], + }, + ) + new_hire = new_hire_factory() + integration.execute(new_hire, {}) + assert integration.params["responses"] == [{"details": "DOSOMETHING#"}] + + assert ( + integration._replace_vars("test {{responses.0.details}}") == "test DOSOMETHING#" + ) diff --git a/back/admin/integrations/utils.py b/back/admin/integrations/utils.py index 5527e1f4e..fd4f8a5fa 100644 --- a/back/admin/integrations/utils.py +++ b/back/admin/integrations/utils.py @@ -5,5 +5,23 @@ def get_value_from_notation(notation, value): notations = notation.split(".") for notation in notations: - value = value[notation] + try: + value = value[notation] + except TypeError: + # check if array + if not isinstance(value, list): + raise + + try: + index = int(notation) + except TypeError: + # keep errors consistent, we are only expecting a KeyError + raise KeyError + + try: + value = value[index] + except IndexError: + # keep errors consistent, we are only expecting a KeyError + raise KeyError + return value diff --git a/docs/Integrations.md b/docs/Integrations.md index 0723366af..32ccaee73 100644 --- a/docs/Integrations.md +++ b/docs/Integrations.md @@ -135,6 +135,14 @@ Throughout the manifest you can use the variables that you have defined in the ` Please do not overwrite these with your own ids !!! +You can also use data from previous requests. If you have an integration with 3 requests, you can use the data from the request 1 in request 2 and the data from request 1 and 2 in request 3. You can do that by using: `{{ responses..the_data_you_need }}` (index starts at 0). So for example, you get this response from the first request: +``` +{ + "form_id": 134 +} +``` +You can then use `{{ responses.0.form_id }}` in any of the following requests in the same integration. + ## Notes * If triggering an integration fails, then it will retry the entire integration again one hour after failing. If it fails again, it will not retry. From 1938f5fc8f3c782178c00a56103a1ece56656c22 Mon Sep 17 00:00:00 2001 From: Stan Triepels <1939656+GDay@users.noreply.github.com> Date: Fri, 29 Sep 2023 12:54:24 +0200 Subject: [PATCH 2/2] Update tests.py --- back/admin/integrations/tests.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/back/admin/integrations/tests.py b/back/admin/integrations/tests.py index a9cfb588f..639980850 100644 --- a/back/admin/integrations/tests.py +++ b/back/admin/integrations/tests.py @@ -523,6 +523,7 @@ def test_get_value_from_notation(): get_value_from_notation("two", test_data) +@pytest.mark.django_db @patch( "admin.integrations.models.Integration.run_request", Mock(return_value=(True, Mock(json=lambda: {"user_data": {"user_id": 123}}))), @@ -549,7 +550,7 @@ def test_integration_save_data_to_user(new_hire_factory, custom_integration_fact assert new_hire.extra_fields == {"FORM_ID": 123} - + @pytest.mark.django_db @patch( "admin.integrations.models.Integration.run_request",