Skip to content

Commit 143499b

Browse files
authored
Merge pull request #25 from dataiku/bug/sc-99081-escape-dots-w-json-path
Bug/sc 99081 escape dots using json path
2 parents f80ccdc + 228d4b4 commit 143499b

8 files changed

Lines changed: 41 additions & 25 deletions

File tree

CHANGELOG.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
# Changelog
22

33

4-
## [Version 1.0.7](https://github.com/dataiku/dss-plugin-api-connect/releases/tag/v1.0.7) - Bugfix release - 2022-08-30
4+
## [Version 1.1.0](https://github.com/dataiku/dss-plugin-api-connect/releases/tag/v1.1.0) - Feature and bugfix release - 2022-09-15
55

66
- Handling Offset pagination on APIs returning an array
77
- Fix throttling calculation
8+
- Allow dots in `Key to next request URL`
9+
- Add NTLM authentication
810

911
## [Version 1.0.6](https://github.com/dataiku/dss-plugin-api-connect/releases/tag/v1.0.6) - Feature and bugfix release - 2022-05-19
1012

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
jsonpath-ng==1.5.3
2+
requests_ntlm==1.1.0

parameter-sets/credential/parameter-set.json

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@
3838
{
3939
"value": "bearer_token",
4040
"label": "Bearer token"
41+
},
42+
{
43+
"value": "ntlm",
44+
"label": "NTLM"
4145
}
4246
]
4347
},
@@ -46,14 +50,14 @@
4650
"label": "User name",
4751
"description": "Can be reused as {{username}}",
4852
"type": "STRING",
49-
"visibilityCondition": "model.login_type == 'basic_login'"
53+
"visibilityCondition": "['basic_login', 'ntlm'].includes(model.login_type)"
5054
},
5155
{
5256
"name": "password",
5357
"label": "Password",
5458
"description": "Can be reused as {{password}}",
5559
"type": "PASSWORD",
56-
"visibilityCondition": "model.login_type == 'basic_login'"
60+
"visibilityCondition": "['basic_login', 'ntlm'].includes(model.login_type)"
5761
},
5862
{
5963
"name": "token",

plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"id": "api-connect",
3-
"version": "1.0.7",
3+
"version": "1.1.0",
44
"meta": {
55
"label": "API Connect",
66
"description": "Retrieve data from any REST API",

python-lib/dku_utils.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import json
22
import copy
3+
from jsonpath_ng.ext import parse
34

45

56
def get_dku_key_values(endpoint_query_string):
@@ -46,7 +47,7 @@ def parse_keys_for_json(items):
4647
def get_value_from_path(dictionary, path, default=None, can_raise=True):
4748
ret = copy.deepcopy(dictionary)
4849
for key in path:
49-
if key in ret and isinstance(ret, dict):
50+
if isinstance(ret, dict) and (key in ret):
5051
ret = ret.get(key)
5152
else:
5253
error_message = "The extraction path {} was not found in the incoming data".format(path)
@@ -84,3 +85,12 @@ def format_template(template, **kwargs):
8485
def is_string(data):
8586
data_type = type(data).__name__
8687
return data_type in ["str", "unicode"]
88+
89+
90+
def extract_key_using_json_path(json_dictionary, json_path):
91+
matches = parse(json_path).find(json_dictionary)
92+
if matches:
93+
res = matches[0].value
94+
return res
95+
else:
96+
return None

python-lib/pagination.py

Lines changed: 4 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from safe_logger import SafeLogger
2-
from dku_utils import get_value_from_path
2+
from dku_utils import get_value_from_path, extract_key_using_json_path
33

44

55
logger = SafeLogger("api-connect plugin Pagination")
@@ -32,7 +32,7 @@ def configure_paging(self, config=None, skip_key=None, limit_key=None, total_key
3232
self.pagination_type = config.get("pagination_type", pagination_type)
3333
if self.pagination_type == "next_page":
3434
self.next_page_key = config.get("next_page_key", next_page_key)
35-
self.next_page_key = None if self.next_page_key == [''] else self.next_page_key
35+
self.next_page_key = None if self.next_page_key == '' else self.next_page_key
3636
elif self.pagination_type in ["offset", "page"]:
3737
self.skip_key = config.get("skip_key", skip_key)
3838

@@ -80,8 +80,8 @@ def update_next_page(self, data, response_links=None):
8080
self.is_last_batch_empty = True
8181
else:
8282
batch_size = 1
83-
if self.next_page_key and (len(self.next_page_key) > 0):
84-
self.next_page_url = self.get_from_path(data, self.next_page_key)
83+
if self.next_page_key:
84+
self.next_page_url = extract_key_using_json_path(data, self.next_page_key)
8585
if self.skip_key:
8686
self.skip = data.get(self.skip_key)
8787
if self.limit_key:
@@ -92,17 +92,6 @@ def update_next_page(self, data, response_links=None):
9292
if self.total:
9393
self.remaining_records = self.total - self.records_to_skip
9494

95-
def get_from_path(self, dictionary, path):
96-
if isinstance(path, list):
97-
edge = dictionary
98-
for key in path:
99-
edge = edge.get(key)
100-
if edge is None:
101-
return None
102-
return edge
103-
else:
104-
return dictionary.get(path)
105-
10695
def has_next_page(self):
10796
if self.is_last_batch_empty:
10897
logger.info("has_next_page:last was batch empty -> False")

python-lib/rest_api_client.py

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ def __init__(self, credential, endpoint, custom_key_values={}):
6060

6161
self.requests_kwargs.update({"params": self.params})
6262
self.pagination = Pagination()
63-
next_page_url_key = endpoint.get("next_page_url_key", "").split('.')
63+
next_page_url_key = endpoint.get("next_page_url_key", "")
6464
top_key = endpoint.get("top_key")
6565
skip_key = endpoint.get("skip_key")
6666
pagination_type = endpoint.get("pagination_type", "na")
@@ -92,10 +92,16 @@ def __init__(self, credential, endpoint, custom_key_values={}):
9292
def set_login(self, credential):
9393
login_type = credential.get("login_type", "no_auth")
9494
if login_type == "basic_login":
95-
self.username = credential.get("username", "")
96-
self.password = credential.get("password", "")
97-
self.auth = (self.username, self.password)
98-
self.requests_kwargs.update({"auth": self.auth})
95+
username = credential.get("username", "")
96+
password = credential.get("password", "")
97+
auth = (username, password)
98+
self.requests_kwargs.update({"auth": auth})
99+
if login_type == "ntlm":
100+
from requests_ntlm import HttpNtlmAuth
101+
username = credential.get("username", "")
102+
password = credential.get("password", "")
103+
auth = HttpNtlmAuth(username, password)
104+
self.requests_kwargs.update({"auth": auth})
99105
if login_type == "bearer_token":
100106
token = credential.get("token", "")
101107
bearer_template = credential.get("bearer_template", "Bearer {{token}}")

tests/python/integration/test_scenario.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,3 +33,6 @@ def test_run_api_connect_redirection(user_dss_clients):
3333

3434
def test_run_api_connect_check_sc_84465(user_dss_clients):
3535
dss_scenario.run(user_dss_clients, project_key=TEST_PROJECT_KEY, scenario_id="CHECKSC84465")
36+
37+
def test_run_api_connect_ntlm_authentication(user_dss_clients):
38+
dss_scenario.run(user_dss_clients, project_key=TEST_PROJECT_KEY, scenario_id="NTLMAUTHENTICATION")

0 commit comments

Comments
 (0)