Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow usage of response of previous request in the same integration #357

Merged
merged 3 commits into from
Sep 29, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions back/admin/integrations/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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":
Expand Down
55 changes: 55 additions & 0 deletions back/admin/integrations/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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#"
)
20 changes: 19 additions & 1 deletion back/admin/integrations/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
8 changes: 8 additions & 0 deletions docs/Integrations.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.<index>.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.
Expand Down